@condorinst/mobile-bridge 0.15.2 → 0.17.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/CHANGELOG.md CHANGED
@@ -7,6 +7,79 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.17.0] — 2026-09-01
11
+
12
+ ### Added
13
+
14
+ - **The shell now relays `nativeVersion` to the sandboxed client.**
15
+ `BridgeClientHandshakeAck` gains `nativeVersion: string | null`, and the shell
16
+ performs the native handshake on the client's behalf to fill it in.
17
+
18
+ This closes a hole the 0.16.0 docs walked straight into. Those docs told
19
+ consumers to "check `nativeVersion` from the handshake ack" before relying on
20
+ the new raw light channels — but a client lives inside a sandboxed iframe and
21
+ handshakes with the *shell*, not the native, and the shell answered with
22
+ `shellVersion` alone. The check was impossible to perform. Worse, nothing in
23
+ the SDK ever called `Bridge.handshake`, so the native version was not merely
24
+ unreachable from the client: nobody obtained it at all.
25
+
26
+ `null` means the native has not answered (or does not exist, as in a browser
27
+ mock) and is honest information, not a placeholder. `Bridge.handshake` has no
28
+ timeout of its own, so the shell bounds the wait at 2s and answers the client
29
+ either way — without that, a client in a browser would hang forever waiting
30
+ for a handshake that never resolves.
31
+
32
+ ### Changed
33
+
34
+ - **The shell touches the native during the client handshake.** Until 0.16.x it
35
+ answered immediately and deliberately did not; a test asserted exactly that.
36
+ That test now asserts the relay instead. Clients see one extra round-trip on
37
+ handshake, bounded at 2s.
38
+ - `SHELL_VERSION` 0.5.1 → 0.6.0.
39
+ - `client_demo` logs `nativeVersion` alongside `shellVersion`, which is how an
40
+ E2E confirms which native it is actually talking to.
41
+
42
+ ## [0.16.0] — 2026-09-01
43
+
44
+ ### Added
45
+
46
+ - **`deviceLightSensors` now carries the raw sensor channels, not just the
47
+ derived spectrum.** Every reading gains `light_sensor_f1..f8`,
48
+ `light_sensor_clear`, `light_sensor_nir` and — on gen2 —
49
+ `light_sensor_z`, `light_sensor_y`, `light_sensor_x`, `light_sensor_fd`.
50
+
51
+ Until now only the matrix output (`wavelength*`) plus `melanopic`/`photopic`
52
+ crossed the bridge; the channels those values were computed from disappeared
53
+ by name. That cost a full day of misdiagnosis: a probe reading
54
+ `data.lightSensor11` got `undefined`, coalesced it with `?? 0`, and reported
55
+ a flat zero for a device that was recording 252.9 lux at that very minute.
56
+ The channels now use the **same names the backend uses** in `user_cmd=log`,
57
+ so history and real time share one vocabulary.
58
+
59
+ On gen1 the four channels the hardware does not have are emitted as `null` —
60
+ present in the schema, absent in the device. `null` means "no such channel",
61
+ never "read zero": `0.0` is a valid reading, and `light_sensor_fd` is
62
+ routinely exactly `0`.
63
+
64
+ Requires **native 0.16.0**. A bundle built against this SDK still runs on an
65
+ older native, which simply will not emit the fields — check `nativeVersion`
66
+ from the handshake ack, or read defensively.
67
+
68
+ ### Changed
69
+
70
+ - **BREAKING (permitted under 0.x): `DeviceLightSensorsPayload.data` is no
71
+ longer `Record<string, unknown>`.** It is now a discriminated union on
72
+ `type`, so `'actlumus'` narrows to `LightSensorsActlumus1Data` (10
73
+ wavelengths, 390–750) and `'actlumus2'` to `LightSensorsActlumus2Data` (14
74
+ wavelengths, 395–800). The two generations share **no** wavelength key, and
75
+ the old permissive type let that mismatch compile: a chart reading the gen1
76
+ list from a gen2 device found `undefined` in every series and rendered blank.
77
+
78
+ Both members are object literal types rather than interfaces, so code that
79
+ still passes `data` around as `Record<string, unknown>` keeps compiling.
80
+ `LightSensorsActlumus1Data`, `LightSensorsActlumus2Data` and
81
+ `LightSensorsRawChannels` are exported.
82
+
10
83
  ## [0.15.2] — 2026-08-31
11
84
 
12
85
  ### Fixed
package/README.md CHANGED
@@ -211,7 +211,7 @@ are what the JS receives via `window.CondorBridge.emit(key, payload)`.
211
211
  |---|---|---|---|
212
212
  | `pingPong` | `'pingPong'` | `PingPongPayload = { data: 'ping' \| 'pong' }` | bidirectional |
213
213
  | `userDevice` | `'userDevice'` | `UserDevicePayload = { lastUpdate, devicesConfig[], devicesTelemetry[], devicesUserConfig[] }` | BG → JS |
214
- | `deviceLightSensors` | `'deviceLightSensors'` | `DeviceLightSensorsPayload = { serialNo, type, data }` | BG → JS |
214
+ | `deviceLightSensors` | `'deviceLightSensors'` | `DeviceLightSensorsPayload` — discriminated by `type`: `{ serialNo, type: 'actlumus', data: LightSensorsActlumus1Data }` \| `{ serialNo, type: 'actlumus2', data: LightSensorsActlumus2Data }`. `data` carries the derived spectrum **and** the raw channels (`light_sensor_*`, native ≥ 0.16.0) | BG → JS |
215
215
  | `syncTime` | `'syncTime'` | `SyncTimeAckPayload = { serialNo, success }` | JS → BG (cmd) / BG → JS (ack) |
216
216
  | `realTime` | `'realTime'` | `RealTimeAckPayload = { serialNo, success, value }` | JS → BG (cmd) / BG → JS (state) |
217
217
  | `deleteMemory` | `'deleteMemory'` | `DeleteMemoryAckPayload = { serialNo, success }` | JS → BG (cmd) / BG → JS (ack) |
package/dist/index.cjs CHANGED
@@ -671,6 +671,8 @@ function onMessage(event) {
671
671
  pendingHandshake2 = null;
672
672
  resolve({
673
673
  shellVersion: msg.ack?.shellVersion ?? "unknown",
674
+ // `?? null` cobre o shell anterior à 0.17.0, que não mandava o campo.
675
+ nativeVersion: msg.ack?.nativeVersion ?? null,
674
676
  accepted: msg.ack?.accepted ?? false
675
677
  });
676
678
  }
@@ -829,6 +831,15 @@ var HandshakeAckMessage = v.object({
829
831
  type: v.literal("handshake-ack"),
830
832
  ack: v.object({
831
833
  shellVersion: v.string(),
834
+ /**
835
+ * Versão do schema declarada pelo **nativo**, repassada pelo shell.
836
+ *
837
+ * `null` quando o nativo ainda não respondeu (ou não existe, como no
838
+ * mock de browser). O cliente roda dentro de um iframe sandboxed e não
839
+ * fala com o nativo diretamente, então este é o **único** caminho pelo
840
+ * qual ele descobre de qual versão são as capacidades disponíveis.
841
+ */
842
+ nativeVersion: v.nullable(v.string()),
832
843
  accepted: v.boolean()
833
844
  })
834
845
  });
@@ -849,7 +860,8 @@ var ShellToClientMessage = v.variant("type", [
849
860
  ]);
850
861
 
851
862
  // src/bridge-shell.ts
852
- var SHELL_VERSION = "0.5.1";
863
+ var SHELL_VERSION = "0.6.0";
864
+ var NATIVE_HANDSHAKE_TIMEOUT_MS = 2e3;
853
865
  var VERIFY_TIMEOUT_MS = 2e3;
854
866
  var OVERRIDE_PREFIX = `<script>
855
867
  (function(){
@@ -887,6 +899,13 @@ var BridgeShell = class {
887
899
  constructor(opts) {
888
900
  this.subscriptions = /* @__PURE__ */ new Map();
889
901
  this.detached = false;
902
+ /**
903
+ * Versão do nativo, obtida uma vez e cacheada. `null` até o nativo
904
+ * responder — e permanentemente `null` num browser sem nativo.
905
+ */
906
+ this.nativeVersion = null;
907
+ /** Handshake com o nativo em voo; garante uma única chamada. */
908
+ this.nativeHandshake = null;
890
909
  // Map de `verify-sandbox` round-trips pendentes — key gerada por nonce.
891
910
  this.pendingVerifies = /* @__PURE__ */ new Map();
892
911
  this.onMessage = async (event) => {
@@ -911,9 +930,11 @@ var BridgeShell = class {
911
930
  await this.handleSend(msg.command, msg.args ?? {});
912
931
  break;
913
932
  case "handshake":
914
- this.postToClient({
915
- type: "handshake-ack",
916
- ack: { shellVersion: SHELL_VERSION, accepted: true }
933
+ void this.resolveNativeVersion().then((nativeVersion) => {
934
+ this.postToClient({
935
+ type: "handshake-ack",
936
+ ack: { shellVersion: SHELL_VERSION, nativeVersion, accepted: true }
937
+ });
917
938
  });
918
939
  break;
919
940
  case "jsError":
@@ -1092,6 +1113,29 @@ var BridgeShell = class {
1092
1113
  }
1093
1114
  Bridge.send(command, args);
1094
1115
  }
1116
+ /**
1117
+ * Obtém o `nativeVersion`, disparando o handshake com o nativo na primeira
1118
+ * vez e cacheando o resultado.
1119
+ *
1120
+ * ⚠️ `Bridge.handshake` **não tem timeout**: a Promise só resolve quando o
1121
+ * nativo emite `handshake-ack`. Num browser sem nativo ela nunca resolve,
1122
+ * então o `race` abaixo é o que garante que o cliente sempre receba
1123
+ * resposta — com `null` — em vez de ficar pendurado.
1124
+ */
1125
+ async resolveNativeVersion() {
1126
+ if (this.nativeVersion !== null) return this.nativeVersion;
1127
+ if (!this.nativeHandshake) {
1128
+ this.nativeHandshake = Bridge.handshake({ clientVersion: SHELL_VERSION }).then((ack) => {
1129
+ this.nativeVersion = ack.nativeVersion;
1130
+ }).catch(() => {
1131
+ });
1132
+ }
1133
+ await Promise.race([
1134
+ this.nativeHandshake,
1135
+ new Promise((resolve) => setTimeout(resolve, NATIVE_HANDSHAKE_TIMEOUT_MS))
1136
+ ]);
1137
+ return this.nativeVersion;
1138
+ }
1095
1139
  postToClient(msg) {
1096
1140
  if (this.detached) return;
1097
1141
  this.iframe.contentWindow?.postMessage(msg, "*");
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/keys.ts","../src/internal/dev-panel.ts","../src/internal/mock.ts","../src/internal/native.ts","../src/internal/subscribers.ts","../src/bridge.ts","../src/bridge-client.ts","../src/bridge-shell.ts","../src/shell-messages.ts"],"sourcesContent":["/**\n * `condor-mobile-bridge` — SDK do bridge JS↔Native do app white-label Condor.\n *\n * Public API: `Bridge` singleton + tipos.\n *\n * Import side effect: instala `window.CondorBridge.emit` no primeiro\n * carregamento do módulo, para que o nativo possa chamar via\n * `evaluateJavascript(\"window.CondorBridge.emit('key', payload)\")`. Para\n * que esta instalação aconteça **antes** do nativo tentar emitir, o\n * import deste módulo deve ser um dos primeiros statements do bundle do\n * cliente.\n *\n * **v0.2.0:** mock mode — quando `window.flutter_inappwebview` não é\n * detectado (browser comum, Storybook, Vite dev server), o adapter ativa\n * automaticamente. `Bridge.isMock`/`mockEmit`/`getMockState`/`installDevPanel`\n * expostos para suporte ao desenvolvimento.\n *\n * **v0.4.0:** tipos estritos por chave em `PayloadOf<K>`. `Bridge.on<K>`\n * infere o payload tipado por chave catalogada. Chaves não-catalogadas\n * caem no fallback permissivo (`Record<string, unknown>`).\n *\n * **v0.5.0:** introduz `BridgeClient` (API para código de cliente externo\n * dentro de `<iframe sandbox=\"allow-scripts\">`) e `BridgeShell` (API\n * para o shell Condor-controlado que envolve o iframe). Comunicação\n * shell↔client via `window.postMessage` com schema Valibot + policy\n * default-deny. Defesa em 4 camadas contra propagação do\n * `window.flutter_inappwebview` ao iframe (vide\n * `condor_wiki/cross-cutting/sleep-white-label-content-transport-and-security.md`\n * §Risco 1).\n *\n * **v0.14.0:** chave observável `language` — o nativo informa o locale cru do\n * aparelho **e** o idioma escolhido nos ajustes do app (ou `null` quando não\n * houve escolha), para o cliente aplicar a própria regra de precedência e poder\n * renderizar idiomas que a camada nativa não suporta. Vide `LanguagePayload`.\n */\n\nexport type { CondorBridge, MockState } from './bridge';\nexport { Bridge } from './bridge';\nexport type { BridgeClientHandshakeAck, CondorBridgeClient } from './bridge-client';\nexport { BridgeClient } from './bridge-client';\nexport type { BridgeShellOptions } from './bridge-shell';\nexport { BridgeShell } from './bridge-shell';\nexport type { AutoRespondResponse, DevPanelOptions } from './internal/dev-panel';\nexport type { MockMessage } from './internal/mock';\nexport type { BridgeKey } from './keys';\nexport { BRIDGE_KEYS } from './keys';\nexport type {\n BridgeIncomingMessage,\n BridgeOutgoingEvent,\n HandshakeAck,\n HandshakeOptions,\n} from './messages';\nexport type {\n DeleteMemoryAckPayload,\n DeviceConnectionPayload,\n DeviceLightSensorsPayload,\n DeviceNotificationPayload,\n KeyPayloads,\n LanguagePayload,\n PayloadOf,\n PingPongPayload,\n RealTimeAckPayload,\n RequestPermissionPayload,\n SensorLogPayload,\n SensorLogQueryPayload,\n SyncTimeAckPayload,\n SystemStatusPayload,\n UserDevicePayload,\n} from './payloads';\nexport type {\n ClientToShellMessage,\n ConfirmationRequest,\n SandboxVerifyResult,\n ShellPolicy,\n ShellToClientMessage,\n} from './shell-messages';\n","/**\n * Catálogo das chaves do bridge JS↔Native.\n *\n * Espelha o lado JS-facing de `ForegroundComCoreKeys` do `condor_core`\n * (monorepo `mobile_applications`). As strings aqui são o que o JS recebe\n * via `window.CondorBridge.emit(key, payload)`.\n *\n * Camada 1 (v0.1.0): catálogo declarativo. Apenas `pingPong` está\n * efetivamente emitida pelo lado Dart no Trio B; as outras 8 são\n * reservadas para o Trio C (`sleep-whitelabel-bridge-keys`) e ficam\n * aqui como contrato forward-looking.\n */\nexport const BRIDGE_KEYS = {\n pingPong: 'pingPong',\n userDevice: 'userDevice',\n deviceLightSensors: 'deviceLightSensors',\n syncTime: 'syncTime',\n realTime: 'realTime',\n deleteMemory: 'deleteMemory',\n deviceNotification: 'deviceNotification',\n deviceConnection: 'deviceConnection',\n sensorLog: 'sensorLog',\n dfu: 'dfu',\n systemStatus: 'systemStatus',\n /**\n * Native → client: o back do SO foi pressionado e o cliente reportou\n * ter histórico interno (`reportNavigation(true)`). O cliente deve voltar\n * UMA página interna. Emitido só quando o nativo decidiu delegar o back\n * ao cliente. Vide `BridgeClient.onBack`.\n */\n navigationBack: 'navigationBack',\n /**\n * Native → client: the app's language state. Carries the raw device locale\n * AND the language explicitly chosen in the app Settings, so the client can\n * apply its own precedence rule — including rendering a language the native\n * chrome does not support. Emitted on attach, after `handshake-ack`, and on\n * every change in Settings. Vide `LanguagePayload`.\n */\n language: 'language',\n} as const;\n\nexport type BridgeKey = (typeof BRIDGE_KEYS)[keyof typeof BRIDGE_KEYS];\n","/**\n * Dev panel — UI flutuante para inspecionar o bridge em mock mode.\n *\n * **Opt-in:** chamar `Bridge.installDevPanel(opts?)` quando quiser ver\n * o painel. Só funciona em mock mode (throws em modo real). Injeta no\n * `document.body`; idempotente (re-install remove o anterior).\n *\n * Conteúdo:\n * - Header com badge \"MOCK\", contador de sends, botão minimizar/maximizar.\n * - Sent log — últimas N mensagens (timestamp, type, payload truncado).\n * - Trigger emit — dropdown com `BRIDGE_KEYS` + textarea payload + botão.\n *\n * Estilos inline + classes prefixadas `condor-mock-panel-*` para reduzir\n * conflito com CSS do cliente.\n */\n\nimport { BRIDGE_KEYS } from '../keys';\nimport type { MockAdapter, MockMessage } from './mock';\n\nconst PANEL_ID = 'condor-mock-panel-root';\nconst REFRESH_INTERVAL_MS = 500;\n\n/**\n * Resposta auto-emitida em reação a um `Bridge.send`, retornada pela\n * policy `onSendForAutoRespond` do cliente. `null` significa \"não\n * responder a este send\".\n *\n * @since v0.3.0\n */\nexport interface AutoRespondResponse {\n key: string;\n payload: unknown;\n}\n\nexport interface DevPanelOptions {\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n maxMessages?: number;\n theme?: 'dark' | 'light';\n startCollapsed?: boolean;\n\n /**\n * Policy de auto-respond: invocada a cada `Bridge.send` quando o\n * toggle \"Auto-respond\" está ligado no painel. Retorna\n * `{key, payload}` para disparar `Bridge.mockEmit(key, payload)`\n * após delay, ou `null` para não responder.\n *\n * Sem esta callback, o checkbox \"Auto-respond\" não aparece no painel.\n *\n * @since v0.3.0\n */\n onSendForAutoRespond?: (msg: MockMessage) => AutoRespondResponse | null;\n\n /**\n * Estado inicial do toggle \"Auto-respond\". Default: `false`\n * (manual permanece padrão; cliente decide quando ligar).\n *\n * @since v0.3.0\n */\n startAutoRespondEnabled?: boolean;\n\n /**\n * Delay em ms entre o `send` e o `mockEmit` da auto-resposta.\n * Default: `50` — aproxima latência de IPC real de native bridge.\n *\n * @since v0.3.0\n */\n autoRespondDelayMs?: number;\n}\n\ninterface InstallParams {\n adapter: MockAdapter;\n options?: DevPanelOptions;\n}\n\ninterface ResolvedOptions {\n position: NonNullable<DevPanelOptions['position']>;\n maxMessages: number;\n theme: NonNullable<DevPanelOptions['theme']>;\n startCollapsed: boolean;\n startAutoRespondEnabled: boolean;\n autoRespondDelayMs: number;\n}\n\nconst DEFAULTS: ResolvedOptions = {\n position: 'bottom-right',\n maxMessages: 20,\n theme: 'dark',\n startCollapsed: false,\n startAutoRespondEnabled: false,\n autoRespondDelayMs: 50,\n};\n\nfunction resolveOptions(opts?: DevPanelOptions): ResolvedOptions {\n return {\n position: opts?.position ?? DEFAULTS.position,\n maxMessages: opts?.maxMessages ?? DEFAULTS.maxMessages,\n theme: opts?.theme ?? DEFAULTS.theme,\n startCollapsed: opts?.startCollapsed ?? DEFAULTS.startCollapsed,\n startAutoRespondEnabled: opts?.startAutoRespondEnabled ?? DEFAULTS.startAutoRespondEnabled,\n autoRespondDelayMs: opts?.autoRespondDelayMs ?? DEFAULTS.autoRespondDelayMs,\n };\n}\n\nfunction applyPanelStyles(el: HTMLElement, opts: ResolvedOptions): void {\n const isDark = opts.theme === 'dark';\n const positions: Record<ResolvedOptions['position'], Partial<CSSStyleDeclaration>> = {\n 'bottom-right': { bottom: '12px', right: '12px' },\n 'bottom-left': { bottom: '12px', left: '12px' },\n 'top-right': { top: '12px', right: '12px' },\n 'top-left': { top: '12px', left: '12px' },\n };\n Object.assign(el.style, {\n position: 'fixed',\n width: '340px',\n maxHeight: '420px',\n zIndex: '2147483647',\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n fontSize: '12px',\n color: isDark ? '#e0e0e0' : '#222',\n background: isDark ? '#1a1a1aee' : '#ffffffee',\n border: isDark ? '1px solid #444' : '1px solid #ccc',\n borderRadius: '6px',\n boxShadow: '0 4px 12px rgba(0,0,0,0.3)',\n overflow: 'hidden',\n display: 'flex',\n flexDirection: 'column',\n ...positions[opts.position],\n });\n}\n\nfunction buildHeader(badge: HTMLElement, counter: HTMLElement, toggle: HTMLElement): HTMLElement {\n const header = document.createElement('div');\n header.className = 'condor-mock-panel-header';\n Object.assign(header.style, {\n padding: '6px 10px',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n background: '#0a84ff',\n color: '#fff',\n fontWeight: '600',\n cursor: 'pointer',\n });\n Object.assign(badge.style, {\n background: '#fff',\n color: '#0a84ff',\n padding: '1px 6px',\n borderRadius: '3px',\n fontSize: '10px',\n letterSpacing: '0.5px',\n });\n badge.textContent = 'MOCK';\n Object.assign(counter.style, {\n marginLeft: 'auto',\n fontSize: '11px',\n opacity: '0.9',\n });\n Object.assign(toggle.style, {\n background: 'transparent',\n border: '1px solid rgba(255,255,255,0.5)',\n color: '#fff',\n cursor: 'pointer',\n padding: '0 6px',\n borderRadius: '3px',\n fontFamily: 'inherit',\n });\n header.append(badge, document.createTextNode('condor-bridge'), counter, toggle);\n return header;\n}\n\nfunction buildSentSection(): { container: HTMLElement; list: HTMLElement } {\n const container = document.createElement('div');\n container.className = 'condor-mock-panel-sent';\n Object.assign(container.style, {\n padding: '6px 10px',\n borderBottom: '1px solid rgba(255,255,255,0.08)',\n maxHeight: '180px',\n overflowY: 'auto',\n });\n const title = document.createElement('div');\n title.textContent = 'Sent';\n Object.assign(title.style, { opacity: '0.7', marginBottom: '4px', fontSize: '11px' });\n const list = document.createElement('div');\n list.className = 'condor-mock-panel-sent-list';\n container.append(title, list);\n return { container, list };\n}\n\nfunction buildTriggerSection(\n bridgeKeys: readonly string[],\n onEmit: (key: string, payloadJson: string) => void,\n onClear: () => void,\n): HTMLElement {\n const container = document.createElement('div');\n container.className = 'condor-mock-panel-trigger';\n Object.assign(container.style, {\n padding: '6px 10px',\n display: 'flex',\n flexDirection: 'column',\n gap: '4px',\n });\n const title = document.createElement('div');\n title.textContent = 'Trigger emit';\n Object.assign(title.style, { opacity: '0.7', fontSize: '11px' });\n\n const select = document.createElement('select');\n select.className = 'condor-mock-panel-key-select';\n Object.assign(select.style, {\n background: 'transparent',\n color: 'inherit',\n border: '1px solid rgba(255,255,255,0.2)',\n padding: '4px',\n borderRadius: '3px',\n fontFamily: 'inherit',\n fontSize: '11px',\n });\n for (const key of bridgeKeys) {\n const opt = document.createElement('option');\n opt.value = key;\n opt.textContent = key;\n select.appendChild(opt);\n }\n const ackOpt = document.createElement('option');\n ackOpt.value = 'handshake-ack';\n ackOpt.textContent = 'handshake-ack';\n select.appendChild(ackOpt);\n\n const textarea = document.createElement('textarea');\n textarea.className = 'condor-mock-panel-payload';\n textarea.placeholder = '{ \"data\": \"pong\" }';\n Object.assign(textarea.style, {\n background: 'transparent',\n color: 'inherit',\n border: '1px solid rgba(255,255,255,0.2)',\n padding: '4px',\n borderRadius: '3px',\n fontFamily: 'inherit',\n fontSize: '11px',\n minHeight: '50px',\n resize: 'vertical',\n });\n\n const buttons = document.createElement('div');\n Object.assign(buttons.style, { display: 'flex', gap: '6px' });\n\n const emitBtn = document.createElement('button');\n emitBtn.type = 'button';\n emitBtn.textContent = 'Emit';\n emitBtn.className = 'condor-mock-panel-emit-btn';\n Object.assign(emitBtn.style, {\n background: '#0a84ff',\n color: '#fff',\n border: 'none',\n padding: '4px 10px',\n borderRadius: '3px',\n cursor: 'pointer',\n fontFamily: 'inherit',\n fontSize: '11px',\n flex: '1',\n });\n emitBtn.addEventListener('click', () => {\n onEmit(select.value, textarea.value);\n });\n\n const clearBtn = document.createElement('button');\n clearBtn.type = 'button';\n clearBtn.textContent = 'Clear sent';\n clearBtn.className = 'condor-mock-panel-clear-btn';\n Object.assign(clearBtn.style, {\n background: 'transparent',\n color: 'inherit',\n border: '1px solid rgba(255,255,255,0.3)',\n padding: '4px 10px',\n borderRadius: '3px',\n cursor: 'pointer',\n fontFamily: 'inherit',\n fontSize: '11px',\n });\n clearBtn.addEventListener('click', onClear);\n\n buttons.append(emitBtn, clearBtn);\n container.append(title, select, textarea, buttons);\n return container;\n}\n\nfunction buildAutoRespondSection(\n initialEnabled: boolean,\n onChange: (next: boolean) => void,\n): HTMLElement {\n const container = document.createElement('div');\n container.className = 'condor-mock-panel-auto-respond';\n Object.assign(container.style, {\n padding: '6px 10px',\n borderBottom: '1px solid rgba(255,255,255,0.08)',\n display: 'flex',\n flexDirection: 'column',\n gap: '2px',\n });\n\n const title = document.createElement('div');\n title.textContent = 'Auto-respond';\n Object.assign(title.style, { opacity: '0.7', fontSize: '11px' });\n\n const row = document.createElement('label');\n Object.assign(row.style, {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n cursor: 'pointer',\n fontSize: '12px',\n });\n\n const checkbox = document.createElement('input');\n checkbox.type = 'checkbox';\n checkbox.className = 'condor-mock-panel-auto-respond-toggle';\n checkbox.checked = initialEnabled;\n Object.assign(checkbox.style, {\n cursor: 'pointer',\n });\n\n const label = document.createElement('span');\n label.textContent = 'Enabled — mockEmit em resposta a cada send (policy do cliente)';\n\n checkbox.addEventListener('change', () => {\n onChange(checkbox.checked);\n });\n\n row.append(checkbox, label);\n container.append(title, row);\n return container;\n}\n\nfunction renderSentList(list: HTMLElement, adapter: MockAdapter, max: number): void {\n list.innerHTML = '';\n const all = adapter.getMessages();\n const tail = all.slice(-max).reverse();\n for (const msg of tail) {\n const row = document.createElement('div');\n Object.assign(row.style, {\n padding: '3px 0',\n borderBottom: '1px solid rgba(255,255,255,0.06)',\n wordBreak: 'break-all',\n });\n const ts = new Date(msg.timestamp).toLocaleTimeString();\n const payload = msg.payload as { type?: string };\n const type = payload?.type ?? '?';\n row.textContent = `${ts} → ${type} ${JSON.stringify(msg.payload).slice(0, 80)}`;\n list.appendChild(row);\n }\n}\n\ninterface InstalledPanel {\n uninstall(): void;\n refresh(): void;\n}\n\nlet currentPanel: InstalledPanel | null = null;\n\nexport function installDevPanel(params: InstallParams): InstalledPanel {\n if (typeof document === 'undefined') {\n throw new Error('condor-mobile-bridge dev panel: document is undefined (Node-only env).');\n }\n\n // Idempotente: remove painel anterior se existir.\n if (currentPanel) {\n currentPanel.uninstall();\n currentPanel = null;\n }\n\n const opts = resolveOptions(params.options);\n const root = document.createElement('div');\n root.id = PANEL_ID;\n applyPanelStyles(root, opts);\n\n const badge = document.createElement('span');\n const counter = document.createElement('span');\n const toggle = document.createElement('button');\n toggle.type = 'button';\n toggle.textContent = opts.startCollapsed ? '+' : '−';\n const header = buildHeader(badge, counter, toggle);\n\n const body = document.createElement('div');\n Object.assign(body.style, {\n display: opts.startCollapsed ? 'none' : 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n });\n\n const { container: sentContainer, list: sentList } = buildSentSection();\n\n // Auto-respond section — conditional render: só aparece se policy fornecida.\n const policy = params.options?.onSendForAutoRespond;\n let autoRespondEnabled = opts.startAutoRespondEnabled;\n let unsubscribeSendListener: (() => void) | null = null;\n\n let autoRespondSection: HTMLElement | null = null;\n if (policy) {\n autoRespondSection = buildAutoRespondSection(autoRespondEnabled, (next) => {\n autoRespondEnabled = next;\n });\n unsubscribeSendListener = params.adapter.onCallHandler((msg) => {\n if (!autoRespondEnabled) return;\n let response: AutoRespondResponse | null;\n try {\n response = policy(msg);\n } catch (err) {\n console.error('[condor-mobile-bridge dev-panel] onSendForAutoRespond threw:', err);\n return;\n }\n if (!response) return;\n setTimeout(() => {\n try {\n params.adapter.triggerEmit(response.key, response.payload);\n } catch (err) {\n console.error(\n '[condor-mobile-bridge dev-panel] triggerEmit failed in auto-respond:',\n err,\n );\n }\n }, opts.autoRespondDelayMs);\n });\n }\n\n const trigger = buildTriggerSection(\n Object.values(BRIDGE_KEYS),\n (key, payloadJson) => {\n let payload: unknown = {};\n const trimmed = payloadJson.trim();\n if (trimmed.length > 0) {\n try {\n payload = JSON.parse(trimmed);\n } catch (err) {\n console.error('[condor-mobile-bridge dev-panel] invalid JSON payload', err);\n return;\n }\n }\n params.adapter.triggerEmit(key, payload);\n },\n () => {\n params.adapter.clearMessages();\n renderSentList(sentList, params.adapter, opts.maxMessages);\n counter.textContent = '0 sent';\n },\n );\n\n if (autoRespondSection) {\n body.append(sentContainer, autoRespondSection, trigger);\n } else {\n body.append(sentContainer, trigger);\n }\n root.append(header, body);\n\n toggle.addEventListener('click', (e) => {\n e.stopPropagation();\n const collapsed = body.style.display === 'none';\n body.style.display = collapsed ? 'flex' : 'none';\n toggle.textContent = collapsed ? '−' : '+';\n });\n\n document.body.appendChild(root);\n\n const refresh = () => {\n const count = params.adapter.getMessages().length;\n counter.textContent = `${count} sent`;\n renderSentList(sentList, params.adapter, opts.maxMessages);\n };\n refresh();\n\n const interval = setInterval(refresh, REFRESH_INTERVAL_MS);\n\n const panel: InstalledPanel = {\n uninstall() {\n clearInterval(interval);\n unsubscribeSendListener?.();\n unsubscribeSendListener = null;\n root.remove();\n if (currentPanel === panel) currentPanel = null;\n },\n refresh,\n };\n currentPanel = panel;\n return panel;\n}\n\n/**\n * Inspeção (testes/debug).\n */\nexport function getInstalledDevPanel(): InstalledPanel | null {\n return currentPanel;\n}\n","/**\n * Mock adapter — ativo quando `window.flutter_inappwebview` não é\n * detectado (browser dev, jsdom sem host instalado, Storybook etc.).\n *\n * Comportamento:\n * - `callHandler` grava `{handlerName, payload, timestamp}` em buffer\n * interno (cap 100, FIFO), loga via `console.debug` e dispatcha\n * listeners registrados via `onCallHandler`.\n * - `triggerEmit` dispatcha via `window.CondorBridge.emit` — bridge real\n * trata como se viesse do nativo (handshake-ack resolve handshake;\n * demais chaves vão pros subscribers).\n * - `getMessages` retorna snapshot read-only do buffer.\n * - `clearMessages` esvazia o buffer (útil em testes).\n * - `onCallHandler(listener)` — registra listener invocado a cada send.\n * Retorna função de unsubscribe. Útil para dev panel reagir a sends\n * (v0.3.0+ auto-respond toggle) ou análise em testes.\n */\n\nconst MAX_BUFFER = 100;\n\nexport interface MockMessage {\n handlerName: string;\n payload: unknown;\n timestamp: number;\n}\n\nexport interface MockAdapter {\n readonly isMock: true;\n callHandler(handlerName: string, payload: unknown): void;\n getMessages(): readonly MockMessage[];\n clearMessages(): void;\n triggerEmit(key: string, payload: unknown): void;\n /**\n * Registra listener invocado a cada `callHandler` (mensagem JS→Native).\n * Retorna função de unsubscribe.\n *\n * Erros em listeners são capturados + logados; não afetam outros\n * listeners nem o pipeline do bridge.\n *\n * @since v0.3.0\n */\n onCallHandler(listener: (msg: MockMessage) => void): () => void;\n}\n\nexport function createMockAdapter(): MockAdapter {\n const messages: MockMessage[] = [];\n const sendListeners = new Set<(msg: MockMessage) => void>();\n\n return {\n isMock: true,\n\n callHandler(handlerName, payload) {\n const msg: MockMessage = { handlerName, payload, timestamp: Date.now() };\n messages.push(msg);\n if (messages.length > MAX_BUFFER) {\n messages.shift();\n }\n console.debug('[condor-mobile-bridge mock] →', handlerName, payload);\n for (const listener of sendListeners) {\n try {\n listener(msg);\n } catch (err) {\n console.error('[condor-mobile-bridge mock] send listener threw:', err);\n }\n }\n },\n\n getMessages() {\n return messages;\n },\n\n clearMessages() {\n messages.length = 0;\n },\n\n triggerEmit(key, payload) {\n const bridge = typeof window !== 'undefined' ? window.CondorBridge : undefined;\n if (!bridge || typeof bridge.emit !== 'function') {\n throw new Error(\n 'condor-mobile-bridge mock: window.CondorBridge not bootstrapped; cannot emit.',\n );\n }\n bridge.emit(key, payload);\n },\n\n onCallHandler(listener) {\n sendListeners.add(listener);\n return () => {\n sendListeners.delete(listener);\n };\n },\n };\n}\n","/**\n * Detecção do host nativo + adapter pattern.\n *\n * **v0.1.0:** lançava erro quando `window.flutter_inappwebview` ausente.\n * **v0.2.0:** ativa mock adapter (`createMockAdapter`) — destrava dev em\n * browser comum sem buildar APK.\n *\n * Adapter ativo é cached na primeira chamada de `getActiveAdapter()`.\n * Tests devem chamar `__resetAdapterForTests()` no `beforeEach` para\n * forçar re-detecção (ex.: após instalar/remover `window.flutter_inappwebview`).\n */\n\nimport { createMockAdapter, type MockAdapter } from './mock';\n\ninterface FlutterInAppWebView {\n callHandler(name: string, ...args: unknown[]): Promise<unknown>;\n}\n\ndeclare global {\n interface Window {\n flutter_inappwebview?: FlutterInAppWebView;\n }\n}\n\nexport interface RealAdapter {\n readonly isMock: false;\n callHandler(handlerName: string, payload: unknown): void;\n}\n\nexport type NativeAdapter = RealAdapter | MockAdapter;\n\nlet activeAdapter: NativeAdapter | null = null;\n\nfunction createRealAdapter(host: FlutterInAppWebView): RealAdapter {\n return {\n isMock: false,\n callHandler(handlerName, payload) {\n void host.callHandler(handlerName, payload);\n },\n };\n}\n\nfunction detectAdapter(): NativeAdapter {\n if (typeof window === 'undefined') {\n return createMockAdapter();\n }\n const host = window.flutter_inappwebview;\n if (host && typeof host.callHandler === 'function') {\n return createRealAdapter(host);\n }\n return createMockAdapter();\n}\n\nexport function getActiveAdapter(): NativeAdapter {\n if (!activeAdapter) {\n activeAdapter = detectAdapter();\n }\n return activeAdapter;\n}\n\nexport function hasNativeHost(): boolean {\n return !getActiveAdapter().isMock;\n}\n\n/**\n * Envia mensagem ao native handler via adapter ativo.\n *\n * Em modo real: fire-and-forget `flutter_inappwebview.callHandler`.\n * Em modo mock: grava no buffer + `console.debug`.\n */\nexport function callNative(handlerName: string, payload: unknown): void {\n getActiveAdapter().callHandler(handlerName, payload);\n}\n\n/**\n * Reseta cache do adapter. **Exportado para uso em testes apenas.**\n *\n * Cliente NUNCA deve chamar isso em código de aplicação — o adapter é\n * detectado uma vez no startup e mantido.\n */\nexport function __resetAdapterForTests(): void {\n activeAdapter = null;\n}\n","import type { BridgeKey } from '../keys';\nimport type { PayloadOf } from '../payloads';\n\ntype Callback = (payload: unknown) => void;\n\nconst subscribers = new Map<string, Set<Callback>>();\n\nexport function addSubscriber<K extends BridgeKey>(\n key: K,\n cb: (payload: PayloadOf<K>) => void,\n): () => void {\n let set = subscribers.get(key);\n if (!set) {\n set = new Set<Callback>();\n subscribers.set(key, set);\n }\n set.add(cb as Callback);\n return () => {\n const current = subscribers.get(key);\n if (!current) return;\n current.delete(cb as Callback);\n if (current.size === 0) {\n subscribers.delete(key);\n }\n };\n}\n\nexport function dispatchToSubscribers(key: string, payload: unknown): void {\n const set = subscribers.get(key);\n if (!set) return;\n for (const cb of set) {\n try {\n cb(payload);\n } catch (err) {\n // Subscriber bugado não deve afetar os outros nem o bridge.\n console.error(`[condor-mobile-bridge] subscriber for \"${key}\" threw:`, err);\n }\n }\n}\n\n/**\n * Limpa todos os subscribers. Útil em testes para isolar casos.\n */\nexport function clearAllSubscribers(): void {\n subscribers.clear();\n}\n\n/**\n * Inspeção (testes/debug).\n */\nexport function getSubscriberCount(key: string): number {\n return subscribers.get(key)?.size ?? 0;\n}\n\n/**\n * Lista das chaves com subscribers ativos (testes/debug/dev panel).\n */\nexport function getSubscriberKeys(): string[] {\n return Array.from(subscribers.keys());\n}\n","import type { DevPanelOptions } from './internal/dev-panel';\nimport { installDevPanel as installDevPanelInternal } from './internal/dev-panel';\nimport type { MockAdapter, MockMessage } from './internal/mock';\nimport { callNative, getActiveAdapter } from './internal/native';\nimport { addSubscriber, dispatchToSubscribers, getSubscriberKeys } from './internal/subscribers';\nimport type { BridgeKey } from './keys';\nimport type { HandshakeAck, HandshakeOptions } from './messages';\nimport type { PayloadOf } from './payloads';\n\nconst HANDSHAKE_ACK_KEY = 'handshake-ack';\nconst NATIVE_HANDLER = 'CondorBridge';\nconst PROTOCOL_VERSION = '0.1.0';\n\ninterface PendingHandshake {\n resolve: (ack: HandshakeAck) => void;\n reject: (err: Error) => void;\n}\n\ninterface WindowCondorBridge {\n emit(key: string, payload: unknown): void;\n}\n\ndeclare global {\n interface Window {\n CondorBridge?: WindowCondorBridge;\n }\n}\n\nlet pendingHandshake: PendingHandshake | null = null;\nlet bridgeBootstrapped = false;\n\nfunction emit(key: string, payload: unknown): void {\n if (key === HANDSHAKE_ACK_KEY && pendingHandshake) {\n const ack = (payload ?? {}) as Partial<HandshakeAck>;\n const resolver = pendingHandshake;\n pendingHandshake = null;\n resolver.resolve({\n nativeVersion: ack.nativeVersion ?? 'unknown',\n accepted: ack.accepted ?? false,\n });\n return;\n }\n dispatchToSubscribers(key, payload);\n}\n\nfunction bootstrapWindowBridge(): void {\n if (bridgeBootstrapped) return;\n if (typeof window === 'undefined') return;\n bridgeBootstrapped = true;\n\n if (window.CondorBridge && typeof window.CondorBridge.emit === 'function') {\n // Já instalado (HMR / double import / mock instalado por testes).\n // Substitui apenas o emit para garantir que o dispatcher mais recente\n // esteja conectado aos subscribers desta instância do módulo.\n window.CondorBridge.emit = emit;\n } else {\n window.CondorBridge = { emit };\n }\n}\n\nbootstrapWindowBridge();\n\nfunction requireMockAdapter(): MockAdapter {\n const adapter = getActiveAdapter();\n if (!adapter.isMock) {\n throw new Error(\n 'condor-mobile-bridge: this API is available only in mock mode (no native host detected).',\n );\n }\n return adapter;\n}\n\nexport interface MockState {\n readonly isMock: true;\n readonly messages: readonly MockMessage[];\n readonly subscriberKeys: readonly string[];\n}\n\nexport interface CondorBridge {\n /**\n * `true` quando o adapter ativo é mock (browser dev, sem\n * `window.flutter_inappwebview`). `false` quando rodando dentro do\n * WebView Flutter.\n */\n readonly isMock: boolean;\n\n /**\n * Envia handshake versionado ao nativo e aguarda `handshake-ack`.\n *\n * Apenas um handshake pode estar pendente por vez. Chamadas paralelas\n * antes do primeiro `ack` chegar são rejeitadas com erro claro.\n *\n * **Em mock mode:** NÃO resolve sozinho. Cliente/teste deve chamar\n * `Bridge.mockEmit('handshake-ack', {nativeVersion, accepted})` para\n * destravar a Promise. Esta decisão (`Explícito`) força testes a serem\n * intencionais sobre o estado nativo.\n */\n handshake(opts: HandshakeOptions): Promise<HandshakeAck>;\n\n /**\n * Subscreve a uma chave observável. Retorna função `unsubscribe`.\n *\n * Múltiplos subscribers por chave são permitidos. Erro em um subscriber\n * não afeta os outros (capturado e logado em `console.error`).\n */\n on<K extends BridgeKey>(key: K, cb: (payload: PayloadOf<K>) => void): () => void;\n\n /**\n * Envia mensagem genérica ao nativo. Use para comandos UI→BG que não\n * tenham helper dedicado. `type` é a string que o native usa para\n * roteamento no `_onJsMessage`.\n *\n * Em mock mode: grava no buffer interno + `console.debug`.\n */\n send(type: string, payload?: Record<string, unknown>): void;\n\n /**\n * Abre a tela nativa de Settings do app. Equivalente a\n * `Bridge.send('openSettings')`.\n */\n openSettings(): void;\n\n /**\n * Dispara `window.CondorBridge.emit(key, payload)` programaticamente —\n * útil para simular eventos nativos em testes e dev em browser.\n *\n * **Throws** se o adapter ativo não for mock.\n */\n mockEmit(key: string, payload?: unknown): void;\n\n /**\n * Snapshot do estado do mock adapter (mensagens enviadas + chaves com\n * subscribers ativos). Useful para asserts em testes de cliente.\n *\n * **Throws** se o adapter ativo não for mock.\n */\n getMockState(): MockState;\n\n /**\n * Injeta painel HTML flutuante no `document.body` para inspecionar o\n * bridge em mock mode. Idempotente — re-install substitui o anterior.\n *\n * **Throws** se o adapter ativo não for mock OU se `document` não existir.\n */\n installDevPanel(options?: DevPanelOptions): void;\n}\n\nexport const Bridge: CondorBridge = {\n get isMock(): boolean {\n return getActiveAdapter().isMock;\n },\n\n handshake(opts: HandshakeOptions): Promise<HandshakeAck> {\n bootstrapWindowBridge();\n if (pendingHandshake) {\n return Promise.reject(\n new Error(\n 'condor-mobile-bridge: handshake already in flight. Await the previous call before issuing another.',\n ),\n );\n }\n return new Promise<HandshakeAck>((resolve, reject) => {\n pendingHandshake = { resolve, reject };\n try {\n callNative(NATIVE_HANDLER, {\n type: 'handshake',\n version: PROTOCOL_VERSION,\n payload: { clientVersion: opts.clientVersion },\n });\n } catch (err) {\n pendingHandshake = null;\n reject(err instanceof Error ? err : new Error(String(err)));\n }\n });\n },\n\n on<K extends BridgeKey>(key: K, cb: (payload: PayloadOf<K>) => void): () => void {\n bootstrapWindowBridge();\n return addSubscriber(key, cb);\n },\n\n send(type: string, payload?: Record<string, unknown>): void {\n callNative(NATIVE_HANDLER, {\n type,\n version: PROTOCOL_VERSION,\n payload: payload ?? {},\n });\n },\n\n openSettings(): void {\n this.send('openSettings');\n },\n\n mockEmit(key: string, payload?: unknown): void {\n requireMockAdapter().triggerEmit(key, payload ?? {});\n },\n\n getMockState(): MockState {\n const adapter = requireMockAdapter();\n return {\n isMock: true,\n messages: adapter.getMessages(),\n subscriberKeys: getSubscriberKeys(),\n };\n },\n\n installDevPanel(options?: DevPanelOptions): void {\n const adapter = requireMockAdapter();\n installDevPanelInternal({ adapter, options });\n },\n};\n\n/**\n * Reseta o estado interno do bridge (handshake pendente).\n *\n * **Exportado para uso em testes apenas.** Não chamar em código de\n * aplicação — quebra a semântica de \"apenas um handshake pendente\".\n */\nexport function __resetBridgeForTests(): void {\n pendingHandshake = null;\n}\n","/**\n * `BridgeClient` (v0.5.0) — API para código do cliente externo rodando\n * dentro de `<iframe sandbox=\"allow-scripts\">` no `sleep_whitelabel`.\n *\n * Surface idêntica ao `Bridge` legado (`on`/`send`/`openSettings`/`handshake`)\n * — cliente importa e não percebe que está em sandbox. Internamente,\n * todas as chamadas viram `window.parent.postMessage(...)` com schema\n * validado pelo shell antes de chegar ao nativo.\n *\n * **Não expõe** `installDevPanel`, `mockEmit`, `isMock`, `getMockState` —\n * essas APIs são responsabilidade do shell (`BridgeShell`).\n *\n * **Threat model & Camada 2 do Risco 1** (vide\n * `sleep-white-label-content-transport-and-security.md`): este módulo\n * também responde ao `verify-sandbox` do shell — função de attestation\n * do próprio iframe sobre se ainda enxerga `window.flutter_inappwebview`\n * ou `window.CondorBridge` (que deveriam ter sido deletados pela Camada 1).\n * Se vier `true` em algum, o shell aborta o boot do app.\n */\n\nimport { BRIDGE_KEYS, type BridgeKey } from './keys';\nimport type { PayloadOf, SensorLogPayload, SensorLogQueryPayload } from './payloads';\nimport type { ClientToShellMessage, ShellToClientMessage } from './shell-messages';\n\nconst PROTOCOL_VERSION = '0.5.0';\nconst HANDSHAKE_TIMEOUT_MS = 5000;\n/**\n * Timeout padrão de uma página de `sensorLog`. Uma página de 1000 logs custa\n * ~2,7 s no pior caso medido (device gen2), então a margem é deliberada.\n */\nconst SENSOR_LOG_TIMEOUT_MS = 10000;\n\ninterface PendingHandshake {\n resolve: (ack: { shellVersion: string; accepted: boolean }) => void;\n reject: (err: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\ninterface Subscriber {\n // Stored as (unknown) — typed inference comes from public `on<K>`.\n cb: (payload: unknown) => void;\n}\n\nconst subscribers = new Map<string, Subscriber[]>();\nlet pendingHandshake: PendingHandshake | null = null;\nlet messageListenerInstalled = false;\n\nfunction postToShell(msg: ClientToShellMessage): void {\n if (typeof window === 'undefined' || window.parent === window) {\n // No parent — not in iframe. Caller bug; silently drop.\n console.warn('[BridgeClient] no parent window; message dropped:', msg.type);\n return;\n }\n window.parent.postMessage(msg, '*');\n}\n\nfunction dispatchEvent(key: string, payload: unknown): void {\n const arr = subscribers.get(key);\n if (!arr || arr.length === 0) return;\n for (const sub of arr) {\n try {\n sub.cb(payload);\n } catch (err) {\n console.error('[BridgeClient] subscriber error:', err);\n }\n }\n}\n\nfunction onMessage(event: MessageEvent): void {\n if (event.source !== window.parent) return;\n // Não validamos com Valibot aqui — o shell é trusted (Condor-controlado).\n // Validamos só o `type` para evitar crashes por payload malformado.\n const data = event.data as Partial<ShellToClientMessage>;\n if (!data || typeof data !== 'object' || typeof data.type !== 'string') return;\n\n switch (data.type) {\n case 'event': {\n const msg = data as Extract<ShellToClientMessage, { type: 'event' }>;\n if (typeof msg.key === 'string') dispatchEvent(msg.key, msg.payload);\n break;\n }\n case 'handshake-ack': {\n const msg = data as Extract<ShellToClientMessage, { type: 'handshake-ack' }>;\n if (pendingHandshake) {\n clearTimeout(pendingHandshake.timer);\n const { resolve } = pendingHandshake;\n pendingHandshake = null;\n resolve({\n shellVersion: msg.ack?.shellVersion ?? 'unknown',\n accepted: msg.ack?.accepted ?? false,\n });\n }\n break;\n }\n case 'nack':\n // Cliente pode ouvir nacks via `Bridge.on('__nack', ...)` em futuras versões.\n // v0.5.0: só loga, sem dispatcher dedicado.\n console.warn('[BridgeClient] command nacked by shell:', data);\n break;\n case 'verify-sandbox': {\n // Camada 2 do Risco 1: shell pergunta se ainda enxergamos os bridges\n // nativos. Resposta autoritativa do iframe sobre seu próprio estado.\n const w = window as unknown as Record<string, unknown>;\n postToShell({\n type: 'sandbox-verify-response',\n flutterBridgeReachable: typeof w.flutter_inappwebview !== 'undefined',\n condorBridgeReachable: typeof w.CondorBridge !== 'undefined',\n });\n break;\n }\n }\n}\n\nfunction ensureMessageListener(): void {\n if (messageListenerInstalled) return;\n if (typeof window === 'undefined') return;\n messageListenerInstalled = true;\n window.addEventListener('message', onMessage);\n}\n\nensureMessageListener();\n\nexport interface BridgeClientHandshakeAck {\n shellVersion: string;\n accepted: boolean;\n}\n\nexport interface CondorBridgeClient {\n /**\n * Versão do protocolo do client.\n */\n readonly protocolVersion: string;\n\n /**\n * Subscreve a uma chave observável. Retorna função `unsubscribe`.\n * Múltiplos subscribers por chave permitidos. Erro em um subscriber\n * não afeta os outros.\n */\n on<K extends BridgeKey>(key: K, cb: (payload: PayloadOf<K>) => void): () => void;\n\n /**\n * Envia comando para o shell. Shell valida contra `ShellPolicy` antes\n * de tocar o nativo. Comandos não permitidos → `nack` (logado em\n * `console.warn` na v0.5.0).\n */\n send(command: string, args?: Record<string, unknown>): void;\n\n /**\n * Abre Settings nativa. Equivalente a `send('openSettings')`.\n */\n openSettings(): void;\n\n /**\n * Pede UMA página de sensor logs e resolve com a resposta correlacionada\n * pelo `requestId` — inclusive quando ela traz `success: false`, que é\n * resposta e não falha de transporte. A Promise só **rejeita** por timeout.\n *\n * Dispensa o cliente de manter o mapa `requestId → resolve` à mão. Para\n * varrer um período, encadeie as chamadas usando o `startingAfter` devolvido\n * até `hasMore` virar `false`: os cursores são dependentes, então as páginas\n * **não** podem ser buscadas em paralelo.\n */\n fetchSensorLog(\n query: SensorLogQueryPayload,\n opts?: { timeoutMs?: number },\n ): Promise<SensorLogPayload>;\n\n /**\n * Solicita UMA permissão via **diálogo nativo in-app** (não abre Settings).\n * Equivalente a `send('requestPermission', { permission })`. Use no botão\n * \"Conceder\" do card Necessárias, com um nome vindo de\n * `systemStatus.missingEssentialPermissions` (ex.: `'bluetoothScan'`).\n * O resultado chega via re-emissão de `systemStatus` (sem chave dedicada).\n */\n requestPermission(permission: string): void;\n\n /**\n * Handshake com o shell. Resolve com `{ shellVersion, accepted }`.\n * Timeout em 5s se shell não responder.\n *\n * Apenas um handshake pode estar pendente por vez.\n */\n handshake(opts: { clientVersion: string }): Promise<BridgeClientHandshakeAck>;\n\n /**\n * Reporta ao nativo se o cliente tem histórico interno para voltar.\n * **Chame a cada mudança de rota interna** (e no boot). O nativo cacheia\n * este estado e o usa para decidir o botão/gesture de voltar do SO:\n * - `true` → o back do SO pede uma volta interna (evento `navigationBack`,\n * vide `onBack`).\n * - `false` → o back do SO fica na home (não sai da página).\n *\n * Equivalente a `send('navigationState', { canGoBack })`.\n */\n reportNavigation(canGoBack: boolean): void;\n\n /**\n * Assina o pedido de back do SO (evento `navigationBack`). O callback deve\n * voltar **uma** página interna do cliente e então chamar\n * `reportNavigation(...)` com o novo estado. Só é chamado quando o cliente\n * havia reportado `reportNavigation(true)`. Retorna função `unsubscribe`.\n */\n onBack(cb: () => void): () => void;\n}\n\nexport const BridgeClient: CondorBridgeClient = {\n protocolVersion: PROTOCOL_VERSION,\n\n on<K extends BridgeKey>(key: K, cb: (payload: PayloadOf<K>) => void): () => void {\n ensureMessageListener();\n const arr = subscribers.get(key) ?? [];\n const sub: Subscriber = { cb: cb as (payload: unknown) => void };\n arr.push(sub);\n subscribers.set(key, arr);\n // Notifica shell para registrar subscription no native (idempotente\n // no shell — múltiplos `subscribe` para a mesma chave são tratados).\n postToShell({ type: 'subscribe', key });\n return () => {\n const remaining = (subscribers.get(key) ?? []).filter((s) => s !== sub);\n subscribers.set(key, remaining);\n if (remaining.length === 0) postToShell({ type: 'unsubscribe', key });\n };\n },\n\n send(command: string, args: Record<string, unknown> = {}): void {\n postToShell({ type: 'send', command, args });\n },\n\n openSettings(): void {\n this.send('openSettings');\n },\n\n fetchSensorLog(\n query: SensorLogQueryPayload,\n opts?: { timeoutMs?: number },\n ): Promise<SensorLogPayload> {\n const timeoutMs = opts?.timeoutMs ?? SENSOR_LOG_TIMEOUT_MS;\n return new Promise<SensorLogPayload>((resolve, reject) => {\n let settled = false;\n const unsubscribe = this.on(BRIDGE_KEYS.sensorLog, (payload) => {\n // Outras páginas em voo compartilham a chave: só a nossa interessa.\n if (settled || payload.requestId !== query.requestId) return;\n settled = true;\n clearTimeout(timer);\n unsubscribe();\n resolve(payload);\n });\n const timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n unsubscribe();\n reject(\n new Error(\n `BridgeClient: sensorLog timeout after ${timeoutMs}ms (requestId=${query.requestId})`,\n ),\n );\n }, timeoutMs);\n this.send('sensorLog', { ...query });\n });\n },\n\n requestPermission(permission: string): void {\n this.send('requestPermission', { permission });\n },\n\n handshake(opts: { clientVersion: string }): Promise<BridgeClientHandshakeAck> {\n ensureMessageListener();\n if (pendingHandshake) {\n return Promise.reject(\n new Error(\n 'BridgeClient: handshake already in flight. Await previous before issuing another.',\n ),\n );\n }\n return new Promise<BridgeClientHandshakeAck>((resolve, reject) => {\n const timer = setTimeout(() => {\n pendingHandshake = null;\n reject(new Error(`BridgeClient: handshake timeout after ${HANDSHAKE_TIMEOUT_MS}ms`));\n }, HANDSHAKE_TIMEOUT_MS);\n pendingHandshake = { resolve, reject, timer };\n postToShell({\n type: 'handshake',\n payload: { clientVersion: opts.clientVersion },\n });\n });\n },\n\n reportNavigation(canGoBack: boolean): void {\n this.send('navigationState', { canGoBack });\n },\n\n onBack(cb: () => void): () => void {\n return this.on(BRIDGE_KEYS.navigationBack, () => cb());\n },\n};\n\n/**\n * Reseta estado interno (subscribers + handshake pendente).\n *\n * **Exportado para uso em testes apenas.** Listener `message` permanece\n * instalado entre testes — é idempotente (checa `event.source ===\n * window.parent` per-call) e o `window` do jsdom persiste entre tests.\n */\nexport function __resetBridgeClientForTests(): void {\n if (pendingHandshake) {\n clearTimeout(pendingHandshake.timer);\n pendingHandshake = null;\n }\n subscribers.clear();\n}\n","/**\n * `BridgeShell` (v0.5.0) — API para o shell Condor-controlado que envolve\n * o conteúdo do cliente externo dentro de `<iframe sandbox=\"allow-scripts\">`.\n *\n * Responsabilidades:\n * 1. **Camada 1 do Risco 1** — `bootstrapClientIframe(iframe, clientPath)`:\n * busca HTML do cliente via `fetch`, prepende script de override que\n * deleta `window.flutter_inappwebview` e `window.CondorBridge` do\n * iframe, e seta como `srcdoc`. Override roda em parse-time, antes\n * de qualquer outro script.\n * 2. **Camada 2 do Risco 1** — `verifySandbox(iframe)`: round-trip\n * `postMessage` que pede ao iframe atestation autoritativa de que\n * `window.flutter_inappwebview` e `window.CondorBridge` são `undefined`.\n * 3. **Roteamento postMessage iframe ↔ nativo:** escuta `message` events\n * do iframe, valida com Valibot, aplica `ShellPolicy` default-deny,\n * e propaga para o `Bridge` legado (que fala com o nativo). Eventos\n * nativos voltam para o iframe via `postMessage`.\n * 4. **Confirmação humana para comandos sensíveis:** comandos em\n * `policy.requiresConfirmation` disparam callback\n * `onConfirmationRequest` antes de tocar o nativo — shell apresenta UI.\n */\n\nimport * as v from 'valibot';\nimport { Bridge } from './bridge';\nimport type { BridgeKey } from './keys';\nimport {\n ClientToShellMessage,\n type ConfirmationRequest,\n type SandboxVerifyResult,\n type ShellPolicy,\n type ShellToClientMessage,\n} from './shell-messages';\n\nconst SHELL_VERSION = '0.5.1';\nconst VERIFY_TIMEOUT_MS = 2000;\n\n/**\n * **Camada 1 do Risco 1 — override prefix.**\n *\n * Script prependado ao srcdoc do iframe pelo `bootstrapClientIframe*`.\n * Roda em parse-time, antes de qualquer outro script do cliente, no\n * próprio documento do iframe (origem null — sem cross-origin block).\n *\n * Usa **getter/setter no-op** + `configurable: false` (não\n * `value/writable: false`). Razão: bundles ESM modernos rodam em strict\n * mode; qualquer `window.X = …` em propriedade não-writable **throws**,\n * o que quebra bootstrap de módulos legados que tentam registrar APIs no\n * window (ex.: `condor-mobile-bridge` legacy faz\n * `window.CondorBridge = {emit}` como side-effect no module load).\n * Com getter/setter no-op, a atribuição passa silenciosamente mas o\n * getter sempre retorna undefined — bridges nativos permanecem\n * inacessíveis no iframe sem quebrar fluxos JS legítimos.\n *\n * Validado empiricamente via pen test ofensivo em `moto g 9 plus`\n * durante o trio sandbox iframe (2026-06-09).\n */\nconst OVERRIDE_PREFIX = `<script>\n(function(){\n try { delete window.flutter_inappwebview; } catch (_) {}\n try { delete window.CondorBridge; } catch (_) {}\n try {\n Object.defineProperty(window, 'flutter_inappwebview', {\n get: function(){ return undefined; },\n set: function(_){ /* no-op: bloqueia injeção do plugin no iframe */ },\n configurable: false,\n });\n } catch (_) {}\n try {\n Object.defineProperty(window, 'CondorBridge', {\n get: function(){ return undefined; },\n set: function(_){ /* no-op: bloqueia bootstrap do package legado */ },\n configurable: false,\n });\n } catch (_) {}\n try {\n // Neutraliza navigator.sendBeacon: canal de exfil que a CSP connect-src\n // não barra de forma confiável em alguns WebViews (pentest 2026-06-24,\n // PT-10). O cliente comunica só via BridgeClient/postMessage — não tem\n // uso legítimo de sendBeacon. Getter no-op retorna função que devolve\n // false; setter no-op ignora tentativa de restaurar.\n Object.defineProperty(navigator, 'sendBeacon', {\n get: function(){ return function(){ return false; }; },\n set: function(_){ /* no-op */ },\n configurable: false,\n });\n } catch (_) {}\n})();\n</script>`;\n\nexport interface BridgeShellOptions {\n /**\n * Iframe que hospeda o cliente. Pode estar vazio no momento da\n * construção — `bootstrapClientIframe` será chamado depois para popular.\n */\n iframe: HTMLIFrameElement;\n\n /**\n * Policy default-deny. Toda chave/comando vindo do iframe é validado\n * contra estas listas. Vide `ShellPolicy`.\n */\n policy: ShellPolicy;\n\n /**\n * Callback síncrono ou assíncrono chamado quando o cliente pede um\n * comando em `policy.requiresConfirmation`. Shell apresenta UI de\n * confirmação; resolve com `true` (aprovar) ou `false` (recusar).\n * Se não fornecido, comandos `requiresConfirmation` são **negados**\n * automaticamente — fail-safe.\n */\n onConfirmationRequest?: (req: ConfirmationRequest) => boolean | Promise<boolean>;\n}\n\nexport class BridgeShell {\n private readonly iframe: HTMLIFrameElement;\n private readonly policy: ShellPolicy;\n private readonly onConfirm?: BridgeShellOptions['onConfirmationRequest'];\n private readonly subscriptions = new Map<BridgeKey, () => void>();\n private detached = false;\n\n // Map de `verify-sandbox` round-trips pendentes — key gerada por nonce.\n private pendingVerifies = new Map<\n string,\n {\n resolve: (r: SandboxVerifyResult) => void;\n reject: (e: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n }\n >();\n\n constructor(opts: BridgeShellOptions) {\n this.iframe = opts.iframe;\n this.policy = opts.policy;\n this.onConfirm = opts.onConfirmationRequest;\n if (typeof window !== 'undefined') {\n window.addEventListener('message', this.onMessage);\n }\n }\n\n /**\n * **Camada 1 do Risco 1.** Bootstrap via fetch de URL.\n *\n * Atalho para o caso comum HTTP/HTTPS: faz `fetch(clientPath)` e\n * delega para `bootstrapClientIframeWithHtml`.\n *\n * **Não funciona em scheme `file://`** — `fetch` em WebView Android\n * (Chromium) bloqueia o scheme com \"URL scheme 'file' is not supported\".\n * Para asset bundled em APK ou bundle inlined no build-time, use\n * `bootstrapClientIframeWithHtml(htmlString)`.\n *\n * **Devo ser chamado uma vez no boot do shell**, antes de qualquer\n * outra interação. Após retornar, `verifySandbox()` deve ser invocado\n * para atestation (Camada 2).\n */\n async bootstrapClientIframe(clientPath = 'client.html'): Promise<void> {\n const res = await fetch(clientPath);\n if (!res.ok) throw new Error(`BridgeShell: falha ao carregar ${clientPath} (${res.status})`);\n const clientHtml = await res.text();\n await this.bootstrapClientIframeWithHtml(clientHtml);\n }\n\n /**\n * **Camada 1 do Risco 1.** Bootstrap a partir de HTML string.\n *\n * Aceita HTML do cliente diretamente (já lido de arquivo, embedado em\n * build-time via `esbuild.define`, lido de IndexedDB, etc.) e seta\n * como `srcdoc` do iframe prefixado pelo override script. Override\n * roda em parse-time, antes de qualquer outro script do cliente.\n *\n * Use quando `fetch` não é aplicável (asset bundled em `file://`,\n * bundle inlined no build, qualquer cenário sem rede). Para HTTP\n * use `bootstrapClientIframe(clientPath)`.\n *\n * **Devo ser chamado uma vez no boot do shell**, antes de qualquer\n * outra interação. Após retornar, `verifySandbox()` deve ser invocado\n * para atestation (Camada 2).\n */\n async bootstrapClientIframeWithHtml(clientHtml: string): Promise<void> {\n this.iframe.srcdoc = OVERRIDE_PREFIX + clientHtml;\n await this.waitForIframeLoad();\n }\n\n private waitForIframeLoad(): Promise<void> {\n return new Promise<void>((resolve) => {\n const onLoad = (): void => {\n this.iframe.removeEventListener('load', onLoad);\n resolve();\n };\n this.iframe.addEventListener('load', onLoad);\n });\n }\n\n /**\n * **Camada 2 do Risco 1.** Round-trip `postMessage` que pede ao iframe\n * atestation autoritativa do estado de `window.flutter_inappwebview`\n * e `window.CondorBridge`. Timeout em 2s.\n *\n * `ok` é `true` apenas se ambos forem `undefined` no iframe. Se vier\n * `false`, **shell deve abortar o boot do app** — Camada 1 falhou e\n * Camada 4 (dual WebView) precisa ser acionada manualmente.\n */\n verifySandbox(): Promise<SandboxVerifyResult> {\n if (!this.iframe.contentWindow) {\n return Promise.reject(new Error('BridgeShell: iframe sem contentWindow'));\n }\n return new Promise<SandboxVerifyResult>((resolve, reject) => {\n const nonce = Math.random().toString(36).slice(2);\n const timer = setTimeout(() => {\n this.pendingVerifies.delete(nonce);\n reject(new Error(`BridgeShell: verify-sandbox timeout após ${VERIFY_TIMEOUT_MS}ms`));\n }, VERIFY_TIMEOUT_MS);\n this.pendingVerifies.set(nonce, { resolve, reject, timer });\n this.postToClient({ type: 'verify-sandbox' });\n });\n }\n\n /**\n * Encerra o shell — remove listener `message`, cancela subscriptions\n * pendentes no `Bridge` nativo, limpa estado interno.\n */\n detach(): void {\n if (this.detached) return;\n this.detached = true;\n if (typeof window !== 'undefined') {\n window.removeEventListener('message', this.onMessage);\n }\n for (const unsub of this.subscriptions.values()) unsub();\n this.subscriptions.clear();\n for (const pending of this.pendingVerifies.values()) {\n clearTimeout(pending.timer);\n pending.reject(new Error('BridgeShell: detached'));\n }\n this.pendingVerifies.clear();\n }\n\n private onMessage = async (event: MessageEvent): Promise<void> => {\n if (this.detached) return;\n if (event.source !== this.iframe.contentWindow) return;\n\n const parsed = v.safeParse(ClientToShellMessage, event.data);\n if (!parsed.success) {\n // Drop silently — possivelmente noise (extensão de browser, dev tool).\n // Loga só em modo dev para diagnose.\n if (typeof console !== 'undefined') {\n console.debug('[BridgeShell] dropped malformed message:', parsed.issues?.[0]?.message);\n }\n return;\n }\n\n const msg = parsed.output;\n switch (msg.type) {\n case 'subscribe':\n await this.handleSubscribe(msg.key as BridgeKey);\n break;\n case 'unsubscribe':\n this.handleUnsubscribe(msg.key as BridgeKey);\n break;\n case 'send':\n await this.handleSend(msg.command, msg.args ?? {});\n break;\n case 'handshake':\n // Handshake do cliente é com o shell (não com o nativo diretamente).\n // Shell responde com sua versão. Se quiser propagar pro nativo, o\n // shell faz isso por iniciativa própria via `Bridge.handshake`.\n this.postToClient({\n type: 'handshake-ack',\n ack: { shellVersion: SHELL_VERSION, accepted: true },\n });\n break;\n case 'jsError':\n // Forward erro JS do iframe para o nativo (roteia para Logs).\n Bridge.send('jsError', {\n origin: 'iframe',\n message: msg.payload.message,\n stack: msg.payload.stack,\n source: msg.payload.source,\n lineno: msg.payload.lineno,\n colno: msg.payload.colno,\n });\n break;\n case 'sandbox-verify-response': {\n // Camada 2: cliente respondeu ao verify-sandbox. Resolve o pending\n // mais antigo (em prática só há um por vez — mantemos map por\n // robustez).\n const first = this.pendingVerifies.keys().next().value;\n if (first !== undefined) {\n const pending = this.pendingVerifies.get(first);\n if (pending) {\n clearTimeout(pending.timer);\n this.pendingVerifies.delete(first);\n const ok = !msg.flutterBridgeReachable && !msg.condorBridgeReachable;\n pending.resolve({\n flutterBridgeReachable: msg.flutterBridgeReachable,\n condorBridgeReachable: msg.condorBridgeReachable,\n ok,\n });\n }\n }\n break;\n }\n }\n };\n\n private async handleSubscribe(key: BridgeKey): Promise<void> {\n if (!this.policy.readOnlyKeys.includes(key)) {\n this.postToClient({ type: 'nack', key, reason: 'not-read-only' });\n return;\n }\n if (this.subscriptions.has(key)) return; // idempotent\n const unsub = Bridge.on(key, (payload) => {\n if (this.detached) return;\n this.postToClient({ type: 'event', key, payload });\n });\n this.subscriptions.set(key, unsub);\n }\n\n private handleUnsubscribe(key: BridgeKey): void {\n const unsub = this.subscriptions.get(key);\n if (!unsub) return;\n unsub();\n this.subscriptions.delete(key);\n }\n\n private async handleSend(command: string, args: Record<string, unknown>): Promise<void> {\n if (this.policy.deniedCommands.includes(command)) {\n this.postToClient({ type: 'nack', command, reason: 'denied' });\n return;\n }\n if (this.policy.requiresConfirmation.includes(command)) {\n if (!this.onConfirm) {\n // Fail-safe: sem callback, comando que requer confirmação é negado.\n this.postToClient({ type: 'nack', command, reason: 'no-confirmation-handler' });\n return;\n }\n let approved = false;\n try {\n approved = await this.onConfirm({ command, args });\n } catch (err) {\n this.postToClient({\n type: 'nack',\n command,\n reason: `confirmation-error: ${err instanceof Error ? err.message : String(err)}`,\n });\n return;\n }\n if (!approved) {\n this.postToClient({ type: 'nack', command, reason: 'user-rejected' });\n return;\n }\n } else if (!this.policy.allowedCommands.includes(command)) {\n // Comando fora de allowed/denied/requiresConfirmation — drop por default.\n this.postToClient({ type: 'nack', command, reason: 'not-allowed' });\n return;\n }\n Bridge.send(command, args);\n }\n\n private postToClient(msg: ShellToClientMessage): void {\n if (this.detached) return;\n this.iframe.contentWindow?.postMessage(msg, '*');\n }\n}\n","/**\n * Schemas Valibot dos `postMessage` shell↔client (v0.5.0).\n *\n * Quando o conteúdo do cliente roda dentro de `<iframe sandbox=\"allow-scripts\">`\n * (origem null), a comunicação com o shell Condor-controlado acontece via\n * `window.postMessage`. Estes schemas são o **único contrato aceito** —\n * qualquer mensagem mal-formada é descartada silenciosamente pelo shell.\n *\n * **Threat model:** o iframe pode ser hostil (supply-chain comprometida,\n * XSS no código do cliente). Estes schemas + a `ShellPolicy` aplicada\n * no `BridgeShell` formam o boundary estrutural — vide\n * `condor_wiki/cross-cutting/sleep-white-label-content-transport-and-security.md`.\n */\n\nimport * as v from 'valibot';\nimport { BRIDGE_KEYS } from './keys';\n\nconst BridgeKeySchema = v.picklist(Object.values(BRIDGE_KEYS) as [string, ...string[]]);\n\n// ─── Client → Shell ──────────────────────────────────────────────────\n\nexport const SubscribeMessage = v.object({\n type: v.literal('subscribe'),\n key: BridgeKeySchema,\n});\n\nexport const UnsubscribeMessage = v.object({\n type: v.literal('unsubscribe'),\n key: BridgeKeySchema,\n});\n\nexport const SendMessage = v.object({\n type: v.literal('send'),\n command: v.string(),\n args: v.optional(v.record(v.string(), v.unknown()), {}),\n});\n\nexport const HandshakeMessage = v.object({\n type: v.literal('handshake'),\n payload: v.object({ clientVersion: v.string() }),\n});\n\nexport const JsErrorMessage = v.object({\n type: v.literal('jsError'),\n payload: v.object({\n message: v.string(),\n stack: v.optional(v.string()),\n source: v.optional(v.string()),\n lineno: v.optional(v.number()),\n colno: v.optional(v.number()),\n }),\n});\n\nexport const SandboxVerifyResponseMessage = v.object({\n type: v.literal('sandbox-verify-response'),\n flutterBridgeReachable: v.boolean(),\n condorBridgeReachable: v.boolean(),\n});\n\nexport const ClientToShellMessage = v.variant('type', [\n SubscribeMessage,\n UnsubscribeMessage,\n SendMessage,\n HandshakeMessage,\n JsErrorMessage,\n SandboxVerifyResponseMessage,\n]);\n\nexport type ClientToShellMessage = v.InferOutput<typeof ClientToShellMessage>;\n\n// ─── Shell → Client ──────────────────────────────────────────────────\n\nexport const EventMessage = v.object({\n type: v.literal('event'),\n key: BridgeKeySchema,\n payload: v.unknown(),\n});\n\nexport const HandshakeAckMessage = v.object({\n type: v.literal('handshake-ack'),\n ack: v.object({\n shellVersion: v.string(),\n accepted: v.boolean(),\n }),\n});\n\nexport const NackMessage = v.object({\n type: v.literal('nack'),\n key: v.optional(v.string()),\n command: v.optional(v.string()),\n reason: v.string(),\n});\n\nexport const VerifySandboxMessage = v.object({\n type: v.literal('verify-sandbox'),\n});\n\nexport const ShellToClientMessage = v.variant('type', [\n EventMessage,\n HandshakeAckMessage,\n NackMessage,\n VerifySandboxMessage,\n]);\n\nexport type ShellToClientMessage = v.InferOutput<typeof ShellToClientMessage>;\n\n// ─── Policy ──────────────────────────────────────────────────────────\n\n/**\n * Policy default-deny aplicada pelo `BridgeShell`. Toda chave/comando\n * vindo do iframe é validado contra estas listas antes de tocar o\n * bridge nativo.\n *\n * - `readOnlyKeys`: chaves que o cliente pode subscrever (observáveis).\n * - `allowedCommands`: comandos pass-through (sem confirmação humana).\n * - `requiresConfirmation`: comandos que disparam callback `onConfirmationRequest`\n * no shell — usuário decide aprovar/recusar via UI nativa do shell.\n * - `deniedCommands`: bloqueio explícito (defesa em profundidade — comandos\n * destrutivos como `dfu` que nunca devem fluir do iframe).\n *\n * **Não embedada no package** — cliente do `BridgeShell` (no monorepo\n * `sleep_whitelabel`) provê a policy concreta. Mantém o package agnóstico\n * ao catálogo e permite policy evoluir sem novo release.\n */\nexport interface ShellPolicy {\n readOnlyKeys: string[];\n allowedCommands: string[];\n requiresConfirmation: string[];\n deniedCommands: string[];\n}\n\n/**\n * Resposta do callback `onConfirmationRequest` do `BridgeShell`.\n *\n * `approve: true` → comando flui para o nativo.\n * `approve: false` → shell envia `nack` ao iframe com `reason: 'user-rejected'`.\n */\nexport interface ConfirmationRequest {\n command: string;\n args: Record<string, unknown>;\n}\n\n/**\n * Estado retornado pelo `verifySandbox()` do `BridgeShell` após\n * round-trip com o iframe. Se algum dos `*Reachable` vier `true`, o\n * boundary está furado — Camada 1 (`bootstrapClientIframe` com override\n * prefix) falhou e a Camada 4 (dual WebView) deve ser acionada.\n */\nexport interface SandboxVerifyResult {\n flutterBridgeReachable: boolean;\n condorBridgeReachable: boolean;\n ok: boolean; // !flutterBridgeReachable && !condorBridgeReachable\n}\n"],"mappings":"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","names":["PROTOCOL_VERSION","subscribers","pendingHandshake","v"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/keys.ts","../src/internal/dev-panel.ts","../src/internal/mock.ts","../src/internal/native.ts","../src/internal/subscribers.ts","../src/bridge.ts","../src/bridge-client.ts","../src/bridge-shell.ts","../src/shell-messages.ts"],"sourcesContent":["/**\n * `condor-mobile-bridge` — SDK do bridge JS↔Native do app white-label Condor.\n *\n * Public API: `Bridge` singleton + tipos.\n *\n * Import side effect: instala `window.CondorBridge.emit` no primeiro\n * carregamento do módulo, para que o nativo possa chamar via\n * `evaluateJavascript(\"window.CondorBridge.emit('key', payload)\")`. Para\n * que esta instalação aconteça **antes** do nativo tentar emitir, o\n * import deste módulo deve ser um dos primeiros statements do bundle do\n * cliente.\n *\n * **v0.2.0:** mock mode — quando `window.flutter_inappwebview` não é\n * detectado (browser comum, Storybook, Vite dev server), o adapter ativa\n * automaticamente. `Bridge.isMock`/`mockEmit`/`getMockState`/`installDevPanel`\n * expostos para suporte ao desenvolvimento.\n *\n * **v0.4.0:** tipos estritos por chave em `PayloadOf<K>`. `Bridge.on<K>`\n * infere o payload tipado por chave catalogada. Chaves não-catalogadas\n * caem no fallback permissivo (`Record<string, unknown>`).\n *\n * **v0.5.0:** introduz `BridgeClient` (API para código de cliente externo\n * dentro de `<iframe sandbox=\"allow-scripts\">`) e `BridgeShell` (API\n * para o shell Condor-controlado que envolve o iframe). Comunicação\n * shell↔client via `window.postMessage` com schema Valibot + policy\n * default-deny. Defesa em 4 camadas contra propagação do\n * `window.flutter_inappwebview` ao iframe (vide\n * `condor_wiki/cross-cutting/sleep-white-label-content-transport-and-security.md`\n * §Risco 1).\n *\n * **v0.14.0:** chave observável `language` — o nativo informa o locale cru do\n * aparelho **e** o idioma escolhido nos ajustes do app (ou `null` quando não\n * houve escolha), para o cliente aplicar a própria regra de precedência e poder\n * renderizar idiomas que a camada nativa não suporta. Vide `LanguagePayload`.\n */\n\nexport type { CondorBridge, MockState } from './bridge';\nexport { Bridge } from './bridge';\nexport type { BridgeClientHandshakeAck, CondorBridgeClient } from './bridge-client';\nexport { BridgeClient } from './bridge-client';\nexport type { BridgeShellOptions } from './bridge-shell';\nexport { BridgeShell } from './bridge-shell';\nexport type { AutoRespondResponse, DevPanelOptions } from './internal/dev-panel';\nexport type { MockMessage } from './internal/mock';\nexport type { BridgeKey } from './keys';\nexport { BRIDGE_KEYS } from './keys';\nexport type {\n BridgeIncomingMessage,\n BridgeOutgoingEvent,\n HandshakeAck,\n HandshakeOptions,\n} from './messages';\nexport type {\n DeleteMemoryAckPayload,\n DeviceConnectionPayload,\n DeviceLightSensorsPayload,\n DeviceNotificationPayload,\n KeyPayloads,\n LanguagePayload,\n LightSensorsActlumus1Data,\n LightSensorsActlumus2Data,\n LightSensorsRawChannels,\n PayloadOf,\n PingPongPayload,\n RealTimeAckPayload,\n RequestPermissionPayload,\n SensorLogPayload,\n SensorLogQueryPayload,\n SyncTimeAckPayload,\n SystemStatusPayload,\n UserDevicePayload,\n} from './payloads';\nexport type {\n ClientToShellMessage,\n ConfirmationRequest,\n SandboxVerifyResult,\n ShellPolicy,\n ShellToClientMessage,\n} from './shell-messages';\n","/**\n * Catálogo das chaves do bridge JS↔Native.\n *\n * Espelha o lado JS-facing de `ForegroundComCoreKeys` do `condor_core`\n * (monorepo `mobile_applications`). As strings aqui são o que o JS recebe\n * via `window.CondorBridge.emit(key, payload)`.\n *\n * Camada 1 (v0.1.0): catálogo declarativo. Apenas `pingPong` está\n * efetivamente emitida pelo lado Dart no Trio B; as outras 8 são\n * reservadas para o Trio C (`sleep-whitelabel-bridge-keys`) e ficam\n * aqui como contrato forward-looking.\n */\nexport const BRIDGE_KEYS = {\n pingPong: 'pingPong',\n userDevice: 'userDevice',\n deviceLightSensors: 'deviceLightSensors',\n syncTime: 'syncTime',\n realTime: 'realTime',\n deleteMemory: 'deleteMemory',\n deviceNotification: 'deviceNotification',\n deviceConnection: 'deviceConnection',\n sensorLog: 'sensorLog',\n dfu: 'dfu',\n systemStatus: 'systemStatus',\n /**\n * Native → client: o back do SO foi pressionado e o cliente reportou\n * ter histórico interno (`reportNavigation(true)`). O cliente deve voltar\n * UMA página interna. Emitido só quando o nativo decidiu delegar o back\n * ao cliente. Vide `BridgeClient.onBack`.\n */\n navigationBack: 'navigationBack',\n /**\n * Native → client: the app's language state. Carries the raw device locale\n * AND the language explicitly chosen in the app Settings, so the client can\n * apply its own precedence rule — including rendering a language the native\n * chrome does not support. Emitted on attach, after `handshake-ack`, and on\n * every change in Settings. Vide `LanguagePayload`.\n */\n language: 'language',\n} as const;\n\nexport type BridgeKey = (typeof BRIDGE_KEYS)[keyof typeof BRIDGE_KEYS];\n","/**\n * Dev panel — UI flutuante para inspecionar o bridge em mock mode.\n *\n * **Opt-in:** chamar `Bridge.installDevPanel(opts?)` quando quiser ver\n * o painel. Só funciona em mock mode (throws em modo real). Injeta no\n * `document.body`; idempotente (re-install remove o anterior).\n *\n * Conteúdo:\n * - Header com badge \"MOCK\", contador de sends, botão minimizar/maximizar.\n * - Sent log — últimas N mensagens (timestamp, type, payload truncado).\n * - Trigger emit — dropdown com `BRIDGE_KEYS` + textarea payload + botão.\n *\n * Estilos inline + classes prefixadas `condor-mock-panel-*` para reduzir\n * conflito com CSS do cliente.\n */\n\nimport { BRIDGE_KEYS } from '../keys';\nimport type { MockAdapter, MockMessage } from './mock';\n\nconst PANEL_ID = 'condor-mock-panel-root';\nconst REFRESH_INTERVAL_MS = 500;\n\n/**\n * Resposta auto-emitida em reação a um `Bridge.send`, retornada pela\n * policy `onSendForAutoRespond` do cliente. `null` significa \"não\n * responder a este send\".\n *\n * @since v0.3.0\n */\nexport interface AutoRespondResponse {\n key: string;\n payload: unknown;\n}\n\nexport interface DevPanelOptions {\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n maxMessages?: number;\n theme?: 'dark' | 'light';\n startCollapsed?: boolean;\n\n /**\n * Policy de auto-respond: invocada a cada `Bridge.send` quando o\n * toggle \"Auto-respond\" está ligado no painel. Retorna\n * `{key, payload}` para disparar `Bridge.mockEmit(key, payload)`\n * após delay, ou `null` para não responder.\n *\n * Sem esta callback, o checkbox \"Auto-respond\" não aparece no painel.\n *\n * @since v0.3.0\n */\n onSendForAutoRespond?: (msg: MockMessage) => AutoRespondResponse | null;\n\n /**\n * Estado inicial do toggle \"Auto-respond\". Default: `false`\n * (manual permanece padrão; cliente decide quando ligar).\n *\n * @since v0.3.0\n */\n startAutoRespondEnabled?: boolean;\n\n /**\n * Delay em ms entre o `send` e o `mockEmit` da auto-resposta.\n * Default: `50` — aproxima latência de IPC real de native bridge.\n *\n * @since v0.3.0\n */\n autoRespondDelayMs?: number;\n}\n\ninterface InstallParams {\n adapter: MockAdapter;\n options?: DevPanelOptions;\n}\n\ninterface ResolvedOptions {\n position: NonNullable<DevPanelOptions['position']>;\n maxMessages: number;\n theme: NonNullable<DevPanelOptions['theme']>;\n startCollapsed: boolean;\n startAutoRespondEnabled: boolean;\n autoRespondDelayMs: number;\n}\n\nconst DEFAULTS: ResolvedOptions = {\n position: 'bottom-right',\n maxMessages: 20,\n theme: 'dark',\n startCollapsed: false,\n startAutoRespondEnabled: false,\n autoRespondDelayMs: 50,\n};\n\nfunction resolveOptions(opts?: DevPanelOptions): ResolvedOptions {\n return {\n position: opts?.position ?? DEFAULTS.position,\n maxMessages: opts?.maxMessages ?? DEFAULTS.maxMessages,\n theme: opts?.theme ?? DEFAULTS.theme,\n startCollapsed: opts?.startCollapsed ?? DEFAULTS.startCollapsed,\n startAutoRespondEnabled: opts?.startAutoRespondEnabled ?? DEFAULTS.startAutoRespondEnabled,\n autoRespondDelayMs: opts?.autoRespondDelayMs ?? DEFAULTS.autoRespondDelayMs,\n };\n}\n\nfunction applyPanelStyles(el: HTMLElement, opts: ResolvedOptions): void {\n const isDark = opts.theme === 'dark';\n const positions: Record<ResolvedOptions['position'], Partial<CSSStyleDeclaration>> = {\n 'bottom-right': { bottom: '12px', right: '12px' },\n 'bottom-left': { bottom: '12px', left: '12px' },\n 'top-right': { top: '12px', right: '12px' },\n 'top-left': { top: '12px', left: '12px' },\n };\n Object.assign(el.style, {\n position: 'fixed',\n width: '340px',\n maxHeight: '420px',\n zIndex: '2147483647',\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n fontSize: '12px',\n color: isDark ? '#e0e0e0' : '#222',\n background: isDark ? '#1a1a1aee' : '#ffffffee',\n border: isDark ? '1px solid #444' : '1px solid #ccc',\n borderRadius: '6px',\n boxShadow: '0 4px 12px rgba(0,0,0,0.3)',\n overflow: 'hidden',\n display: 'flex',\n flexDirection: 'column',\n ...positions[opts.position],\n });\n}\n\nfunction buildHeader(badge: HTMLElement, counter: HTMLElement, toggle: HTMLElement): HTMLElement {\n const header = document.createElement('div');\n header.className = 'condor-mock-panel-header';\n Object.assign(header.style, {\n padding: '6px 10px',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n background: '#0a84ff',\n color: '#fff',\n fontWeight: '600',\n cursor: 'pointer',\n });\n Object.assign(badge.style, {\n background: '#fff',\n color: '#0a84ff',\n padding: '1px 6px',\n borderRadius: '3px',\n fontSize: '10px',\n letterSpacing: '0.5px',\n });\n badge.textContent = 'MOCK';\n Object.assign(counter.style, {\n marginLeft: 'auto',\n fontSize: '11px',\n opacity: '0.9',\n });\n Object.assign(toggle.style, {\n background: 'transparent',\n border: '1px solid rgba(255,255,255,0.5)',\n color: '#fff',\n cursor: 'pointer',\n padding: '0 6px',\n borderRadius: '3px',\n fontFamily: 'inherit',\n });\n header.append(badge, document.createTextNode('condor-bridge'), counter, toggle);\n return header;\n}\n\nfunction buildSentSection(): { container: HTMLElement; list: HTMLElement } {\n const container = document.createElement('div');\n container.className = 'condor-mock-panel-sent';\n Object.assign(container.style, {\n padding: '6px 10px',\n borderBottom: '1px solid rgba(255,255,255,0.08)',\n maxHeight: '180px',\n overflowY: 'auto',\n });\n const title = document.createElement('div');\n title.textContent = 'Sent';\n Object.assign(title.style, { opacity: '0.7', marginBottom: '4px', fontSize: '11px' });\n const list = document.createElement('div');\n list.className = 'condor-mock-panel-sent-list';\n container.append(title, list);\n return { container, list };\n}\n\nfunction buildTriggerSection(\n bridgeKeys: readonly string[],\n onEmit: (key: string, payloadJson: string) => void,\n onClear: () => void,\n): HTMLElement {\n const container = document.createElement('div');\n container.className = 'condor-mock-panel-trigger';\n Object.assign(container.style, {\n padding: '6px 10px',\n display: 'flex',\n flexDirection: 'column',\n gap: '4px',\n });\n const title = document.createElement('div');\n title.textContent = 'Trigger emit';\n Object.assign(title.style, { opacity: '0.7', fontSize: '11px' });\n\n const select = document.createElement('select');\n select.className = 'condor-mock-panel-key-select';\n Object.assign(select.style, {\n background: 'transparent',\n color: 'inherit',\n border: '1px solid rgba(255,255,255,0.2)',\n padding: '4px',\n borderRadius: '3px',\n fontFamily: 'inherit',\n fontSize: '11px',\n });\n for (const key of bridgeKeys) {\n const opt = document.createElement('option');\n opt.value = key;\n opt.textContent = key;\n select.appendChild(opt);\n }\n const ackOpt = document.createElement('option');\n ackOpt.value = 'handshake-ack';\n ackOpt.textContent = 'handshake-ack';\n select.appendChild(ackOpt);\n\n const textarea = document.createElement('textarea');\n textarea.className = 'condor-mock-panel-payload';\n textarea.placeholder = '{ \"data\": \"pong\" }';\n Object.assign(textarea.style, {\n background: 'transparent',\n color: 'inherit',\n border: '1px solid rgba(255,255,255,0.2)',\n padding: '4px',\n borderRadius: '3px',\n fontFamily: 'inherit',\n fontSize: '11px',\n minHeight: '50px',\n resize: 'vertical',\n });\n\n const buttons = document.createElement('div');\n Object.assign(buttons.style, { display: 'flex', gap: '6px' });\n\n const emitBtn = document.createElement('button');\n emitBtn.type = 'button';\n emitBtn.textContent = 'Emit';\n emitBtn.className = 'condor-mock-panel-emit-btn';\n Object.assign(emitBtn.style, {\n background: '#0a84ff',\n color: '#fff',\n border: 'none',\n padding: '4px 10px',\n borderRadius: '3px',\n cursor: 'pointer',\n fontFamily: 'inherit',\n fontSize: '11px',\n flex: '1',\n });\n emitBtn.addEventListener('click', () => {\n onEmit(select.value, textarea.value);\n });\n\n const clearBtn = document.createElement('button');\n clearBtn.type = 'button';\n clearBtn.textContent = 'Clear sent';\n clearBtn.className = 'condor-mock-panel-clear-btn';\n Object.assign(clearBtn.style, {\n background: 'transparent',\n color: 'inherit',\n border: '1px solid rgba(255,255,255,0.3)',\n padding: '4px 10px',\n borderRadius: '3px',\n cursor: 'pointer',\n fontFamily: 'inherit',\n fontSize: '11px',\n });\n clearBtn.addEventListener('click', onClear);\n\n buttons.append(emitBtn, clearBtn);\n container.append(title, select, textarea, buttons);\n return container;\n}\n\nfunction buildAutoRespondSection(\n initialEnabled: boolean,\n onChange: (next: boolean) => void,\n): HTMLElement {\n const container = document.createElement('div');\n container.className = 'condor-mock-panel-auto-respond';\n Object.assign(container.style, {\n padding: '6px 10px',\n borderBottom: '1px solid rgba(255,255,255,0.08)',\n display: 'flex',\n flexDirection: 'column',\n gap: '2px',\n });\n\n const title = document.createElement('div');\n title.textContent = 'Auto-respond';\n Object.assign(title.style, { opacity: '0.7', fontSize: '11px' });\n\n const row = document.createElement('label');\n Object.assign(row.style, {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n cursor: 'pointer',\n fontSize: '12px',\n });\n\n const checkbox = document.createElement('input');\n checkbox.type = 'checkbox';\n checkbox.className = 'condor-mock-panel-auto-respond-toggle';\n checkbox.checked = initialEnabled;\n Object.assign(checkbox.style, {\n cursor: 'pointer',\n });\n\n const label = document.createElement('span');\n label.textContent = 'Enabled — mockEmit em resposta a cada send (policy do cliente)';\n\n checkbox.addEventListener('change', () => {\n onChange(checkbox.checked);\n });\n\n row.append(checkbox, label);\n container.append(title, row);\n return container;\n}\n\nfunction renderSentList(list: HTMLElement, adapter: MockAdapter, max: number): void {\n list.innerHTML = '';\n const all = adapter.getMessages();\n const tail = all.slice(-max).reverse();\n for (const msg of tail) {\n const row = document.createElement('div');\n Object.assign(row.style, {\n padding: '3px 0',\n borderBottom: '1px solid rgba(255,255,255,0.06)',\n wordBreak: 'break-all',\n });\n const ts = new Date(msg.timestamp).toLocaleTimeString();\n const payload = msg.payload as { type?: string };\n const type = payload?.type ?? '?';\n row.textContent = `${ts} → ${type} ${JSON.stringify(msg.payload).slice(0, 80)}`;\n list.appendChild(row);\n }\n}\n\ninterface InstalledPanel {\n uninstall(): void;\n refresh(): void;\n}\n\nlet currentPanel: InstalledPanel | null = null;\n\nexport function installDevPanel(params: InstallParams): InstalledPanel {\n if (typeof document === 'undefined') {\n throw new Error('condor-mobile-bridge dev panel: document is undefined (Node-only env).');\n }\n\n // Idempotente: remove painel anterior se existir.\n if (currentPanel) {\n currentPanel.uninstall();\n currentPanel = null;\n }\n\n const opts = resolveOptions(params.options);\n const root = document.createElement('div');\n root.id = PANEL_ID;\n applyPanelStyles(root, opts);\n\n const badge = document.createElement('span');\n const counter = document.createElement('span');\n const toggle = document.createElement('button');\n toggle.type = 'button';\n toggle.textContent = opts.startCollapsed ? '+' : '−';\n const header = buildHeader(badge, counter, toggle);\n\n const body = document.createElement('div');\n Object.assign(body.style, {\n display: opts.startCollapsed ? 'none' : 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n });\n\n const { container: sentContainer, list: sentList } = buildSentSection();\n\n // Auto-respond section — conditional render: só aparece se policy fornecida.\n const policy = params.options?.onSendForAutoRespond;\n let autoRespondEnabled = opts.startAutoRespondEnabled;\n let unsubscribeSendListener: (() => void) | null = null;\n\n let autoRespondSection: HTMLElement | null = null;\n if (policy) {\n autoRespondSection = buildAutoRespondSection(autoRespondEnabled, (next) => {\n autoRespondEnabled = next;\n });\n unsubscribeSendListener = params.adapter.onCallHandler((msg) => {\n if (!autoRespondEnabled) return;\n let response: AutoRespondResponse | null;\n try {\n response = policy(msg);\n } catch (err) {\n console.error('[condor-mobile-bridge dev-panel] onSendForAutoRespond threw:', err);\n return;\n }\n if (!response) return;\n setTimeout(() => {\n try {\n params.adapter.triggerEmit(response.key, response.payload);\n } catch (err) {\n console.error(\n '[condor-mobile-bridge dev-panel] triggerEmit failed in auto-respond:',\n err,\n );\n }\n }, opts.autoRespondDelayMs);\n });\n }\n\n const trigger = buildTriggerSection(\n Object.values(BRIDGE_KEYS),\n (key, payloadJson) => {\n let payload: unknown = {};\n const trimmed = payloadJson.trim();\n if (trimmed.length > 0) {\n try {\n payload = JSON.parse(trimmed);\n } catch (err) {\n console.error('[condor-mobile-bridge dev-panel] invalid JSON payload', err);\n return;\n }\n }\n params.adapter.triggerEmit(key, payload);\n },\n () => {\n params.adapter.clearMessages();\n renderSentList(sentList, params.adapter, opts.maxMessages);\n counter.textContent = '0 sent';\n },\n );\n\n if (autoRespondSection) {\n body.append(sentContainer, autoRespondSection, trigger);\n } else {\n body.append(sentContainer, trigger);\n }\n root.append(header, body);\n\n toggle.addEventListener('click', (e) => {\n e.stopPropagation();\n const collapsed = body.style.display === 'none';\n body.style.display = collapsed ? 'flex' : 'none';\n toggle.textContent = collapsed ? '−' : '+';\n });\n\n document.body.appendChild(root);\n\n const refresh = () => {\n const count = params.adapter.getMessages().length;\n counter.textContent = `${count} sent`;\n renderSentList(sentList, params.adapter, opts.maxMessages);\n };\n refresh();\n\n const interval = setInterval(refresh, REFRESH_INTERVAL_MS);\n\n const panel: InstalledPanel = {\n uninstall() {\n clearInterval(interval);\n unsubscribeSendListener?.();\n unsubscribeSendListener = null;\n root.remove();\n if (currentPanel === panel) currentPanel = null;\n },\n refresh,\n };\n currentPanel = panel;\n return panel;\n}\n\n/**\n * Inspeção (testes/debug).\n */\nexport function getInstalledDevPanel(): InstalledPanel | null {\n return currentPanel;\n}\n","/**\n * Mock adapter — ativo quando `window.flutter_inappwebview` não é\n * detectado (browser dev, jsdom sem host instalado, Storybook etc.).\n *\n * Comportamento:\n * - `callHandler` grava `{handlerName, payload, timestamp}` em buffer\n * interno (cap 100, FIFO), loga via `console.debug` e dispatcha\n * listeners registrados via `onCallHandler`.\n * - `triggerEmit` dispatcha via `window.CondorBridge.emit` — bridge real\n * trata como se viesse do nativo (handshake-ack resolve handshake;\n * demais chaves vão pros subscribers).\n * - `getMessages` retorna snapshot read-only do buffer.\n * - `clearMessages` esvazia o buffer (útil em testes).\n * - `onCallHandler(listener)` — registra listener invocado a cada send.\n * Retorna função de unsubscribe. Útil para dev panel reagir a sends\n * (v0.3.0+ auto-respond toggle) ou análise em testes.\n */\n\nconst MAX_BUFFER = 100;\n\nexport interface MockMessage {\n handlerName: string;\n payload: unknown;\n timestamp: number;\n}\n\nexport interface MockAdapter {\n readonly isMock: true;\n callHandler(handlerName: string, payload: unknown): void;\n getMessages(): readonly MockMessage[];\n clearMessages(): void;\n triggerEmit(key: string, payload: unknown): void;\n /**\n * Registra listener invocado a cada `callHandler` (mensagem JS→Native).\n * Retorna função de unsubscribe.\n *\n * Erros em listeners são capturados + logados; não afetam outros\n * listeners nem o pipeline do bridge.\n *\n * @since v0.3.0\n */\n onCallHandler(listener: (msg: MockMessage) => void): () => void;\n}\n\nexport function createMockAdapter(): MockAdapter {\n const messages: MockMessage[] = [];\n const sendListeners = new Set<(msg: MockMessage) => void>();\n\n return {\n isMock: true,\n\n callHandler(handlerName, payload) {\n const msg: MockMessage = { handlerName, payload, timestamp: Date.now() };\n messages.push(msg);\n if (messages.length > MAX_BUFFER) {\n messages.shift();\n }\n console.debug('[condor-mobile-bridge mock] →', handlerName, payload);\n for (const listener of sendListeners) {\n try {\n listener(msg);\n } catch (err) {\n console.error('[condor-mobile-bridge mock] send listener threw:', err);\n }\n }\n },\n\n getMessages() {\n return messages;\n },\n\n clearMessages() {\n messages.length = 0;\n },\n\n triggerEmit(key, payload) {\n const bridge = typeof window !== 'undefined' ? window.CondorBridge : undefined;\n if (!bridge || typeof bridge.emit !== 'function') {\n throw new Error(\n 'condor-mobile-bridge mock: window.CondorBridge not bootstrapped; cannot emit.',\n );\n }\n bridge.emit(key, payload);\n },\n\n onCallHandler(listener) {\n sendListeners.add(listener);\n return () => {\n sendListeners.delete(listener);\n };\n },\n };\n}\n","/**\n * Detecção do host nativo + adapter pattern.\n *\n * **v0.1.0:** lançava erro quando `window.flutter_inappwebview` ausente.\n * **v0.2.0:** ativa mock adapter (`createMockAdapter`) — destrava dev em\n * browser comum sem buildar APK.\n *\n * Adapter ativo é cached na primeira chamada de `getActiveAdapter()`.\n * Tests devem chamar `__resetAdapterForTests()` no `beforeEach` para\n * forçar re-detecção (ex.: após instalar/remover `window.flutter_inappwebview`).\n */\n\nimport { createMockAdapter, type MockAdapter } from './mock';\n\ninterface FlutterInAppWebView {\n callHandler(name: string, ...args: unknown[]): Promise<unknown>;\n}\n\ndeclare global {\n interface Window {\n flutter_inappwebview?: FlutterInAppWebView;\n }\n}\n\nexport interface RealAdapter {\n readonly isMock: false;\n callHandler(handlerName: string, payload: unknown): void;\n}\n\nexport type NativeAdapter = RealAdapter | MockAdapter;\n\nlet activeAdapter: NativeAdapter | null = null;\n\nfunction createRealAdapter(host: FlutterInAppWebView): RealAdapter {\n return {\n isMock: false,\n callHandler(handlerName, payload) {\n void host.callHandler(handlerName, payload);\n },\n };\n}\n\nfunction detectAdapter(): NativeAdapter {\n if (typeof window === 'undefined') {\n return createMockAdapter();\n }\n const host = window.flutter_inappwebview;\n if (host && typeof host.callHandler === 'function') {\n return createRealAdapter(host);\n }\n return createMockAdapter();\n}\n\nexport function getActiveAdapter(): NativeAdapter {\n if (!activeAdapter) {\n activeAdapter = detectAdapter();\n }\n return activeAdapter;\n}\n\nexport function hasNativeHost(): boolean {\n return !getActiveAdapter().isMock;\n}\n\n/**\n * Envia mensagem ao native handler via adapter ativo.\n *\n * Em modo real: fire-and-forget `flutter_inappwebview.callHandler`.\n * Em modo mock: grava no buffer + `console.debug`.\n */\nexport function callNative(handlerName: string, payload: unknown): void {\n getActiveAdapter().callHandler(handlerName, payload);\n}\n\n/**\n * Reseta cache do adapter. **Exportado para uso em testes apenas.**\n *\n * Cliente NUNCA deve chamar isso em código de aplicação — o adapter é\n * detectado uma vez no startup e mantido.\n */\nexport function __resetAdapterForTests(): void {\n activeAdapter = null;\n}\n","import type { BridgeKey } from '../keys';\nimport type { PayloadOf } from '../payloads';\n\ntype Callback = (payload: unknown) => void;\n\nconst subscribers = new Map<string, Set<Callback>>();\n\nexport function addSubscriber<K extends BridgeKey>(\n key: K,\n cb: (payload: PayloadOf<K>) => void,\n): () => void {\n let set = subscribers.get(key);\n if (!set) {\n set = new Set<Callback>();\n subscribers.set(key, set);\n }\n set.add(cb as Callback);\n return () => {\n const current = subscribers.get(key);\n if (!current) return;\n current.delete(cb as Callback);\n if (current.size === 0) {\n subscribers.delete(key);\n }\n };\n}\n\nexport function dispatchToSubscribers(key: string, payload: unknown): void {\n const set = subscribers.get(key);\n if (!set) return;\n for (const cb of set) {\n try {\n cb(payload);\n } catch (err) {\n // Subscriber bugado não deve afetar os outros nem o bridge.\n console.error(`[condor-mobile-bridge] subscriber for \"${key}\" threw:`, err);\n }\n }\n}\n\n/**\n * Limpa todos os subscribers. Útil em testes para isolar casos.\n */\nexport function clearAllSubscribers(): void {\n subscribers.clear();\n}\n\n/**\n * Inspeção (testes/debug).\n */\nexport function getSubscriberCount(key: string): number {\n return subscribers.get(key)?.size ?? 0;\n}\n\n/**\n * Lista das chaves com subscribers ativos (testes/debug/dev panel).\n */\nexport function getSubscriberKeys(): string[] {\n return Array.from(subscribers.keys());\n}\n","import type { DevPanelOptions } from './internal/dev-panel';\nimport { installDevPanel as installDevPanelInternal } from './internal/dev-panel';\nimport type { MockAdapter, MockMessage } from './internal/mock';\nimport { callNative, getActiveAdapter } from './internal/native';\nimport { addSubscriber, dispatchToSubscribers, getSubscriberKeys } from './internal/subscribers';\nimport type { BridgeKey } from './keys';\nimport type { HandshakeAck, HandshakeOptions } from './messages';\nimport type { PayloadOf } from './payloads';\n\nconst HANDSHAKE_ACK_KEY = 'handshake-ack';\nconst NATIVE_HANDLER = 'CondorBridge';\nconst PROTOCOL_VERSION = '0.1.0';\n\ninterface PendingHandshake {\n resolve: (ack: HandshakeAck) => void;\n reject: (err: Error) => void;\n}\n\ninterface WindowCondorBridge {\n emit(key: string, payload: unknown): void;\n}\n\ndeclare global {\n interface Window {\n CondorBridge?: WindowCondorBridge;\n }\n}\n\nlet pendingHandshake: PendingHandshake | null = null;\nlet bridgeBootstrapped = false;\n\nfunction emit(key: string, payload: unknown): void {\n if (key === HANDSHAKE_ACK_KEY && pendingHandshake) {\n const ack = (payload ?? {}) as Partial<HandshakeAck>;\n const resolver = pendingHandshake;\n pendingHandshake = null;\n resolver.resolve({\n nativeVersion: ack.nativeVersion ?? 'unknown',\n accepted: ack.accepted ?? false,\n });\n return;\n }\n dispatchToSubscribers(key, payload);\n}\n\nfunction bootstrapWindowBridge(): void {\n if (bridgeBootstrapped) return;\n if (typeof window === 'undefined') return;\n bridgeBootstrapped = true;\n\n if (window.CondorBridge && typeof window.CondorBridge.emit === 'function') {\n // Já instalado (HMR / double import / mock instalado por testes).\n // Substitui apenas o emit para garantir que o dispatcher mais recente\n // esteja conectado aos subscribers desta instância do módulo.\n window.CondorBridge.emit = emit;\n } else {\n window.CondorBridge = { emit };\n }\n}\n\nbootstrapWindowBridge();\n\nfunction requireMockAdapter(): MockAdapter {\n const adapter = getActiveAdapter();\n if (!adapter.isMock) {\n throw new Error(\n 'condor-mobile-bridge: this API is available only in mock mode (no native host detected).',\n );\n }\n return adapter;\n}\n\nexport interface MockState {\n readonly isMock: true;\n readonly messages: readonly MockMessage[];\n readonly subscriberKeys: readonly string[];\n}\n\nexport interface CondorBridge {\n /**\n * `true` quando o adapter ativo é mock (browser dev, sem\n * `window.flutter_inappwebview`). `false` quando rodando dentro do\n * WebView Flutter.\n */\n readonly isMock: boolean;\n\n /**\n * Envia handshake versionado ao nativo e aguarda `handshake-ack`.\n *\n * Apenas um handshake pode estar pendente por vez. Chamadas paralelas\n * antes do primeiro `ack` chegar são rejeitadas com erro claro.\n *\n * **Em mock mode:** NÃO resolve sozinho. Cliente/teste deve chamar\n * `Bridge.mockEmit('handshake-ack', {nativeVersion, accepted})` para\n * destravar a Promise. Esta decisão (`Explícito`) força testes a serem\n * intencionais sobre o estado nativo.\n */\n handshake(opts: HandshakeOptions): Promise<HandshakeAck>;\n\n /**\n * Subscreve a uma chave observável. Retorna função `unsubscribe`.\n *\n * Múltiplos subscribers por chave são permitidos. Erro em um subscriber\n * não afeta os outros (capturado e logado em `console.error`).\n */\n on<K extends BridgeKey>(key: K, cb: (payload: PayloadOf<K>) => void): () => void;\n\n /**\n * Envia mensagem genérica ao nativo. Use para comandos UI→BG que não\n * tenham helper dedicado. `type` é a string que o native usa para\n * roteamento no `_onJsMessage`.\n *\n * Em mock mode: grava no buffer interno + `console.debug`.\n */\n send(type: string, payload?: Record<string, unknown>): void;\n\n /**\n * Abre a tela nativa de Settings do app. Equivalente a\n * `Bridge.send('openSettings')`.\n */\n openSettings(): void;\n\n /**\n * Dispara `window.CondorBridge.emit(key, payload)` programaticamente —\n * útil para simular eventos nativos em testes e dev em browser.\n *\n * **Throws** se o adapter ativo não for mock.\n */\n mockEmit(key: string, payload?: unknown): void;\n\n /**\n * Snapshot do estado do mock adapter (mensagens enviadas + chaves com\n * subscribers ativos). Useful para asserts em testes de cliente.\n *\n * **Throws** se o adapter ativo não for mock.\n */\n getMockState(): MockState;\n\n /**\n * Injeta painel HTML flutuante no `document.body` para inspecionar o\n * bridge em mock mode. Idempotente — re-install substitui o anterior.\n *\n * **Throws** se o adapter ativo não for mock OU se `document` não existir.\n */\n installDevPanel(options?: DevPanelOptions): void;\n}\n\nexport const Bridge: CondorBridge = {\n get isMock(): boolean {\n return getActiveAdapter().isMock;\n },\n\n handshake(opts: HandshakeOptions): Promise<HandshakeAck> {\n bootstrapWindowBridge();\n if (pendingHandshake) {\n return Promise.reject(\n new Error(\n 'condor-mobile-bridge: handshake already in flight. Await the previous call before issuing another.',\n ),\n );\n }\n return new Promise<HandshakeAck>((resolve, reject) => {\n pendingHandshake = { resolve, reject };\n try {\n callNative(NATIVE_HANDLER, {\n type: 'handshake',\n version: PROTOCOL_VERSION,\n payload: { clientVersion: opts.clientVersion },\n });\n } catch (err) {\n pendingHandshake = null;\n reject(err instanceof Error ? err : new Error(String(err)));\n }\n });\n },\n\n on<K extends BridgeKey>(key: K, cb: (payload: PayloadOf<K>) => void): () => void {\n bootstrapWindowBridge();\n return addSubscriber(key, cb);\n },\n\n send(type: string, payload?: Record<string, unknown>): void {\n callNative(NATIVE_HANDLER, {\n type,\n version: PROTOCOL_VERSION,\n payload: payload ?? {},\n });\n },\n\n openSettings(): void {\n this.send('openSettings');\n },\n\n mockEmit(key: string, payload?: unknown): void {\n requireMockAdapter().triggerEmit(key, payload ?? {});\n },\n\n getMockState(): MockState {\n const adapter = requireMockAdapter();\n return {\n isMock: true,\n messages: adapter.getMessages(),\n subscriberKeys: getSubscriberKeys(),\n };\n },\n\n installDevPanel(options?: DevPanelOptions): void {\n const adapter = requireMockAdapter();\n installDevPanelInternal({ adapter, options });\n },\n};\n\n/**\n * Reseta o estado interno do bridge (handshake pendente).\n *\n * **Exportado para uso em testes apenas.** Não chamar em código de\n * aplicação — quebra a semântica de \"apenas um handshake pendente\".\n */\nexport function __resetBridgeForTests(): void {\n pendingHandshake = null;\n}\n","/**\n * `BridgeClient` (v0.5.0) — API para código do cliente externo rodando\n * dentro de `<iframe sandbox=\"allow-scripts\">` no `sleep_whitelabel`.\n *\n * Surface idêntica ao `Bridge` legado (`on`/`send`/`openSettings`/`handshake`)\n * — cliente importa e não percebe que está em sandbox. Internamente,\n * todas as chamadas viram `window.parent.postMessage(...)` com schema\n * validado pelo shell antes de chegar ao nativo.\n *\n * **Não expõe** `installDevPanel`, `mockEmit`, `isMock`, `getMockState` —\n * essas APIs são responsabilidade do shell (`BridgeShell`).\n *\n * **Threat model & Camada 2 do Risco 1** (vide\n * `sleep-white-label-content-transport-and-security.md`): este módulo\n * também responde ao `verify-sandbox` do shell — função de attestation\n * do próprio iframe sobre se ainda enxerga `window.flutter_inappwebview`\n * ou `window.CondorBridge` (que deveriam ter sido deletados pela Camada 1).\n * Se vier `true` em algum, o shell aborta o boot do app.\n */\n\nimport { BRIDGE_KEYS, type BridgeKey } from './keys';\nimport type { PayloadOf, SensorLogPayload, SensorLogQueryPayload } from './payloads';\nimport type { ClientToShellMessage, ShellToClientMessage } from './shell-messages';\n\nconst PROTOCOL_VERSION = '0.5.0';\nconst HANDSHAKE_TIMEOUT_MS = 5000;\n/**\n * Timeout padrão de uma página de `sensorLog`. Uma página de 1000 logs custa\n * ~2,7 s no pior caso medido (device gen2), então a margem é deliberada.\n */\nconst SENSOR_LOG_TIMEOUT_MS = 10000;\n\ninterface PendingHandshake {\n resolve: (ack: BridgeClientHandshakeAck) => void;\n reject: (err: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\ninterface Subscriber {\n // Stored as (unknown) — typed inference comes from public `on<K>`.\n cb: (payload: unknown) => void;\n}\n\nconst subscribers = new Map<string, Subscriber[]>();\nlet pendingHandshake: PendingHandshake | null = null;\nlet messageListenerInstalled = false;\n\nfunction postToShell(msg: ClientToShellMessage): void {\n if (typeof window === 'undefined' || window.parent === window) {\n // No parent — not in iframe. Caller bug; silently drop.\n console.warn('[BridgeClient] no parent window; message dropped:', msg.type);\n return;\n }\n window.parent.postMessage(msg, '*');\n}\n\nfunction dispatchEvent(key: string, payload: unknown): void {\n const arr = subscribers.get(key);\n if (!arr || arr.length === 0) return;\n for (const sub of arr) {\n try {\n sub.cb(payload);\n } catch (err) {\n console.error('[BridgeClient] subscriber error:', err);\n }\n }\n}\n\nfunction onMessage(event: MessageEvent): void {\n if (event.source !== window.parent) return;\n // Não validamos com Valibot aqui — o shell é trusted (Condor-controlado).\n // Validamos só o `type` para evitar crashes por payload malformado.\n const data = event.data as Partial<ShellToClientMessage>;\n if (!data || typeof data !== 'object' || typeof data.type !== 'string') return;\n\n switch (data.type) {\n case 'event': {\n const msg = data as Extract<ShellToClientMessage, { type: 'event' }>;\n if (typeof msg.key === 'string') dispatchEvent(msg.key, msg.payload);\n break;\n }\n case 'handshake-ack': {\n const msg = data as Extract<ShellToClientMessage, { type: 'handshake-ack' }>;\n if (pendingHandshake) {\n clearTimeout(pendingHandshake.timer);\n const { resolve } = pendingHandshake;\n pendingHandshake = null;\n resolve({\n shellVersion: msg.ack?.shellVersion ?? 'unknown',\n // `?? null` cobre o shell anterior à 0.17.0, que não mandava o campo.\n nativeVersion: msg.ack?.nativeVersion ?? null,\n accepted: msg.ack?.accepted ?? false,\n });\n }\n break;\n }\n case 'nack':\n // Cliente pode ouvir nacks via `Bridge.on('__nack', ...)` em futuras versões.\n // v0.5.0: só loga, sem dispatcher dedicado.\n console.warn('[BridgeClient] command nacked by shell:', data);\n break;\n case 'verify-sandbox': {\n // Camada 2 do Risco 1: shell pergunta se ainda enxergamos os bridges\n // nativos. Resposta autoritativa do iframe sobre seu próprio estado.\n const w = window as unknown as Record<string, unknown>;\n postToShell({\n type: 'sandbox-verify-response',\n flutterBridgeReachable: typeof w.flutter_inappwebview !== 'undefined',\n condorBridgeReachable: typeof w.CondorBridge !== 'undefined',\n });\n break;\n }\n }\n}\n\nfunction ensureMessageListener(): void {\n if (messageListenerInstalled) return;\n if (typeof window === 'undefined') return;\n messageListenerInstalled = true;\n window.addEventListener('message', onMessage);\n}\n\nensureMessageListener();\n\nexport interface BridgeClientHandshakeAck {\n shellVersion: string;\n /**\n * Versão do schema do **nativo**, repassada pelo shell — `null` se o nativo\n * ainda não respondeu ou não existe (mock de browser).\n *\n * É por este número que um cliente decide se pode depender de capacidade\n * nova: não há negociação de versão, e o cliente sandboxed não alcança o\n * nativo por nenhum outro caminho. Ex.: canais crus de luz\n * (`light_sensor_*` em `deviceLightSensors`) existem a partir da `0.16.0`.\n */\n nativeVersion: string | null;\n accepted: boolean;\n}\n\nexport interface CondorBridgeClient {\n /**\n * Versão do protocolo do client.\n */\n readonly protocolVersion: string;\n\n /**\n * Subscreve a uma chave observável. Retorna função `unsubscribe`.\n * Múltiplos subscribers por chave permitidos. Erro em um subscriber\n * não afeta os outros.\n */\n on<K extends BridgeKey>(key: K, cb: (payload: PayloadOf<K>) => void): () => void;\n\n /**\n * Envia comando para o shell. Shell valida contra `ShellPolicy` antes\n * de tocar o nativo. Comandos não permitidos → `nack` (logado em\n * `console.warn` na v0.5.0).\n */\n send(command: string, args?: Record<string, unknown>): void;\n\n /**\n * Abre Settings nativa. Equivalente a `send('openSettings')`.\n */\n openSettings(): void;\n\n /**\n * Pede UMA página de sensor logs e resolve com a resposta correlacionada\n * pelo `requestId` — inclusive quando ela traz `success: false`, que é\n * resposta e não falha de transporte. A Promise só **rejeita** por timeout.\n *\n * Dispensa o cliente de manter o mapa `requestId → resolve` à mão. Para\n * varrer um período, encadeie as chamadas usando o `startingAfter` devolvido\n * até `hasMore` virar `false`: os cursores são dependentes, então as páginas\n * **não** podem ser buscadas em paralelo.\n */\n fetchSensorLog(\n query: SensorLogQueryPayload,\n opts?: { timeoutMs?: number },\n ): Promise<SensorLogPayload>;\n\n /**\n * Solicita UMA permissão via **diálogo nativo in-app** (não abre Settings).\n * Equivalente a `send('requestPermission', { permission })`. Use no botão\n * \"Conceder\" do card Necessárias, com um nome vindo de\n * `systemStatus.missingEssentialPermissions` (ex.: `'bluetoothScan'`).\n * O resultado chega via re-emissão de `systemStatus` (sem chave dedicada).\n */\n requestPermission(permission: string): void;\n\n /**\n * Handshake com o shell. Resolve com `{ shellVersion, accepted }`.\n * Timeout em 5s se shell não responder.\n *\n * Apenas um handshake pode estar pendente por vez.\n */\n handshake(opts: { clientVersion: string }): Promise<BridgeClientHandshakeAck>;\n\n /**\n * Reporta ao nativo se o cliente tem histórico interno para voltar.\n * **Chame a cada mudança de rota interna** (e no boot). O nativo cacheia\n * este estado e o usa para decidir o botão/gesture de voltar do SO:\n * - `true` → o back do SO pede uma volta interna (evento `navigationBack`,\n * vide `onBack`).\n * - `false` → o back do SO fica na home (não sai da página).\n *\n * Equivalente a `send('navigationState', { canGoBack })`.\n */\n reportNavigation(canGoBack: boolean): void;\n\n /**\n * Assina o pedido de back do SO (evento `navigationBack`). O callback deve\n * voltar **uma** página interna do cliente e então chamar\n * `reportNavigation(...)` com o novo estado. Só é chamado quando o cliente\n * havia reportado `reportNavigation(true)`. Retorna função `unsubscribe`.\n */\n onBack(cb: () => void): () => void;\n}\n\nexport const BridgeClient: CondorBridgeClient = {\n protocolVersion: PROTOCOL_VERSION,\n\n on<K extends BridgeKey>(key: K, cb: (payload: PayloadOf<K>) => void): () => void {\n ensureMessageListener();\n const arr = subscribers.get(key) ?? [];\n const sub: Subscriber = { cb: cb as (payload: unknown) => void };\n arr.push(sub);\n subscribers.set(key, arr);\n // Notifica shell para registrar subscription no native (idempotente\n // no shell — múltiplos `subscribe` para a mesma chave são tratados).\n postToShell({ type: 'subscribe', key });\n return () => {\n const remaining = (subscribers.get(key) ?? []).filter((s) => s !== sub);\n subscribers.set(key, remaining);\n if (remaining.length === 0) postToShell({ type: 'unsubscribe', key });\n };\n },\n\n send(command: string, args: Record<string, unknown> = {}): void {\n postToShell({ type: 'send', command, args });\n },\n\n openSettings(): void {\n this.send('openSettings');\n },\n\n fetchSensorLog(\n query: SensorLogQueryPayload,\n opts?: { timeoutMs?: number },\n ): Promise<SensorLogPayload> {\n const timeoutMs = opts?.timeoutMs ?? SENSOR_LOG_TIMEOUT_MS;\n return new Promise<SensorLogPayload>((resolve, reject) => {\n let settled = false;\n const unsubscribe = this.on(BRIDGE_KEYS.sensorLog, (payload) => {\n // Outras páginas em voo compartilham a chave: só a nossa interessa.\n if (settled || payload.requestId !== query.requestId) return;\n settled = true;\n clearTimeout(timer);\n unsubscribe();\n resolve(payload);\n });\n const timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n unsubscribe();\n reject(\n new Error(\n `BridgeClient: sensorLog timeout after ${timeoutMs}ms (requestId=${query.requestId})`,\n ),\n );\n }, timeoutMs);\n this.send('sensorLog', { ...query });\n });\n },\n\n requestPermission(permission: string): void {\n this.send('requestPermission', { permission });\n },\n\n handshake(opts: { clientVersion: string }): Promise<BridgeClientHandshakeAck> {\n ensureMessageListener();\n if (pendingHandshake) {\n return Promise.reject(\n new Error(\n 'BridgeClient: handshake already in flight. Await previous before issuing another.',\n ),\n );\n }\n return new Promise<BridgeClientHandshakeAck>((resolve, reject) => {\n const timer = setTimeout(() => {\n pendingHandshake = null;\n reject(new Error(`BridgeClient: handshake timeout after ${HANDSHAKE_TIMEOUT_MS}ms`));\n }, HANDSHAKE_TIMEOUT_MS);\n pendingHandshake = { resolve, reject, timer };\n postToShell({\n type: 'handshake',\n payload: { clientVersion: opts.clientVersion },\n });\n });\n },\n\n reportNavigation(canGoBack: boolean): void {\n this.send('navigationState', { canGoBack });\n },\n\n onBack(cb: () => void): () => void {\n return this.on(BRIDGE_KEYS.navigationBack, () => cb());\n },\n};\n\n/**\n * Reseta estado interno (subscribers + handshake pendente).\n *\n * **Exportado para uso em testes apenas.** Listener `message` permanece\n * instalado entre testes — é idempotente (checa `event.source ===\n * window.parent` per-call) e o `window` do jsdom persiste entre tests.\n */\nexport function __resetBridgeClientForTests(): void {\n if (pendingHandshake) {\n clearTimeout(pendingHandshake.timer);\n pendingHandshake = null;\n }\n subscribers.clear();\n}\n","/**\n * `BridgeShell` (v0.5.0) — API para o shell Condor-controlado que envolve\n * o conteúdo do cliente externo dentro de `<iframe sandbox=\"allow-scripts\">`.\n *\n * Responsabilidades:\n * 1. **Camada 1 do Risco 1** — `bootstrapClientIframe(iframe, clientPath)`:\n * busca HTML do cliente via `fetch`, prepende script de override que\n * deleta `window.flutter_inappwebview` e `window.CondorBridge` do\n * iframe, e seta como `srcdoc`. Override roda em parse-time, antes\n * de qualquer outro script.\n * 2. **Camada 2 do Risco 1** — `verifySandbox(iframe)`: round-trip\n * `postMessage` que pede ao iframe atestation autoritativa de que\n * `window.flutter_inappwebview` e `window.CondorBridge` são `undefined`.\n * 3. **Roteamento postMessage iframe ↔ nativo:** escuta `message` events\n * do iframe, valida com Valibot, aplica `ShellPolicy` default-deny,\n * e propaga para o `Bridge` legado (que fala com o nativo). Eventos\n * nativos voltam para o iframe via `postMessage`.\n * 4. **Confirmação humana para comandos sensíveis:** comandos em\n * `policy.requiresConfirmation` disparam callback\n * `onConfirmationRequest` antes de tocar o nativo — shell apresenta UI.\n */\n\nimport * as v from 'valibot';\nimport { Bridge } from './bridge';\nimport type { BridgeKey } from './keys';\nimport {\n ClientToShellMessage,\n type ConfirmationRequest,\n type SandboxVerifyResult,\n type ShellPolicy,\n type ShellToClientMessage,\n} from './shell-messages';\n\nconst SHELL_VERSION = '0.6.0';\n\n/**\n * Janela que o shell espera pelo handshake do nativo antes de responder ao\n * cliente com `nativeVersion: null`. Curta de propósito: o canal com o nativo\n * é local, e é melhor o cliente receber `null` rápido do que esperar.\n */\nconst NATIVE_HANDSHAKE_TIMEOUT_MS = 2000;\nconst VERIFY_TIMEOUT_MS = 2000;\n\n/**\n * **Camada 1 do Risco 1 — override prefix.**\n *\n * Script prependado ao srcdoc do iframe pelo `bootstrapClientIframe*`.\n * Roda em parse-time, antes de qualquer outro script do cliente, no\n * próprio documento do iframe (origem null — sem cross-origin block).\n *\n * Usa **getter/setter no-op** + `configurable: false` (não\n * `value/writable: false`). Razão: bundles ESM modernos rodam em strict\n * mode; qualquer `window.X = …` em propriedade não-writable **throws**,\n * o que quebra bootstrap de módulos legados que tentam registrar APIs no\n * window (ex.: `condor-mobile-bridge` legacy faz\n * `window.CondorBridge = {emit}` como side-effect no module load).\n * Com getter/setter no-op, a atribuição passa silenciosamente mas o\n * getter sempre retorna undefined — bridges nativos permanecem\n * inacessíveis no iframe sem quebrar fluxos JS legítimos.\n *\n * Validado empiricamente via pen test ofensivo em `moto g 9 plus`\n * durante o trio sandbox iframe (2026-06-09).\n */\nconst OVERRIDE_PREFIX = `<script>\n(function(){\n try { delete window.flutter_inappwebview; } catch (_) {}\n try { delete window.CondorBridge; } catch (_) {}\n try {\n Object.defineProperty(window, 'flutter_inappwebview', {\n get: function(){ return undefined; },\n set: function(_){ /* no-op: bloqueia injeção do plugin no iframe */ },\n configurable: false,\n });\n } catch (_) {}\n try {\n Object.defineProperty(window, 'CondorBridge', {\n get: function(){ return undefined; },\n set: function(_){ /* no-op: bloqueia bootstrap do package legado */ },\n configurable: false,\n });\n } catch (_) {}\n try {\n // Neutraliza navigator.sendBeacon: canal de exfil que a CSP connect-src\n // não barra de forma confiável em alguns WebViews (pentest 2026-06-24,\n // PT-10). O cliente comunica só via BridgeClient/postMessage — não tem\n // uso legítimo de sendBeacon. Getter no-op retorna função que devolve\n // false; setter no-op ignora tentativa de restaurar.\n Object.defineProperty(navigator, 'sendBeacon', {\n get: function(){ return function(){ return false; }; },\n set: function(_){ /* no-op */ },\n configurable: false,\n });\n } catch (_) {}\n})();\n</script>`;\n\nexport interface BridgeShellOptions {\n /**\n * Iframe que hospeda o cliente. Pode estar vazio no momento da\n * construção — `bootstrapClientIframe` será chamado depois para popular.\n */\n iframe: HTMLIFrameElement;\n\n /**\n * Policy default-deny. Toda chave/comando vindo do iframe é validado\n * contra estas listas. Vide `ShellPolicy`.\n */\n policy: ShellPolicy;\n\n /**\n * Callback síncrono ou assíncrono chamado quando o cliente pede um\n * comando em `policy.requiresConfirmation`. Shell apresenta UI de\n * confirmação; resolve com `true` (aprovar) ou `false` (recusar).\n * Se não fornecido, comandos `requiresConfirmation` são **negados**\n * automaticamente — fail-safe.\n */\n onConfirmationRequest?: (req: ConfirmationRequest) => boolean | Promise<boolean>;\n}\n\nexport class BridgeShell {\n private readonly iframe: HTMLIFrameElement;\n private readonly policy: ShellPolicy;\n private readonly onConfirm?: BridgeShellOptions['onConfirmationRequest'];\n private readonly subscriptions = new Map<BridgeKey, () => void>();\n private detached = false;\n\n /**\n * Versão do nativo, obtida uma vez e cacheada. `null` até o nativo\n * responder — e permanentemente `null` num browser sem nativo.\n */\n private nativeVersion: string | null = null;\n /** Handshake com o nativo em voo; garante uma única chamada. */\n private nativeHandshake: Promise<void> | null = null;\n\n // Map de `verify-sandbox` round-trips pendentes — key gerada por nonce.\n private pendingVerifies = new Map<\n string,\n {\n resolve: (r: SandboxVerifyResult) => void;\n reject: (e: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n }\n >();\n\n constructor(opts: BridgeShellOptions) {\n this.iframe = opts.iframe;\n this.policy = opts.policy;\n this.onConfirm = opts.onConfirmationRequest;\n if (typeof window !== 'undefined') {\n window.addEventListener('message', this.onMessage);\n }\n }\n\n /**\n * **Camada 1 do Risco 1.** Bootstrap via fetch de URL.\n *\n * Atalho para o caso comum HTTP/HTTPS: faz `fetch(clientPath)` e\n * delega para `bootstrapClientIframeWithHtml`.\n *\n * **Não funciona em scheme `file://`** — `fetch` em WebView Android\n * (Chromium) bloqueia o scheme com \"URL scheme 'file' is not supported\".\n * Para asset bundled em APK ou bundle inlined no build-time, use\n * `bootstrapClientIframeWithHtml(htmlString)`.\n *\n * **Devo ser chamado uma vez no boot do shell**, antes de qualquer\n * outra interação. Após retornar, `verifySandbox()` deve ser invocado\n * para atestation (Camada 2).\n */\n async bootstrapClientIframe(clientPath = 'client.html'): Promise<void> {\n const res = await fetch(clientPath);\n if (!res.ok) throw new Error(`BridgeShell: falha ao carregar ${clientPath} (${res.status})`);\n const clientHtml = await res.text();\n await this.bootstrapClientIframeWithHtml(clientHtml);\n }\n\n /**\n * **Camada 1 do Risco 1.** Bootstrap a partir de HTML string.\n *\n * Aceita HTML do cliente diretamente (já lido de arquivo, embedado em\n * build-time via `esbuild.define`, lido de IndexedDB, etc.) e seta\n * como `srcdoc` do iframe prefixado pelo override script. Override\n * roda em parse-time, antes de qualquer outro script do cliente.\n *\n * Use quando `fetch` não é aplicável (asset bundled em `file://`,\n * bundle inlined no build, qualquer cenário sem rede). Para HTTP\n * use `bootstrapClientIframe(clientPath)`.\n *\n * **Devo ser chamado uma vez no boot do shell**, antes de qualquer\n * outra interação. Após retornar, `verifySandbox()` deve ser invocado\n * para atestation (Camada 2).\n */\n async bootstrapClientIframeWithHtml(clientHtml: string): Promise<void> {\n this.iframe.srcdoc = OVERRIDE_PREFIX + clientHtml;\n await this.waitForIframeLoad();\n }\n\n private waitForIframeLoad(): Promise<void> {\n return new Promise<void>((resolve) => {\n const onLoad = (): void => {\n this.iframe.removeEventListener('load', onLoad);\n resolve();\n };\n this.iframe.addEventListener('load', onLoad);\n });\n }\n\n /**\n * **Camada 2 do Risco 1.** Round-trip `postMessage` que pede ao iframe\n * atestation autoritativa do estado de `window.flutter_inappwebview`\n * e `window.CondorBridge`. Timeout em 2s.\n *\n * `ok` é `true` apenas se ambos forem `undefined` no iframe. Se vier\n * `false`, **shell deve abortar o boot do app** — Camada 1 falhou e\n * Camada 4 (dual WebView) precisa ser acionada manualmente.\n */\n verifySandbox(): Promise<SandboxVerifyResult> {\n if (!this.iframe.contentWindow) {\n return Promise.reject(new Error('BridgeShell: iframe sem contentWindow'));\n }\n return new Promise<SandboxVerifyResult>((resolve, reject) => {\n const nonce = Math.random().toString(36).slice(2);\n const timer = setTimeout(() => {\n this.pendingVerifies.delete(nonce);\n reject(new Error(`BridgeShell: verify-sandbox timeout após ${VERIFY_TIMEOUT_MS}ms`));\n }, VERIFY_TIMEOUT_MS);\n this.pendingVerifies.set(nonce, { resolve, reject, timer });\n this.postToClient({ type: 'verify-sandbox' });\n });\n }\n\n /**\n * Encerra o shell — remove listener `message`, cancela subscriptions\n * pendentes no `Bridge` nativo, limpa estado interno.\n */\n detach(): void {\n if (this.detached) return;\n this.detached = true;\n if (typeof window !== 'undefined') {\n window.removeEventListener('message', this.onMessage);\n }\n for (const unsub of this.subscriptions.values()) unsub();\n this.subscriptions.clear();\n for (const pending of this.pendingVerifies.values()) {\n clearTimeout(pending.timer);\n pending.reject(new Error('BridgeShell: detached'));\n }\n this.pendingVerifies.clear();\n }\n\n private onMessage = async (event: MessageEvent): Promise<void> => {\n if (this.detached) return;\n if (event.source !== this.iframe.contentWindow) return;\n\n const parsed = v.safeParse(ClientToShellMessage, event.data);\n if (!parsed.success) {\n // Drop silently — possivelmente noise (extensão de browser, dev tool).\n // Loga só em modo dev para diagnose.\n if (typeof console !== 'undefined') {\n console.debug('[BridgeShell] dropped malformed message:', parsed.issues?.[0]?.message);\n }\n return;\n }\n\n const msg = parsed.output;\n switch (msg.type) {\n case 'subscribe':\n await this.handleSubscribe(msg.key as BridgeKey);\n break;\n case 'unsubscribe':\n this.handleUnsubscribe(msg.key as BridgeKey);\n break;\n case 'send':\n await this.handleSend(msg.command, msg.args ?? {});\n break;\n case 'handshake':\n // O cliente faz handshake com o **shell**, não com o nativo — ele vive\n // num iframe sandboxed e não alcança o nativo. Por isso o shell faz o\n // handshake com o nativo em nome dele e repassa o `nativeVersion`:\n // sem isso, um cliente não tem como saber de qual versão são as\n // capacidades que recebe, e a instrução \"cheque o nativeVersion antes\n // de depender de capacidade nova\" fica impossível de cumprir.\n void this.resolveNativeVersion().then((nativeVersion) => {\n this.postToClient({\n type: 'handshake-ack',\n ack: { shellVersion: SHELL_VERSION, nativeVersion, accepted: true },\n });\n });\n break;\n case 'jsError':\n // Forward erro JS do iframe para o nativo (roteia para Logs).\n Bridge.send('jsError', {\n origin: 'iframe',\n message: msg.payload.message,\n stack: msg.payload.stack,\n source: msg.payload.source,\n lineno: msg.payload.lineno,\n colno: msg.payload.colno,\n });\n break;\n case 'sandbox-verify-response': {\n // Camada 2: cliente respondeu ao verify-sandbox. Resolve o pending\n // mais antigo (em prática só há um por vez — mantemos map por\n // robustez).\n const first = this.pendingVerifies.keys().next().value;\n if (first !== undefined) {\n const pending = this.pendingVerifies.get(first);\n if (pending) {\n clearTimeout(pending.timer);\n this.pendingVerifies.delete(first);\n const ok = !msg.flutterBridgeReachable && !msg.condorBridgeReachable;\n pending.resolve({\n flutterBridgeReachable: msg.flutterBridgeReachable,\n condorBridgeReachable: msg.condorBridgeReachable,\n ok,\n });\n }\n }\n break;\n }\n }\n };\n\n private async handleSubscribe(key: BridgeKey): Promise<void> {\n if (!this.policy.readOnlyKeys.includes(key)) {\n this.postToClient({ type: 'nack', key, reason: 'not-read-only' });\n return;\n }\n if (this.subscriptions.has(key)) return; // idempotent\n const unsub = Bridge.on(key, (payload) => {\n if (this.detached) return;\n this.postToClient({ type: 'event', key, payload });\n });\n this.subscriptions.set(key, unsub);\n }\n\n private handleUnsubscribe(key: BridgeKey): void {\n const unsub = this.subscriptions.get(key);\n if (!unsub) return;\n unsub();\n this.subscriptions.delete(key);\n }\n\n private async handleSend(command: string, args: Record<string, unknown>): Promise<void> {\n if (this.policy.deniedCommands.includes(command)) {\n this.postToClient({ type: 'nack', command, reason: 'denied' });\n return;\n }\n if (this.policy.requiresConfirmation.includes(command)) {\n if (!this.onConfirm) {\n // Fail-safe: sem callback, comando que requer confirmação é negado.\n this.postToClient({ type: 'nack', command, reason: 'no-confirmation-handler' });\n return;\n }\n let approved = false;\n try {\n approved = await this.onConfirm({ command, args });\n } catch (err) {\n this.postToClient({\n type: 'nack',\n command,\n reason: `confirmation-error: ${err instanceof Error ? err.message : String(err)}`,\n });\n return;\n }\n if (!approved) {\n this.postToClient({ type: 'nack', command, reason: 'user-rejected' });\n return;\n }\n } else if (!this.policy.allowedCommands.includes(command)) {\n // Comando fora de allowed/denied/requiresConfirmation — drop por default.\n this.postToClient({ type: 'nack', command, reason: 'not-allowed' });\n return;\n }\n Bridge.send(command, args);\n }\n\n /**\n * Obtém o `nativeVersion`, disparando o handshake com o nativo na primeira\n * vez e cacheando o resultado.\n *\n * ⚠️ `Bridge.handshake` **não tem timeout**: a Promise só resolve quando o\n * nativo emite `handshake-ack`. Num browser sem nativo ela nunca resolve,\n * então o `race` abaixo é o que garante que o cliente sempre receba\n * resposta — com `null` — em vez de ficar pendurado.\n */\n private async resolveNativeVersion(): Promise<string | null> {\n if (this.nativeVersion !== null) return this.nativeVersion;\n if (!this.nativeHandshake) {\n this.nativeHandshake = Bridge.handshake({ clientVersion: SHELL_VERSION })\n .then((ack) => {\n this.nativeVersion = ack.nativeVersion;\n })\n .catch(() => {\n // Sem nativo (ou recusado): segue `null`, que é informação honesta.\n });\n }\n await Promise.race([\n this.nativeHandshake,\n new Promise<void>((resolve) => setTimeout(resolve, NATIVE_HANDSHAKE_TIMEOUT_MS)),\n ]);\n return this.nativeVersion;\n }\n\n private postToClient(msg: ShellToClientMessage): void {\n if (this.detached) return;\n this.iframe.contentWindow?.postMessage(msg, '*');\n }\n}\n","/**\n * Schemas Valibot dos `postMessage` shell↔client (v0.5.0).\n *\n * Quando o conteúdo do cliente roda dentro de `<iframe sandbox=\"allow-scripts\">`\n * (origem null), a comunicação com o shell Condor-controlado acontece via\n * `window.postMessage`. Estes schemas são o **único contrato aceito** —\n * qualquer mensagem mal-formada é descartada silenciosamente pelo shell.\n *\n * **Threat model:** o iframe pode ser hostil (supply-chain comprometida,\n * XSS no código do cliente). Estes schemas + a `ShellPolicy` aplicada\n * no `BridgeShell` formam o boundary estrutural — vide\n * `condor_wiki/cross-cutting/sleep-white-label-content-transport-and-security.md`.\n */\n\nimport * as v from 'valibot';\nimport { BRIDGE_KEYS } from './keys';\n\nconst BridgeKeySchema = v.picklist(Object.values(BRIDGE_KEYS) as [string, ...string[]]);\n\n// ─── Client → Shell ──────────────────────────────────────────────────\n\nexport const SubscribeMessage = v.object({\n type: v.literal('subscribe'),\n key: BridgeKeySchema,\n});\n\nexport const UnsubscribeMessage = v.object({\n type: v.literal('unsubscribe'),\n key: BridgeKeySchema,\n});\n\nexport const SendMessage = v.object({\n type: v.literal('send'),\n command: v.string(),\n args: v.optional(v.record(v.string(), v.unknown()), {}),\n});\n\nexport const HandshakeMessage = v.object({\n type: v.literal('handshake'),\n payload: v.object({ clientVersion: v.string() }),\n});\n\nexport const JsErrorMessage = v.object({\n type: v.literal('jsError'),\n payload: v.object({\n message: v.string(),\n stack: v.optional(v.string()),\n source: v.optional(v.string()),\n lineno: v.optional(v.number()),\n colno: v.optional(v.number()),\n }),\n});\n\nexport const SandboxVerifyResponseMessage = v.object({\n type: v.literal('sandbox-verify-response'),\n flutterBridgeReachable: v.boolean(),\n condorBridgeReachable: v.boolean(),\n});\n\nexport const ClientToShellMessage = v.variant('type', [\n SubscribeMessage,\n UnsubscribeMessage,\n SendMessage,\n HandshakeMessage,\n JsErrorMessage,\n SandboxVerifyResponseMessage,\n]);\n\nexport type ClientToShellMessage = v.InferOutput<typeof ClientToShellMessage>;\n\n// ─── Shell → Client ──────────────────────────────────────────────────\n\nexport const EventMessage = v.object({\n type: v.literal('event'),\n key: BridgeKeySchema,\n payload: v.unknown(),\n});\n\nexport const HandshakeAckMessage = v.object({\n type: v.literal('handshake-ack'),\n ack: v.object({\n shellVersion: v.string(),\n /**\n * Versão do schema declarada pelo **nativo**, repassada pelo shell.\n *\n * `null` quando o nativo ainda não respondeu (ou não existe, como no\n * mock de browser). O cliente roda dentro de um iframe sandboxed e não\n * fala com o nativo diretamente, então este é o **único** caminho pelo\n * qual ele descobre de qual versão são as capacidades disponíveis.\n */\n nativeVersion: v.nullable(v.string()),\n accepted: v.boolean(),\n }),\n});\n\nexport const NackMessage = v.object({\n type: v.literal('nack'),\n key: v.optional(v.string()),\n command: v.optional(v.string()),\n reason: v.string(),\n});\n\nexport const VerifySandboxMessage = v.object({\n type: v.literal('verify-sandbox'),\n});\n\nexport const ShellToClientMessage = v.variant('type', [\n EventMessage,\n HandshakeAckMessage,\n NackMessage,\n VerifySandboxMessage,\n]);\n\nexport type ShellToClientMessage = v.InferOutput<typeof ShellToClientMessage>;\n\n// ─── Policy ──────────────────────────────────────────────────────────\n\n/**\n * Policy default-deny aplicada pelo `BridgeShell`. Toda chave/comando\n * vindo do iframe é validado contra estas listas antes de tocar o\n * bridge nativo.\n *\n * - `readOnlyKeys`: chaves que o cliente pode subscrever (observáveis).\n * - `allowedCommands`: comandos pass-through (sem confirmação humana).\n * - `requiresConfirmation`: comandos que disparam callback `onConfirmationRequest`\n * no shell — usuário decide aprovar/recusar via UI nativa do shell.\n * - `deniedCommands`: bloqueio explícito (defesa em profundidade — comandos\n * destrutivos como `dfu` que nunca devem fluir do iframe).\n *\n * **Não embedada no package** — cliente do `BridgeShell` (no monorepo\n * `sleep_whitelabel`) provê a policy concreta. Mantém o package agnóstico\n * ao catálogo e permite policy evoluir sem novo release.\n */\nexport interface ShellPolicy {\n readOnlyKeys: string[];\n allowedCommands: string[];\n requiresConfirmation: string[];\n deniedCommands: string[];\n}\n\n/**\n * Resposta do callback `onConfirmationRequest` do `BridgeShell`.\n *\n * `approve: true` → comando flui para o nativo.\n * `approve: false` → shell envia `nack` ao iframe com `reason: 'user-rejected'`.\n */\nexport interface ConfirmationRequest {\n command: string;\n args: Record<string, unknown>;\n}\n\n/**\n * Estado retornado pelo `verifySandbox()` do `BridgeShell` após\n * round-trip com o iframe. Se algum dos `*Reachable` vier `true`, o\n * boundary está furado — Camada 1 (`bootstrapClientIframe` com override\n * prefix) falhou e a Camada 4 (dual WebView) deve ser acionada.\n */\nexport interface SandboxVerifyResult {\n flutterBridgeReachable: boolean;\n condorBridgeReachable: boolean;\n ok: boolean; // !flutterBridgeReachable && !condorBridgeReachable\n}\n"],"mappings":"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","names":["PROTOCOL_VERSION","subscribers","pendingHandshake","v"]}