feat(host): add typed host capability boundary
Introduce hemx-host with typed capability manifests, calls, events, host-check failures, reusable browser/PWA and native-shell profiles, and a tiny optional browser adapter for haptics/share that returns host events without DOM mutation. req: host/001 req: host/002 req: host/003 req: host/004 req: host/005
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# Recipe: typed host capabilities
|
||||
|
||||
`hemx-host` is the boundary between a hemx app and a browser, PWA,
|
||||
WebView, or native shell. It is not a mobile framework and it is not a new UI
|
||||
runtime. A host adapter can perform explicit host side effects or return facts;
|
||||
app code still owns domain decisions and returns normal hemx effects. req: host/001 req: host/002
|
||||
|
||||
## Contract
|
||||
|
||||
Declare the capability shape the app may use:
|
||||
|
||||
```rust
|
||||
use hemx_host::{Capability, CapabilityManifest, CapabilityShape, CapabilityUse};
|
||||
|
||||
let manifest = CapabilityManifest::new([
|
||||
CapabilityUse::new(Capability::Haptics, CapabilityShape::Fire),
|
||||
CapabilityUse::new(Capability::Share, CapabilityShape::Request),
|
||||
]);
|
||||
```
|
||||
|
||||
Check the manifest against the concrete host profile before executing calls:
|
||||
|
||||
```rust
|
||||
use hemx_host::{HostProfile, HostCheckError};
|
||||
|
||||
let host = HostProfile::new(
|
||||
"web",
|
||||
[CapabilityUse::new(Capability::Share, CapabilityShape::Request)],
|
||||
);
|
||||
|
||||
let result: Result<(), HostCheckError> = manifest.check(&host);
|
||||
```
|
||||
|
||||
Permission-sensitive capabilities such as microphone, camera, notifications,
|
||||
secure storage, file picker, and geolocation need a user-facing reason in the
|
||||
manifest before standard host checks pass. req: host/003 req: host/004
|
||||
|
||||
## Browser/PWA adapter
|
||||
|
||||
`hemx-host::BROWSER_HOST_JS` is an optional tiny browser adapter. It exposes
|
||||
`window.hemxBrowserHost.perform(call)`, accepts the serde JSON shape of
|
||||
`HostCall`, calls browser APIs such as `navigator.share` or `navigator.vibrate`,
|
||||
and returns the serde JSON shape of `HostEvent`. It does not query, patch, or
|
||||
own the DOM; the app consumes the host event and returns ordinary hemx effects.
|
||||
req: host/001 req: host/002 req: host/005
|
||||
|
||||
## Event flow
|
||||
|
||||
Host events are facts, not app mutations:
|
||||
|
||||
```text
|
||||
HostEvent
|
||||
→ app/domain command
|
||||
→ domain validation and optional persistence
|
||||
→ projection/rendering
|
||||
→ hemx EffectBatch
|
||||
```
|
||||
|
||||
Adapters must not mutate DOM, append domain events, or write application state
|
||||
on behalf of the app. req: host/002 req: host/005
|
||||
|
||||
## Mobile
|
||||
|
||||
iOS and Android shells are thin host adapters around a WebView. They implement
|
||||
manifest-backed calls such as haptics, share, microphone streams, secure
|
||||
storage, notifications, and explicit custom capabilities; hemx still owns UI
|
||||
effects and the app still owns state. req: host/001 req: host/002
|
||||
Reference in New Issue
Block a user