Skip to content

Latest commit

 

History

History
240 lines (177 loc) · 11.4 KB

File metadata and controls

240 lines (177 loc) · 11.4 KB

Native bridge specification

Scope: Web3 Browser PWA ↔ native shell (iOS / Android / Desktop WebView). Alignment: Reuse and extend the existing CashTrees / POS client bridge family — do not invent a parallel injection namespace.

Injected global Product Notes
window.CashTreesIOS Consumer PWA (SilentPassUI) + shared CashTrees shell WKWebView messageHandlers.CashTreesIOS
window.CashTreesAndroid Same @JavascriptInterface
window.BeamioPOS POS PWA (posPwa) Optional; may coexist with CashTrees*
window.Web3BrowserDesktop Web3 Browser desktop shell (new) Same method names where applicable

Detection (prefer injected globals over UA):

CashTreesIOS → ios
CashTreesAndroid → android
Web3BrowserDesktop → desktop
else → browser  // no raw sockets until a host injects

Event bus (Native → PWA):

Platform CustomEvent name
iOS cashtreesios
Android cashtreesandroid
Desktop (recommended) web3browser
POS legacy beamiopos

Payload shape: { action: string, …fields }. Async results carry requestId when the PWA started the call.

iOS vs Android argument style (must preserve):

Style iOS Android
Structured args Object payload { requestId, url, … } Often plain string / JSON string
openURL openURL({ url }) openURL(url: string)
publishAppState object JSON string
scanQr scanQr({ requestId }) scanQr(requestId: string)

PWA helpers must normalize both (see SilentPassUI openExternalUrl, scanQrViaCashTreesNative).


1. Existing client bridge catalog (align / reuse)

Source of truth in sibling products (copy semantics only — no ../.. imports):

Area SilentPassUI POS PWA
NFC / QR / openURL utils/cashTreesNativeNfc.ts, cashTreesIOSBridge.ts bridge/cashTreesScanBridge.ts
Embedded OTA utils/cashTreesEmbeddedPwaUpdate.ts utils/cashTreesEmbeddedPwaUpdate.ts
App state / chat notify utils/cashTreesNativeAppStateBridge.ts bridge/posNativeAppStateBridge.ts
Push bind utils/cashTreesPushBind.ts bridge/posCashTreesPushBind.ts
Lifecycle utils/cashTreesAppLifecycle.ts (visibility + same events)
Print — bridge/cashTreesPrintBridge.ts
POS navigate / wallet — bridge/nativeBridge.ts (BeamioPOS)

1.1 Shell probe & external URL

Method Direction Semantics
getNfcStatus() PWA → Native Probe shell / NFC: ready | no_hardware | nfc_disabled | nfc_permission_denied | …
openURL PWA → Native Open http(s) / mailto / tel in system browser (allowlist). Web fallback: window.open. Required for Explorer / docs / onramp.

1.2 Camera / QR

Method Direction Semantics
scanQr PWA → Native Camera QR; result via event action: 'scanQr' + requestId / ok / text
scanRecoveryQr PWA → Native Recovery QR variant; same event pattern
saveRecoveryQrToPhotos PWA → Native Optional: save recovery image to Photos

1.3 NFC (physical card)

Method Direction Semantics
startPhysicalCardBind PWA → Native Arm NFC read / bind
cancelPhysicalCardBind PWA → Native Cancel armed session
(events) Native → PWA NFC detail: ok, tagUidHex, ndefUri, sun params, error

Web3 Browser may omit NFC in Phase 0–1; keep method names reserved if the same CashTrees shell binary is shared.

1.4 Embedded OTA (shell upgrade path)

Method / event Direction Semantics
getEmbeddedPwaVersion() PWA → Native Current embedded bundle version
getEmbeddedPwaPendingVersion() PWA → Native Downloaded pending version
applyEmbeddedPwaUpdate() PWA → Native Apply zip / restart WebView content
embeddedPwaUpdateAvailable Native → PWA Banner: new version ready
applyEmbeddedPwaUpdate (event) Native → PWA Ack / progress if shell posts it

Manifest: update.json + zip — not Service Worker as shell upgrade path.

1.5 App chrome / push / lifecycle

Method / event Direction Semantics
publishAppState PWA → Native Footer badge, app icon badge, etc.
notifyBackgroundChat PWA → Native Local alert while shell backgrounded (optional; SI push remains primary for chat)
bindPushIdentity PWA → Native Bind { eoa, pgpKeyId? } for FCM / APNs
pushDeviceToken Native → PWA Device token for Cluster bind
appLifecycle Native → PWA phase: active | inactive | background
debugLog(level, message) PWA → Native Dev logging into native console
webContentReady PWA → Native First-paint handoff (splash) — shell documentStart injection

1.6 POS-only (BeamioPOS) — do not require on Web3 Browser

Method Semantics
platform 'ios' | 'android' | 'web'
getWalletAddress / getWalletPrivateKeyHex / hasStoredWallet Legacy display / migrate hints — signing truth is PWA IndexedDB
createWallet / restoreWallet Prefer PWA IndexedDB path
navigateNative(action) Charge / History etc. → native UI (POS abandoned native UI; keep for shell routing)
resendParentPermissionRequest Staff permission resend
printReceipt AirPrint / receipt (CashTreesIOS.printReceipt)

Web3 Browser wallet secrets stay in this app’s IndexedDB (Consumer wallet rules). Do not depend on POS Keychain-only wallet APIs.


2. Web3 Browser extensions (new — required for SI / web3://)

These are additions on the same globals (CashTreesIOS / CashTreesAndroid / Web3BrowserDesktop). Prefer the same CustomEvent bus.

2.1 Client sockets (TCP; TLS optional)

Method Direction Contract
socketOpen({ requestId, host, port, tls? }) PWA → Native Open outbound TCP (optional TLS)
socketWrite({ socketId, dataBase64 }) PWA → Native Write bytes
socketClose(socketId) PWA → Native Close
event socket Native → PWA See below

Events (action: 'socket' or type: 'socket'):

event Fields
open socketId, requestId
data socketId, dataBase64
close socketId, reason?
error socketId?, message, requestId?

MVP policy: allowlist destinations (CoNET SI / known entry domains / loopback). No arbitrary FS. Binary always base64 on the bridge.

UDP (Phase 2+): udpOpen / udpSend / udpClose — same base64 pattern; follow conet-depin-udp-forward-protocol (never put AES keys in route-B-decryptable commands).

2.2 Local website HTTP (primary: ZIP + port)

Product path: PWA packs site files from IndexedDB into a ZIP, passes ZIP + local TCP port to the shell; native unzips into a sandbox and starts a static HTTP server on that port (prefer 127.0.0.1).

Full flow: local-website-serve.md.

Method Direction Contract
hostServeWebsite({ requestId, port, siteId, zipBase64?, loopbackOnly?, rootPath? }) PWA → Native Single-shot: unzip + listen; return { ok, origin, port }
hostServeWebsiteStart({ requestId, port, siteId, byteLength, … }) PWA → Native Begin chunked ZIP transfer
hostServeWebsiteChunk({ requestId, offset, dataBase64 }) PWA → Native Raw ZIP byte slice at offset (not base64-of-whole-file)
hostServeWebsiteFinish({ requestId }) PWA → Native Assemble ZIP → unzip → listen; same result as single-shot
hostStopWebsite(port) PWA → Native Stop HTTP on port; release sandbox
event hostServe Native → PWA ready | error | stopped (see types)

Limits: soft single-shot cap HOST_SERVE_ZIP_SINGLE_SHOT_MAX_BASE64_CHARS (~6M chars). Larger sites must use Start/Chunk/Finish.

Truth: IndexedDB remains the durable site store; native sandbox is a serve cache rebuilt on each successful publish.

Secondary (optional): reverse-proxy bind

Method Direction Contract
hostBind({ logicalPort, loopbackOnly? }) PWA → Native Listen only; each GET → PWA
hostUnbind(logicalPort) PWA → Native Stop listen
event hostRequest Native → PWA { requestId, method, path, headers? }
hostRespond({ requestId, status, headers?, bodyBase64? }) PWA → Native Body from IndexedDB resolvePath

Prefer hostServeWebsite for product publish. Do not treat native disk alone as long-term truth.

2.3 Inherited must-haves for Web3 Browser shell

Minimum for a shippable Web3 Browser shell (in addition to §2.1–2.2):

Capability Why
openURL Explorer, GitBook, onramp
Embedded OTA trio + events Shell version bumps
appLifecycle Pause SI / reconnect policy
webContentReady Splash handoff
debugLog Field diagnostics

Optional in early phases: NFC, QR, push, print, POS navigate.


3. Capability matrix

Capability Consumer CashTrees POS Web3 Browser
getNfcStatus / NFC bind ✅ ✅ Optional
scanQr / recovery QR ✅ ✅ Optional
openURL ✅ ✅ Required
Embedded OTA ✅ ✅ Required
publishAppState / push / lifecycle ✅ ✅ Recommended
printReceipt — ✅ (iOS) Out of scope
BeamioPOS.navigateNative — ✅ Out of scope
socketOpen/Write/Close ❌ ❌ Required (new)
hostServeWebsite (+ chunked) / hostStopWebsite ❌ ❌ Required (new)
hostBind / hostRespond ❌ ❌ Optional secondary

4. Security

  • openURL: only http / https / mailto / tel.
  • Sockets: destination allowlist; no plaintext Layer Minus bypass — HTTP /post body remains { "data": "<OpenPGP armor>" } only.
  • Never log private keys, full OpenPGP armor, or UDP plaintext / Securitykey.
  • Local website: loopback-first; validate ZIP paths (reject ..); public bind only with explicit product approval.
  • Do not use the bridge as a second wallet secret store (IndexedDB remains Consumer/Web3 Browser truth).

5. Implementation notes (per platform)

Platform Direction
iOS Extend CashTreesIOS WK handler + cashtreesios events; object payloads
Android Extend CashTreesAndroid interface; string/JSON where existing APIs use strings
Desktop (macOS) macos/ SwiftPM AppKit + WKWebView — inject Web3BrowserDesktop (see macos/README.md). Windows/Linux TBD

TypeScript contracts: src/bridge/nativeBridge.ts.

6. AI checklist

  • New shell methods reuse CashTrees naming / event bus where possible?
  • iOS object vs Android string variants both handled in the PWA helper?
  • Socket APIs present for SI; hostServeWebsite (+ stop) for web3:// publish?
  • openURL + Embedded OTA still present?
  • No ../.. import of SilentPassUI / posPwa bridge modules?
  • No plaintext /post bypass fields via bridge?