Skip to content

JavaScript Bridge

aaalllexxx edited this page Jun 29, 2026 · 1 revision

JavaScript Bridge (enpaf.js)

ENPAF injects a global enpaf object into every page. It's the JS side of the bridge: call Python, listen for events, use storage, and reach device features.

You don't need to add a <script> for the bridge — ENPAF injects it into your <head>. It works the same in the browser (dev) and in the on-device WebView; the only difference is the transport (Socket.IO/HTTP vs. the Android JS interface), which is handled for you.

enpaf.ready(() => {
  // bridge is connected
});

Core

enpaf.call(name, params) → Promise

Call a Python @app.bridge_handler.

const res = await enpaf.call("get_user", { id: 1 });

Rejects with an Error if the handler is missing or raises.

enpaf.on(event, handler) / enpaf.off(event, handler?)

Subscribe / unsubscribe to events pushed from Python (app.emit) or fired by capability modules.

enpaf.on("progress", (d) => updateBar(d.percent));

enpaf.emit(event, data)

Send an event to Python (handled by @app.on(event) / bridge JS-event handlers).

enpaf.emit("button_clicked", { id: "save" });

enpaf.navigate(path)

Navigate to another page ("/about", or an absolute URL).

enpaf.ready(callback)

Run a callback once the bridge is connected.

Properties

Property Description
enpaf.version Bridge version string.
enpaf.isAndroid true when running inside the Android WebView.
enpaf.connected Whether the bridge is connected.

Storage — enpaf.storage

Async wrappers over the Python Storage key/value store.

await enpaf.storage.set("theme", "dark");
const theme = await enpaf.storage.get("theme");   // "dark"
await enpaf.storage.delete("theme");

Device — enpaf.device

Quick device actions (with sensible browser fallbacks in dev).

Method Description
toast(message, duration?) Show a toast ("short"/"long").
vibrate(ms) Vibrate.
notify(title, text?, id?) System notification.
share(text, title?) Share sheet.
setOrientation(mode) "portrait", "landscape", "auto".
clipboard(text) Copy text.
openUrl(url) Open in the system browser.
getInfo() Basic info (resolves via __enpaf_ping).
enpaf.device.toast("Saved!");
enpaf.device.vibrate(200);

Sensors — enpaf.sensors

Read device sensors and state from Python.

Method Returns
read(name, opts?) One snapshot of "accelerometer", "gyroscope", "magnetometer", "light", "proximity", "pressure", …
list() Hardware sensors present.
location() Last known location.
bluetooth() Adapter state + bonded devices.
nfc() NFC adapter state.
audioLevel(duration?) Mic peak amplitude (needs RECORD_AUDIO).
battery() Level + charging.
network() Connectivity info.
snapshot() Common sensors + state in one call.
const a = await enpaf.sensors.read("accelerometer");
console.log(a.values); // [x, y, z]

Permissions — enpaf.permissions

Request dangerous permissions on demand (the system prompt appears when you choose).

Method Returns
check(permission) { granted }.
checkAll(list) { granted: [...], denied: [...], results: {...} }.
request(list) Shows the prompt; resolves with the grant result.
const res = await enpaf.permissions.request(["CAMERA", "RECORD_AUDIO"]);
if (res.granted.includes("android.permission.CAMERA")) { /* ... */ }

NFC — enpaf.nfc

Full read/write/lock. Reading uses the last-tapped tag; writing is most reliable with the arm-then-tap flow (arm*), which resolves when the user taps a tag.

Method Description
status() { present, enabled }.
read() NDEF content { records: [...] }.
writeText(text, lang?) / armText(...) Text record.
writeUri(uri) / armUri(...) URL/URI (also tel:, mailto:, geo:, sms:).
writeApp(pkg, uri?) / armApp(...) App-launch (AAR) record.
writeMime(mime, data) / armMime(...) MIME record.
writeWifi(ssid, password, opts?) / armWifi(...) Wi-Fi join credentials.
writeContact(c) / armContact(...) vCard.
writeRecords(records) / armRecords(...) Multiple records at once.
lock() / armLock() Permanently make the tag read-only (irreversible).
onTag(handler) Subscribe to tag-tapped events.
onWriteResult(handler) Results of armed writes.
cancel() Cancel a pending armed write.
// Arm a URL, then ask the user to tap a tag:
const res = await enpaf.nfc.armUri("https://example.com");
console.log(res.written);

Capability modules

Each Python capability module is reachable via enpaf.mod(module, method, args) or the typed shortcuts below. Full behavior + events: Device Capabilities.

Wi-Fi — enpaf.wifi

enpaf.wifi.scan();                       // -> emits "wifi_scan_result"
enpaf.wifi.onResult((n) => console.log(n.ssid, n.rssi));
enpaf.wifi.connect("MySSID", "password");

status(), info(), scan(), networks(), enable(), connect(ssid, pw), disconnect(), and onResult/onFinished/onConnected/onError.

Bluetooth — enpaf.bluetooth

enpaf.bluetooth.discover();              // -> emits "bluetooth_device_found"
enpaf.bluetooth.onFound((d) => console.log(d.name, d.address));

status(), enable(), paired(), discover(), stopDiscovery(), connect(address), listen(name), send(text), disconnect(), and onFound/onConnected/onData/onDisconnected/onDiscoveryFinished/onError.

Media — enpaf.media

takePicture(), recordVideo(), pickMedia(type), recordAudio(duration).

Others

enpaf.location.get();
enpaf.battery.info();   enpaf.battery.network();
enpaf.audio.level(durationSec);
enpaf.notifications.notify({ title, text });

Biometric — enpaf.biometric

const { available } = await enpaf.biometric.available();
if (available) {
  const res = await enpaf.biometric.authenticate({ title: "Unlock" });
  if (res.success) { /* ... */ }
}

Utils — enpaf.utils

enpaf.utils.formatDate(Date.now());   // locale date string
enpaf.utils.uid();                    // "enpaf_xxxxxxxx"

Low-level gateways

enpaf.api(method, args);              // -> Python DeviceAPI (allow-listed)
enpaf.mod(module, method, args);      // -> Python capability module

These back the typed helpers above; reach for them only for methods without a shortcut.

Clone this wiki locally