@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 +32 -0
- package/dist/index.cjs +48 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +48 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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.
|
|
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.
|
|
915
|
-
|
|
916
|
-
|
|
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, "*");
|
package/dist/index.cjs.map
CHANGED
|
@@ -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":"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","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.
|
|
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.
|
|
876
|
-
|
|
877
|
-
|
|
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