-
Notifications
You must be signed in to change notification settings - Fork 0
JavaScript Bridge
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
});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.
Subscribe / unsubscribe to events pushed from Python (app.emit) or fired by
capability modules.
enpaf.on("progress", (d) => updateBar(d.percent));Send an event to Python (handled by @app.on(event) / bridge JS-event
handlers).
enpaf.emit("button_clicked", { id: "save" });Navigate to another page ("/about", or an absolute URL).
Run a callback once the bridge is connected.
| Property | Description |
|---|---|
enpaf.version |
Bridge version string. |
enpaf.isAndroid |
true when running inside the Android WebView. |
enpaf.connected |
Whether the bridge is connected. |
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");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);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]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")) { /* ... */ }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);Each Python capability module is reachable via enpaf.mod(module, method, args)
or the typed shortcuts below. Full behavior + events: Device Capabilities.
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.
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.
takePicture(), recordVideo(), pickMedia(type), recordAudio(duration).
enpaf.location.get();
enpaf.battery.info(); enpaf.battery.network();
enpaf.audio.level(durationSec);
enpaf.notifications.notify({ title, text });const { available } = await enpaf.biometric.available();
if (available) {
const res = await enpaf.biometric.authenticate({ title: "Unlock" });
if (res.success) { /* ... */ }
}enpaf.utils.formatDate(Date.now()); // locale date string
enpaf.utils.uid(); // "enpaf_xxxxxxxx"enpaf.api(method, args); // -> Python DeviceAPI (allow-listed)
enpaf.mod(module, method, args); // -> Python capability moduleThese back the typed helpers above; reach for them only for methods without a shortcut.
Getting started
Reference
- CLI Reference
- enpaf.json Configuration
- Python API
- JavaScript Bridge
- Storage
- Events
- Device Capabilities
Building & shipping
Project