@condorinst/mobile-bridge 0.22.0 β 0.23.1
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/AGENTS.md +133 -34
- package/CHANGELOG.md +187 -0
- package/README.md +30 -481
- package/contract/bridge-contract.json +32 -21
- package/dist/cli.cjs +126 -29
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +126 -29
- package/dist/cli.js.map +1 -1
- package/dist/dev-harness.global.js +402 -55
- package/dist/dev.cjs +403 -55
- package/dist/dev.cjs.map +1 -1
- package/dist/dev.d.cts +245 -9
- package/dist/dev.d.ts +245 -9
- package/dist/dev.js +402 -55
- package/dist/dev.js.map +1 -1
- package/dist/index.cjs +30 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +154 -26
- package/dist/index.d.ts +154 -26
- package/dist/index.js +29 -8
- package/dist/index.js.map +1 -1
- package/docs/agent-guide.md +9 -265
- package/docs/bridge-contract.md +317 -26
- package/docs/client-guide.md +34 -400
- package/docs/device-testing.md +235 -0
- package/docs/pilot-onboarding.md +41 -115
- package/docs/shell-integration.md +292 -0
- package/docs/troubleshooting.md +19 -11
- package/examples/minimal-home/README.md +2 -2
- package/examples/minimal-home/package.json +1 -1
- package/examples/minimal-home/src/main.ts +23 -3
- package/llms-full.txt +769 -865
- package/llms.txt +13 -15
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -613,6 +613,11 @@ var Bridge = {
|
|
|
613
613
|
};
|
|
614
614
|
|
|
615
615
|
// src/bridge-client.ts
|
|
616
|
+
function createRequestId() {
|
|
617
|
+
const bytes = new Uint8Array(16);
|
|
618
|
+
crypto.getRandomValues(bytes);
|
|
619
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
620
|
+
}
|
|
616
621
|
var PROTOCOL_VERSION2 = "0.5.0";
|
|
617
622
|
var HANDSHAKE_TIMEOUT_MS = 5e3;
|
|
618
623
|
var SENSOR_LOG_TIMEOUT_MS = 1e4;
|
|
@@ -624,6 +629,11 @@ function insideShell() {
|
|
|
624
629
|
}
|
|
625
630
|
var subscribers2 = /* @__PURE__ */ new Map();
|
|
626
631
|
var lastSystemStatus = null;
|
|
632
|
+
function trustedHasDevices(status) {
|
|
633
|
+
if (!status || typeof status.hasDevices !== "boolean") return null;
|
|
634
|
+
if (status.hasDevicesKnown === false) return null;
|
|
635
|
+
return status.hasDevices;
|
|
636
|
+
}
|
|
627
637
|
var pendingHandshake2 = null;
|
|
628
638
|
var messageListenerInstalled = false;
|
|
629
639
|
function postToShell(msg) {
|
|
@@ -709,13 +719,18 @@ var BridgeClient = {
|
|
|
709
719
|
if (remaining.length === 0) postToShell({ type: "unsubscribe", key });
|
|
710
720
|
};
|
|
711
721
|
},
|
|
712
|
-
send(command,
|
|
722
|
+
send(command, ...rest) {
|
|
723
|
+
const args = rest[0] ?? {};
|
|
713
724
|
postToShell({ type: "send", command, args });
|
|
714
725
|
},
|
|
715
726
|
openSettings() {
|
|
716
727
|
this.send("openSettings");
|
|
717
728
|
},
|
|
718
|
-
fetchSensorLog(
|
|
729
|
+
fetchSensorLog(input, opts) {
|
|
730
|
+
const query = {
|
|
731
|
+
...input,
|
|
732
|
+
requestId: input.requestId ?? createRequestId()
|
|
733
|
+
};
|
|
719
734
|
const timeoutMs = opts?.timeoutMs ?? SENSOR_LOG_TIMEOUT_MS;
|
|
720
735
|
return new Promise((resolve, reject) => {
|
|
721
736
|
let settled = false;
|
|
@@ -753,18 +768,23 @@ var BridgeClient = {
|
|
|
753
768
|
});
|
|
754
769
|
},
|
|
755
770
|
requestUserDevices(opts) {
|
|
756
|
-
let hasDevices =
|
|
771
|
+
let hasDevices = trustedHasDevices(lastSystemStatus);
|
|
757
772
|
const getFromServer = opts?.getFromServer ?? false;
|
|
758
773
|
return retryUntilReply({
|
|
759
774
|
timeoutMs: opts?.timeoutMs ?? SERVICE_TIMEOUT_MS,
|
|
760
775
|
send: () => this.send("userDevice", { getFromServer }),
|
|
761
776
|
listen: (done, resend) => {
|
|
762
|
-
const offDevices = this.on(
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
777
|
+
const offDevices = this.on(BRIDGE_KEYS.userDevice, (devices) => {
|
|
778
|
+
if (devices.error === void 0 || devices.error === null) {
|
|
779
|
+
done({ status: "ok", devices });
|
|
780
|
+
} else if (devices.error === "NO_DEVICES") {
|
|
781
|
+
done({ status: "no-devices" });
|
|
782
|
+
} else {
|
|
783
|
+
done({ status: "error", code: String(devices.error) });
|
|
784
|
+
}
|
|
785
|
+
});
|
|
766
786
|
const offStatus = this.on(BRIDGE_KEYS.systemStatus, (status) => {
|
|
767
|
-
hasDevices = status
|
|
787
|
+
hasDevices = trustedHasDevices(status);
|
|
768
788
|
resend();
|
|
769
789
|
});
|
|
770
790
|
return () => {
|
|
@@ -1233,6 +1253,7 @@ export {
|
|
|
1233
1253
|
BridgeClient,
|
|
1234
1254
|
BridgeShell,
|
|
1235
1255
|
NATIVE_CHANNEL_NAME,
|
|
1256
|
+
createRequestId,
|
|
1236
1257
|
versionAtLeast
|
|
1237
1258
|
};
|
|
1238
1259
|
//# sourceMappingURL=index.js.map
|
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","../src/version.ts"],"sourcesContent":["/**\n * Catalogue of the JSβNative bridge keys.\n *\n * Mirrors the JS-facing side of `ForegroundComCoreKeys` in `condor_core`.\n * The strings here are what JavaScript receives through\n * `window.CondorBridge.emit(key, payload)`.\n *\n * Thirteen keys exist. A sandboxed client can subscribe to twelve of them:\n * `dfu` is denied by the shell policy and skipped natively. See\n * `docs/bridge-contract.md` for what each one carries and when it is emitted.\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: the OS back button was pressed and the client had\n * reported internal history via `reportNavigation(true)`. Go back exactly\n * ONE internal page. Emitted only when the native side decided to delegate\n * the back gesture. See `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. See `LanguagePayload`.\n */\n language: 'language',\n} as const;\n\nexport type BridgeKey = (typeof BRIDGE_KEYS)[keyof typeof BRIDGE_KEYS];\n","/**\n * Dev panel β a floating UI for inspecting the bridge in mock mode.\n *\n * **Opt-in:** call `Bridge.installDevPanel(opts?)` when you want it. It only\n * works in mock mode and throws in real mode. It injects into `document.body`\n * and is idempotent β re-installing removes the previous panel.\n *\n * Contents:\n * - a header with a \"MOCK\" badge, a send counter, and a minimise button;\n * - a sent log with the last N messages (timestamp, type, truncated payload);\n * - a trigger-emit control: a `BRIDGE_KEYS` dropdown, a payload textarea, and\n * a button.\n *\n * Styles are inline and classes are prefixed `condor-mock-panel-*`, to reduce\n * collisions with the client's own CSS.\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 * A reply emitted automatically in reaction to a `Bridge.send`, returned by the\n * client's `onSendForAutoRespond` policy. `null` means \"do not answer this\n * send\".\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 * Auto-respond policy: invoked on every `Bridge.send` while the panel's\n * \"Auto-respond\" toggle is on. Return `{ key, payload }` to fire\n * `Bridge.mockEmit(key, payload)` after the delay, or `null` to stay silent.\n *\n * Without this callback the \"Auto-respond\" checkbox does not appear.\n */\n onSendForAutoRespond?: (msg: MockMessage) => AutoRespondResponse | null;\n\n /**\n * Initial state of the \"Auto-respond\" toggle. Defaults to `false` β manual\n * stays the default, and the client decides when to turn it on.\n */\n startAutoRespondEnabled?: boolean;\n\n /**\n * Delay in milliseconds between the `send` and the auto-response `mockEmit`.\n * Defaults to `50`, which approximates the IPC latency of the real native\n * bridge.\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/** Inspection helper, for tests and debugging. */\nexport function getInstalledDevPanel(): InstalledPanel | null {\n return currentPanel;\n}\n","/**\n * Mock adapter β active when no native host is detected: a plain browser,\n * jsdom without an installed host, Storybook, and so on.\n *\n * Behaviour:\n * - `callHandler` records `{ handlerName, payload, timestamp }` in an internal\n * buffer (capped at 100, FIFO), logs through `console.debug`, and dispatches\n * to listeners registered with `onCallHandler`.\n * - `triggerEmit` dispatches through `window.CondorBridge.emit`, so the real\n * bridge treats it as if it came from the native side: `handshake-ack`\n * resolves the handshake, every other key reaches its subscribers.\n * - `getMessages` returns a read-only snapshot of the buffer.\n * - `clearMessages` empties it, which is useful in tests.\n * - `onCallHandler(listener)` registers a listener invoked on every send and\n * returns an unsubscribe function β used by the dev panel's auto-respond\n * toggle, and for assertions in tests.\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 * Registers a listener invoked on every `callHandler` (a JS β native\n * message). Returns an unsubscribe function.\n *\n * Errors thrown by a listener are caught and logged; they affect neither the\n * other listeners nor the bridge pipeline.\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 * Native host detection, behind an adapter.\n *\n * Detection order: the `window.CondorNative` JavaScript channel\n * (`webview_flutter`) first, then the legacy `window.flutter_inappwebview`,\n * then the mock. The channel only accepts strings, so the message travels as\n * JSON. `setOutgoingStamp` lets the shell stamp every outgoing message β the\n * nonce β without monkey-patching the host.\n *\n * With no host at all the mock adapter activates, which is what makes browser\n * development possible without building an APK.\n *\n * The active adapter is cached on the first `getActiveAdapter()` call. Tests\n * should call `__resetAdapterForTests()` in `beforeEach` to force\n * re-detection, for instance after installing or removing\n * `window.CondorNative`.\n */\n\nimport { createMockAdapter, type MockAdapter } from './mock';\n\n/**\n * Name of the JavaScript channel the native side registers with\n * `WebViewController.addJavaScriptChannel`.\n *\n * It cannot be `CondorBridge`: the plugin publishes the channel as\n * `window.<name>`, which would collide with the `window.CondorBridge` emitter\n * this SDK installs.\n */\nexport const NATIVE_CHANNEL_NAME = 'CondorNative';\n\ninterface FlutterInAppWebView {\n callHandler(name: string, ...args: unknown[]): Promise<unknown>;\n}\n\ninterface NativeChannel {\n postMessage(message: string): void;\n}\n\ndeclare global {\n interface Window {\n flutter_inappwebview?: FlutterInAppWebView;\n CondorNative?: NativeChannel;\n }\n}\n\n/**\n * Transforma toda mensagem JS β Native imediatamente antes do envio.\n * Recebe e devolve o envelope `{type, version, payload}`.\n */\nexport type OutgoingStamp = (message: Record<string, unknown>) => Record<string, unknown>;\n\nlet outgoingStamp: OutgoingStamp | null = null;\n\nexport function setOutgoingStamp(stamp: OutgoingStamp | null): void {\n outgoingStamp = stamp;\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 createChannelAdapter(channel: NativeChannel): RealAdapter {\n return {\n isMock: false,\n // Single channel: `handlerName` does not travel β the native side routes\n // on `type`.\n callHandler(_handlerName, payload) {\n channel.postMessage(JSON.stringify(payload));\n },\n };\n}\n\nfunction createLegacyAdapter(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 channel = window.CondorNative;\n if (channel && typeof channel.postMessage === 'function') {\n return createChannelAdapter(channel);\n }\n const host = window.flutter_inappwebview;\n if (host && typeof host.callHandler === 'function') {\n return createLegacyAdapter(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 * Sends a message to the native handler through the active adapter.\n *\n * Real mode: fire-and-forget over `CondorNative.postMessage` (JSON) or, on the\n * legacy host, `flutter_inappwebview.callHandler`.\n * Mock mode: recorded in the buffer and logged with `console.debug`.\n *\n * The `setOutgoingStamp` transform is applied on every adapter, so what the\n * mock records is exactly what the native side would have received.\n */\nexport function callNative(handlerName: string, payload: Record<string, unknown>): void {\n const stamped = outgoingStamp ? outgoingStamp(payload) : payload;\n getActiveAdapter().callHandler(handlerName, stamped);\n}\n\n/**\n * Resets the adapter cache. **Exported for tests only.**\n *\n * Client code must never call this: the adapter is detected once at startup\n * and kept for the lifetime of the page.\n */\nexport function __resetAdapterForTests(): void {\n activeAdapter = null;\n outgoingStamp = 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 // A buggy subscriber must not affect the others, or the 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 * Inspection helper, for tests and debugging.\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 {\n callNative,\n getActiveAdapter,\n type OutgoingStamp,\n setOutgoingStamp,\n} 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 // Already installed (HMR, double import, or a mock installed by tests).\n // Replace only `emit`, so the newest dispatcher is the one wired to the\n // subscribers of this module instance.\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` when the active adapter is the mock β a plain browser, with neither\n * `window.CondorNative` nor `window.flutter_inappwebview`. `false` inside the\n * Flutter WebView.\n */\n readonly isMock: boolean;\n\n /**\n * Sends a versioned handshake to the native side and awaits `handshake-ack`.\n *\n * Only one handshake may be in flight; a parallel call before the first ack\n * arrives is rejected with an explicit error.\n *\n * **In mock mode it does not resolve on its own.** The caller must emit\n * `Bridge.mockEmit('handshake-ack', { nativeVersion, accepted })` to unblock\n * the promise. That is deliberate: it forces tests to be explicit about the\n * native state they are simulating.\n */\n handshake(opts: HandshakeOptions): Promise<HandshakeAck>;\n\n /**\n * Subscribes to an observable key. Returns an `unsubscribe` function.\n *\n * Multiple subscribers per key are allowed; a throw in one does not affect\n * the others (it is caught and logged with `console.error`).\n */\n on<K extends BridgeKey>(key: K, cb: (payload: PayloadOf<K>) => void): () => void;\n\n /**\n * Sends a generic message to the native side, for commands without a\n * dedicated helper. `type` is the string the native side routes on.\n *\n * Fire-and-forget: no return value and no delivery confirmation. A payload\n * above 64 KB, or an unknown `type`, is dropped natively without a reply.\n *\n * In mock mode it is recorded in the internal buffer and logged with\n * `console.debug`.\n */\n send(type: string, payload?: Record<string, unknown>): void;\n\n /**\n * Opens the app's native Settings screen. Equivalent to\n * `Bridge.send('openSettings')`.\n */\n openSettings(): void;\n\n /**\n * Registers a transform applied to **every** JS β native message, the\n * handshake included, immediately before it is sent. Pass `null` to remove.\n *\n * It exists so the shell can stamp its nonce (`payload._shellNonce`) at a\n * single chokepoint. Wrapping `send` alone is not enough β `handshake` calls\n * the native layer directly, and a message without the nonce is dropped and\n * logged as a security event.\n *\n * **Client code must not use this.**\n */\n setOutgoingStamp(stamp: OutgoingStamp | null): void;\n\n /**\n * Fires `window.CondorBridge.emit(key, payload)` programmatically β useful to\n * simulate native events in tests and in browser development.\n *\n * **Throws** when the active adapter is not the mock.\n */\n mockEmit(key: string, payload?: unknown): void;\n\n /**\n * Snapshot of the mock adapter state: messages sent, and keys with active\n * subscribers. Useful for assertions in client tests.\n *\n * **Throws** when the active adapter is not the mock.\n */\n getMockState(): MockState;\n\n /**\n * Injects a floating HTML panel into `document.body` for inspecting the\n * bridge in mock mode. Idempotent β re-installing replaces the previous one.\n *\n * **Throws** when the active adapter is not the mock, or `document` does not\n * exist.\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 setOutgoingStamp(stamp: OutgoingStamp | null): void {\n setOutgoingStamp(stamp);\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 * Resets the bridge's internal state (the pending handshake).\n *\n * **Exported for tests only.** Do not call it from application code β it breaks\n * the \"only one handshake in flight\" invariant.\n */\nexport function __resetBridgeForTests(): void {\n pendingHandshake = null;\n}\n","/**\n * `BridgeClient` β **the API for client code**, running inside\n * `<iframe sandbox=\"allow-scripts\">` in the Condor Canvas app.\n *\n * This is what you want if you are building the bundle that renders as the\n * app's Home. Every call becomes a `window.parent.postMessage(...)` that the\n * Condor shell validates against a schema and a default-deny policy before it\n * reaches the native layer. You never touch the native globals β the shell\n * deletes them before your bundle runs.\n *\n * It deliberately does **not** expose `installDevPanel`, `mockEmit`, `isMock`\n * or `getMockState`: those belong to the shell (`BridgeShell`). To run a bundle\n * in a browser, use the dev harness (`npx condor-mobile-bridge dev`, or\n * `createDevHarness` from `@condorinst/mobile-bridge/dev`).\n *\n * The module also answers the shell's `verify-sandbox` probe β the iframe\n * attesting whether it can still see the native globals. If any is reachable,\n * the shell aborts the boot rather than render client code with a path to the\n * native layer.\n */\n\nimport { BRIDGE_KEYS, type BridgeKey } from './keys';\nimport type {\n PayloadOf,\n SensorLogPayload,\n SensorLogQueryPayload,\n UserDevicePayload,\n} from './payloads';\nimport type { ClientToShellMessage, ShellToClientMessage } from './shell-messages';\n\nconst PROTOCOL_VERSION = '0.5.0';\nconst HANDSHAKE_TIMEOUT_MS = 5000;\n/**\n * Default timeout for one `sensorLog` page. A 1000-log page costs about 2.7 s\n * in the worst case measured (a gen2 device), so the margin is deliberate.\n */\nconst SENSOR_LOG_TIMEOUT_MS = 10000;\n/**\n * Default deadline of `waitForService` and `requestUserDevices`. On a cold\n * start the app's background service can take several seconds to come up.\n */\nconst SERVICE_TIMEOUT_MS = 30000;\n/** Resend schedule while a reply is pending, in ms after the previous send. */\nconst RESEND_BACKOFF_MS = [1500, 3000, 6000, 10000];\n\nconst NOT_IN_SHELL_HINT =\n 'Not running inside the Condor shell. To develop in a browser, run ' +\n '`npx condor-mobile-bridge dev -i dist/index.html`, or mount the page with ' +\n 'createDevHarness() from \"@condorinst/mobile-bridge/dev\".';\n\nfunction insideShell(): boolean {\n return typeof window !== 'undefined' && window.parent !== window;\n}\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[]>();\n/**\n * Last `systemStatus` received, so `requestUserDevices` knows `hasDevices`\n * even when the emission that follows the handshake arrived before it ran.\n */\nlet lastSystemStatus: { hasDevices?: unknown } | null = null;\nlet pendingHandshake: PendingHandshake | null = null;\nlet messageListenerInstalled = false;\n\nfunction postToShell(msg: ClientToShellMessage): void {\n if (!insideShell()) {\n console.warn(`[BridgeClient] message dropped (${msg.type}). ${NOT_IN_SHELL_HINT}`);\n return;\n }\n window.parent.postMessage(msg, '*');\n}\n\nfunction dispatchEvent(key: string, payload: unknown): void {\n if (key === BRIDGE_KEYS.systemStatus && payload && typeof payload === 'object') {\n lastSystemStatus = payload as { hasDevices?: unknown };\n }\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 // No Valibot validation here β the shell is trusted (Condor-controlled).\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` covers shells older than 0.17.0, which omitted the field.\n nativeVersion: msg.ack?.nativeVersion ?? null,\n accepted: msg.ack?.accepted ?? false,\n });\n }\n break;\n }\n case 'nack':\n // A future version may let clients observe nacks explicitly.\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 nativeChannelReachable: typeof w.CondorNative !== '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 * Schema version of the **native** side, relayed by the shell. `null` when\n * the native side has not answered, or the shell is older than 0.6.0.\n *\n * **This number is the only capability signal a client gets.** There is no\n * version negotiation, and a sandboxed client reaches the native side by no\n * other path. For example, the raw light channels (`light_sensor_*` in\n * `deviceLightSensors`) exist from `0.16.0`. Always keep a working branch\n * for `null`. The dev harness reports `0.17.0` unless a scenario says\n * otherwise.\n */\n nativeVersion: string | null;\n /**\n * Whether the native side accepted your `clientVersion`. It is **always\n * `true`** β there is no hard validation β so it carries no information.\n * Never branch on it; branch on {@link nativeVersion}.\n */\n accepted: boolean;\n}\n\nexport interface CondorBridgeClient {\n /** Version of the client-side postMessage protocol. */\n readonly protocolVersion: string;\n\n /**\n * Subscribes to an observable key. Returns an `unsubscribe` function β\n * call it when a view unmounts, or handlers accumulate and every one of them\n * re-renders.\n *\n * Multiple subscribers per key are allowed, and a throw in one does not\n * affect the others. Subscribe *before* sending the command that triggers\n * the reply: the reply can arrive before your next statement runs.\n */\n on<K extends BridgeKey>(key: K, cb: (payload: PayloadOf<K>) => void): () => void;\n\n /**\n * Sends a command to the shell, which validates it against the policy before\n * it touches the native layer.\n *\n * **Fire-and-forget: no return value, no throw, no delivery confirmation.**\n * A command that is not allowed produces a `nack` that surfaces only as a\n * `console.warn`. A malformed one is dropped in silence by the native side.\n * Replies, when a command has one, arrive on the corresponding key β see\n * `docs/bridge-contract.md`.\n */\n send(command: string, args?: Record<string, unknown>): void;\n\n /** Opens the native Settings screen. Equivalent to `send('openSettings')`. */\n openSettings(): void;\n\n /**\n * Requests ONE page of sensor logs and resolves with the reply correlated by\n * `requestId` β **including when it carries `success: false`**, which is an\n * answer, not a transport failure. The promise only **rejects** on timeout,\n * so always check `success` before reading `logs`.\n *\n * Saves you from keeping a `requestId β resolve` map by hand. To sweep a\n * period, chain calls using the returned `startingAfter` until `hasMore`\n * becomes `false`: the cursors are dependent, so pages **cannot** be fetched\n * in parallel.\n */\n fetchSensorLog(\n query: SensorLogQueryPayload,\n opts?: { timeoutMs?: number },\n ): Promise<SensorLogPayload>;\n\n /**\n * Requests ONE permission through the **in-app native dialog** (it does not\n * open Settings). Use it for the \"Grant\" button of your required-permissions\n * card, with a name taken from `systemStatus.missingEssentialPermissions`,\n * e.g. `'bluetoothScan'`.\n *\n * **There is no result key.** The outcome arrives as a fresh `systemStatus`\n * emission; your card disappears when the array empties. A name outside the\n * native enum is dropped in silence.\n */\n requestPermission(permission: string): void;\n\n /**\n * Resolves when the app's **background service** answers a `ping`.\n *\n * Commands that need device data (`userDevice`, `ping`) travel to a service\n * the app starts after your bundle is already running. A command sent before\n * the service is up is **lost without a reply** β the handshake, `systemStatus`\n * and `language` work earlier, which makes the bridge look ready when it is\n * not. This helper resends `ping` with backoff (1.5 s, 3 s, 6 s, then every\n * 10 s) until a `pingPong` arrives.\n *\n * Never rejects: resolves `{ status: 'timeout' }` after `timeoutMs`\n * (default 30 s).\n */\n waitForService(opts?: { timeoutMs?: number }): Promise<{ status: 'ready' | 'timeout' }>;\n\n /**\n * Requests the user's devices and **keeps asking** until they arrive. Use\n * this instead of `send('userDevice')`, which may never be answered:\n *\n * - on a cold start the first request is lost while the background service\n * comes up;\n * - an account with no linked device gets no reply at all.\n *\n * Resends with backoff (1.5 s, 3 s, 6 s, then every 10 s) and on every\n * `systemStatus` while pending. Never rejects. Resolves with\n * `{ status: 'ok', devices }`, or `{ status: 'timeout', hasDevices }` after\n * `timeoutMs` (default 30 s), where `hasDevices` is the last\n * `systemStatus.hasDevices` seen (`null` if none). `false` there **suggests**\n * an account with no device β show an empty state with a retry button β but\n * the app also reports `false` when it could not reach the server.\n *\n * `getFromServer: true` asks the app to refresh from the server; leave it\n * `false` (default) at boot, where the cached list is enough.\n */\n requestUserDevices(opts?: {\n timeoutMs?: number;\n getFromServer?: boolean;\n }): Promise<\n { status: 'ok'; devices: UserDevicePayload } | { status: 'timeout'; hasDevices: boolean | null }\n >;\n\n /**\n * Handshakes with the shell. Resolves with\n * `{ shellVersion, nativeVersion, accepted }` β read `nativeVersion` to learn\n * what this device can do, and ignore `accepted`, which is always `true`.\n *\n * Rejects after 5 s if the shell does not answer, and **at once** when the\n * page is not inside the Condor shell (opened directly in a browser) β run\n * `npx condor-mobile-bridge dev` instead. Only one handshake may be in flight\n * at a time.\n */\n handshake(opts: { clientVersion: string }): Promise<BridgeClientHandshakeAck>;\n\n /**\n * Reports to the native side whether the client has internal history to go\n * back to. **Call it on every internal navigation**, and at boot β not once.\n * The native side caches the value and uses it to decide what the OS back\n * button does:\n * - `true` β back asks you to go back one page (the `navigationBack` event,\n * see {@link onBack});\n * - `false` β back stays with the app and does not leave the Home.\n *\n * Equivalent to `send('navigationState', { canGoBack })`.\n */\n reportNavigation(canGoBack: boolean): void;\n\n /**\n * Subscribes to the OS back request (the `navigationBack` event). The\n * callback must go back **one** internal page and then call\n * {@link reportNavigation} with the new state. It only fires when you had\n * reported `reportNavigation(true)`. Returns an `unsubscribe` function.\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 // in the shell β repeated `subscribe` for the same key is handled).\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 // Other in-flight pages share the key: only ours is relevant.\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 waitForService(opts?: { timeoutMs?: number }): Promise<{ status: 'ready' | 'timeout' }> {\n return retryUntilReply<{ status: 'ready' | 'timeout' }>({\n timeoutMs: opts?.timeoutMs ?? SERVICE_TIMEOUT_MS,\n send: () => this.send('ping'),\n listen: (done) =>\n this.on(BRIDGE_KEYS.pingPong, (payload) => {\n if (payload.data === 'pong') done({ status: 'ready' });\n }),\n onTimeout: () => ({ status: 'timeout' }),\n });\n },\n\n requestUserDevices(opts?: { timeoutMs?: number; getFromServer?: boolean }) {\n type Result =\n | { status: 'ok'; devices: UserDevicePayload }\n | { status: 'timeout'; hasDevices: boolean | null };\n let hasDevices: boolean | null =\n typeof lastSystemStatus?.hasDevices === 'boolean' ? lastSystemStatus.hasDevices : null;\n const getFromServer = opts?.getFromServer ?? false;\n return retryUntilReply<Result>({\n timeoutMs: opts?.timeoutMs ?? SERVICE_TIMEOUT_MS,\n send: () => this.send('userDevice', { getFromServer }),\n listen: (done, resend) => {\n const offDevices = this.on(BRIDGE_KEYS.userDevice, (devices) =>\n done({ status: 'ok', devices }),\n );\n const offStatus = this.on(BRIDGE_KEYS.systemStatus, (status) => {\n hasDevices = status.hasDevices;\n resend();\n });\n return () => {\n offDevices();\n offStatus();\n };\n },\n onTimeout: () => ({ status: 'timeout', hasDevices }),\n });\n },\n\n handshake(opts: { clientVersion: string }): Promise<BridgeClientHandshakeAck> {\n ensureMessageListener();\n if (!insideShell()) {\n return Promise.reject(new Error(`BridgeClient: handshake impossible. ${NOT_IN_SHELL_HINT}`));\n }\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 * Sends, then resends on a backoff schedule (and whenever `listen` asks) until\n * `listen` reports a reply or `timeoutMs` passes. Never rejects.\n */\nfunction retryUntilReply<T>(opts: {\n timeoutMs: number;\n send: () => void;\n listen: (done: (result: T) => void, resend: () => void) => () => void;\n onTimeout: () => T;\n}): Promise<T> {\n return new Promise<T>((resolve) => {\n let settled = false;\n let attempt = 0;\n let lastSend = 0;\n let resendTimer: ReturnType<typeof setTimeout> | undefined;\n\n const finish = (result: T): void => {\n if (settled) return;\n settled = true;\n clearTimeout(deadline);\n clearTimeout(resendTimer);\n unlisten();\n resolve(result);\n };\n const sendNow = (): void => {\n if (settled) return;\n lastSend = Date.now();\n opts.send();\n const delay = RESEND_BACKOFF_MS[Math.min(attempt, RESEND_BACKOFF_MS.length - 1)] ?? 10000;\n attempt += 1;\n clearTimeout(resendTimer);\n resendTimer = setTimeout(sendNow, delay);\n };\n // An external nudge (a fresh systemStatus) resends at most once per second.\n const resend = (): void => {\n if (Date.now() - lastSend >= 1000) sendNow();\n };\n\n const unlisten = opts.listen(finish, resend);\n const deadline = setTimeout(() => finish(opts.onTimeout()), opts.timeoutMs);\n sendNow();\n });\n}\n\n/**\n * Reseta estado interno (subscribers + handshake pendente).\n *\n * **Exportado para uso em testes apenas.** Listener `message` permanece\n * installed between tests β it is idempotent (it checks `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 lastSystemStatus = null;\n}\n","/**\n * `BridgeShell` β the API for the **Condor-controlled shell** that wraps\n * external client content inside `<iframe sandbox=\"allow-scripts\">`.\n *\n * This is not client-facing. If you are writing the bundle that renders as the\n * app's Home, you want `BridgeClient`.\n *\n * Responsibilities:\n * 1. **Layer 1 β `bootstrapClientIframe(iframe, clientPath)`:** fetches the\n * client HTML, prepends an override script that removes the native globals\n * from the iframe, and sets it as `srcdoc`. The override runs at parse time,\n * before any other script.\n * 2. **Layer 2 β `verifySandbox(iframe)`:** a `postMessage` round trip asking\n * the iframe to attest that the native globals really are `undefined`.\n * 3. **Routing between iframe and native:** listens for `message` events from\n * the iframe, validates them with Valibot, applies the default-deny\n * `ShellPolicy`, and forwards to `Bridge`. Native events go back to the\n * iframe over `postMessage`.\n * 4. **Human confirmation for sensitive commands:** commands listed in\n * `policy.requiresConfirmation` fire the `onConfirmationRequest` callback\n * before touching the native side, so the shell can present UI.\n */\n\nimport * as v from 'valibot';\nimport { Bridge } from './bridge';\nimport type { BridgeKey } from './keys';\nimport {\n ClientToShellMessageSchema,\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 * How long the shell waits for the native handshake before answering the client\n * with `nativeVersion: null`. Deliberately short: the native channel is local,\n * and a fast `null` serves the client better than a slow answer.\n */\nconst NATIVE_HANDSHAKE_TIMEOUT_MS = 2000;\nconst VERIFY_TIMEOUT_MS = 2000;\n\n/**\n * **Layer 1 β the override prefix.**\n *\n * A script prepended to the iframe's `srcdoc` by `bootstrapClientIframe*`. It\n * runs at parse time, before any client script, inside the iframe's own\n * document (origin `null`, so there is no cross-origin block).\n *\n * It uses a **no-op getter/setter** with `configurable: false`, rather than\n * `value` with `writable: false`. Modern ESM bundles run in strict mode, where\n * any `window.X = β¦` on a non-writable property **throws** β which would break\n * legacy modules that register APIs on `window` at load time (this SDK itself\n * does `window.CondorBridge = { emit }` as an import side effect). With a no-op\n * getter/setter the assignment passes silently while the getter always returns\n * `undefined`: the native bridges stay unreachable without breaking legitimate\n * JavaScript.\n *\n * Validated empirically with an offensive pen test on a physical device.\n *\n * **Known limit.** The `webview_flutter` channel is injected into **every**\n * frame (iOS: a user script with `forMainFrameOnly: false`; Android:\n * `addJavascriptInterface`). Measured on an iPhone and a Xiaomi device: the\n * prefix does remove `window.CondorNative` from the iframe, but **a child\n * iframe created by the client receives the channel again**, and on iOS\n * `window.webkit.messageHandlers` cannot be locked (`defineProperty` throws).\n * This layer is defence in depth; the actual guarantee is Layer 3 β the nonce\n * validated natively, which discarded every message sent along those paths.\n */\nconst OVERRIDE_PREFIX = `<script>\n(function(){\n try { delete window.flutter_inappwebview; } catch (_) {}\n try { delete window.CondorBridge; } catch (_) {}\n try { delete window.CondorNative; } catch (_) {}\n try {\n Object.defineProperty(window, 'flutter_inappwebview', {\n get: function(){ return undefined; },\n set: function(_){ /* no-op: blocks the plugin injecting into the iframe */ },\n configurable: false,\n });\n } catch (_) {}\n try {\n Object.defineProperty(window, 'CondorNative', {\n get: function(){ return undefined; },\n set: function(_){ /* no-op: bloqueia o canal do webview_flutter 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 // Neutralize navigator.sendBeacon: an exfiltration channel that CSP\n // connect-src does not reliably block in some WebViews (pen test PT-10).\n // The client communicates only through BridgeClient/postMessage, so it has\n // no legitimate use for sendBeacon. The no-op getter returns a function\n // that answers false; the no-op setter ignores attempts to restore it.\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 * The iframe hosting the client. It may be empty at construction time β\n * `bootstrapClientIframe` is called later to populate it.\n */\n iframe: HTMLIFrameElement;\n\n /**\n * The default-deny policy. Every key and command arriving from the iframe is\n * checked against these lists. See `ShellPolicy`.\n */\n policy: ShellPolicy;\n\n /**\n * Synchronous or asynchronous callback invoked when the client issues a\n * command listed in `policy.requiresConfirmation`. The shell presents its\n * confirmation UI and resolves `true` to approve or `false` to decline.\n *\n * If it is not provided, such commands are **denied** automatically β\n * 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 * The native version, fetched once and cached. `null` until the native side\n * answers, and permanently `null` in a browser with no native host.\n */\n private nativeVersion: string | null = null;\n /** In-flight native handshake; guarantees a single call. */\n private nativeHandshake: Promise<void> | null = null;\n\n // Pending `verify-sandbox` round trips, keyed by a generated 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 * **Layer 1.** Bootstraps by fetching a URL.\n *\n * A shortcut for the common HTTP/HTTPS case: it runs `fetch(clientPath)` and\n * delegates to `bootstrapClientIframeWithHtml`.\n *\n * **It does not work on the `file://` scheme** β Android's Chromium WebView\n * blocks it with \"URL scheme 'file' is not supported\". For an asset bundled\n * in the APK, or a bundle inlined at build time, use\n * `bootstrapClientIframeWithHtml(htmlString)` instead.\n *\n * **Call it once at shell boot**, before any other interaction. After it\n * returns, invoke `verifySandbox()` for attestation (Layer 2).\n */\n async bootstrapClientIframe(clientPath = 'client.html'): Promise<void> {\n const res = await fetch(clientPath);\n if (!res.ok) throw new Error(`BridgeShell: failed to load ${clientPath} (${res.status})`);\n const clientHtml = await res.text();\n await this.bootstrapClientIframeWithHtml(clientHtml);\n }\n\n /**\n * **Layer 1.** Bootstraps from an HTML string.\n *\n * Takes the client HTML directly β already read from a file, embedded at\n * build time, read from storage β and sets it as the iframe's `srcdoc`,\n * prefixed by the override script, which runs at parse time before any\n * client script.\n *\n * Use this when `fetch` does not apply: an asset bundled under `file://`, a\n * bundle inlined at build time, any scenario without network. Android\n * WebView blocks `fetch` on the `file://` scheme, so this is the path the\n * app actually takes. For HTTP, use `bootstrapClientIframe(clientPath)`.\n *\n * **Call it once at shell boot**, before any other interaction. After it\n * returns, invoke `verifySandbox()` for attestation (Layer 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 * **Layer 2.** A `postMessage` round trip asking the iframe for an\n * authoritative attestation of whether the native globals are reachable.\n * Times out after 2 s.\n *\n * `ok` is `true` only when none of them is reachable. If it comes back\n * `false`, **the shell must abort the app boot**: Layer 1 failed, and client\n * code would run with a path to the native layer.\n */\n verifySandbox(): Promise<SandboxVerifyResult> {\n if (!this.iframe.contentWindow) {\n return Promise.reject(new Error('BridgeShell: iframe has no 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 timed out after ${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 * Tears the shell down: removes the `message` listener, cancels pending\n * subscriptions on the native `Bridge`, and clears internal state.\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(ClientToShellMessageSchema, event.data);\n if (!parsed.success) {\n // Drop silently β most likely noise (a browser extension, a 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 // The client handshakes with the **shell**, not the native side: it\n // lives in a sandboxed iframe and cannot reach the native layer. So the\n // shell handshakes with the native side on its behalf and relays\n // `nativeVersion`. Without this a client has no way to know which\n // capabilities it is getting, and the instruction \"check nativeVersion\n // before depending on a new capability\" is impossible to follow.\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 the iframe's JS error to the native side, which routes it\n // to logging.\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 // Layer 2: the client answered verify-sandbox. Resolve the oldest\n // pending entry β in practice there is only ever one, but the map keeps\n // it robust.\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 // `?? false`: a client on SDK < 0.18.0 does not know the new\n // channel and omits the field β its attestation is weaker, not\n // false.\n const nativeChannelReachable = msg.nativeChannelReachable ?? false;\n const ok =\n !msg.flutterBridgeReachable && !msg.condorBridgeReachable && !nativeChannelReachable;\n pending.resolve({\n flutterBridgeReachable: msg.flutterBridgeReachable,\n condorBridgeReachable: msg.condorBridgeReachable,\n nativeChannelReachable,\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: with no callback, a command requiring confirmation is denied.\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 * Resolves `nativeVersion`, firing the native handshake the first time and\n * caching the result.\n *\n * β οΈ `Bridge.handshake` has **no timeout**: its promise only settles when the\n * native side emits `handshake-ack`. In a browser with no native host it\n * never settles, so the race below is what guarantees the client always gets\n * an answer β `null` β instead of hanging.\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 // No native host, or refused: stay `null`, which is honest.\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 * Valibot schemas for the shellβclient `postMessage` protocol.\n *\n * Client content runs inside `<iframe sandbox=\"allow-scripts\">` with a `null`\n * origin, so it talks to the Condor-controlled shell over `window.postMessage`.\n * These schemas are the **only accepted contract** β any malformed message is\n * discarded by the shell in silence, which is why hand-rolled `postMessage`\n * calls appear to do nothing. Use `BridgeClient`.\n *\n * **Threat model:** the iframe may be hostile (a compromised supply chain, XSS\n * in the client code). These schemas plus the `ShellPolicy` enforced by\n * `BridgeShell` form the structural boundary.\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 // Optional: clients on SDK < 0.18.0 do not send it.\n nativeChannelReachable: v.optional(v.boolean()),\n});\n\nexport const ClientToShellMessageSchema = v.variant('type', [\n SubscribeMessage,\n UnsubscribeMessage,\n SendMessage,\n HandshakeMessage,\n JsErrorMessage,\n SandboxVerifyResponseMessage,\n]);\n\n/** Union of every client β shell message. Type only; the runtime schema is `ClientToShellMessageSchema`, which is not part of the public API. */\nexport type ClientToShellMessage = v.InferOutput<typeof ClientToShellMessageSchema>;\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 * Schema version declared by the **native** side, relayed by the shell.\n *\n * `null` when the native side has not answered, or does not exist (browser\n * mock mode). The client runs inside a sandboxed iframe and never talks to\n * the native side directly, so this is the **only** way it can learn which\n * capabilities are available.\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 ShellToClientMessageSchema = v.variant('type', [\n EventMessage,\n HandshakeAckMessage,\n NackMessage,\n VerifySandboxMessage,\n]);\n\n/** Union of every shell β client message. Type only; the runtime schema is `ShellToClientMessageSchema`, which is not part of the public API. */\nexport type ShellToClientMessage = v.InferOutput<typeof ShellToClientMessageSchema>;\n\n// βββ Policy ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n\n/**\n * Default-deny policy enforced by `BridgeShell`. Every key and command coming\n * from the iframe is checked against these lists before it touches the native\n * bridge.\n *\n * - `readOnlyKeys` β keys the client may subscribe to.\n * - `allowedCommands` β pass-through commands, no human confirmation.\n * - `requiresConfirmation` β commands that fire the shell's\n * `onConfirmationRequest` callback, so a person approves or declines.\n * - `deniedCommands` β explicit block, defence in depth: destructive commands\n * such as `dfu` that must never flow from the iframe.\n *\n * **Not embedded in the package** β the `BridgeShell` host supplies the\n * concrete policy. That keeps the package agnostic to the catalogue and lets\n * the policy evolve without a release.\n */\nexport interface ShellPolicy {\n readOnlyKeys: string[];\n allowedCommands: string[];\n requiresConfirmation: string[];\n deniedCommands: string[];\n}\n\n/**\n * Argument of the `BridgeShell` `onConfirmationRequest` callback.\n *\n * Resolving `approve: true` lets the command flow to the native side.\n * Resolving `approve: false` makes the shell send the iframe a `nack` with\n * `reason: 'user-rejected'` β which client code only ever sees as a console\n * warning, so the ack it was waiting for simply never arrives.\n */\nexport interface ConfirmationRequest {\n command: string;\n args: Record<string, unknown>;\n}\n\n/**\n * Result of `BridgeShell.verifySandbox()` after a round trip with the iframe.\n * If any `*Reachable` flag comes back `true`, the boundary is leaking: the\n * override prefix injected by `bootstrapClientIframe` failed, and the app must\n * not render client code with a path to the native layer.\n */\nexport interface SandboxVerifyResult {\n flutterBridgeReachable: boolean;\n condorBridgeReachable: boolean;\n /** Whether `window.CondorNative` is visible inside the iframe. */\n nativeChannelReachable: boolean;\n /** `true` only when none of the three is reachable. */\n ok: boolean;\n}\n","/**\n * `versionAtLeast(ack.nativeVersion, '0.17.0')` β the capability check every\n * client needs. Compares the three numeric segments; `null` (an unknown native\n * side) is never at least anything, so it always takes the baseline branch.\n *\n * Do not compare version strings directly: `'0.9.0' > '0.16.0'` is `true` as\n * strings and false as versions.\n */\nexport function versionAtLeast(version: string | null | undefined, min: string): boolean {\n if (!version) return false;\n const a = version.split('.').map((n) => Number.parseInt(n, 10) || 0);\n const b = min.split('.').map((n) => Number.parseInt(n, 10) || 0);\n for (let i = 0; i < 3; i++) {\n const x = a[i] ?? 0;\n const y = b[i] ?? 0;\n if (x !== y) return x > y;\n }\n return true;\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","../src/version.ts"],"sourcesContent":["/**\n * Catalogue of the JSβNative bridge keys.\n *\n * Mirrors the JS-facing side of `ForegroundComCoreKeys` in `condor_core`.\n * The strings here are what JavaScript receives through\n * `window.CondorBridge.emit(key, payload)`.\n *\n * Thirteen keys exist. A sandboxed client can subscribe to twelve of them:\n * `dfu` is denied by the shell policy and skipped natively. See\n * `docs/bridge-contract.md` for what each one carries and when it is emitted.\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: the OS back button was pressed and the client had\n * reported internal history via `reportNavigation(true)`. Go back exactly\n * ONE internal page. Emitted only when the native side decided to delegate\n * the back gesture. See `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. See `LanguagePayload`.\n */\n language: 'language',\n} as const;\n\nexport type BridgeKey = (typeof BRIDGE_KEYS)[keyof typeof BRIDGE_KEYS];\n","/**\n * Dev panel β a floating UI for inspecting the bridge in mock mode.\n *\n * **Opt-in:** call `Bridge.installDevPanel(opts?)` when you want it. It only\n * works in mock mode and throws in real mode. It injects into `document.body`\n * and is idempotent β re-installing removes the previous panel.\n *\n * Contents:\n * - a header with a \"MOCK\" badge, a send counter, and a minimise button;\n * - a sent log with the last N messages (timestamp, type, truncated payload);\n * - a trigger-emit control: a `BRIDGE_KEYS` dropdown, a payload textarea, and\n * a button.\n *\n * Styles are inline and classes are prefixed `condor-mock-panel-*`, to reduce\n * collisions with the client's own CSS.\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 * A reply emitted automatically in reaction to a `Bridge.send`, returned by the\n * client's `onSendForAutoRespond` policy. `null` means \"do not answer this\n * send\".\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 * Auto-respond policy: invoked on every `Bridge.send` while the panel's\n * \"Auto-respond\" toggle is on. Return `{ key, payload }` to fire\n * `Bridge.mockEmit(key, payload)` after the delay, or `null` to stay silent.\n *\n * Without this callback the \"Auto-respond\" checkbox does not appear.\n */\n onSendForAutoRespond?: (msg: MockMessage) => AutoRespondResponse | null;\n\n /**\n * Initial state of the \"Auto-respond\" toggle. Defaults to `false` β manual\n * stays the default, and the client decides when to turn it on.\n */\n startAutoRespondEnabled?: boolean;\n\n /**\n * Delay in milliseconds between the `send` and the auto-response `mockEmit`.\n * Defaults to `50`, which approximates the IPC latency of the real native\n * bridge.\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/** Inspection helper, for tests and debugging. */\nexport function getInstalledDevPanel(): InstalledPanel | null {\n return currentPanel;\n}\n","/**\n * Mock adapter β active when no native host is detected: a plain browser,\n * jsdom without an installed host, Storybook, and so on.\n *\n * Behaviour:\n * - `callHandler` records `{ handlerName, payload, timestamp }` in an internal\n * buffer (capped at 100, FIFO), logs through `console.debug`, and dispatches\n * to listeners registered with `onCallHandler`.\n * - `triggerEmit` dispatches through `window.CondorBridge.emit`, so the real\n * bridge treats it as if it came from the native side: `handshake-ack`\n * resolves the handshake, every other key reaches its subscribers.\n * - `getMessages` returns a read-only snapshot of the buffer.\n * - `clearMessages` empties it, which is useful in tests.\n * - `onCallHandler(listener)` registers a listener invoked on every send and\n * returns an unsubscribe function β used by the dev panel's auto-respond\n * toggle, and for assertions in tests.\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 * Registers a listener invoked on every `callHandler` (a JS β native\n * message). Returns an unsubscribe function.\n *\n * Errors thrown by a listener are caught and logged; they affect neither the\n * other listeners nor the bridge pipeline.\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 * Native host detection, behind an adapter.\n *\n * Detection order: the `window.CondorNative` JavaScript channel\n * (`webview_flutter`) first, then the legacy `window.flutter_inappwebview`,\n * then the mock. The channel only accepts strings, so the message travels as\n * JSON. `setOutgoingStamp` lets the shell stamp every outgoing message β the\n * nonce β without monkey-patching the host.\n *\n * With no host at all the mock adapter activates, which is what makes browser\n * development possible without building an APK.\n *\n * The active adapter is cached on the first `getActiveAdapter()` call. Tests\n * should call `__resetAdapterForTests()` in `beforeEach` to force\n * re-detection, for instance after installing or removing\n * `window.CondorNative`.\n */\n\nimport { createMockAdapter, type MockAdapter } from './mock';\n\n/**\n * Name of the JavaScript channel the native side registers with\n * `WebViewController.addJavaScriptChannel`.\n *\n * It cannot be `CondorBridge`: the plugin publishes the channel as\n * `window.<name>`, which would collide with the `window.CondorBridge` emitter\n * this SDK installs.\n */\nexport const NATIVE_CHANNEL_NAME = 'CondorNative';\n\ninterface FlutterInAppWebView {\n callHandler(name: string, ...args: unknown[]): Promise<unknown>;\n}\n\ninterface NativeChannel {\n postMessage(message: string): void;\n}\n\ndeclare global {\n interface Window {\n flutter_inappwebview?: FlutterInAppWebView;\n CondorNative?: NativeChannel;\n }\n}\n\n/**\n * Transforma toda mensagem JS β Native imediatamente antes do envio.\n * Recebe e devolve o envelope `{type, version, payload}`.\n */\nexport type OutgoingStamp = (message: Record<string, unknown>) => Record<string, unknown>;\n\nlet outgoingStamp: OutgoingStamp | null = null;\n\nexport function setOutgoingStamp(stamp: OutgoingStamp | null): void {\n outgoingStamp = stamp;\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 createChannelAdapter(channel: NativeChannel): RealAdapter {\n return {\n isMock: false,\n // Single channel: `handlerName` does not travel β the native side routes\n // on `type`.\n callHandler(_handlerName, payload) {\n channel.postMessage(JSON.stringify(payload));\n },\n };\n}\n\nfunction createLegacyAdapter(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 channel = window.CondorNative;\n if (channel && typeof channel.postMessage === 'function') {\n return createChannelAdapter(channel);\n }\n const host = window.flutter_inappwebview;\n if (host && typeof host.callHandler === 'function') {\n return createLegacyAdapter(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 * Sends a message to the native handler through the active adapter.\n *\n * Real mode: fire-and-forget over `CondorNative.postMessage` (JSON) or, on the\n * legacy host, `flutter_inappwebview.callHandler`.\n * Mock mode: recorded in the buffer and logged with `console.debug`.\n *\n * The `setOutgoingStamp` transform is applied on every adapter, so what the\n * mock records is exactly what the native side would have received.\n */\nexport function callNative(handlerName: string, payload: Record<string, unknown>): void {\n const stamped = outgoingStamp ? outgoingStamp(payload) : payload;\n getActiveAdapter().callHandler(handlerName, stamped);\n}\n\n/**\n * Resets the adapter cache. **Exported for tests only.**\n *\n * Client code must never call this: the adapter is detected once at startup\n * and kept for the lifetime of the page.\n */\nexport function __resetAdapterForTests(): void {\n activeAdapter = null;\n outgoingStamp = 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 // A buggy subscriber must not affect the others, or the 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 * Inspection helper, for tests and debugging.\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 {\n callNative,\n getActiveAdapter,\n type OutgoingStamp,\n setOutgoingStamp,\n} 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 // Already installed (HMR, double import, or a mock installed by tests).\n // Replace only `emit`, so the newest dispatcher is the one wired to the\n // subscribers of this module instance.\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` when the active adapter is the mock β a plain browser, with neither\n * `window.CondorNative` nor `window.flutter_inappwebview`. `false` inside the\n * Flutter WebView.\n */\n readonly isMock: boolean;\n\n /**\n * Sends a versioned handshake to the native side and awaits `handshake-ack`.\n *\n * Only one handshake may be in flight; a parallel call before the first ack\n * arrives is rejected with an explicit error.\n *\n * **In mock mode it does not resolve on its own.** The caller must emit\n * `Bridge.mockEmit('handshake-ack', { nativeVersion, accepted })` to unblock\n * the promise. That is deliberate: it forces tests to be explicit about the\n * native state they are simulating.\n */\n handshake(opts: HandshakeOptions): Promise<HandshakeAck>;\n\n /**\n * Subscribes to an observable key. Returns an `unsubscribe` function.\n *\n * Multiple subscribers per key are allowed; a throw in one does not affect\n * the others (it is caught and logged with `console.error`).\n */\n on<K extends BridgeKey>(key: K, cb: (payload: PayloadOf<K>) => void): () => void;\n\n /**\n * Sends a generic message to the native side, for commands without a\n * dedicated helper. `type` is the string the native side routes on.\n *\n * Fire-and-forget: no return value and no delivery confirmation. A payload\n * above 64 KB, or an unknown `type`, is dropped natively without a reply.\n *\n * In mock mode it is recorded in the internal buffer and logged with\n * `console.debug`.\n */\n send(type: string, payload?: Record<string, unknown>): void;\n\n /**\n * Opens the app's native Settings screen. Equivalent to\n * `Bridge.send('openSettings')`.\n */\n openSettings(): void;\n\n /**\n * Registers a transform applied to **every** JS β native message, the\n * handshake included, immediately before it is sent. Pass `null` to remove.\n *\n * It exists so the shell can stamp its nonce (`payload._shellNonce`) at a\n * single chokepoint. Wrapping `send` alone is not enough β `handshake` calls\n * the native layer directly, and a message without the nonce is dropped and\n * logged as a security event.\n *\n * **Client code must not use this.**\n */\n setOutgoingStamp(stamp: OutgoingStamp | null): void;\n\n /**\n * Fires `window.CondorBridge.emit(key, payload)` programmatically β useful to\n * simulate native events in tests and in browser development.\n *\n * **Throws** when the active adapter is not the mock.\n */\n mockEmit(key: string, payload?: unknown): void;\n\n /**\n * Snapshot of the mock adapter state: messages sent, and keys with active\n * subscribers. Useful for assertions in client tests.\n *\n * **Throws** when the active adapter is not the mock.\n */\n getMockState(): MockState;\n\n /**\n * Injects a floating HTML panel into `document.body` for inspecting the\n * bridge in mock mode. Idempotent β re-installing replaces the previous one.\n *\n * **Throws** when the active adapter is not the mock, or `document` does not\n * exist.\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 setOutgoingStamp(stamp: OutgoingStamp | null): void {\n setOutgoingStamp(stamp);\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 * Resets the bridge's internal state (the pending handshake).\n *\n * **Exported for tests only.** Do not call it from application code β it breaks\n * the \"only one handshake in flight\" invariant.\n */\nexport function __resetBridgeForTests(): void {\n pendingHandshake = null;\n}\n","/**\n * `BridgeClient` β **the API for client code**, running inside\n * `<iframe sandbox=\"allow-scripts\">` in the Condor Canvas app.\n *\n * This is what you want if you are building the bundle that renders as the\n * app's Home. Every call becomes a `window.parent.postMessage(...)` that the\n * Condor shell validates against a schema and a default-deny policy before it\n * reaches the native layer. You never touch the native globals β the shell\n * deletes them before your bundle runs.\n *\n * It deliberately does **not** expose `installDevPanel`, `mockEmit`, `isMock`\n * or `getMockState`: those belong to the shell (`BridgeShell`). To run a bundle\n * in a browser, use the dev harness (`npx condor-mobile-bridge dev`, or\n * `createDevHarness` from `@condorinst/mobile-bridge/dev`).\n *\n * The module also answers the shell's `verify-sandbox` probe β the iframe\n * attesting whether it can still see the native globals. If any is reachable,\n * the shell aborts the boot rather than render client code with a path to the\n * native layer.\n */\n\nimport { BRIDGE_KEYS, type BridgeKey } from './keys';\nimport type {\n CommandArgsTuple,\n CommandName,\n PayloadOf,\n SensorLogPayload,\n SensorLogQueryPayload,\n UserDevicePayload,\n} from './payloads';\nimport type { ClientToShellMessage, ShellToClientMessage } from './shell-messages';\n\n/**\n * A unique `requestId` for `sensorLog`. Built on `crypto.getRandomValues`,\n * which works in any context β unlike `crypto.randomUUID`, which exists only in\n * a secure context, and the app's sandboxed iframe is probably not one.\n */\nexport function createRequestId(): string {\n const bytes = new Uint8Array(16);\n crypto.getRandomValues(bytes);\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n\n/** A `sensorLog` query for `fetchSensorLog`: `requestId` is filled in if absent. */\nexport type SensorLogFetchQuery = Omit<SensorLogQueryPayload, 'requestId'> & {\n requestId?: string;\n};\n\nconst PROTOCOL_VERSION = '0.5.0';\nconst HANDSHAKE_TIMEOUT_MS = 5000;\n/**\n * Default timeout for one `sensorLog` page. A 1000-log page costs about 2.7 s\n * in the worst case measured (a gen2 device), so the margin is deliberate.\n */\nconst SENSOR_LOG_TIMEOUT_MS = 10000;\n/**\n * Default deadline of `waitForService` and `requestUserDevices`. On a cold\n * start the app's background service can take several seconds to come up.\n */\nconst SERVICE_TIMEOUT_MS = 30000;\n/** Resend schedule while a reply is pending, in ms after the previous send. */\nconst RESEND_BACKOFF_MS = [1500, 3000, 6000, 10000];\n\nconst NOT_IN_SHELL_HINT =\n 'Not running inside the Condor shell. To develop in a browser, run ' +\n '`npx condor-mobile-bridge dev -i dist/index.html`, or mount the page with ' +\n 'createDevHarness() from \"@condorinst/mobile-bridge/dev\".';\n\nfunction insideShell(): boolean {\n return typeof window !== 'undefined' && window.parent !== window;\n}\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[]>();\n/**\n * Last `systemStatus` received, so `requestUserDevices` knows `hasDevices`\n * even when the emission that follows the handshake arrived before it ran.\n */\nlet lastSystemStatus: { hasDevices?: unknown; hasDevicesKnown?: unknown } | null = null;\n\n/**\n * `systemStatus.hasDevices` when it can be trusted: `null` when no status\n * arrived yet, or when the app says it could not ask the server\n * (`hasDevicesKnown: false`, nativeVersion 0.18.0+).\n */\nfunction trustedHasDevices(status: { hasDevices?: unknown; hasDevicesKnown?: unknown } | null) {\n if (!status || typeof status.hasDevices !== 'boolean') return null;\n if (status.hasDevicesKnown === false) return null;\n return status.hasDevices;\n}\nlet pendingHandshake: PendingHandshake | null = null;\nlet messageListenerInstalled = false;\n\nfunction postToShell(msg: ClientToShellMessage): void {\n if (!insideShell()) {\n console.warn(`[BridgeClient] message dropped (${msg.type}). ${NOT_IN_SHELL_HINT}`);\n return;\n }\n window.parent.postMessage(msg, '*');\n}\n\nfunction dispatchEvent(key: string, payload: unknown): void {\n if (key === BRIDGE_KEYS.systemStatus && payload && typeof payload === 'object') {\n lastSystemStatus = payload as { hasDevices?: unknown; hasDevicesKnown?: unknown };\n }\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 // No Valibot validation here β the shell is trusted (Condor-controlled).\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` covers shells older than 0.17.0, which omitted the field.\n nativeVersion: msg.ack?.nativeVersion ?? null,\n accepted: msg.ack?.accepted ?? false,\n });\n }\n break;\n }\n case 'nack':\n // A future version may let clients observe nacks explicitly.\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 nativeChannelReachable: typeof w.CondorNative !== '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 * Schema version of the **native** side, relayed by the shell. `null` when\n * the native side has not answered, or the shell is older than 0.6.0.\n *\n * **This number is the only capability signal a client gets.** There is no\n * version negotiation, and a sandboxed client reaches the native side by no\n * other path. For example, the raw light channels (`light_sensor_*` in\n * `deviceLightSensors`) exist from `0.16.0`. Always keep a working branch\n * for `null`. The dev harness reports `0.18.0` unless a scenario says\n * otherwise.\n */\n nativeVersion: string | null;\n /**\n * Whether the native side accepted your `clientVersion`. It is **always\n * `true`** β there is no hard validation β so it carries no information.\n * Never branch on it; branch on {@link nativeVersion}.\n */\n accepted: boolean;\n}\n\n/** What {@link CondorBridgeClient.requestUserDevices} resolves with. */\nexport type UserDevicesResult =\n /** The list arrived. It may be empty. */\n | { status: 'ok'; devices: UserDevicePayload }\n /** The server says the account has no linked device (nativeVersion 0.18.0+). */\n | { status: 'no-devices' }\n /** The app could not load the list: `NETWORK`, `SESSION`, `UNKNOWN` (0.18.0+). */\n | { status: 'error'; code: string }\n /**\n * No answer before the deadline β the only failure an app below 0.18.0 can\n * produce. `hasDevices` is the last trustworthy `systemStatus.hasDevices`,\n * or `null`.\n */\n | { status: 'timeout'; hasDevices: boolean | null };\n\nexport interface CondorBridgeClient {\n /** Version of the client-side postMessage protocol. */\n readonly protocolVersion: string;\n\n /**\n * Subscribes to an observable key. Returns an `unsubscribe` function β\n * call it when a view unmounts, or handlers accumulate and every one of them\n * re-renders.\n *\n * Multiple subscribers per key are allowed, and a throw in one does not\n * affect the others. Subscribe *before* sending the command that triggers\n * the reply: the reply can arrive before your next statement runs.\n */\n on<K extends BridgeKey>(key: K, cb: (payload: PayloadOf<K>) => void): () => void;\n\n /**\n * Sends a command to the shell, which validates it against the policy before\n * it touches the native layer.\n *\n * **Fire-and-forget: no return value, no throw, no delivery confirmation.**\n * A command that is not allowed produces a `nack` that surfaces only as a\n * `console.warn`. A malformed one is dropped in silence by the native side.\n * Replies, when a command has one, arrive on the corresponding key β see\n * `docs/bridge-contract.md`.\n */\n send<C extends CommandName>(command: C, ...args: CommandArgsTuple<C>): void;\n\n /** Opens the native Settings screen. Equivalent to `send('openSettings')`. */\n openSettings(): void;\n\n /**\n * Requests ONE page of sensor logs and resolves with the reply correlated by\n * `requestId` β **including when it carries `success: false`**, which is an\n * answer, not a transport failure. The promise only **rejects** on timeout,\n * so always check `success` before reading `logs`.\n *\n * Saves you from keeping a `requestId β resolve` map by hand. To sweep a\n * period, chain calls using the returned `startingAfter` until `hasMore`\n * becomes `false`: the cursors are dependent, so pages **cannot** be fetched\n * in parallel. Leave `requestId` out: one is created for you\n * ({@link createRequestId}).\n */\n fetchSensorLog(\n query: SensorLogFetchQuery,\n opts?: { timeoutMs?: number },\n ): Promise<SensorLogPayload>;\n\n /**\n * Requests ONE permission through the **in-app native dialog** (it does not\n * open Settings). Use it for the \"Grant\" button of your required-permissions\n * card, with a name taken from `systemStatus.missingEssentialPermissions`,\n * e.g. `'bluetoothScan'`.\n *\n * **There is no result key.** The outcome arrives as a fresh `systemStatus`\n * emission; your card disappears when the array empties. A name outside the\n * native enum is dropped in silence.\n */\n requestPermission(permission: string): void;\n\n /**\n * Resolves when the app's **background service** answers a `ping`.\n *\n * Commands that need device data (`userDevice`, `ping`) travel to a service\n * the app starts after your bundle is already running. A command sent before\n * the service is up is **lost without a reply** β the handshake, `systemStatus`\n * and `language` work earlier, which makes the bridge look ready when it is\n * not. This helper resends `ping` with backoff (1.5 s, 3 s, 6 s, then every\n * 10 s) until a `pingPong` arrives.\n *\n * Never rejects: resolves `{ status: 'timeout' }` after `timeoutMs`\n * (default 30 s).\n */\n waitForService(opts?: { timeoutMs?: number }): Promise<{ status: 'ready' | 'timeout' }>;\n\n /**\n * Requests the user's devices and **keeps asking** until they arrive. Use\n * this instead of `send('userDevice')`, which may never be answered on an app\n * below `nativeVersion` 0.18.0:\n *\n * - on a cold start the first request is lost while the background service\n * comes up;\n * - an account with no linked device gets no reply at all.\n *\n * Resends with backoff (1.5 s, 3 s, 6 s, then every 10 s) and on every\n * `systemStatus` while pending. Never rejects. Resolves a\n * {@link UserDevicesResult}:\n * - `ok` β render `devices`;\n * - `no-devices` β the server confirmed there is none (0.18.0+);\n * - `error` β the list could not load (`NETWORK`, `SESSION`, `UNKNOWN`;\n * 0.18.0+): show it with a retry;\n * - `timeout` β no answer in `timeoutMs` (default 30 s). On an older app this\n * is how both failures look; `hasDevices === false` then **suggests** an\n * account with no device, worded so it is true either way.\n *\n * `getFromServer: true` asks the app to refresh from the server; leave it\n * `false` (default) at boot, where the cached list is enough.\n */\n requestUserDevices(opts?: {\n timeoutMs?: number;\n getFromServer?: boolean;\n }): Promise<UserDevicesResult>;\n\n /**\n * Handshakes with the shell. Resolves with\n * `{ shellVersion, nativeVersion, accepted }` β read `nativeVersion` to learn\n * what this device can do, and ignore `accepted`, which is always `true`.\n *\n * Rejects after 5 s if the shell does not answer, and **at once** when the\n * page is not inside the Condor shell (opened directly in a browser) β run\n * `npx condor-mobile-bridge dev` instead. Only one handshake may be in flight\n * at a time.\n */\n handshake(opts: { clientVersion: string }): Promise<BridgeClientHandshakeAck>;\n\n /**\n * Reports to the native side whether the client has internal history to go\n * back to. **Call it on every internal navigation**, and at boot β not once.\n * The native side caches the value and uses it to decide what the OS back\n * button does:\n * - `true` β back asks you to go back one page (the `navigationBack` event,\n * see {@link onBack});\n * - `false` β back stays with the app and does not leave the Home.\n *\n * Equivalent to `send('navigationState', { canGoBack })`.\n */\n reportNavigation(canGoBack: boolean): void;\n\n /**\n * Subscribes to the OS back request (the `navigationBack` event). The\n * callback must go back **one** internal page and then call\n * {@link reportNavigation} with the new state. It only fires when you had\n * reported `reportNavigation(true)`. Returns an `unsubscribe` function.\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 // in the shell β repeated `subscribe` for the same key is handled).\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<C extends CommandName>(command: C, ...rest: CommandArgsTuple<C>): void {\n const args = (rest[0] ?? {}) as Record<string, unknown>;\n postToShell({ type: 'send', command, args });\n },\n\n openSettings(): void {\n this.send('openSettings');\n },\n\n fetchSensorLog(\n input: SensorLogFetchQuery,\n opts?: { timeoutMs?: number },\n ): Promise<SensorLogPayload> {\n const query: SensorLogQueryPayload = {\n ...input,\n requestId: input.requestId ?? createRequestId(),\n };\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 // Other in-flight pages share the key: only ours is relevant.\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 waitForService(opts?: { timeoutMs?: number }): Promise<{ status: 'ready' | 'timeout' }> {\n return retryUntilReply<{ status: 'ready' | 'timeout' }>({\n timeoutMs: opts?.timeoutMs ?? SERVICE_TIMEOUT_MS,\n send: () => this.send('ping'),\n listen: (done) =>\n this.on(BRIDGE_KEYS.pingPong, (payload) => {\n if (payload.data === 'pong') done({ status: 'ready' });\n }),\n onTimeout: () => ({ status: 'timeout' }),\n });\n },\n\n requestUserDevices(opts?: { timeoutMs?: number; getFromServer?: boolean }) {\n let hasDevices = trustedHasDevices(lastSystemStatus);\n const getFromServer = opts?.getFromServer ?? false;\n return retryUntilReply<UserDevicesResult>({\n timeoutMs: opts?.timeoutMs ?? SERVICE_TIMEOUT_MS,\n send: () => this.send('userDevice', { getFromServer }),\n listen: (done, resend) => {\n const offDevices = this.on(BRIDGE_KEYS.userDevice, (devices) => {\n if (devices.error === undefined || devices.error === null) {\n done({ status: 'ok', devices });\n } else if (devices.error === 'NO_DEVICES') {\n done({ status: 'no-devices' });\n } else {\n done({ status: 'error', code: String(devices.error) });\n }\n });\n const offStatus = this.on(BRIDGE_KEYS.systemStatus, (status) => {\n hasDevices = trustedHasDevices(status);\n resend();\n });\n return () => {\n offDevices();\n offStatus();\n };\n },\n onTimeout: () => ({ status: 'timeout', hasDevices }),\n });\n },\n\n handshake(opts: { clientVersion: string }): Promise<BridgeClientHandshakeAck> {\n ensureMessageListener();\n if (!insideShell()) {\n return Promise.reject(new Error(`BridgeClient: handshake impossible. ${NOT_IN_SHELL_HINT}`));\n }\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 * Sends, then resends on a backoff schedule (and whenever `listen` asks) until\n * `listen` reports a reply or `timeoutMs` passes. Never rejects.\n */\nfunction retryUntilReply<T>(opts: {\n timeoutMs: number;\n send: () => void;\n listen: (done: (result: T) => void, resend: () => void) => () => void;\n onTimeout: () => T;\n}): Promise<T> {\n return new Promise<T>((resolve) => {\n let settled = false;\n let attempt = 0;\n let lastSend = 0;\n let resendTimer: ReturnType<typeof setTimeout> | undefined;\n\n const finish = (result: T): void => {\n if (settled) return;\n settled = true;\n clearTimeout(deadline);\n clearTimeout(resendTimer);\n unlisten();\n resolve(result);\n };\n const sendNow = (): void => {\n if (settled) return;\n lastSend = Date.now();\n opts.send();\n const delay = RESEND_BACKOFF_MS[Math.min(attempt, RESEND_BACKOFF_MS.length - 1)] ?? 10000;\n attempt += 1;\n clearTimeout(resendTimer);\n resendTimer = setTimeout(sendNow, delay);\n };\n // An external nudge (a fresh systemStatus) resends at most once per second.\n const resend = (): void => {\n if (Date.now() - lastSend >= 1000) sendNow();\n };\n\n const unlisten = opts.listen(finish, resend);\n const deadline = setTimeout(() => finish(opts.onTimeout()), opts.timeoutMs);\n sendNow();\n });\n}\n\n/**\n * Reseta estado interno (subscribers + handshake pendente).\n *\n * **Exportado para uso em testes apenas.** Listener `message` permanece\n * installed between tests β it is idempotent (it checks `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 lastSystemStatus = null;\n}\n","/**\n * `BridgeShell` β the API for the **Condor-controlled shell** that wraps\n * external client content inside `<iframe sandbox=\"allow-scripts\">`.\n *\n * This is not client-facing. If you are writing the bundle that renders as the\n * app's Home, you want `BridgeClient`.\n *\n * Responsibilities:\n * 1. **Layer 1 β `bootstrapClientIframe(iframe, clientPath)`:** fetches the\n * client HTML, prepends an override script that removes the native globals\n * from the iframe, and sets it as `srcdoc`. The override runs at parse time,\n * before any other script.\n * 2. **Layer 2 β `verifySandbox(iframe)`:** a `postMessage` round trip asking\n * the iframe to attest that the native globals really are `undefined`.\n * 3. **Routing between iframe and native:** listens for `message` events from\n * the iframe, validates them with Valibot, applies the default-deny\n * `ShellPolicy`, and forwards to `Bridge`. Native events go back to the\n * iframe over `postMessage`.\n * 4. **Human confirmation for sensitive commands:** commands listed in\n * `policy.requiresConfirmation` fire the `onConfirmationRequest` callback\n * before touching the native side, so the shell can present UI.\n */\n\nimport * as v from 'valibot';\nimport { Bridge } from './bridge';\nimport type { BridgeKey } from './keys';\nimport {\n ClientToShellMessageSchema,\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 * How long the shell waits for the native handshake before answering the client\n * with `nativeVersion: null`. Deliberately short: the native channel is local,\n * and a fast `null` serves the client better than a slow answer.\n */\nconst NATIVE_HANDSHAKE_TIMEOUT_MS = 2000;\nconst VERIFY_TIMEOUT_MS = 2000;\n\n/**\n * **Layer 1 β the override prefix.**\n *\n * A script prepended to the iframe's `srcdoc` by `bootstrapClientIframe*`. It\n * runs at parse time, before any client script, inside the iframe's own\n * document (origin `null`, so there is no cross-origin block).\n *\n * It uses a **no-op getter/setter** with `configurable: false`, rather than\n * `value` with `writable: false`. Modern ESM bundles run in strict mode, where\n * any `window.X = β¦` on a non-writable property **throws** β which would break\n * legacy modules that register APIs on `window` at load time (this SDK itself\n * does `window.CondorBridge = { emit }` as an import side effect). With a no-op\n * getter/setter the assignment passes silently while the getter always returns\n * `undefined`: the native bridges stay unreachable without breaking legitimate\n * JavaScript.\n *\n * Validated empirically with an offensive pen test on a physical device.\n *\n * **Known limit.** The `webview_flutter` channel is injected into **every**\n * frame (iOS: a user script with `forMainFrameOnly: false`; Android:\n * `addJavascriptInterface`). Measured on an iPhone and a Xiaomi device: the\n * prefix does remove `window.CondorNative` from the iframe, but **a child\n * iframe created by the client receives the channel again**, and on iOS\n * `window.webkit.messageHandlers` cannot be locked (`defineProperty` throws).\n * This layer is defence in depth; the actual guarantee is Layer 3 β the nonce\n * validated natively, which discarded every message sent along those paths.\n */\nconst OVERRIDE_PREFIX = `<script>\n(function(){\n try { delete window.flutter_inappwebview; } catch (_) {}\n try { delete window.CondorBridge; } catch (_) {}\n try { delete window.CondorNative; } catch (_) {}\n try {\n Object.defineProperty(window, 'flutter_inappwebview', {\n get: function(){ return undefined; },\n set: function(_){ /* no-op: blocks the plugin injecting into the iframe */ },\n configurable: false,\n });\n } catch (_) {}\n try {\n Object.defineProperty(window, 'CondorNative', {\n get: function(){ return undefined; },\n set: function(_){ /* no-op: bloqueia o canal do webview_flutter 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 // Neutralize navigator.sendBeacon: an exfiltration channel that CSP\n // connect-src does not reliably block in some WebViews (pen test PT-10).\n // The client communicates only through BridgeClient/postMessage, so it has\n // no legitimate use for sendBeacon. The no-op getter returns a function\n // that answers false; the no-op setter ignores attempts to restore it.\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 * The iframe hosting the client. It may be empty at construction time β\n * `bootstrapClientIframe` is called later to populate it.\n */\n iframe: HTMLIFrameElement;\n\n /**\n * The default-deny policy. Every key and command arriving from the iframe is\n * checked against these lists. See `ShellPolicy`.\n */\n policy: ShellPolicy;\n\n /**\n * Synchronous or asynchronous callback invoked when the client issues a\n * command listed in `policy.requiresConfirmation`. The shell presents its\n * confirmation UI and resolves `true` to approve or `false` to decline.\n *\n * If it is not provided, such commands are **denied** automatically β\n * 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 * The native version, fetched once and cached. `null` until the native side\n * answers, and permanently `null` in a browser with no native host.\n */\n private nativeVersion: string | null = null;\n /** In-flight native handshake; guarantees a single call. */\n private nativeHandshake: Promise<void> | null = null;\n\n // Pending `verify-sandbox` round trips, keyed by a generated 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 * **Layer 1.** Bootstraps by fetching a URL.\n *\n * A shortcut for the common HTTP/HTTPS case: it runs `fetch(clientPath)` and\n * delegates to `bootstrapClientIframeWithHtml`.\n *\n * **It does not work on the `file://` scheme** β Android's Chromium WebView\n * blocks it with \"URL scheme 'file' is not supported\". For an asset bundled\n * in the APK, or a bundle inlined at build time, use\n * `bootstrapClientIframeWithHtml(htmlString)` instead.\n *\n * **Call it once at shell boot**, before any other interaction. After it\n * returns, invoke `verifySandbox()` for attestation (Layer 2).\n */\n async bootstrapClientIframe(clientPath = 'client.html'): Promise<void> {\n const res = await fetch(clientPath);\n if (!res.ok) throw new Error(`BridgeShell: failed to load ${clientPath} (${res.status})`);\n const clientHtml = await res.text();\n await this.bootstrapClientIframeWithHtml(clientHtml);\n }\n\n /**\n * **Layer 1.** Bootstraps from an HTML string.\n *\n * Takes the client HTML directly β already read from a file, embedded at\n * build time, read from storage β and sets it as the iframe's `srcdoc`,\n * prefixed by the override script, which runs at parse time before any\n * client script.\n *\n * Use this when `fetch` does not apply: an asset bundled under `file://`, a\n * bundle inlined at build time, any scenario without network. Android\n * WebView blocks `fetch` on the `file://` scheme, so this is the path the\n * app actually takes. For HTTP, use `bootstrapClientIframe(clientPath)`.\n *\n * **Call it once at shell boot**, before any other interaction. After it\n * returns, invoke `verifySandbox()` for attestation (Layer 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 * **Layer 2.** A `postMessage` round trip asking the iframe for an\n * authoritative attestation of whether the native globals are reachable.\n * Times out after 2 s.\n *\n * `ok` is `true` only when none of them is reachable. If it comes back\n * `false`, **the shell must abort the app boot**: Layer 1 failed, and client\n * code would run with a path to the native layer.\n */\n verifySandbox(): Promise<SandboxVerifyResult> {\n if (!this.iframe.contentWindow) {\n return Promise.reject(new Error('BridgeShell: iframe has no 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 timed out after ${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 * Tears the shell down: removes the `message` listener, cancels pending\n * subscriptions on the native `Bridge`, and clears internal state.\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(ClientToShellMessageSchema, event.data);\n if (!parsed.success) {\n // Drop silently β most likely noise (a browser extension, a 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 // The client handshakes with the **shell**, not the native side: it\n // lives in a sandboxed iframe and cannot reach the native layer. So the\n // shell handshakes with the native side on its behalf and relays\n // `nativeVersion`. Without this a client has no way to know which\n // capabilities it is getting, and the instruction \"check nativeVersion\n // before depending on a new capability\" is impossible to follow.\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 the iframe's JS error to the native side, which routes it\n // to logging.\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 // Layer 2: the client answered verify-sandbox. Resolve the oldest\n // pending entry β in practice there is only ever one, but the map keeps\n // it robust.\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 // `?? false`: a client on SDK < 0.18.0 does not know the new\n // channel and omits the field β its attestation is weaker, not\n // false.\n const nativeChannelReachable = msg.nativeChannelReachable ?? false;\n const ok =\n !msg.flutterBridgeReachable && !msg.condorBridgeReachable && !nativeChannelReachable;\n pending.resolve({\n flutterBridgeReachable: msg.flutterBridgeReachable,\n condorBridgeReachable: msg.condorBridgeReachable,\n nativeChannelReachable,\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: with no callback, a command requiring confirmation is denied.\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 * Resolves `nativeVersion`, firing the native handshake the first time and\n * caching the result.\n *\n * β οΈ `Bridge.handshake` has **no timeout**: its promise only settles when the\n * native side emits `handshake-ack`. In a browser with no native host it\n * never settles, so the race below is what guarantees the client always gets\n * an answer β `null` β instead of hanging.\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 // No native host, or refused: stay `null`, which is honest.\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 * Valibot schemas for the shellβclient `postMessage` protocol.\n *\n * Client content runs inside `<iframe sandbox=\"allow-scripts\">` with a `null`\n * origin, so it talks to the Condor-controlled shell over `window.postMessage`.\n * These schemas are the **only accepted contract** β any malformed message is\n * discarded by the shell in silence, which is why hand-rolled `postMessage`\n * calls appear to do nothing. Use `BridgeClient`.\n *\n * **Threat model:** the iframe may be hostile (a compromised supply chain, XSS\n * in the client code). These schemas plus the `ShellPolicy` enforced by\n * `BridgeShell` form the structural boundary.\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 // Optional: clients on SDK < 0.18.0 do not send it.\n nativeChannelReachable: v.optional(v.boolean()),\n});\n\nexport const ClientToShellMessageSchema = v.variant('type', [\n SubscribeMessage,\n UnsubscribeMessage,\n SendMessage,\n HandshakeMessage,\n JsErrorMessage,\n SandboxVerifyResponseMessage,\n]);\n\n/** Union of every client β shell message. Type only; the runtime schema is `ClientToShellMessageSchema`, which is not part of the public API. */\nexport type ClientToShellMessage = v.InferOutput<typeof ClientToShellMessageSchema>;\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 * Schema version declared by the **native** side, relayed by the shell.\n *\n * `null` when the native side has not answered, or does not exist (browser\n * mock mode). The client runs inside a sandboxed iframe and never talks to\n * the native side directly, so this is the **only** way it can learn which\n * capabilities are available.\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 ShellToClientMessageSchema = v.variant('type', [\n EventMessage,\n HandshakeAckMessage,\n NackMessage,\n VerifySandboxMessage,\n]);\n\n/** Union of every shell β client message. Type only; the runtime schema is `ShellToClientMessageSchema`, which is not part of the public API. */\nexport type ShellToClientMessage = v.InferOutput<typeof ShellToClientMessageSchema>;\n\n// βββ Policy ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n\n/**\n * Default-deny policy enforced by `BridgeShell`. Every key and command coming\n * from the iframe is checked against these lists before it touches the native\n * bridge.\n *\n * - `readOnlyKeys` β keys the client may subscribe to.\n * - `allowedCommands` β pass-through commands, no human confirmation.\n * - `requiresConfirmation` β commands that fire the shell's\n * `onConfirmationRequest` callback, so a person approves or declines.\n * - `deniedCommands` β explicit block, defence in depth: destructive commands\n * such as `dfu` that must never flow from the iframe.\n *\n * **Not embedded in the package** β the `BridgeShell` host supplies the\n * concrete policy. That keeps the package agnostic to the catalogue and lets\n * the policy evolve without a release.\n */\nexport interface ShellPolicy {\n readOnlyKeys: string[];\n allowedCommands: string[];\n requiresConfirmation: string[];\n deniedCommands: string[];\n}\n\n/**\n * Argument of the `BridgeShell` `onConfirmationRequest` callback.\n *\n * Resolving `approve: true` lets the command flow to the native side.\n * Resolving `approve: false` makes the shell send the iframe a `nack` with\n * `reason: 'user-rejected'` β which client code only ever sees as a console\n * warning, so the ack it was waiting for simply never arrives.\n */\nexport interface ConfirmationRequest {\n command: string;\n args: Record<string, unknown>;\n}\n\n/**\n * Result of `BridgeShell.verifySandbox()` after a round trip with the iframe.\n * If any `*Reachable` flag comes back `true`, the boundary is leaking: the\n * override prefix injected by `bootstrapClientIframe` failed, and the app must\n * not render client code with a path to the native layer.\n */\nexport interface SandboxVerifyResult {\n flutterBridgeReachable: boolean;\n condorBridgeReachable: boolean;\n /** Whether `window.CondorNative` is visible inside the iframe. */\n nativeChannelReachable: boolean;\n /** `true` only when none of the three is reachable. */\n ok: boolean;\n}\n","/**\n * `versionAtLeast(ack.nativeVersion, '0.17.0')` β the capability check every\n * client needs. Compares the three numeric segments; `null` (an unknown native\n * side) is never at least anything, so it always takes the baseline branch.\n *\n * Do not compare version strings directly: `'0.9.0' > '0.16.0'` is `true` as\n * strings and false as versions.\n */\nexport function versionAtLeast(version: string | null | undefined, min: string): boolean {\n if (!version) return false;\n const a = version.split('.').map((n) => Number.parseInt(n, 10) || 0);\n const b = min.split('.').map((n) => Number.parseInt(n, 10) || 0);\n for (let i = 0; i < 3; i++) {\n const x = a[i] ?? 0;\n const y = b[i] ?? 0;\n if (x !== y) return x > y;\n }\n return true;\n}\n"],"mappings":"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","names":["PROTOCOL_VERSION","subscribers","pendingHandshake","v"]}
|