@condorinst/mobile-bridge 0.16.0 → 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,38 @@ 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
+
10
42
  ## [0.16.0] — 2026-09-01
11
43
 
12
44
  ### Added
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 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: { 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACYO,IAAM,cAAc;AAAA,EACzB,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,oBAAoB;AAAA,EACpB,UAAU;AAAA,EACV,UAAU;AAAA,EACV,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,kBAAkB;AAAA,EAClB,WAAW;AAAA,EACX,KAAK;AAAA,EACL,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOd,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQhB,UAAU;AACZ;;;ACpBA,IAAM,WAAW;AACjB,IAAM,sBAAsB;AA+D5B,IAAM,WAA4B;AAAA,EAChC,UAAU;AAAA,EACV,aAAa;AAAA,EACb,OAAO;AAAA,EACP,gBAAgB;AAAA,EAChB,yBAAyB;AAAA,EACzB,oBAAoB;AACtB;AAEA,SAAS,eAAe,MAAyC;AAC/D,SAAO;AAAA,IACL,UAAU,MAAM,YAAY,SAAS;AAAA,IACrC,aAAa,MAAM,eAAe,SAAS;AAAA,IAC3C,OAAO,MAAM,SAAS,SAAS;AAAA,IAC/B,gBAAgB,MAAM,kBAAkB,SAAS;AAAA,IACjD,yBAAyB,MAAM,2BAA2B,SAAS;AAAA,IACnE,oBAAoB,MAAM,sBAAsB,SAAS;AAAA,EAC3D;AACF;AAEA,SAAS,iBAAiB,IAAiB,MAA6B;AACtE,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,YAA+E;AAAA,IACnF,gBAAgB,EAAE,QAAQ,QAAQ,OAAO,OAAO;AAAA,IAChD,eAAe,EAAE,QAAQ,QAAQ,MAAM,OAAO;AAAA,IAC9C,aAAa,EAAE,KAAK,QAAQ,OAAO,OAAO;AAAA,IAC1C,YAAY,EAAE,KAAK,QAAQ,MAAM,OAAO;AAAA,EAC1C;AACA,SAAO,OAAO,GAAG,OAAO;AAAA,IACtB,UAAU;AAAA,IACV,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,OAAO,SAAS,YAAY;AAAA,IAC5B,YAAY,SAAS,cAAc;AAAA,IACnC,QAAQ,SAAS,mBAAmB;AAAA,IACpC,cAAc;AAAA,IACd,WAAW;AAAA,IACX,UAAU;AAAA,IACV,SAAS;AAAA,IACT,eAAe;AAAA,IACf,GAAG,UAAU,KAAK,QAAQ;AAAA,EAC5B,CAAC;AACH;AAEA,SAAS,YAAY,OAAoB,SAAsB,QAAkC;AAC/F,QAAM,SAAS,SAAS,cAAc,KAAK;AAC3C,SAAO,YAAY;AACnB,SAAO,OAAO,OAAO,OAAO;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,KAAK;AAAA,IACL,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,EACV,CAAC;AACD,SAAO,OAAO,MAAM,OAAO;AAAA,IACzB,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,SAAS;AAAA,IACT,cAAc;AAAA,IACd,UAAU;AAAA,IACV,eAAe;AAAA,EACjB,CAAC;AACD,QAAM,cAAc;AACpB,SAAO,OAAO,QAAQ,OAAO;AAAA,IAC3B,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,SAAS;AAAA,EACX,CAAC;AACD,SAAO,OAAO,OAAO,OAAO;AAAA,IAC1B,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,cAAc;AAAA,IACd,YAAY;AAAA,EACd,CAAC;AACD,SAAO,OAAO,OAAO,SAAS,eAAe,eAAe,GAAG,SAAS,MAAM;AAC9E,SAAO;AACT;AAEA,SAAS,mBAAkE;AACzE,QAAM,YAAY,SAAS,cAAc,KAAK;AAC9C,YAAU,YAAY;AACtB,SAAO,OAAO,UAAU,OAAO;AAAA,IAC7B,SAAS;AAAA,IACT,cAAc;AAAA,IACd,WAAW;AAAA,IACX,WAAW;AAAA,EACb,CAAC;AACD,QAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,QAAM,cAAc;AACpB,SAAO,OAAO,MAAM,OAAO,EAAE,SAAS,OAAO,cAAc,OAAO,UAAU,OAAO,CAAC;AACpF,QAAM,OAAO,SAAS,cAAc,KAAK;AACzC,OAAK,YAAY;AACjB,YAAU,OAAO,OAAO,IAAI;AAC5B,SAAO,EAAE,WAAW,KAAK;AAC3B;AAEA,SAAS,oBACP,YACA,QACA,SACa;AACb,QAAM,YAAY,SAAS,cAAc,KAAK;AAC9C,YAAU,YAAY;AACtB,SAAO,OAAO,UAAU,OAAO;AAAA,IAC7B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,eAAe;AAAA,IACf,KAAK;AAAA,EACP,CAAC;AACD,QAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,QAAM,cAAc;AACpB,SAAO,OAAO,MAAM,OAAO,EAAE,SAAS,OAAO,UAAU,OAAO,CAAC;AAE/D,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,YAAY;AACnB,SAAO,OAAO,OAAO,OAAO;AAAA,IAC1B,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,UAAU;AAAA,EACZ,CAAC;AACD,aAAW,OAAO,YAAY;AAC5B,UAAM,MAAM,SAAS,cAAc,QAAQ;AAC3C,QAAI,QAAQ;AACZ,QAAI,cAAc;AAClB,WAAO,YAAY,GAAG;AAAA,EACxB;AACA,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,QAAQ;AACf,SAAO,cAAc;AACrB,SAAO,YAAY,MAAM;AAEzB,QAAM,WAAW,SAAS,cAAc,UAAU;AAClD,WAAS,YAAY;AACrB,WAAS,cAAc;AACvB,SAAO,OAAO,SAAS,OAAO;AAAA,IAC5B,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,WAAW;AAAA,IACX,QAAQ;AAAA,EACV,CAAC;AAED,QAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,SAAO,OAAO,QAAQ,OAAO,EAAE,SAAS,QAAQ,KAAK,MAAM,CAAC;AAE5D,QAAM,UAAU,SAAS,cAAc,QAAQ;AAC/C,UAAQ,OAAO;AACf,UAAQ,cAAc;AACtB,UAAQ,YAAY;AACpB,SAAO,OAAO,QAAQ,OAAO;AAAA,IAC3B,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,cAAc;AAAA,IACd,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,MAAM;AAAA,EACR,CAAC;AACD,UAAQ,iBAAiB,SAAS,MAAM;AACtC,WAAO,OAAO,OAAO,SAAS,KAAK;AAAA,EACrC,CAAC;AAED,QAAM,WAAW,SAAS,cAAc,QAAQ;AAChD,WAAS,OAAO;AAChB,WAAS,cAAc;AACvB,WAAS,YAAY;AACrB,SAAO,OAAO,SAAS,OAAO;AAAA,IAC5B,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,cAAc;AAAA,IACd,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,UAAU;AAAA,EACZ,CAAC;AACD,WAAS,iBAAiB,SAAS,OAAO;AAE1C,UAAQ,OAAO,SAAS,QAAQ;AAChC,YAAU,OAAO,OAAO,QAAQ,UAAU,OAAO;AACjD,SAAO;AACT;AAEA,SAAS,wBACP,gBACA,UACa;AACb,QAAM,YAAY,SAAS,cAAc,KAAK;AAC9C,YAAU,YAAY;AACtB,SAAO,OAAO,UAAU,OAAO;AAAA,IAC7B,SAAS;AAAA,IACT,cAAc;AAAA,IACd,SAAS;AAAA,IACT,eAAe;AAAA,IACf,KAAK;AAAA,EACP,CAAC;AAED,QAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,QAAM,cAAc;AACpB,SAAO,OAAO,MAAM,OAAO,EAAE,SAAS,OAAO,UAAU,OAAO,CAAC;AAE/D,QAAM,MAAM,SAAS,cAAc,OAAO;AAC1C,SAAO,OAAO,IAAI,OAAO;AAAA,IACvB,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,WAAW,SAAS,cAAc,OAAO;AAC/C,WAAS,OAAO;AAChB,WAAS,YAAY;AACrB,WAAS,UAAU;AACnB,SAAO,OAAO,SAAS,OAAO;AAAA,IAC5B,QAAQ;AAAA,EACV,CAAC;AAED,QAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,QAAM,cAAc;AAEpB,WAAS,iBAAiB,UAAU,MAAM;AACxC,aAAS,SAAS,OAAO;AAAA,EAC3B,CAAC;AAED,MAAI,OAAO,UAAU,KAAK;AAC1B,YAAU,OAAO,OAAO,GAAG;AAC3B,SAAO;AACT;AAEA,SAAS,eAAe,MAAmB,SAAsB,KAAmB;AAClF,OAAK,YAAY;AACjB,QAAM,MAAM,QAAQ,YAAY;AAChC,QAAM,OAAO,IAAI,MAAM,CAAC,GAAG,EAAE,QAAQ;AACrC,aAAW,OAAO,MAAM;AACtB,UAAM,MAAM,SAAS,cAAc,KAAK;AACxC,WAAO,OAAO,IAAI,OAAO;AAAA,MACvB,SAAS;AAAA,MACT,cAAc;AAAA,MACd,WAAW;AAAA,IACb,CAAC;AACD,UAAM,KAAK,IAAI,KAAK,IAAI,SAAS,EAAE,mBAAmB;AACtD,UAAM,UAAU,IAAI;AACpB,UAAM,OAAO,SAAS,QAAQ;AAC9B,QAAI,cAAc,GAAG,EAAE,aAAQ,IAAI,KAAK,KAAK,UAAU,IAAI,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;AAChF,SAAK,YAAY,GAAG;AAAA,EACtB;AACF;AAOA,IAAI,eAAsC;AAEnC,SAAS,gBAAgB,QAAuC;AACrE,MAAI,OAAO,aAAa,aAAa;AACnC,UAAM,IAAI,MAAM,wEAAwE;AAAA,EAC1F;AAGA,MAAI,cAAc;AAChB,iBAAa,UAAU;AACvB,mBAAe;AAAA,EACjB;AAEA,QAAM,OAAO,eAAe,OAAO,OAAO;AAC1C,QAAM,OAAO,SAAS,cAAc,KAAK;AACzC,OAAK,KAAK;AACV,mBAAiB,MAAM,IAAI;AAE3B,QAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,QAAM,UAAU,SAAS,cAAc,MAAM;AAC7C,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,OAAO;AACd,SAAO,cAAc,KAAK,iBAAiB,MAAM;AACjD,QAAM,SAAS,YAAY,OAAO,SAAS,MAAM;AAEjD,QAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAO,OAAO,KAAK,OAAO;AAAA,IACxB,SAAS,KAAK,iBAAiB,SAAS;AAAA,IACxC,eAAe;AAAA,IACf,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,EAAE,WAAW,eAAe,MAAM,SAAS,IAAI,iBAAiB;AAGtE,QAAM,SAAS,OAAO,SAAS;AAC/B,MAAI,qBAAqB,KAAK;AAC9B,MAAI,0BAA+C;AAEnD,MAAI,qBAAyC;AAC7C,MAAI,QAAQ;AACV,yBAAqB,wBAAwB,oBAAoB,CAAC,SAAS;AACzE,2BAAqB;AAAA,IACvB,CAAC;AACD,8BAA0B,OAAO,QAAQ,cAAc,CAAC,QAAQ;AAC9D,UAAI,CAAC,mBAAoB;AACzB,UAAI;AACJ,UAAI;AACF,mBAAW,OAAO,GAAG;AAAA,MACvB,SAAS,KAAK;AACZ,gBAAQ,MAAM,gEAAgE,GAAG;AACjF;AAAA,MACF;AACA,UAAI,CAAC,SAAU;AACf,iBAAW,MAAM;AACf,YAAI;AACF,iBAAO,QAAQ,YAAY,SAAS,KAAK,SAAS,OAAO;AAAA,QAC3D,SAAS,KAAK;AACZ,kBAAQ;AAAA,YACN;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF,GAAG,KAAK,kBAAkB;AAAA,IAC5B,CAAC;AAAA,EACH;AAEA,QAAM,UAAU;AAAA,IACd,OAAO,OAAO,WAAW;AAAA,IACzB,CAAC,KAAK,gBAAgB;AACpB,UAAI,UAAmB,CAAC;AACxB,YAAM,UAAU,YAAY,KAAK;AACjC,UAAI,QAAQ,SAAS,GAAG;AACtB,YAAI;AACF,oBAAU,KAAK,MAAM,OAAO;AAAA,QAC9B,SAAS,KAAK;AACZ,kBAAQ,MAAM,yDAAyD,GAAG;AAC1E;AAAA,QACF;AAAA,MACF;AACA,aAAO,QAAQ,YAAY,KAAK,OAAO;AAAA,IACzC;AAAA,IACA,MAAM;AACJ,aAAO,QAAQ,cAAc;AAC7B,qBAAe,UAAU,OAAO,SAAS,KAAK,WAAW;AACzD,cAAQ,cAAc;AAAA,IACxB;AAAA,EACF;AAEA,MAAI,oBAAoB;AACtB,SAAK,OAAO,eAAe,oBAAoB,OAAO;AAAA,EACxD,OAAO;AACL,SAAK,OAAO,eAAe,OAAO;AAAA,EACpC;AACA,OAAK,OAAO,QAAQ,IAAI;AAExB,SAAO,iBAAiB,SAAS,CAAC,MAAM;AACtC,MAAE,gBAAgB;AAClB,UAAM,YAAY,KAAK,MAAM,YAAY;AACzC,SAAK,MAAM,UAAU,YAAY,SAAS;AAC1C,WAAO,cAAc,YAAY,WAAM;AAAA,EACzC,CAAC;AAED,WAAS,KAAK,YAAY,IAAI;AAE9B,QAAM,UAAU,MAAM;AACpB,UAAM,QAAQ,OAAO,QAAQ,YAAY,EAAE;AAC3C,YAAQ,cAAc,GAAG,KAAK;AAC9B,mBAAe,UAAU,OAAO,SAAS,KAAK,WAAW;AAAA,EAC3D;AACA,UAAQ;AAER,QAAM,WAAW,YAAY,SAAS,mBAAmB;AAEzD,QAAM,QAAwB;AAAA,IAC5B,YAAY;AACV,oBAAc,QAAQ;AACtB,gCAA0B;AAC1B,gCAA0B;AAC1B,WAAK,OAAO;AACZ,UAAI,iBAAiB,MAAO,gBAAe;AAAA,IAC7C;AAAA,IACA;AAAA,EACF;AACA,iBAAe;AACf,SAAO;AACT;;;AChdA,IAAM,aAAa;AA0BZ,SAAS,oBAAiC;AAC/C,QAAM,WAA0B,CAAC;AACjC,QAAM,gBAAgB,oBAAI,IAAgC;AAE1D,SAAO;AAAA,IACL,QAAQ;AAAA,IAER,YAAY,aAAa,SAAS;AAChC,YAAM,MAAmB,EAAE,aAAa,SAAS,WAAW,KAAK,IAAI,EAAE;AACvE,eAAS,KAAK,GAAG;AACjB,UAAI,SAAS,SAAS,YAAY;AAChC,iBAAS,MAAM;AAAA,MACjB;AACA,cAAQ,MAAM,sCAAiC,aAAa,OAAO;AACnE,iBAAW,YAAY,eAAe;AACpC,YAAI;AACF,mBAAS,GAAG;AAAA,QACd,SAAS,KAAK;AACZ,kBAAQ,MAAM,oDAAoD,GAAG;AAAA,QACvE;AAAA,MACF;AAAA,IACF;AAAA,IAEA,cAAc;AACZ,aAAO;AAAA,IACT;AAAA,IAEA,gBAAgB;AACd,eAAS,SAAS;AAAA,IACpB;AAAA,IAEA,YAAY,KAAK,SAAS;AACxB,YAAM,SAAS,OAAO,WAAW,cAAc,OAAO,eAAe;AACrE,UAAI,CAAC,UAAU,OAAO,OAAO,SAAS,YAAY;AAChD,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,aAAO,KAAK,KAAK,OAAO;AAAA,IAC1B;AAAA,IAEA,cAAc,UAAU;AACtB,oBAAc,IAAI,QAAQ;AAC1B,aAAO,MAAM;AACX,sBAAc,OAAO,QAAQ;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AACF;;;AC7DA,IAAI,gBAAsC;AAE1C,SAAS,kBAAkB,MAAwC;AACjE,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,YAAY,aAAa,SAAS;AAChC,WAAK,KAAK,YAAY,aAAa,OAAO;AAAA,IAC5C;AAAA,EACF;AACF;AAEA,SAAS,gBAA+B;AACtC,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,kBAAkB;AAAA,EAC3B;AACA,QAAM,OAAO,OAAO;AACpB,MAAI,QAAQ,OAAO,KAAK,gBAAgB,YAAY;AAClD,WAAO,kBAAkB,IAAI;AAAA,EAC/B;AACA,SAAO,kBAAkB;AAC3B;AAEO,SAAS,mBAAkC;AAChD,MAAI,CAAC,eAAe;AAClB,oBAAgB,cAAc;AAAA,EAChC;AACA,SAAO;AACT;AAYO,SAAS,WAAW,aAAqB,SAAwB;AACtE,mBAAiB,EAAE,YAAY,aAAa,OAAO;AACrD;;;ACnEA,IAAM,cAAc,oBAAI,IAA2B;AAE5C,SAAS,cACd,KACA,IACY;AACZ,MAAI,MAAM,YAAY,IAAI,GAAG;AAC7B,MAAI,CAAC,KAAK;AACR,UAAM,oBAAI,IAAc;AACxB,gBAAY,IAAI,KAAK,GAAG;AAAA,EAC1B;AACA,MAAI,IAAI,EAAc;AACtB,SAAO,MAAM;AACX,UAAM,UAAU,YAAY,IAAI,GAAG;AACnC,QAAI,CAAC,QAAS;AACd,YAAQ,OAAO,EAAc;AAC7B,QAAI,QAAQ,SAAS,GAAG;AACtB,kBAAY,OAAO,GAAG;AAAA,IACxB;AAAA,EACF;AACF;AAEO,SAAS,sBAAsB,KAAa,SAAwB;AACzE,QAAM,MAAM,YAAY,IAAI,GAAG;AAC/B,MAAI,CAAC,IAAK;AACV,aAAW,MAAM,KAAK;AACpB,QAAI;AACF,SAAG,OAAO;AAAA,IACZ,SAAS,KAAK;AAEZ,cAAQ,MAAM,0CAA0C,GAAG,YAAY,GAAG;AAAA,IAC5E;AAAA,EACF;AACF;AAmBO,SAAS,oBAA8B;AAC5C,SAAO,MAAM,KAAK,YAAY,KAAK,CAAC;AACtC;;;AClDA,IAAM,oBAAoB;AAC1B,IAAM,iBAAiB;AACvB,IAAM,mBAAmB;AAiBzB,IAAI,mBAA4C;AAChD,IAAI,qBAAqB;AAEzB,SAAS,KAAK,KAAa,SAAwB;AACjD,MAAI,QAAQ,qBAAqB,kBAAkB;AACjD,UAAM,MAAO,WAAW,CAAC;AACzB,UAAM,WAAW;AACjB,uBAAmB;AACnB,aAAS,QAAQ;AAAA,MACf,eAAe,IAAI,iBAAiB;AAAA,MACpC,UAAU,IAAI,YAAY;AAAA,IAC5B,CAAC;AACD;AAAA,EACF;AACA,wBAAsB,KAAK,OAAO;AACpC;AAEA,SAAS,wBAA8B;AACrC,MAAI,mBAAoB;AACxB,MAAI,OAAO,WAAW,YAAa;AACnC,uBAAqB;AAErB,MAAI,OAAO,gBAAgB,OAAO,OAAO,aAAa,SAAS,YAAY;AAIzE,WAAO,aAAa,OAAO;AAAA,EAC7B,OAAO;AACL,WAAO,eAAe,EAAE,KAAK;AAAA,EAC/B;AACF;AAEA,sBAAsB;AAEtB,SAAS,qBAAkC;AACzC,QAAM,UAAU,iBAAiB;AACjC,MAAI,CAAC,QAAQ,QAAQ;AACnB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AA6EO,IAAM,SAAuB;AAAA,EAClC,IAAI,SAAkB;AACpB,WAAO,iBAAiB,EAAE;AAAA,EAC5B;AAAA,EAEA,UAAU,MAA+C;AACvD,0BAAsB;AACtB,QAAI,kBAAkB;AACpB,aAAO,QAAQ;AAAA,QACb,IAAI;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO,IAAI,QAAsB,CAAC,SAAS,WAAW;AACpD,yBAAmB,EAAE,SAAS,OAAO;AACrC,UAAI;AACF,mBAAW,gBAAgB;AAAA,UACzB,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SAAS,EAAE,eAAe,KAAK,cAAc;AAAA,QAC/C,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,2BAAmB;AACnB,eAAO,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,MAC5D;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,GAAwB,KAAQ,IAAiD;AAC/E,0BAAsB;AACtB,WAAO,cAAc,KAAK,EAAE;AAAA,EAC9B;AAAA,EAEA,KAAK,MAAc,SAAyC;AAC1D,eAAW,gBAAgB;AAAA,MACzB;AAAA,MACA,SAAS;AAAA,MACT,SAAS,WAAW,CAAC;AAAA,IACvB,CAAC;AAAA,EACH;AAAA,EAEA,eAAqB;AACnB,SAAK,KAAK,cAAc;AAAA,EAC1B;AAAA,EAEA,SAAS,KAAa,SAAyB;AAC7C,uBAAmB,EAAE,YAAY,KAAK,WAAW,CAAC,CAAC;AAAA,EACrD;AAAA,EAEA,eAA0B;AACxB,UAAM,UAAU,mBAAmB;AACnC,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,UAAU,QAAQ,YAAY;AAAA,MAC9B,gBAAgB,kBAAkB;AAAA,IACpC;AAAA,EACF;AAAA,EAEA,gBAAgB,SAAiC;AAC/C,UAAM,UAAU,mBAAmB;AACnC,oBAAwB,EAAE,SAAS,QAAQ,CAAC;AAAA,EAC9C;AACF;;;AC1LA,IAAMA,oBAAmB;AACzB,IAAM,uBAAuB;AAK7B,IAAM,wBAAwB;AAa9B,IAAMC,eAAc,oBAAI,IAA0B;AAClD,IAAIC,oBAA4C;AAChD,IAAI,2BAA2B;AAE/B,SAAS,YAAY,KAAiC;AACpD,MAAI,OAAO,WAAW,eAAe,OAAO,WAAW,QAAQ;AAE7D,YAAQ,KAAK,qDAAqD,IAAI,IAAI;AAC1E;AAAA,EACF;AACA,SAAO,OAAO,YAAY,KAAK,GAAG;AACpC;AAEA,SAAS,cAAc,KAAa,SAAwB;AAC1D,QAAM,MAAMD,aAAY,IAAI,GAAG;AAC/B,MAAI,CAAC,OAAO,IAAI,WAAW,EAAG;AAC9B,aAAW,OAAO,KAAK;AACrB,QAAI;AACF,UAAI,GAAG,OAAO;AAAA,IAChB,SAAS,KAAK;AACZ,cAAQ,MAAM,oCAAoC,GAAG;AAAA,IACvD;AAAA,EACF;AACF;AAEA,SAAS,UAAU,OAA2B;AAC5C,MAAI,MAAM,WAAW,OAAO,OAAQ;AAGpC,QAAM,OAAO,MAAM;AACnB,MAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,OAAO,KAAK,SAAS,SAAU;AAExE,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK,SAAS;AACZ,YAAM,MAAM;AACZ,UAAI,OAAO,IAAI,QAAQ,SAAU,eAAc,IAAI,KAAK,IAAI,OAAO;AACnE;AAAA,IACF;AAAA,IACA,KAAK,iBAAiB;AACpB,YAAM,MAAM;AACZ,UAAIC,mBAAkB;AACpB,qBAAaA,kBAAiB,KAAK;AACnC,cAAM,EAAE,QAAQ,IAAIA;AACpB,QAAAA,oBAAmB;AACnB,gBAAQ;AAAA,UACN,cAAc,IAAI,KAAK,gBAAgB;AAAA;AAAA,UAEvC,eAAe,IAAI,KAAK,iBAAiB;AAAA,UACzC,UAAU,IAAI,KAAK,YAAY;AAAA,QACjC,CAAC;AAAA,MACH;AACA;AAAA,IACF;AAAA,IACA,KAAK;AAGH,cAAQ,KAAK,2CAA2C,IAAI;AAC5D;AAAA,IACF,KAAK,kBAAkB;AAGrB,YAAM,IAAI;AACV,kBAAY;AAAA,QACV,MAAM;AAAA,QACN,wBAAwB,OAAO,EAAE,yBAAyB;AAAA,QAC1D,uBAAuB,OAAO,EAAE,iBAAiB;AAAA,MACnD,CAAC;AACD;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,wBAA8B;AACrC,MAAI,yBAA0B;AAC9B,MAAI,OAAO,WAAW,YAAa;AACnC,6BAA2B;AAC3B,SAAO,iBAAiB,WAAW,SAAS;AAC9C;AAEA,sBAAsB;AA+Ff,IAAM,eAAmC;AAAA,EAC9C,iBAAiBF;AAAA,EAEjB,GAAwB,KAAQ,IAAiD;AAC/E,0BAAsB;AACtB,UAAM,MAAMC,aAAY,IAAI,GAAG,KAAK,CAAC;AACrC,UAAM,MAAkB,EAAE,GAAqC;AAC/D,QAAI,KAAK,GAAG;AACZ,IAAAA,aAAY,IAAI,KAAK,GAAG;AAGxB,gBAAY,EAAE,MAAM,aAAa,IAAI,CAAC;AACtC,WAAO,MAAM;AACX,YAAM,aAAaA,aAAY,IAAI,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,MAAM,MAAM,GAAG;AACtE,MAAAA,aAAY,IAAI,KAAK,SAAS;AAC9B,UAAI,UAAU,WAAW,EAAG,aAAY,EAAE,MAAM,eAAe,IAAI,CAAC;AAAA,IACtE;AAAA,EACF;AAAA,EAEA,KAAK,SAAiB,OAAgC,CAAC,GAAS;AAC9D,gBAAY,EAAE,MAAM,QAAQ,SAAS,KAAK,CAAC;AAAA,EAC7C;AAAA,EAEA,eAAqB;AACnB,SAAK,KAAK,cAAc;AAAA,EAC1B;AAAA,EAEA,eACE,OACA,MAC2B;AAC3B,UAAM,YAAY,MAAM,aAAa;AACrC,WAAO,IAAI,QAA0B,CAAC,SAAS,WAAW;AACxD,UAAI,UAAU;AACd,YAAM,cAAc,KAAK,GAAG,YAAY,WAAW,CAAC,YAAY;AAE9D,YAAI,WAAW,QAAQ,cAAc,MAAM,UAAW;AACtD,kBAAU;AACV,qBAAa,KAAK;AAClB,oBAAY;AACZ,gBAAQ,OAAO;AAAA,MACjB,CAAC;AACD,YAAM,QAAQ,WAAW,MAAM;AAC7B,YAAI,QAAS;AACb,kBAAU;AACV,oBAAY;AACZ;AAAA,UACE,IAAI;AAAA,YACF,yCAAyC,SAAS,iBAAiB,MAAM,SAAS;AAAA,UACpF;AAAA,QACF;AAAA,MACF,GAAG,SAAS;AACZ,WAAK,KAAK,aAAa,EAAE,GAAG,MAAM,CAAC;AAAA,IACrC,CAAC;AAAA,EACH;AAAA,EAEA,kBAAkB,YAA0B;AAC1C,SAAK,KAAK,qBAAqB,EAAE,WAAW,CAAC;AAAA,EAC/C;AAAA,EAEA,UAAU,MAAoE;AAC5E,0BAAsB;AACtB,QAAIC,mBAAkB;AACpB,aAAO,QAAQ;AAAA,QACb,IAAI;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO,IAAI,QAAkC,CAAC,SAAS,WAAW;AAChE,YAAM,QAAQ,WAAW,MAAM;AAC7B,QAAAA,oBAAmB;AACnB,eAAO,IAAI,MAAM,yCAAyC,oBAAoB,IAAI,CAAC;AAAA,MACrF,GAAG,oBAAoB;AACvB,MAAAA,oBAAmB,EAAE,SAAS,QAAQ,MAAM;AAC5C,kBAAY;AAAA,QACV,MAAM;AAAA,QACN,SAAS,EAAE,eAAe,KAAK,cAAc;AAAA,MAC/C,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,iBAAiB,WAA0B;AACzC,SAAK,KAAK,mBAAmB,EAAE,UAAU,CAAC;AAAA,EAC5C;AAAA,EAEA,OAAO,IAA4B;AACjC,WAAO,KAAK,GAAG,YAAY,gBAAgB,MAAM,GAAG,CAAC;AAAA,EACvD;AACF;;;AC5RA,IAAAC,KAAmB;;;ACRnB,QAAmB;AAGnB,IAAM,kBAAoB,WAAS,OAAO,OAAO,WAAW,CAA0B;AAI/E,IAAM,mBAAqB,SAAO;AAAA,EACvC,MAAQ,UAAQ,WAAW;AAAA,EAC3B,KAAK;AACP,CAAC;AAEM,IAAM,qBAAuB,SAAO;AAAA,EACzC,MAAQ,UAAQ,aAAa;AAAA,EAC7B,KAAK;AACP,CAAC;AAEM,IAAM,cAAgB,SAAO;AAAA,EAClC,MAAQ,UAAQ,MAAM;AAAA,EACtB,SAAW,SAAO;AAAA,EAClB,MAAQ,WAAW,SAAS,SAAO,GAAK,UAAQ,CAAC,GAAG,CAAC,CAAC;AACxD,CAAC;AAEM,IAAM,mBAAqB,SAAO;AAAA,EACvC,MAAQ,UAAQ,WAAW;AAAA,EAC3B,SAAW,SAAO,EAAE,eAAiB,SAAO,EAAE,CAAC;AACjD,CAAC;AAEM,IAAM,iBAAmB,SAAO;AAAA,EACrC,MAAQ,UAAQ,SAAS;AAAA,EACzB,SAAW,SAAO;AAAA,IAChB,SAAW,SAAO;AAAA,IAClB,OAAS,WAAW,SAAO,CAAC;AAAA,IAC5B,QAAU,WAAW,SAAO,CAAC;AAAA,IAC7B,QAAU,WAAW,SAAO,CAAC;AAAA,IAC7B,OAAS,WAAW,SAAO,CAAC;AAAA,EAC9B,CAAC;AACH,CAAC;AAEM,IAAM,+BAAiC,SAAO;AAAA,EACnD,MAAQ,UAAQ,yBAAyB;AAAA,EACzC,wBAA0B,UAAQ;AAAA,EAClC,uBAAyB,UAAQ;AACnC,CAAC;AAEM,IAAM,uBAAyB,UAAQ,QAAQ;AAAA,EACpD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAMM,IAAM,eAAiB,SAAO;AAAA,EACnC,MAAQ,UAAQ,OAAO;AAAA,EACvB,KAAK;AAAA,EACL,SAAW,UAAQ;AACrB,CAAC;AAEM,IAAM,sBAAwB,SAAO;AAAA,EAC1C,MAAQ,UAAQ,eAAe;AAAA,EAC/B,KAAO,SAAO;AAAA,IACZ,cAAgB,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASvB,eAAiB,WAAW,SAAO,CAAC;AAAA,IACpC,UAAY,UAAQ;AAAA,EACtB,CAAC;AACH,CAAC;AAEM,IAAM,cAAgB,SAAO;AAAA,EAClC,MAAQ,UAAQ,MAAM;AAAA,EACtB,KAAO,WAAW,SAAO,CAAC;AAAA,EAC1B,SAAW,WAAW,SAAO,CAAC;AAAA,EAC9B,QAAU,SAAO;AACnB,CAAC;AAEM,IAAM,uBAAyB,SAAO;AAAA,EAC3C,MAAQ,UAAQ,gBAAgB;AAClC,CAAC;AAEM,IAAM,uBAAyB,UAAQ,QAAQ;AAAA,EACpD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;;;AD9ED,IAAM,gBAAgB;AAOtB,IAAM,8BAA8B;AACpC,IAAM,oBAAoB;AAsB1B,IAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwDjB,IAAM,cAAN,MAAkB;AAAA,EAyBvB,YAAY,MAA0B;AArBtC,SAAiB,gBAAgB,oBAAI,IAA2B;AAChE,SAAQ,WAAW;AAMnB;AAAA;AAAA;AAAA;AAAA,SAAQ,gBAA+B;AAEvC;AAAA,SAAQ,kBAAwC;AAGhD;AAAA,SAAQ,kBAAkB,oBAAI,IAO5B;AA2GF,SAAQ,YAAY,OAAO,UAAuC;AAChE,UAAI,KAAK,SAAU;AACnB,UAAI,MAAM,WAAW,KAAK,OAAO,cAAe;AAEhD,YAAM,SAAW,aAAU,sBAAsB,MAAM,IAAI;AAC3D,UAAI,CAAC,OAAO,SAAS;AAGnB,YAAI,OAAO,YAAY,aAAa;AAClC,kBAAQ,MAAM,4CAA4C,OAAO,SAAS,CAAC,GAAG,OAAO;AAAA,QACvF;AACA;AAAA,MACF;AAEA,YAAM,MAAM,OAAO;AACnB,cAAQ,IAAI,MAAM;AAAA,QAChB,KAAK;AACH,gBAAM,KAAK,gBAAgB,IAAI,GAAgB;AAC/C;AAAA,QACF,KAAK;AACH,eAAK,kBAAkB,IAAI,GAAgB;AAC3C;AAAA,QACF,KAAK;AACH,gBAAM,KAAK,WAAW,IAAI,SAAS,IAAI,QAAQ,CAAC,CAAC;AACjD;AAAA,QACF,KAAK;AAOH,eAAK,KAAK,qBAAqB,EAAE,KAAK,CAAC,kBAAkB;AACvD,iBAAK,aAAa;AAAA,cAChB,MAAM;AAAA,cACN,KAAK,EAAE,cAAc,eAAe,eAAe,UAAU,KAAK;AAAA,YACpE,CAAC;AAAA,UACH,CAAC;AACD;AAAA,QACF,KAAK;AAEH,iBAAO,KAAK,WAAW;AAAA,YACrB,QAAQ;AAAA,YACR,SAAS,IAAI,QAAQ;AAAA,YACrB,OAAO,IAAI,QAAQ;AAAA,YACnB,QAAQ,IAAI,QAAQ;AAAA,YACpB,QAAQ,IAAI,QAAQ;AAAA,YACpB,OAAO,IAAI,QAAQ;AAAA,UACrB,CAAC;AACD;AAAA,QACF,KAAK,2BAA2B;AAI9B,gBAAM,QAAQ,KAAK,gBAAgB,KAAK,EAAE,KAAK,EAAE;AACjD,cAAI,UAAU,QAAW;AACvB,kBAAM,UAAU,KAAK,gBAAgB,IAAI,KAAK;AAC9C,gBAAI,SAAS;AACX,2BAAa,QAAQ,KAAK;AAC1B,mBAAK,gBAAgB,OAAO,KAAK;AACjC,oBAAM,KAAK,CAAC,IAAI,0BAA0B,CAAC,IAAI;AAC/C,sBAAQ,QAAQ;AAAA,gBACd,wBAAwB,IAAI;AAAA,gBAC5B,uBAAuB,IAAI;AAAA,gBAC3B;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF;AACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AA/KE,SAAK,SAAS,KAAK;AACnB,SAAK,SAAS,KAAK;AACnB,SAAK,YAAY,KAAK;AACtB,QAAI,OAAO,WAAW,aAAa;AACjC,aAAO,iBAAiB,WAAW,KAAK,SAAS;AAAA,IACnD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAM,sBAAsB,aAAa,eAA8B;AACrE,UAAM,MAAM,MAAM,MAAM,UAAU;AAClC,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,kCAAkC,UAAU,KAAK,IAAI,MAAM,GAAG;AAC3F,UAAM,aAAa,MAAM,IAAI,KAAK;AAClC,UAAM,KAAK,8BAA8B,UAAU;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,MAAM,8BAA8B,YAAmC;AACrE,SAAK,OAAO,SAAS,kBAAkB;AACvC,UAAM,KAAK,kBAAkB;AAAA,EAC/B;AAAA,EAEQ,oBAAmC;AACzC,WAAO,IAAI,QAAc,CAAC,YAAY;AACpC,YAAM,SAAS,MAAY;AACzB,aAAK,OAAO,oBAAoB,QAAQ,MAAM;AAC9C,gBAAQ;AAAA,MACV;AACA,WAAK,OAAO,iBAAiB,QAAQ,MAAM;AAAA,IAC7C,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,gBAA8C;AAC5C,QAAI,CAAC,KAAK,OAAO,eAAe;AAC9B,aAAO,QAAQ,OAAO,IAAI,MAAM,uCAAuC,CAAC;AAAA,IAC1E;AACA,WAAO,IAAI,QAA6B,CAAC,SAAS,WAAW;AAC3D,YAAM,QAAQ,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC;AAChD,YAAM,QAAQ,WAAW,MAAM;AAC7B,aAAK,gBAAgB,OAAO,KAAK;AACjC,eAAO,IAAI,MAAM,+CAA4C,iBAAiB,IAAI,CAAC;AAAA,MACrF,GAAG,iBAAiB;AACpB,WAAK,gBAAgB,IAAI,OAAO,EAAE,SAAS,QAAQ,MAAM,CAAC;AAC1D,WAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAAA,IAC9C,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAe;AACb,QAAI,KAAK,SAAU;AACnB,SAAK,WAAW;AAChB,QAAI,OAAO,WAAW,aAAa;AACjC,aAAO,oBAAoB,WAAW,KAAK,SAAS;AAAA,IACtD;AACA,eAAW,SAAS,KAAK,cAAc,OAAO,EAAG,OAAM;AACvD,SAAK,cAAc,MAAM;AACzB,eAAW,WAAW,KAAK,gBAAgB,OAAO,GAAG;AACnD,mBAAa,QAAQ,KAAK;AAC1B,cAAQ,OAAO,IAAI,MAAM,uBAAuB,CAAC;AAAA,IACnD;AACA,SAAK,gBAAgB,MAAM;AAAA,EAC7B;AAAA,EA2EA,MAAc,gBAAgB,KAA+B;AAC3D,QAAI,CAAC,KAAK,OAAO,aAAa,SAAS,GAAG,GAAG;AAC3C,WAAK,aAAa,EAAE,MAAM,QAAQ,KAAK,QAAQ,gBAAgB,CAAC;AAChE;AAAA,IACF;AACA,QAAI,KAAK,cAAc,IAAI,GAAG,EAAG;AACjC,UAAM,QAAQ,OAAO,GAAG,KAAK,CAAC,YAAY;AACxC,UAAI,KAAK,SAAU;AACnB,WAAK,aAAa,EAAE,MAAM,SAAS,KAAK,QAAQ,CAAC;AAAA,IACnD,CAAC;AACD,SAAK,cAAc,IAAI,KAAK,KAAK;AAAA,EACnC;AAAA,EAEQ,kBAAkB,KAAsB;AAC9C,UAAM,QAAQ,KAAK,cAAc,IAAI,GAAG;AACxC,QAAI,CAAC,MAAO;AACZ,UAAM;AACN,SAAK,cAAc,OAAO,GAAG;AAAA,EAC/B;AAAA,EAEA,MAAc,WAAW,SAAiB,MAA8C;AACtF,QAAI,KAAK,OAAO,eAAe,SAAS,OAAO,GAAG;AAChD,WAAK,aAAa,EAAE,MAAM,QAAQ,SAAS,QAAQ,SAAS,CAAC;AAC7D;AAAA,IACF;AACA,QAAI,KAAK,OAAO,qBAAqB,SAAS,OAAO,GAAG;AACtD,UAAI,CAAC,KAAK,WAAW;AAEnB,aAAK,aAAa,EAAE,MAAM,QAAQ,SAAS,QAAQ,0BAA0B,CAAC;AAC9E;AAAA,MACF;AACA,UAAI,WAAW;AACf,UAAI;AACF,mBAAW,MAAM,KAAK,UAAU,EAAE,SAAS,KAAK,CAAC;AAAA,MACnD,SAAS,KAAK;AACZ,aAAK,aAAa;AAAA,UAChB,MAAM;AAAA,UACN;AAAA,UACA,QAAQ,uBAAuB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,QACjF,CAAC;AACD;AAAA,MACF;AACA,UAAI,CAAC,UAAU;AACb,aAAK,aAAa,EAAE,MAAM,QAAQ,SAAS,QAAQ,gBAAgB,CAAC;AACpE;AAAA,MACF;AAAA,IACF,WAAW,CAAC,KAAK,OAAO,gBAAgB,SAAS,OAAO,GAAG;AAEzD,WAAK,aAAa,EAAE,MAAM,QAAQ,SAAS,QAAQ,cAAc,CAAC;AAClE;AAAA,IACF;AACA,WAAO,KAAK,SAAS,IAAI;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAc,uBAA+C;AAC3D,QAAI,KAAK,kBAAkB,KAAM,QAAO,KAAK;AAC7C,QAAI,CAAC,KAAK,iBAAiB;AACzB,WAAK,kBAAkB,OAAO,UAAU,EAAE,eAAe,cAAc,CAAC,EACrE,KAAK,CAAC,QAAQ;AACb,aAAK,gBAAgB,IAAI;AAAA,MAC3B,CAAC,EACA,MAAM,MAAM;AAAA,MAEb,CAAC;AAAA,IACL;AACA,UAAM,QAAQ,KAAK;AAAA,MACjB,KAAK;AAAA,MACL,IAAI,QAAc,CAAC,YAAY,WAAW,SAAS,2BAA2B,CAAC;AAAA,IACjF,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,aAAa,KAAiC;AACpD,QAAI,KAAK,SAAU;AACnB,SAAK,OAAO,eAAe,YAAY,KAAK,GAAG;AAAA,EACjD;AACF;","names":["PROTOCOL_VERSION","subscribers","pendingHandshake","v"]}
package/dist/index.d.cts CHANGED
@@ -207,6 +207,11 @@ interface UserDevicePayload {
207
207
  * defensivamente. Não são opcionais no tipo de propósito — opcional
208
208
  * esconderia o skew de versão em vez de deixá-lo explícito.
209
209
  *
210
+ * ⚠️ O `nativeVersion` só chega ao cliente a partir do **SDK 0.17.0**: até a
211
+ * `0.16.x` o shell respondia o handshake do cliente apenas com o
212
+ * `shellVersion`, então essa checagem era impossível de cumprir de dentro do
213
+ * iframe.
214
+ *
210
215
  * `null` significa **canal ausente nesta geração de hardware**, nunca "leitura
211
216
  * zero": `0.0` é leitura válida. Mesma distinção que o backend faz com
212
217
  * `float | null`.
@@ -639,6 +644,16 @@ declare const Bridge: CondorBridge;
639
644
 
640
645
  interface BridgeClientHandshakeAck {
641
646
  shellVersion: string;
647
+ /**
648
+ * Versão do schema do **nativo**, repassada pelo shell — `null` se o nativo
649
+ * ainda não respondeu ou não existe (mock de browser).
650
+ *
651
+ * É por este número que um cliente decide se pode depender de capacidade
652
+ * nova: não há negociação de versão, e o cliente sandboxed não alcança o
653
+ * nativo por nenhum outro caminho. Ex.: canais crus de luz
654
+ * (`light_sensor_*` em `deviceLightSensors`) existem a partir da `0.16.0`.
655
+ */
656
+ nativeVersion: string | null;
642
657
  accepted: boolean;
643
658
  }
644
659
  interface CondorBridgeClient {
@@ -765,6 +780,15 @@ declare const ShellToClientMessage: v.VariantSchema<"type", [v.ObjectSchema<{
765
780
  readonly type: v.LiteralSchema<"handshake-ack", undefined>;
766
781
  readonly ack: v.ObjectSchema<{
767
782
  readonly shellVersion: v.StringSchema<undefined>;
783
+ /**
784
+ * Versão do schema declarada pelo **nativo**, repassada pelo shell.
785
+ *
786
+ * `null` quando o nativo ainda não respondeu (ou não existe, como no
787
+ * mock de browser). O cliente roda dentro de um iframe sandboxed e não
788
+ * fala com o nativo diretamente, então este é o **único** caminho pelo
789
+ * qual ele descobre de qual versão são as capacidades disponíveis.
790
+ */
791
+ readonly nativeVersion: v.NullableSchema<v.StringSchema<undefined>, undefined>;
768
792
  readonly accepted: v.BooleanSchema<undefined>;
769
793
  }, undefined>;
770
794
  }, undefined>, v.ObjectSchema<{
@@ -868,6 +892,13 @@ declare class BridgeShell {
868
892
  private readonly onConfirm?;
869
893
  private readonly subscriptions;
870
894
  private detached;
895
+ /**
896
+ * Versão do nativo, obtida uma vez e cacheada. `null` até o nativo
897
+ * responder — e permanentemente `null` num browser sem nativo.
898
+ */
899
+ private nativeVersion;
900
+ /** Handshake com o nativo em voo; garante uma única chamada. */
901
+ private nativeHandshake;
871
902
  private pendingVerifies;
872
903
  constructor(opts: BridgeShellOptions);
873
904
  /**
@@ -923,6 +954,16 @@ declare class BridgeShell {
923
954
  private handleSubscribe;
924
955
  private handleUnsubscribe;
925
956
  private handleSend;
957
+ /**
958
+ * Obtém o `nativeVersion`, disparando o handshake com o nativo na primeira
959
+ * vez e cacheando o resultado.
960
+ *
961
+ * ⚠️ `Bridge.handshake` **não tem timeout**: a Promise só resolve quando o
962
+ * nativo emite `handshake-ack`. Num browser sem nativo ela nunca resolve,
963
+ * então o `race` abaixo é o que garante que o cliente sempre receba
964
+ * resposta — com `null` — em vez de ficar pendurado.
965
+ */
966
+ private resolveNativeVersion;
926
967
  private postToClient;
927
968
  }
928
969
 
package/dist/index.d.ts CHANGED
@@ -207,6 +207,11 @@ interface UserDevicePayload {
207
207
  * defensivamente. Não são opcionais no tipo de propósito — opcional
208
208
  * esconderia o skew de versão em vez de deixá-lo explícito.
209
209
  *
210
+ * ⚠️ O `nativeVersion` só chega ao cliente a partir do **SDK 0.17.0**: até a
211
+ * `0.16.x` o shell respondia o handshake do cliente apenas com o
212
+ * `shellVersion`, então essa checagem era impossível de cumprir de dentro do
213
+ * iframe.
214
+ *
210
215
  * `null` significa **canal ausente nesta geração de hardware**, nunca "leitura
211
216
  * zero": `0.0` é leitura válida. Mesma distinção que o backend faz com
212
217
  * `float | null`.
@@ -639,6 +644,16 @@ declare const Bridge: CondorBridge;
639
644
 
640
645
  interface BridgeClientHandshakeAck {
641
646
  shellVersion: string;
647
+ /**
648
+ * Versão do schema do **nativo**, repassada pelo shell — `null` se o nativo
649
+ * ainda não respondeu ou não existe (mock de browser).
650
+ *
651
+ * É por este número que um cliente decide se pode depender de capacidade
652
+ * nova: não há negociação de versão, e o cliente sandboxed não alcança o
653
+ * nativo por nenhum outro caminho. Ex.: canais crus de luz
654
+ * (`light_sensor_*` em `deviceLightSensors`) existem a partir da `0.16.0`.
655
+ */
656
+ nativeVersion: string | null;
642
657
  accepted: boolean;
643
658
  }
644
659
  interface CondorBridgeClient {
@@ -765,6 +780,15 @@ declare const ShellToClientMessage: v.VariantSchema<"type", [v.ObjectSchema<{
765
780
  readonly type: v.LiteralSchema<"handshake-ack", undefined>;
766
781
  readonly ack: v.ObjectSchema<{
767
782
  readonly shellVersion: v.StringSchema<undefined>;
783
+ /**
784
+ * Versão do schema declarada pelo **nativo**, repassada pelo shell.
785
+ *
786
+ * `null` quando o nativo ainda não respondeu (ou não existe, como no
787
+ * mock de browser). O cliente roda dentro de um iframe sandboxed e não
788
+ * fala com o nativo diretamente, então este é o **único** caminho pelo
789
+ * qual ele descobre de qual versão são as capacidades disponíveis.
790
+ */
791
+ readonly nativeVersion: v.NullableSchema<v.StringSchema<undefined>, undefined>;
768
792
  readonly accepted: v.BooleanSchema<undefined>;
769
793
  }, undefined>;
770
794
  }, undefined>, v.ObjectSchema<{
@@ -868,6 +892,13 @@ declare class BridgeShell {
868
892
  private readonly onConfirm?;
869
893
  private readonly subscriptions;
870
894
  private detached;
895
+ /**
896
+ * Versão do nativo, obtida uma vez e cacheada. `null` até o nativo
897
+ * responder — e permanentemente `null` num browser sem nativo.
898
+ */
899
+ private nativeVersion;
900
+ /** Handshake com o nativo em voo; garante uma única chamada. */
901
+ private nativeHandshake;
871
902
  private pendingVerifies;
872
903
  constructor(opts: BridgeShellOptions);
873
904
  /**
@@ -923,6 +954,16 @@ declare class BridgeShell {
923
954
  private handleSubscribe;
924
955
  private handleUnsubscribe;
925
956
  private handleSend;
957
+ /**
958
+ * Obtém o `nativeVersion`, disparando o handshake com o nativo na primeira
959
+ * vez e cacheando o resultado.
960
+ *
961
+ * ⚠️ `Bridge.handshake` **não tem timeout**: a Promise só resolve quando o
962
+ * nativo emite `handshake-ack`. Num browser sem nativo ela nunca resolve,
963
+ * então o `race` abaixo é o que garante que o cliente sempre receba
964
+ * resposta — com `null` — em vez de ficar pendurado.
965
+ */
966
+ private resolveNativeVersion;
926
967
  private postToClient;
927
968
  }
928
969
 
package/dist/index.js CHANGED
@@ -632,6 +632,8 @@ function onMessage(event) {
632
632
  pendingHandshake2 = null;
633
633
  resolve({
634
634
  shellVersion: msg.ack?.shellVersion ?? "unknown",
635
+ // `?? null` cobre o shell anterior à 0.17.0, que não mandava o campo.
636
+ nativeVersion: msg.ack?.nativeVersion ?? null,
635
637
  accepted: msg.ack?.accepted ?? false
636
638
  });
637
639
  }
@@ -790,6 +792,15 @@ var HandshakeAckMessage = v.object({
790
792
  type: v.literal("handshake-ack"),
791
793
  ack: v.object({
792
794
  shellVersion: v.string(),
795
+ /**
796
+ * Versão do schema declarada pelo **nativo**, repassada pelo shell.
797
+ *
798
+ * `null` quando o nativo ainda não respondeu (ou não existe, como no
799
+ * mock de browser). O cliente roda dentro de um iframe sandboxed e não
800
+ * fala com o nativo diretamente, então este é o **único** caminho pelo
801
+ * qual ele descobre de qual versão são as capacidades disponíveis.
802
+ */
803
+ nativeVersion: v.nullable(v.string()),
793
804
  accepted: v.boolean()
794
805
  })
795
806
  });
@@ -810,7 +821,8 @@ var ShellToClientMessage = v.variant("type", [
810
821
  ]);
811
822
 
812
823
  // src/bridge-shell.ts
813
- var SHELL_VERSION = "0.5.1";
824
+ var SHELL_VERSION = "0.6.0";
825
+ var NATIVE_HANDSHAKE_TIMEOUT_MS = 2e3;
814
826
  var VERIFY_TIMEOUT_MS = 2e3;
815
827
  var OVERRIDE_PREFIX = `<script>
816
828
  (function(){
@@ -848,6 +860,13 @@ var BridgeShell = class {
848
860
  constructor(opts) {
849
861
  this.subscriptions = /* @__PURE__ */ new Map();
850
862
  this.detached = false;
863
+ /**
864
+ * Versão do nativo, obtida uma vez e cacheada. `null` até o nativo
865
+ * responder — e permanentemente `null` num browser sem nativo.
866
+ */
867
+ this.nativeVersion = null;
868
+ /** Handshake com o nativo em voo; garante uma única chamada. */
869
+ this.nativeHandshake = null;
851
870
  // Map de `verify-sandbox` round-trips pendentes — key gerada por nonce.
852
871
  this.pendingVerifies = /* @__PURE__ */ new Map();
853
872
  this.onMessage = async (event) => {
@@ -872,9 +891,11 @@ var BridgeShell = class {
872
891
  await this.handleSend(msg.command, msg.args ?? {});
873
892
  break;
874
893
  case "handshake":
875
- this.postToClient({
876
- type: "handshake-ack",
877
- ack: { shellVersion: SHELL_VERSION, accepted: true }
894
+ void this.resolveNativeVersion().then((nativeVersion) => {
895
+ this.postToClient({
896
+ type: "handshake-ack",
897
+ ack: { shellVersion: SHELL_VERSION, nativeVersion, accepted: true }
898
+ });
878
899
  });
879
900
  break;
880
901
  case "jsError":
@@ -1053,6 +1074,29 @@ var BridgeShell = class {
1053
1074
  }
1054
1075
  Bridge.send(command, args);
1055
1076
  }
1077
+ /**
1078
+ * Obtém o `nativeVersion`, disparando o handshake com o nativo na primeira
1079
+ * vez e cacheando o resultado.
1080
+ *
1081
+ * ⚠️ `Bridge.handshake` **não tem timeout**: a Promise só resolve quando o
1082
+ * nativo emite `handshake-ack`. Num browser sem nativo ela nunca resolve,
1083
+ * então o `race` abaixo é o que garante que o cliente sempre receba
1084
+ * resposta — com `null` — em vez de ficar pendurado.
1085
+ */
1086
+ async resolveNativeVersion() {
1087
+ if (this.nativeVersion !== null) return this.nativeVersion;
1088
+ if (!this.nativeHandshake) {
1089
+ this.nativeHandshake = Bridge.handshake({ clientVersion: SHELL_VERSION }).then((ack) => {
1090
+ this.nativeVersion = ack.nativeVersion;
1091
+ }).catch(() => {
1092
+ });
1093
+ }
1094
+ await Promise.race([
1095
+ this.nativeHandshake,
1096
+ new Promise((resolve) => setTimeout(resolve, NATIVE_HANDSHAKE_TIMEOUT_MS))
1097
+ ]);
1098
+ return this.nativeVersion;
1099
+ }
1056
1100
  postToClient(msg) {
1057
1101
  if (this.detached) return;
1058
1102
  this.iframe.contentWindow?.postMessage(msg, "*");
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../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 * 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/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 * 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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@condorinst/mobile-bridge",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "description": "TypeScript SDK for the JS↔Native bridge of the Condor white-label mobile app.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "private": false,