@blario/react-native 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +377 -2
- package/dist/BlarProvider.d.ts +74 -0
- package/dist/actions/batched.d.ts +1 -0
- package/dist/actions/click.d.ts +4 -0
- package/dist/actions/commit-watch.d.ts +15 -0
- package/dist/actions/events.d.ts +35 -0
- package/dist/actions/executor.d.ts +29 -0
- package/dist/actions/highlight.d.ts +4 -0
- package/dist/actions/interaction-guards.d.ts +9 -0
- package/dist/actions/landing.d.ts +11 -0
- package/dist/actions/navigation-driver.d.ts +22 -0
- package/dist/actions/parse.d.ts +4 -0
- package/dist/actions/result.d.ts +4 -0
- package/dist/actions/scrolling.d.ts +12 -0
- package/dist/actions/services.d.ts +20 -0
- package/dist/actions/settle.d.ts +13 -0
- package/dist/actions/switch.d.ts +3 -0
- package/dist/actions/target.d.ts +25 -0
- package/dist/actions/text-input.d.ts +9 -0
- package/dist/actions/types.d.ts +59 -0
- package/dist/agent/batch-commands.d.ts +17 -0
- package/dist/agent/compose.d.ts +23 -0
- package/dist/agent/controller.d.ts +28 -0
- package/dist/agent/frame-runner.d.ts +9 -0
- package/dist/agent/frames.d.ts +180 -0
- package/dist/agent/handlers/agent-command.d.ts +5 -0
- package/dist/agent/handlers/batch.d.ts +5 -0
- package/dist/agent/handlers/consent-screenshot.d.ts +4 -0
- package/dist/agent/handlers/context.d.ts +16 -0
- package/dist/agent/handlers/dom-state.d.ts +4 -0
- package/dist/agent/handlers/element-context.d.ts +2 -0
- package/dist/agent/handlers/screenshot.d.ts +3 -0
- package/dist/agent/handlers/text-dom.d.ts +5 -0
- package/dist/agent/stage.d.ts +13 -0
- package/dist/agent-mode/action-description.d.ts +3 -0
- package/dist/agent-mode/bubbles.d.ts +10 -0
- package/dist/agent-mode/colors.d.ts +12 -0
- package/dist/agent-mode/controller.d.ts +92 -0
- package/dist/agent-mode/cursor-follow.d.ts +12 -0
- package/dist/agent-mode/cursor.d.ts +37 -0
- package/dist/agent-mode/frames.d.ts +36 -0
- package/dist/agent-mode/haptics.d.ts +6 -0
- package/dist/agent-mode/keep-awake.d.ts +19 -0
- package/dist/agent-mode/layer-stacking.d.ts +7 -0
- package/dist/agent-mode/markdown.d.ts +19 -0
- package/dist/agent-mode/panel-geometry.d.ts +6 -0
- package/dist/agent-mode/resume.d.ts +13 -0
- package/dist/agent-mode/run-memory.d.ts +19 -0
- package/dist/agent-mode/spotlight-controller.d.ts +68 -0
- package/dist/agent-mode/spotlight.d.ts +6 -0
- package/dist/agent-mode/state.d.ts +9 -0
- package/dist/agent-mode/status.d.ts +11 -0
- package/dist/agent-mode/timers.d.ts +6 -0
- package/dist/agent-mode/ui/AgentDock.d.ts +37 -0
- package/dist/agent-mode/ui/AgentLayer.d.ts +19 -0
- package/dist/agent-mode/ui/AgentLayerHost.d.ts +8 -0
- package/dist/agent-mode/ui/AgentPanel.d.ts +19 -0
- package/dist/agent-mode/ui/AgentTap.d.ts +10 -0
- package/dist/agent-mode/ui/MarkdownText.d.ts +8 -0
- package/dist/agent-mode/ui/MessageBubbles.d.ts +9 -0
- package/dist/agent-mode/ui/PendingOverlay.d.ts +5 -0
- package/dist/agent-mode/ui/SpotlightLayer.d.ts +9 -0
- package/dist/agent-mode/ui/SpotlightOverlay.d.ts +7 -0
- package/dist/agent-mode/ui/StatusCard.d.ts +14 -0
- package/dist/agent-mode/ui/TargetPulse.d.ts +9 -0
- package/dist/agent-mode/ui/TouchShield.d.ts +5 -0
- package/dist/agent-mode/ui/WarningIcon.d.ts +6 -0
- package/dist/agent-mode/ui/full-window-overlay.d.ts +5 -0
- package/dist/agent-mode/ui/layer-host.d.ts +2 -0
- package/dist/backend/api-client.d.ts +38 -0
- package/dist/backend/api-types.d.ts +25 -0
- package/dist/backend/app-info.d.ts +14 -0
- package/dist/backend/backend-transport.d.ts +70 -0
- package/dist/backend/backoff.d.ts +9 -0
- package/dist/backend/base64.d.ts +1 -0
- package/dist/backend/errors.d.ts +17 -0
- package/dist/backend/foreground.d.ts +1 -0
- package/dist/backend/health.d.ts +17 -0
- package/dist/backend/identity-proof.d.ts +23 -0
- package/dist/backend/identity.d.ts +27 -0
- package/dist/backend/message-metadata.d.ts +19 -0
- package/dist/backend/presence.d.ts +20 -0
- package/dist/backend/response-cache.d.ts +9 -0
- package/dist/backend/session-change.d.ts +2 -0
- package/dist/backend/session-socket.d.ts +49 -0
- package/dist/backend/session.d.ts +39 -0
- package/dist/backend/socket-url.d.ts +9 -0
- package/dist/backend/storage.d.ts +13 -0
- package/dist/backend/tab-id.d.ts +2 -0
- package/dist/blar.d.ts +37 -0
- package/dist/chat/ChatLayer.d.ts +29 -0
- package/dist/chat/ChatSheet.d.ts +11 -0
- package/dist/chat/ChatView.d.ts +19 -0
- package/dist/chat/Launcher.d.ts +14 -0
- package/dist/chat/bridge.d.ts +22 -0
- package/dist/chat/chat-coordinator.d.ts +57 -0
- package/dist/chat/chat-state.d.ts +20 -0
- package/dist/chat/navigation.d.ts +5 -0
- package/dist/chat/options.d.ts +22 -0
- package/dist/chat/webview.d.ts +10 -0
- package/dist/chat/widget-bundle.generated.d.ts +2 -0
- package/dist/chat/widget-shell.d.ts +24 -0
- package/dist/confirmation/port.d.ts +12 -0
- package/dist/fiber/locate.d.ts +7 -0
- package/dist/fiber/narrow.d.ts +5 -0
- package/dist/fiber/reader.d.ts +10 -0
- package/dist/fiber/text.d.ts +4 -0
- package/dist/fiber/types.d.ts +21 -0
- package/dist/host/border-radius.d.ts +1 -0
- package/dist/host/instance.d.ts +9 -0
- package/dist/host/measure.d.ts +3 -0
- package/dist/host/rect.d.ts +22 -0
- package/dist/host/visible-area.d.ts +2 -0
- package/dist/index.d.ts +10 -0
- package/dist/nudge/NudgeBubble.d.ts +15 -0
- package/dist/nudge/nudge.d.ts +23 -0
- package/dist/optional/expo-haptics.d.ts +1 -0
- package/dist/optional/expo-keep-awake.d.ts +1 -0
- package/dist/optional/react-native-haptic-feedback.d.ts +1 -0
- package/dist/optional/react-native-keep-awake.d.ts +1 -0
- package/dist/overlay/AgentOverlay.d.ts +5 -0
- package/dist/screenshot/capture-backend.d.ts +6 -0
- package/dist/screenshot/screenshotter.d.ts +18 -0
- package/dist/screenshot/skia.d.ts +35 -0
- package/dist/screenshot/view-shot.d.ts +2 -0
- package/dist/snapshot/capture.d.ts +36 -0
- package/dist/snapshot/classify.d.ts +11 -0
- package/dist/snapshot/collect.d.ts +27 -0
- package/dist/snapshot/element-context.d.ts +9 -0
- package/dist/snapshot/icon.d.ts +2 -0
- package/dist/snapshot/kinds.d.ts +3 -0
- package/dist/snapshot/modals.d.ts +2 -0
- package/dist/snapshot/navigation.d.ts +14 -0
- package/dist/snapshot/ordering.d.ts +2 -0
- package/dist/snapshot/properties.d.ts +14 -0
- package/dist/snapshot/registry.d.ts +16 -0
- package/dist/snapshot/render.d.ts +10 -0
- package/dist/snapshot/route-summary.d.ts +3 -0
- package/dist/snapshot/scroll.d.ts +15 -0
- package/dist/snapshot/text-layout.d.ts +8 -0
- package/dist/snapshot/view.d.ts +30 -0
- package/dist/snapshot/visibility.d.ts +17 -0
- package/dist/snapshot/wrappers.d.ts +11 -0
- package/dist/telemetry/SdkErrorBoundary.d.ts +15 -0
- package/dist/telemetry/build-info.generated.d.ts +2 -0
- package/dist/telemetry/envelope.d.ts +53 -0
- package/dist/telemetry/reporter.d.ts +33 -0
- package/dist/telemetry/scrub.d.ts +1 -0
- package/dist/telemetry/sdk-reporter.d.ts +5 -0
- package/dist/transport/connection-options.d.ts +18 -0
- package/dist/transport/relay-transport.d.ts +17 -0
- package/dist/transport/transport.d.ts +7 -0
- package/dist/ui/insets.d.ts +8 -0
- package/dist/ui/strings.d.ts +33 -0
- package/dist/ui/useInsets.d.ts +2 -0
- package/dist/version.d.ts +1 -0
- package/package.json +85 -4
- package/src/BlarProvider.tsx +462 -0
- package/src/actions/batched.ts +16 -0
- package/src/actions/click.ts +54 -0
- package/src/actions/commit-watch.ts +86 -0
- package/src/actions/events.ts +58 -0
- package/src/actions/executor.ts +147 -0
- package/src/actions/highlight.ts +13 -0
- package/src/actions/interaction-guards.ts +44 -0
- package/src/actions/landing.ts +26 -0
- package/src/actions/navigation-driver.ts +131 -0
- package/src/actions/parse.ts +82 -0
- package/src/actions/result.ts +14 -0
- package/src/actions/scrolling.ts +112 -0
- package/src/actions/services.ts +24 -0
- package/src/actions/settle.ts +40 -0
- package/src/actions/switch.ts +31 -0
- package/src/actions/target.ts +77 -0
- package/src/actions/text-input.ts +82 -0
- package/src/actions/types.ts +52 -0
- package/src/agent/batch-commands.ts +33 -0
- package/src/agent/compose.ts +67 -0
- package/src/agent/controller.ts +106 -0
- package/src/agent/frame-runner.ts +27 -0
- package/src/agent/frames.ts +193 -0
- package/src/agent/handlers/agent-command.ts +74 -0
- package/src/agent/handlers/batch.ts +72 -0
- package/src/agent/handlers/consent-screenshot.ts +44 -0
- package/src/agent/handlers/context.ts +17 -0
- package/src/agent/handlers/dom-state.ts +19 -0
- package/src/agent/handlers/element-context.ts +9 -0
- package/src/agent/handlers/screenshot.ts +24 -0
- package/src/agent/handlers/text-dom.ts +17 -0
- package/src/agent/stage.ts +22 -0
- package/src/agent-mode/action-description.ts +25 -0
- package/src/agent-mode/bubbles.ts +31 -0
- package/src/agent-mode/colors.ts +40 -0
- package/src/agent-mode/controller.ts +459 -0
- package/src/agent-mode/cursor-follow.ts +43 -0
- package/src/agent-mode/cursor.ts +118 -0
- package/src/agent-mode/frames.ts +70 -0
- package/src/agent-mode/haptics.ts +49 -0
- package/src/agent-mode/keep-awake.ts +107 -0
- package/src/agent-mode/layer-stacking.ts +16 -0
- package/src/agent-mode/markdown.ts +84 -0
- package/src/agent-mode/panel-geometry.ts +27 -0
- package/src/agent-mode/resume.ts +16 -0
- package/src/agent-mode/run-memory.ts +65 -0
- package/src/agent-mode/spotlight-controller.ts +255 -0
- package/src/agent-mode/spotlight.ts +14 -0
- package/src/agent-mode/state.ts +36 -0
- package/src/agent-mode/status.ts +13 -0
- package/src/agent-mode/timers.ts +11 -0
- package/src/agent-mode/ui/AgentDock.tsx +285 -0
- package/src/agent-mode/ui/AgentLayer.tsx +123 -0
- package/src/agent-mode/ui/AgentLayerHost.tsx +37 -0
- package/src/agent-mode/ui/AgentPanel.tsx +187 -0
- package/src/agent-mode/ui/AgentTap.tsx +190 -0
- package/src/agent-mode/ui/MarkdownText.tsx +55 -0
- package/src/agent-mode/ui/MessageBubbles.tsx +58 -0
- package/src/agent-mode/ui/PendingOverlay.tsx +32 -0
- package/src/agent-mode/ui/SpotlightLayer.tsx +60 -0
- package/src/agent-mode/ui/SpotlightOverlay.tsx +35 -0
- package/src/agent-mode/ui/StatusCard.tsx +137 -0
- package/src/agent-mode/ui/TargetPulse.tsx +74 -0
- package/src/agent-mode/ui/TouchShield.tsx +22 -0
- package/src/agent-mode/ui/WarningIcon.tsx +32 -0
- package/src/agent-mode/ui/full-window-overlay.ts +16 -0
- package/src/agent-mode/ui/layer-host.ts +11 -0
- package/src/backend/api-client.ts +210 -0
- package/src/backend/api-types.ts +56 -0
- package/src/backend/app-info.ts +40 -0
- package/src/backend/backend-transport.ts +338 -0
- package/src/backend/backoff.ts +16 -0
- package/src/backend/base64.ts +25 -0
- package/src/backend/errors.ts +32 -0
- package/src/backend/foreground.ts +10 -0
- package/src/backend/health.ts +64 -0
- package/src/backend/identity-proof.ts +151 -0
- package/src/backend/identity.ts +31 -0
- package/src/backend/message-metadata.ts +28 -0
- package/src/backend/presence.ts +95 -0
- package/src/backend/response-cache.ts +45 -0
- package/src/backend/session-change.ts +14 -0
- package/src/backend/session-socket.ts +292 -0
- package/src/backend/session.ts +188 -0
- package/src/backend/socket-url.ts +25 -0
- package/src/backend/storage.ts +49 -0
- package/src/backend/tab-id.ts +24 -0
- package/src/blar.ts +100 -0
- package/src/chat/ChatLayer.tsx +109 -0
- package/src/chat/ChatSheet.tsx +82 -0
- package/src/chat/ChatView.tsx +127 -0
- package/src/chat/Launcher.tsx +72 -0
- package/src/chat/bridge.ts +56 -0
- package/src/chat/chat-coordinator.ts +189 -0
- package/src/chat/chat-state.ts +35 -0
- package/src/chat/navigation.ts +15 -0
- package/src/chat/options.ts +39 -0
- package/src/chat/webview.ts +23 -0
- package/src/chat/widget-bundle.generated.ts +2 -0
- package/src/chat/widget-shell.ts +170 -0
- package/src/confirmation/port.ts +15 -0
- package/src/fiber/locate.ts +41 -0
- package/src/fiber/narrow.ts +15 -0
- package/src/fiber/reader.ts +98 -0
- package/src/fiber/text.ts +52 -0
- package/src/fiber/types.ts +24 -0
- package/src/host/border-radius.ts +11 -0
- package/src/host/instance.ts +30 -0
- package/src/host/measure.ts +25 -0
- package/src/host/rect.ts +45 -0
- package/src/host/visible-area.ts +5 -0
- package/src/index.ts +10 -0
- package/src/nudge/NudgeBubble.tsx +117 -0
- package/src/nudge/nudge.ts +100 -0
- package/src/optional/expo-haptics.ts +11 -0
- package/src/optional/expo-keep-awake.ts +11 -0
- package/src/optional/react-native-haptic-feedback.ts +11 -0
- package/src/optional/react-native-keep-awake.ts +11 -0
- package/src/overlay/AgentOverlay.tsx +16 -0
- package/src/screenshot/capture-backend.ts +7 -0
- package/src/screenshot/screenshotter.ts +39 -0
- package/src/screenshot/skia.ts +107 -0
- package/src/screenshot/view-shot.ts +41 -0
- package/src/snapshot/capture.ts +163 -0
- package/src/snapshot/classify.ts +40 -0
- package/src/snapshot/collect.ts +136 -0
- package/src/snapshot/element-context.ts +66 -0
- package/src/snapshot/icon.ts +21 -0
- package/src/snapshot/kinds.ts +10 -0
- package/src/snapshot/modals.ts +21 -0
- package/src/snapshot/navigation.ts +47 -0
- package/src/snapshot/ordering.ts +26 -0
- package/src/snapshot/properties.ts +71 -0
- package/src/snapshot/registry.ts +33 -0
- package/src/snapshot/render.ts +140 -0
- package/src/snapshot/route-summary.ts +15 -0
- package/src/snapshot/scroll.ts +90 -0
- package/src/snapshot/text-layout.ts +59 -0
- package/src/snapshot/view.ts +87 -0
- package/src/snapshot/visibility.ts +63 -0
- package/src/snapshot/wrappers.ts +69 -0
- package/src/telemetry/SdkErrorBoundary.tsx +28 -0
- package/src/telemetry/build-info.generated.ts +2 -0
- package/src/telemetry/envelope.ts +83 -0
- package/src/telemetry/reporter.ts +170 -0
- package/src/telemetry/scrub.ts +10 -0
- package/src/telemetry/sdk-reporter.ts +37 -0
- package/src/transport/connection-options.ts +65 -0
- package/src/transport/relay-transport.ts +82 -0
- package/src/transport/transport.ts +8 -0
- package/src/ui/insets.ts +31 -0
- package/src/ui/strings.ts +102 -0
- package/src/ui/useInsets.ts +10 -0
- package/src/version.ts +1 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Blar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,378 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @blario/react-native
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Blar agent SDK for React Native. It mirrors the web widget's agent: it parses the React component tree into the
|
|
4
|
+
web `dom_state` v3 snapshot, hands out its own per-capture ids (`btn-N`, `inp-N`, `scr-N`) and resolves an id back
|
|
5
|
+
to its component to act on it.
|
|
6
|
+
|
|
7
|
+
Pure JS/TS, no native code. Works on the old architecture and on the New Architecture.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @blario/react-native react-native-webview
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
With Expo, let it pick the versions that match your SDK:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx expo install @blario/react-native react-native-webview @react-native-async-storage/async-storage react-native-safe-area-context
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Needs `react` >= 18.2 and `react-native` >= 0.74. `react-native-webview` runs the chat (the web widget) and is the
|
|
22
|
+
only peer you need to get started; the rest are optional and the SDK works without them:
|
|
23
|
+
|
|
24
|
+
| Peer | Without it |
|
|
25
|
+
| --- | --- |
|
|
26
|
+
| `@react-native-async-storage/async-storage` | the contact is kept in memory, so every launch is a new anonymous contact |
|
|
27
|
+
| `react-native-safe-area-context` | fixed fallback insets are used instead of the device's |
|
|
28
|
+
| `react-native-view-shot` (or `@shopify/react-native-skia` on iOS) | a screenshot request answers `sdk_error` |
|
|
29
|
+
| `react-native-screens` | on iOS the agent layer is drawn in the root tree instead of its own window |
|
|
30
|
+
| `expo-haptics` or `react-native-haptic-feedback` | no buzz when a confirmation appears |
|
|
31
|
+
| `expo-keep-awake` or `react-native-keep-awake` | the screen may sleep during an agent run |
|
|
32
|
+
|
|
33
|
+
Native peers need a rebuild of the app (`npx expo prebuild` / `pod install`) unless Expo Go already ships them. The
|
|
34
|
+
package ships its TypeScript source, which Metro compiles with the rest of your app, plus type declarations in `dist/`.
|
|
35
|
+
Then wrap the app as shown in [Connect to the Blar backend](#connect-to-the-blar-backend).
|
|
36
|
+
|
|
37
|
+
### Versions
|
|
38
|
+
|
|
39
|
+
Versions follow semver and each one is published to npm when it reaches `main`. While the major is `0` a minor release
|
|
40
|
+
may change the API, and the `^0.2.0` range npm writes by default stays within one minor. The `latest` dist-tag is the
|
|
41
|
+
newest stable release and `next` the newest prerelease (`0.3.0-beta.0`), installed with
|
|
42
|
+
`npm install @blario/react-native@next`. `SDK_VERSION` is the installed version, and it is what the SDK reports to the
|
|
43
|
+
backend.
|
|
44
|
+
|
|
45
|
+
## Integrate
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { BlarProvider } from '@blario/react-native';
|
|
49
|
+
import { createNavigationContainerRef, NavigationContainer } from '@react-navigation/native';
|
|
50
|
+
|
|
51
|
+
const navigationRef = createNavigationContainerRef();
|
|
52
|
+
|
|
53
|
+
export default function App() {
|
|
54
|
+
return (
|
|
55
|
+
<BlarProvider navigationRef={navigationRef} relayUrl="ws://localhost:8790">
|
|
56
|
+
<NavigationContainer ref={navigationRef}>{/* app */}</NavigationContainer>
|
|
57
|
+
</BlarProvider>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`navigationRef` is optional. Without it `navigate` only reaches routes of the navigators on the focused path.
|
|
63
|
+
Screenshots use `react-native-view-shot` when it is installed, otherwise `@shopify/react-native-skia`
|
|
64
|
+
(`makeImageFromView`) on iOS. Android requires view-shot: Skia's Android capture can raise a fatal native error
|
|
65
|
+
when a view unmounts during capture. With no supported capture module, a screenshot answers `sdk_error`.
|
|
66
|
+
Each module is resolved once when the SDK loads:
|
|
67
|
+
|
|
68
|
+
- view-shot leaves a host `Modal` out (it is a separate window), so the response carries `partial: true` and
|
|
69
|
+
`omitted: ['modal']` while one is open.
|
|
70
|
+
- Skia on iOS walks the view tree. A host `Modal` is presented by its own view controller, outside the captured
|
|
71
|
+
view, so it is reported as omitted, as with view-shot. A capture narrower than `maxWidth` is sent at its own width,
|
|
72
|
+
never upscaled.
|
|
73
|
+
|
|
74
|
+
Neither includes the status bar, the chat or the agent layer.
|
|
75
|
+
|
|
76
|
+
The implicit `ws://localhost:8790` relay is available only in development when no backend settings are provided.
|
|
77
|
+
Production requires both `publishableKey` and `apiBaseUrl`, or an explicit `relayUrl`. Invalid or partial backend
|
|
78
|
+
settings disable the SDK while the host app keeps rendering. API URLs must use HTTP(S); relay URLs must use WS(S).
|
|
79
|
+
Surrounding whitespace and scheme/host casing are normalized, and API base URLs must have no query or fragment.
|
|
80
|
+
|
|
81
|
+
Installed from npm, Metro needs no configuration. Only a linked checkout (the example app's `file:..` dependency) needs
|
|
82
|
+
the SDK folder watched and a single copy of `react`/`react-native` (see its `metro.config.js`).
|
|
83
|
+
|
|
84
|
+
## Connect to the Blar backend
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
<BlarProvider
|
|
88
|
+
publishableKey="<publishable-key>"
|
|
89
|
+
apiBaseUrl="https://api.blar.io"
|
|
90
|
+
user={{ externalId: 'u-1', email: 'ana@x.cl', name: 'Ana', country: 'CL', getIdentityToken: () => fetchToken() }}
|
|
91
|
+
language="es"
|
|
92
|
+
debug
|
|
93
|
+
>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`language` is `'es'` or `'en'` and defaults to `'es'`; unsupported runtime values also fall back to `'es'` for the
|
|
97
|
+
SDK's own texts and the chat's language. With `publishableKey` and `apiBaseUrl` the provider uses the backend
|
|
98
|
+
transport. It mirrors the web widget: `contacts/load/` then `contacts/identify/` with `X-Publishable-Key`,
|
|
99
|
+
`X-Source-Id` and the identity proof (`X-Identity-Token` / `X-Identity-Signature`, refreshed once through
|
|
100
|
+
`getProof` / `getIdentityToken`), the session socket `/sessions/chat/<id>/?publishable_key&source_id&tab_id` with the
|
|
101
|
+
proof as a subprotocol, ping/pong with `{visibility, hidden_ms, lag_ms, sdk_version}`, reconnect with backoff,
|
|
102
|
+
response replay after a reconnect, and a presence heartbeat every 30 s while the app is active and touched in the last
|
|
103
|
+
3 minutes. `source_id` persists in AsyncStorage when installed, otherwise in memory. `enabled={false}` keeps the SDK
|
|
104
|
+
off; changing it on a mounted provider starts or stops the socket, the agent and the chat.
|
|
105
|
+
|
|
106
|
+
Identity tokens must have three nonempty base64url JWT segments; identity signatures must be hexadecimal.
|
|
107
|
+
Malformed static values or provider results are treated as proof failures and never sent in native headers.
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { Blar } from '@blario/react-native';
|
|
111
|
+
|
|
112
|
+
await Blar.setUser({ externalId: 'u-1', email: 'ana@x.cl' });
|
|
113
|
+
await Blar.logout();
|
|
114
|
+
Blar.isConnected();
|
|
115
|
+
await Blar.getMessageMetadata({ includeTextDom: true });
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Risky actions (`irreversible`, `destructive`, or `confirmation_required`) ask for confirmation in a native panel on the
|
|
119
|
+
status card; a decline or a 60 s timeout answers `user_cancelled`.
|
|
120
|
+
|
|
121
|
+
### Drive the app with the real on-site agent
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
npm run harness -- --key <publishable-key> --external-id <id> --email <email> --base http://localhost:55180 "crea un cliente llamado Ana Díaz"
|
|
125
|
+
harness/tap-confirm.sh Confirmar 240 # approves the confirmation on the emulator (adb + uiautomator)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The harness identifies the same contact as the app (`--external-id` and `--email`, or `BLAR_EXTERNAL_ID` and `BLAR_EMAIL`;
|
|
129
|
+
`--name` and `--country` are optional), posts the message through
|
|
130
|
+
`/api/ai/contact-sessions/<id>/widget/messages/create/` without a `tab_id`, so the app's socket answers as the holder,
|
|
131
|
+
and prints the conversation as it grows.
|
|
132
|
+
|
|
133
|
+
## Chat and nudges
|
|
134
|
+
|
|
135
|
+
With the backend transport the provider also renders the chat. It needs `react-native-webview` (a peer dependency)
|
|
136
|
+
and optionally `react-native-safe-area-context` for insets.
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
<BlarProvider
|
|
140
|
+
publishableKey="<publishable-key>"
|
|
141
|
+
apiBaseUrl="https://api.blar.io"
|
|
142
|
+
user={user}
|
|
143
|
+
language="es"
|
|
144
|
+
strings={{ agentThinking: 'Pensando…' }}
|
|
145
|
+
chat={{ launcher: { visible: true, side: 'left', offsetY: 88 }, primaryColor: '#7C3AED' }}
|
|
146
|
+
>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
Blar.open();
|
|
151
|
+
Blar.close();
|
|
152
|
+
Blar.getUnreadCount();
|
|
153
|
+
Blar.isChatOpen();
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
- The web support widget runs inside a `react-native-webview` in `messagesOnly` mode, served from a generated HTML
|
|
157
|
+
shell on the API origin. The bundle is generated, not committed (`src/chat/widget-bundle.generated.ts` is git-ignored): build
|
|
158
|
+
`support-widget.min.js` in `web-sdk/`, then run `npm run embed-widget` before `npm run typecheck` or the example
|
|
159
|
+
app (the unit tests do not need it). Or pass `chat.scriptUrl` to load it from a CDN instead.
|
|
160
|
+
- One contact, one session, one executor: the page seeds the widget with the native `tab_id`, identifies with the same
|
|
161
|
+
identity and source, and boots it with `agentExecution: false`, so it ignores every agent command and only the native
|
|
162
|
+
runtime executes. Messages the user sends carry `Blar.getMessageMetadata()` (platform, screen path, text tree). The
|
|
163
|
+
widget's `onSessionChange` reports a new conversation and the native socket follows it. When the page leaves its
|
|
164
|
+
session (an escalation, a new or an ended conversation), native ends any run there and drops the socket until the
|
|
165
|
+
page reports the next one. Its `onClose` closes the sheet, and the chat reopens when the sheet does.
|
|
166
|
+
- The chat page never navigates away: a link it opens (a message link, an attachment, "Powered by Blar") goes to the
|
|
167
|
+
system browser through `Linking`, and frames inside the page load as usual.
|
|
168
|
+
- Replying works as in WhatsApp: drag a message to the right and let go, or hold it, and the composer quotes it. This is
|
|
169
|
+
the widget's own touch gesture, so it needs no native code.
|
|
170
|
+
- Assistant messages that arrive while the sheet is not open raise the unread badge.
|
|
171
|
+
- Nudges arrive as native bubbles with the same sender, message, progress and actions as the web widget. Accepting
|
|
172
|
+
calls `POST /api/activation/nudges/open/` and opens the chat on the nudge session (`openSession`, without reloading
|
|
173
|
+
the page); dismissing and snoozing call the `dismiss` and `snooze` endpoints. A heartbeat that reports a pending
|
|
174
|
+
nudge refreshes the session so the bubble shows without waiting for a restart.
|
|
175
|
+
- `strings` overrides any of the confirmation, chat, nudge and agent mode texts; `es` and `en` defaults ship in the
|
|
176
|
+
package.
|
|
177
|
+
|
|
178
|
+
## Agent mode
|
|
179
|
+
|
|
180
|
+
A run looks and behaves like the web widget's agent mode (`web-sdk/src/managers/agent-mode-state.ts`,
|
|
181
|
+
`web-sdk/src/agent/agent-mode-ui.ts`), driven by `AgentModeController`:
|
|
182
|
+
|
|
183
|
+
- The first `agent_command` or `agent_command_batch` of a run starts a 2 s pending phase ("La IA va a tomar el
|
|
184
|
+
control"); its commands are acknowledged at once and run when it ends. Reads (`dom_state`, text tree, screenshots)
|
|
185
|
+
never start a run. A `history` frame with `agent_mode_active` restores a run without the pending phase.
|
|
186
|
+
- A run survives the app being killed, like the web's per-tab resume flag. The session id and the time of the last
|
|
187
|
+
agent frame are kept in AsyncStorage while the run is active; connecting to that session again within 120 s (the
|
|
188
|
+
backend's longest wait on an SDK answer) brings the layer back without the pending phase. It then waits 30 s for an
|
|
189
|
+
agent frame, absorbing one completion meant for the killed app. Every exit, a session change and a logout clear it.
|
|
190
|
+
- While active the chat sheet collapses, the launcher hides, a status card shows the state ("Pensando", "Ejecutando
|
|
191
|
+
acción...", or the backend's progress label) with a Stop button, and each step's sentence shows as a message bubble
|
|
192
|
+
(markdown, deduplicated, read for 6 to 18 s). A queued message shows a chip on the card for 5 s.
|
|
193
|
+
- There is no cursor. Each `click`, `check` and `type` shows a fingertip ring on its target (40 dp, white with a dark
|
|
194
|
+
hairline, filled with the primary colour): it appears on the target, stays pinned to it while it moves, presses and
|
|
195
|
+
sends out one ripple once it settles, and is gone 450 ms later. Scrolls, keys, navigation and highlights draw
|
|
196
|
+
nothing. A click or a switch waits for the landing, at most 1.8 s, before the gesture. The status card fades while a
|
|
197
|
+
tap lands on something underneath it. Reduced motion keeps only fades.
|
|
198
|
+
- Readings and confirmations live in a white panel attached to the top of the status card, the two reading as one
|
|
199
|
+
surface. Before it shows, the panel is laid out unseen and its target is scrolled so that it sits in the middle of
|
|
200
|
+
the free area above the stack (the nearest scroll container, by an offset); when the target still sits under the
|
|
201
|
+
stack (a tab bar, a sticky button), the whole stack docks at the top of the screen. The dock is decided once per
|
|
202
|
+
panel. The message is capped at 40 % of the free area and scrolls inside the panel beyond that.
|
|
203
|
+
- A `highlight` dims the screen 60 % around a rounded hole over the target (padding 8, tracked while it moves) and
|
|
204
|
+
shows a reading panel: the step's sentence (markdown), a bar filling over the reading time (6 to 18 s at 120 wpm,
|
|
205
|
+
counted from when the panel is on screen) and "Omitir". The status card keeps its text and its Stop. The action is
|
|
206
|
+
answered when the reading ends, so the agent waits for the user; Omitir or the app going to the background ends it
|
|
207
|
+
early, Stop or Back answers `user_cancelled`. The `duration_ms` the backend sends is ignored, as on the web. Step
|
|
208
|
+
bubbles are hidden while the panel is up.
|
|
209
|
+
- An action that needs confirmation (`confirmation_required`, or an irreversible or destructive risk; never a
|
|
210
|
+
`highlight` or `scroll_to`) dims around its target, outlined and pulsing with a white edge, and asks in the panel:
|
|
211
|
+
the step's sentence, or the action's own description, then **Detener** and **Confirmar** (48 dp, the confirm text in
|
|
212
|
+
the colour that reads on the primary). The status card says "Confirmación pendiente" and hides its own Stop. A
|
|
213
|
+
destructive action adds "Esta acción no se puede deshacer" and turns the button into a red **Sí, continuar**.
|
|
214
|
+
Detener or Back stops the whole run, as on the web; a tap on the dim backdrop only nudges the panel. 60 s without an
|
|
215
|
+
answer declines it. Both answer `user_cancelled`, with a message that tells a decline from silence. The confirmation
|
|
216
|
+
buzzes once when it appears if `react-native-haptic-feedback` or `expo-haptics` is installed (both optional peers).
|
|
217
|
+
Once approved, what the user saw is captured (JPEG 0.6, before the action runs) and sent on
|
|
218
|
+
`{command_id}:screenshot` as the consent evidence the backend keeps; a failed capture is reported there as
|
|
219
|
+
`CAPTURE_FAILED`, and nothing is sent without a capture module or after a Stop.
|
|
220
|
+
- Touches on the app are swallowed by a shield that shows "Toca Detener para tomar el control" and pulses Stop. The
|
|
221
|
+
agent never goes through touches, so its actions are unaffected.
|
|
222
|
+
- Stop, or the Android back button, sends `agent_cancel` and ends the run; an action not yet dispatched and the rest
|
|
223
|
+
of a batch stand down. The run also ends on `agent_execution_complete`, `agent_acknowledged`, `agent_cancelled`,
|
|
224
|
+
`session_closed`, a message that waits for the user, a conversation replaced by an objective or any other session
|
|
225
|
+
change, a socket that gave up, or 120 s without agent activity. The chat opens again when it ends.
|
|
226
|
+
- The layer lives in its own window: a transparent `Modal` on Android (re-raised when the agent opens a host `Modal`
|
|
227
|
+
on top of it), `FullWindowOverlay` from `react-native-screens` on iOS when installed, the root tree otherwise. It is
|
|
228
|
+
excluded from snapshots and screenshots.
|
|
229
|
+
- The screen stays on from the AI turn through the run when `expo-keep-awake` or `react-native-keep-awake` is
|
|
230
|
+
installed (both optional peers); without one this is a no-op, reported once with `debug`.
|
|
231
|
+
|
|
232
|
+
Known differences from the web: the pending dim covers the whole screen (the web dims only the chat window); the
|
|
233
|
+
layer takes window focus, so an open keyboard closes when a run starts; `session_closed` ends the run (the web only
|
|
234
|
+
tears it down). Visual effects (dot grid, glow, slime) come in a later milestone.
|
|
235
|
+
|
|
236
|
+
### Test nudges without a real delivery
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
npm run proxy -- --log proxy.log # :55181 -> the local backend (HTTP and the session socket)
|
|
240
|
+
# EXPO_PUBLIC_BLAR_API_BASE_URL=http://localhost:55181, adb reverse tcp:55181 tcp:55181, restart Metro with --clear
|
|
241
|
+
npm run inject -- history --milestone 9001 # a nudge as the history frame the backend sends on connect
|
|
242
|
+
npm run inject -- live --milestone 9002 # the same nudge as a live message frame
|
|
243
|
+
npm run inject -- continuation --cta "Continuar" --milestone 9003
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
The proxy forwards everything to the backend untouched, tags the app's own session socket (user agent without
|
|
247
|
+
"Mozilla") as native, and `inject` pushes the frame only to that socket. Every request to
|
|
248
|
+
`/api/activation/nudges/*` is logged with its headers, body and the backend's answer. `GET /__proxy/state` lists the
|
|
249
|
+
open sockets and the last requests.
|
|
250
|
+
|
|
251
|
+
## Run the example app
|
|
252
|
+
|
|
253
|
+
`example/` is an Expo SDK 51 app (AgendaPro-like screens, React Navigation) that depends on the SDK through `file:..`
|
|
254
|
+
and runs in Expo Go on an Android emulator. Build and embed the widget first (see Develop).
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
cd example
|
|
258
|
+
cp .env.example .env.local # local backend URL, publishable key and test contact; never committed
|
|
259
|
+
npm ci
|
|
260
|
+
adb reverse tcp:8081 tcp:8081 && adb reverse tcp:55180 tcp:55180
|
|
261
|
+
npx expo start --clear # open it in Expo Go
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
`EXPO_PUBLIC_*` values are inlined when Metro bundles, so restart it with `--clear` after editing `.env.local`. Without a
|
|
265
|
+
publishable key the provider talks to the dev relay instead.
|
|
266
|
+
|
|
267
|
+
## Run the dev relay
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
npm run relay # app socket ws://localhost:8790, HTTP http://localhost:8791
|
|
271
|
+
adb reverse tcp:8790 tcp:8790 # Android emulator/device reaches the relay on localhost
|
|
272
|
+
relay/ctl.sh snap # POST /dom_state?text=1
|
|
273
|
+
relay/ctl.sh act "Guardar" click # find the id by text in a fresh snapshot, then POST /command
|
|
274
|
+
relay/ctl.sh shot # POST /screenshot, saved under relay/shots/
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
| Request | Body | Reply |
|
|
278
|
+
| --- | --- | --- |
|
|
279
|
+
| `POST /dom_state[?text=1]` | none | `{schema_version, platform, screen, routes, html_snapshot}` or the snapshot text |
|
|
280
|
+
| `POST /command` | `{action: {type, ...}, target?: {agent_id}}` | `{success, no_op, error?, message?}` |
|
|
281
|
+
| `POST /screenshot` | `{options?: {quality, maxWidth}}` | `{path, bytes, screen}` |
|
|
282
|
+
| `GET /health` | none | `{app_connected}` |
|
|
283
|
+
|
|
284
|
+
Wire envelope (mirrors the backend): `agent_command` / `request_dom_state` / `request_screenshot` in,
|
|
285
|
+
`command_ack` then `sdk_response` (`agent_command_response`, `dom_state_response`, `screenshot_response`) or
|
|
286
|
+
`sdk_error` out.
|
|
287
|
+
|
|
288
|
+
## Actions
|
|
289
|
+
|
|
290
|
+
| `action.type` | Fields | Target |
|
|
291
|
+
| --- | --- | --- |
|
|
292
|
+
| `click` | | `btn-N` (a switch toggles, an input is focused) |
|
|
293
|
+
| `type` | `value`, `clear_first` (default true) | `inp-N` text input |
|
|
294
|
+
| `check` | `checked` (omit to toggle) | `inp-N` switch |
|
|
295
|
+
| `press_key` | `key` (`Enter` only) | `inp-N`, or the last input used |
|
|
296
|
+
| `scroll` | `direction` up/down/left/right, `amount` px | `scr-N` |
|
|
297
|
+
| `scroll_to` | | any element, uses its nearest scroll container |
|
|
298
|
+
| `navigate` | `route` (`Name` or `Parent/Child`), `params` | none |
|
|
299
|
+
| `highlight` | `duration_ms` (default 3000) | any element |
|
|
300
|
+
|
|
301
|
+
`click`, `type`, `check` and `highlight` scroll the target into view first. Elements that sit beyond their scroll
|
|
302
|
+
viewport are listed with `offscreen=above|below|left|right` (at most 30, nearest first).
|
|
303
|
+
|
|
304
|
+
## Develop
|
|
305
|
+
|
|
306
|
+
The chat embeds this repo's widget build, which is generated and git-ignored, so build it before the typecheck or the
|
|
307
|
+
example app (the unit tests do not need it).
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
(cd ../web-sdk && pnpm install && pnpm build) # the widget
|
|
311
|
+
npm ci
|
|
312
|
+
npm run embed-widget # src/chat/widget-bundle.generated.ts from ../web-sdk/dist/support-widget.min.js
|
|
313
|
+
npm run telemetry-config # src/telemetry/build-info.generated.ts from SENTRY_DSN / SENTRY_ENVIRONMENT (empty by default: no reporting)
|
|
314
|
+
npm run typecheck
|
|
315
|
+
npm test
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
CI (`.github/workflows/react-native-sdk-ci.yaml`) runs the same steps on every change under `react-native-sdk/`, plus
|
|
319
|
+
`npm run build`, which emits the type declarations into `dist/` (git-ignored; `prepack` runs it). The widget deploy
|
|
320
|
+
workflows ignore those changes.
|
|
321
|
+
|
|
322
|
+
## Release
|
|
323
|
+
|
|
324
|
+
A release is a version bump that reaches `main`, like a widget deploy. npm never takes the same version twice, so a push
|
|
325
|
+
to `main` publishes only when `package.json` carries a version npm does not have yet; without a bump nothing is
|
|
326
|
+
published.
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
cd react-native-sdk
|
|
330
|
+
npm version minor --no-git-tag-version # patch | minor | major; rewrites package.json, the lockfile and src/version.ts
|
|
331
|
+
git commit -am "Release @blario/react-native 0.2.0"
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
Merge that to `dev`, then `dev` to `main` as usual. For a prerelease use
|
|
335
|
+
`npm version preminor --preid beta --no-git-tag-version` (`0.3.0-beta.0`); a version with a `-` is published under the
|
|
336
|
+
`next` dist-tag, so `latest` never moves to it.
|
|
337
|
+
|
|
338
|
+
`.github/workflows/react-native-sdk-release.yaml` runs on pushes to `main` that change `react-native-sdk/package.json`
|
|
339
|
+
and stops there when npm already has that version. Otherwise it builds the widget with
|
|
340
|
+
`API_BASE_URL=https://api.blar.io` and the repo's Sentry secrets, uploads its source maps and injects the debug IDs (the
|
|
341
|
+
same steps as `deplot.yaml`), embeds it, runs the typecheck and the tests, writes the Sentry DSN into the package
|
|
342
|
+
(`npm run telemetry-config`), packs the tarball, checks that it holds the embedded widget, `dist/index.d.ts` and the
|
|
343
|
+
DSN, and publishes that exact tarball. It uses the `SENTRY_DSN`, `SENTRY_AUTH_TOKEN`, `SENTRY_ORG` and `SENTRY_PROJECT`
|
|
344
|
+
repository secrets, and a release fails if any is missing. A failed release is retried with "Re-run jobs" on its run. A
|
|
345
|
+
published version can never be replaced, so fix a bad release with the next patch and deprecate the bad one
|
|
346
|
+
(`npm deprecate @blario/react-native@0.2.0 "use 0.2.1"`).
|
|
347
|
+
|
|
348
|
+
### First release, once
|
|
349
|
+
|
|
350
|
+
There is no npm token: the workflow publishes with npm's trusted publishing (OIDC), which needs the package to exist
|
|
351
|
+
before it can be configured. The repository is private, so npm does not attach provenance to what it publishes.
|
|
352
|
+
|
|
353
|
+
1. Reserve the name by hand from a throwaway directory, signed in to npm as a maintainer of `@blario/core` (`berrazuriz1` or `josem7`):
|
|
354
|
+
`npm publish --access public` with a `package.json` of `{ "name": "@blario/react-native", "version": "0.0.0", "license": "MIT" }`.
|
|
355
|
+
2. On npmjs.com, open the package, Settings, Trusted Publisher, GitHub Actions: organisation `blarApp`, repository
|
|
356
|
+
`support-web-component`, workflow `react-native-sdk-release.yaml`, no environment, and allow `npm publish`. Save
|
|
357
|
+
(npm does not validate it until the first publish) and publish the first real version within 2 days or the setting
|
|
358
|
+
expires.
|
|
359
|
+
3. Optional hardening under Settings, Publishing access: require 2FA and disallow tokens. It does not affect OIDC.
|
|
360
|
+
4. Merge `dev` into `main`. `package.json` is at `0.1.0`, which npm does not have, so that push publishes it.
|
|
361
|
+
|
|
362
|
+
If trusted publishing is not wanted, a granular npm token (Read and write, scoped to `@blario`, 2FA bypass) stored as the
|
|
363
|
+
`NODE_AUTH_TOKEN` of the publish step works too, but npm is retiring direct publishing with 2FA-bypass tokens in January
|
|
364
|
+
2027.
|
|
365
|
+
|
|
366
|
+
## Error reporting
|
|
367
|
+
|
|
368
|
+
Like the web widget, the SDK reports its own contained failures to Blar's Sentry, through a client that is isolated from
|
|
369
|
+
the host app: it installs no global error handler and no native crash hook, never touches the app's own Sentry, and
|
|
370
|
+
only sees errors the SDK catches itself (the agent runtime, the backend transport and a boundary around the SDK's own
|
|
371
|
+
UI, never the app's components). Events carry the SDK version, platform, publishable key, `source_id`, session id and
|
|
372
|
+
the user's external id; emails, bearer tokens and identity tokens are scrubbed from messages. Network failures and
|
|
373
|
+
refused credentials only become breadcrumbs, and at most 50 events are sent per launch. Without a DSN (the repo
|
|
374
|
+
default, set only by the release job) nothing is sent. `enabled={false}` stops the SDK, and its reporting with it.
|
|
375
|
+
|
|
376
|
+
Stack traces from the app's own bundle cannot be symbolicated on Blar's side, so events group by context and error type
|
|
377
|
+
rather than by stack. The embedded chat widget reports as the web widget does, with its source maps uploaded by the
|
|
378
|
+
release job. Both use the `production-react-native` Sentry environment.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React, { Component, type ReactNode } from 'react';
|
|
2
|
+
import { type AgentModeSnapshot } from './agent-mode/controller.ts';
|
|
3
|
+
import { type CursorSnapshot } from './agent-mode/cursor.ts';
|
|
4
|
+
import { type SpotlightSnapshot } from './agent-mode/spotlight-controller.ts';
|
|
5
|
+
import type { BlarIdentity } from './backend/identity.ts';
|
|
6
|
+
import type { NavigationRefLike } from './actions/navigation-driver.ts';
|
|
7
|
+
import { type ChatSnapshot } from './chat/chat-coordinator.ts';
|
|
8
|
+
import { type ChatOptions } from './chat/options.ts';
|
|
9
|
+
import { type Language, type UiStringOverrides } from './ui/strings.ts';
|
|
10
|
+
export interface BlarProviderProps {
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
publishableKey?: string;
|
|
13
|
+
apiBaseUrl?: string;
|
|
14
|
+
user?: BlarIdentity | null;
|
|
15
|
+
relayUrl?: string;
|
|
16
|
+
navigationRef?: NavigationRefLike | null;
|
|
17
|
+
language?: Language;
|
|
18
|
+
strings?: UiStringOverrides;
|
|
19
|
+
chat?: ChatOptions;
|
|
20
|
+
enabled?: boolean;
|
|
21
|
+
debug?: boolean;
|
|
22
|
+
}
|
|
23
|
+
interface BlarProviderState {
|
|
24
|
+
spotlight: SpotlightSnapshot;
|
|
25
|
+
chat: ChatSnapshot | null;
|
|
26
|
+
agentMode: AgentModeSnapshot | null;
|
|
27
|
+
cursor: CursorSnapshot;
|
|
28
|
+
reduceMotion: boolean;
|
|
29
|
+
layerGeneration: number;
|
|
30
|
+
}
|
|
31
|
+
export declare class BlarProvider extends Component<BlarProviderProps, BlarProviderState> {
|
|
32
|
+
private connection;
|
|
33
|
+
private readonly cursor;
|
|
34
|
+
private readonly spotlight;
|
|
35
|
+
state: BlarProviderState;
|
|
36
|
+
private readonly contentRef;
|
|
37
|
+
private controller;
|
|
38
|
+
private agentMode;
|
|
39
|
+
private transport;
|
|
40
|
+
private backend;
|
|
41
|
+
private coordinator;
|
|
42
|
+
private chatControls;
|
|
43
|
+
private shownNudge;
|
|
44
|
+
private readonly releases;
|
|
45
|
+
private stackingCheckQueued;
|
|
46
|
+
private loggedPhase;
|
|
47
|
+
private readonly stacking;
|
|
48
|
+
private readonly attachCursor;
|
|
49
|
+
private readonly detachCursor;
|
|
50
|
+
componentDidMount(): void;
|
|
51
|
+
componentDidUpdate(previous: BlarProviderProps): void;
|
|
52
|
+
componentWillUnmount(): void;
|
|
53
|
+
private startSdk;
|
|
54
|
+
private stopSdk;
|
|
55
|
+
render(): React.JSX.Element;
|
|
56
|
+
private renderAgentLayer;
|
|
57
|
+
private renderChat;
|
|
58
|
+
private chatOptions;
|
|
59
|
+
private watchForeground;
|
|
60
|
+
private watchMotionPreference;
|
|
61
|
+
private createAgentMode;
|
|
62
|
+
private createTransport;
|
|
63
|
+
private createChat;
|
|
64
|
+
private attachBackend;
|
|
65
|
+
private queueStackingCheck;
|
|
66
|
+
private keepLayerOnTop;
|
|
67
|
+
private countHostModals;
|
|
68
|
+
private noteNudge;
|
|
69
|
+
private debug;
|
|
70
|
+
private followWidgetSession;
|
|
71
|
+
private readChatMetadata;
|
|
72
|
+
private readChatProof;
|
|
73
|
+
}
|
|
74
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runBatched(callback: () => void): void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Fiber } from '../fiber/types.ts';
|
|
2
|
+
export declare class CommitWatch {
|
|
3
|
+
private readonly getAnchorFiber;
|
|
4
|
+
private readonly onCommit?;
|
|
5
|
+
private watchedRoot;
|
|
6
|
+
private originalDescriptor;
|
|
7
|
+
private watchedSetter;
|
|
8
|
+
private commits;
|
|
9
|
+
private baseline;
|
|
10
|
+
constructor(getAnchorFiber: () => Fiber | null, onCommit?: (() => void) | undefined);
|
|
11
|
+
begin(): void;
|
|
12
|
+
hasCommitted(): boolean;
|
|
13
|
+
release(): void;
|
|
14
|
+
private install;
|
|
15
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type Rect } from '../host/rect.ts';
|
|
2
|
+
export interface SyntheticPressEvent {
|
|
3
|
+
nativeEvent: {
|
|
4
|
+
pageX: number;
|
|
5
|
+
pageY: number;
|
|
6
|
+
locationX: number;
|
|
7
|
+
locationY: number;
|
|
8
|
+
timestamp: number;
|
|
9
|
+
target: number;
|
|
10
|
+
touches: never[];
|
|
11
|
+
changedTouches: never[];
|
|
12
|
+
};
|
|
13
|
+
persist: () => void;
|
|
14
|
+
preventDefault: () => void;
|
|
15
|
+
stopPropagation: () => void;
|
|
16
|
+
isPropagationStopped: () => boolean;
|
|
17
|
+
isDefaultPrevented: () => boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface SyntheticTextChangeEvent {
|
|
20
|
+
nativeEvent: {
|
|
21
|
+
text: string;
|
|
22
|
+
eventCount: number;
|
|
23
|
+
target: number;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export interface SyntheticSubmitEvent {
|
|
27
|
+
nativeEvent: {
|
|
28
|
+
text: string;
|
|
29
|
+
eventCount: number;
|
|
30
|
+
target: number;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export declare function buildPressEvent(rect: Rect): SyntheticPressEvent;
|
|
34
|
+
export declare function buildTextChangeEvent(text: string): SyntheticTextChangeEvent;
|
|
35
|
+
export declare function buildSubmitEvent(text: string): SyntheticSubmitEvent;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { SnapshotCapturer } from '../snapshot/capture.ts';
|
|
2
|
+
import type { CommitWatch } from './commit-watch.ts';
|
|
3
|
+
import type { ActionServices } from './services.ts';
|
|
4
|
+
import { type ResolvedTarget } from './target.ts';
|
|
5
|
+
import type { ActionOutcome, AgentCommandData } from './types.ts';
|
|
6
|
+
export interface ExecutionOptions {
|
|
7
|
+
isCancelled: () => boolean;
|
|
8
|
+
}
|
|
9
|
+
export type Preparation = {
|
|
10
|
+
ok: true;
|
|
11
|
+
target: ResolvedTarget | null;
|
|
12
|
+
} | {
|
|
13
|
+
ok: false;
|
|
14
|
+
outcome: ActionOutcome;
|
|
15
|
+
};
|
|
16
|
+
export declare class ActionExecutor {
|
|
17
|
+
private readonly capturer;
|
|
18
|
+
private readonly services;
|
|
19
|
+
private readonly commitWatch;
|
|
20
|
+
constructor(capturer: SnapshotCapturer, services: ActionServices, commitWatch: CommitWatch);
|
|
21
|
+
prepare(command: AgentCommandData): Promise<Preparation>;
|
|
22
|
+
execute(command: AgentCommandData, target: ResolvedTarget | null, options: ExecutionOptions): Promise<ActionOutcome>;
|
|
23
|
+
private perform;
|
|
24
|
+
private revealTarget;
|
|
25
|
+
private pointAt;
|
|
26
|
+
private resolveTarget;
|
|
27
|
+
private missingTarget;
|
|
28
|
+
private dispatch;
|
|
29
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ActionServices } from './services.ts';
|
|
2
|
+
import { type ResolvedTarget } from './target.ts';
|
|
3
|
+
import type { HandlerResult } from './types.ts';
|
|
4
|
+
export declare function highlight(target: ResolvedTarget, text: string | null, services: ActionServices): Promise<HandlerResult>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Fiber } from '../fiber/types.ts';
|
|
2
|
+
export type GuardVerdict = {
|
|
3
|
+
allowed: true;
|
|
4
|
+
} | {
|
|
5
|
+
allowed: false;
|
|
6
|
+
reason: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function checkInteractable(fiber: Fiber, ancestors: Fiber[]): GuardVerdict;
|
|
9
|
+
export declare function checkEditable(fiber: Fiber, ancestors: Fiber[]): GuardVerdict;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Rect } from '../host/rect.ts';
|
|
2
|
+
import type { Clock } from './settle.ts';
|
|
3
|
+
import type { AgentAction } from './types.ts';
|
|
4
|
+
export interface CursorPort {
|
|
5
|
+
moveTo: (measure: () => Promise<Rect | null>) => void;
|
|
6
|
+
whenLanded: () => Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
export declare const LANDING_MAX_MS = 1800;
|
|
9
|
+
export declare function tapsTarget(action: AgentAction): boolean;
|
|
10
|
+
export declare function waitsForLanding(action: AgentAction): boolean;
|
|
11
|
+
export declare function waitForLanding(cursor: CursorPort, clock: Clock): Promise<void>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type UnknownRecord } from '../fiber/narrow.ts';
|
|
2
|
+
import { type ScreenRef } from '../snapshot/navigation.ts';
|
|
3
|
+
import type { HandlerResult } from './types.ts';
|
|
4
|
+
export interface NavigationRefLike {
|
|
5
|
+
isReady: () => boolean;
|
|
6
|
+
navigate(...args: unknown[]): void;
|
|
7
|
+
getRootState: () => unknown;
|
|
8
|
+
}
|
|
9
|
+
export interface NavigationSources {
|
|
10
|
+
readFocusedScreens: () => ScreenRef[];
|
|
11
|
+
getNavigationRef: () => NavigationRefLike | null;
|
|
12
|
+
}
|
|
13
|
+
export declare class NavigationDriver {
|
|
14
|
+
private readonly sources;
|
|
15
|
+
constructor(sources: NavigationSources);
|
|
16
|
+
listRefRoutePaths(): string[];
|
|
17
|
+
navigateTo(route: string, params: UnknownRecord | null): HandlerResult;
|
|
18
|
+
private navigateAlongPath;
|
|
19
|
+
private collectRoutePaths;
|
|
20
|
+
private navigateThroughFocusedScreens;
|
|
21
|
+
private navigateThroughRef;
|
|
22
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type AgentCommandData, type PageContentRequest } from './types.ts';
|
|
2
|
+
export declare function parsePageContentRequest(options: unknown): PageContentRequest;
|
|
3
|
+
export declare function parseAgentCommand(data: unknown): AgentCommandData | null;
|
|
4
|
+
export declare function describeUnparsedAction(data: unknown): string;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ActionErrorCode, FailedResult, HandlerResult } from './types.ts';
|
|
2
|
+
export declare function succeeded(message?: string): HandlerResult;
|
|
3
|
+
export declare function failed(error: ActionErrorCode, message: string): FailedResult;
|
|
4
|
+
export declare function failedFromException(error: unknown): FailedResult;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Band } from '../host/rect.ts';
|
|
2
|
+
import type { ResolvedTarget } from './target.ts';
|
|
3
|
+
import type { AgentAction, HandlerResult } from './types.ts';
|
|
4
|
+
type ScrollAction = Extract<AgentAction, {
|
|
5
|
+
type: 'scroll';
|
|
6
|
+
}>;
|
|
7
|
+
export declare function scrollContainer(target: ResolvedTarget, action: ScrollAction): Promise<HandlerResult>;
|
|
8
|
+
export declare function scrollIntoView(target: ResolvedTarget, options?: {
|
|
9
|
+
animated: boolean;
|
|
10
|
+
}): Promise<HandlerResult>;
|
|
11
|
+
export declare function scrollIntoBand(target: ResolvedTarget, band: Band): Promise<HandlerResult>;
|
|
12
|
+
export {};
|