mirror of
https://github.com/stablyai/orca.git
synced 2026-11-02 10:08:13 +00:00
* fix(mobile): wall hosts that cannot serve the page instead of opening native screens * refactor(mobile): drop the native-route state and the shell fallback prop; unknown routes say unavailable * test(mobile): read the nullable page route refusal in its policy test * refactor(mobile): every build is the OTA shell; drop the native/OTA build switch The owner retired the native-screen fallback with no emergency native build, so EXPO_PUBLIC_MOBILE_SHELL, mobileShellBuildKind, shellSwitchDecision, the Metro cache-key suffix and both release workflows' shell input go. Every host route mounts the shell; a route naming no screen the shell could open gets the existing refusal screen instead of a native screen. Claude-Session: https://claude.ai/code/session_6cea92f6 * refactor(mobile): delete native screens the OTA shell no longer reaches With every build the OTA shell, these native siblings run nowhere: the native-executed closure (index.js plus every non-web route) does not reach them, and the page resolves their .web siblings. Each .web sibling takes the plain name, its web-overrides entry goes, and the native-only rich Markdown editor and Mermaid WebView generators and their outputs go with them. Kept: native siblings the node test suite still renders shared screens through (terminal WebView, browser frame path, clipboard, dictation, media picker, live input, snapshot budget, input styles). Claude-Session: https://claude.ai/code/session_6cea92f6 * test(mobile): drop the phone-preview comparison the deleted native sibling held Claude-Session: https://claude.ai/code/session_6cea92f6 * refactor(mobile): drop the dead web route, flag-era comments and the one-value shell kind The host route files no longer switch, so their comments say what they do now: a route naming no screen shows the unavailable screen. app/h/[hostId]/web.tsx duplicated index.tsx and nothing linked to it, so it and its stack entry go (the bundle sweep is re-measured: 77 scripts at 15 routes). Diagnostics print the bridge protocol on its own instead of a shell kind that has one value. Claude-Session: https://claude.ai/code/session_6cea92f6 * refactor(mobile): one host for the rich editor, plain Text, and drop two unused native deps MobileSelectableText was react-native's Text, so callers use Text. The rich Markdown editor's host-facing seams (messages, URL prompt, keyboard inset) are required now that the page is its only host; the WebView defaults go. Comments that described deleted native components are rewritten, and expo-image-manipulator and react-native-uitextview leave package.json and the lockfile. Claude-Session: https://claude.ai/code/session_6cea92f6
67 lines
2.2 KiB
TypeScript
67 lines
2.2 KiB
TypeScript
import { memo, useMemo } from 'react'
|
|
import { StyleSheet, View } from 'react-native'
|
|
import { buildNativeChatVisualDocument } from '../../../src/shared/native-chat-visual-shell'
|
|
import type { MobileNativeChatVisualHostMode } from './mobile-native-chat-visual-host-document'
|
|
import { MOBILE_NATIVE_CHAT_VISUAL_THEME } from './mobile-native-chat-visual-theme'
|
|
|
|
export type MobileNativeChatVisualFrameProps = {
|
|
html: string
|
|
title: string
|
|
mode: MobileNativeChatVisualHostMode
|
|
/** The frame cannot show this visual (it navigated away, or its web process keeps dying). */
|
|
onFailed: () => void
|
|
}
|
|
|
|
/** No script runs, so nothing reports a height; a fixed frame the visual scrolls inside. */
|
|
const SEALED_INLINE_HEIGHT = 320
|
|
|
|
/**
|
|
* Inside the hybrid shell's page: the visual rendered sealed, with no script.
|
|
*
|
|
* The page is served under the shell's response-header policy (`script-src 'self'`,
|
|
* `frame-src 'none'`), and a `srcdoc` frame inherits that policy, so a visual's inline scripts
|
|
* cannot run here without loosening the page's own policy. Static markup, CSS and images still
|
|
* render; script-drawn charts do not. An empty `sandbox` keeps the frame an opaque origin that runs
|
|
* nothing and navigates nothing, as the page's HTML preview does.
|
|
*/
|
|
export const MobileNativeChatVisualFrame = memo(function MobileNativeChatVisualFrame({
|
|
html,
|
|
title,
|
|
mode
|
|
}: MobileNativeChatVisualFrameProps) {
|
|
// No script runs in this frame, so nothing ever reports on this channel.
|
|
const document = useMemo(
|
|
() =>
|
|
buildNativeChatVisualDocument({
|
|
html,
|
|
channel: 'sealed',
|
|
theme: MOBILE_NATIVE_CHAT_VISUAL_THEME
|
|
}),
|
|
[html]
|
|
)
|
|
return (
|
|
<View style={mode === 'inline' ? styles.inline : styles.fullscreen}>
|
|
<iframe
|
|
title={title}
|
|
sandbox=""
|
|
srcDoc={document}
|
|
referrerPolicy="no-referrer"
|
|
style={IFRAME_STYLE}
|
|
/>
|
|
</View>
|
|
)
|
|
})
|
|
|
|
/** A DOM style, not a `StyleSheet` entry: this element is an `iframe` and not a react-native view. */
|
|
const IFRAME_STYLE = {
|
|
border: 'none',
|
|
width: '100%',
|
|
height: '100%',
|
|
backgroundColor: 'transparent'
|
|
} as const
|
|
|
|
const styles = StyleSheet.create({
|
|
inline: { width: '100%', height: SEALED_INLINE_HEIGHT },
|
|
fullscreen: { flex: 1 }
|
|
})
|