anchordb-lens-link
v1.3.2
Published
Anchor Lens Link — open a QA build's AnchorDB database in Anchor Lens on the same Android phone, from a file. No laptop, no relay.
Maintainers
Readme
anchordb-lens-link
Open a QA build's AnchorDB database in Anchor Lens, on the same Android phone, from a file. No laptop, no relay, no pairing code.
Overview · Report a bug or get support
npm install anchordb-lens-linkimport { enableLensLink } from "anchordb-lens-link";
import { db } from "./db";
// QA builds only — see "Keep it out of production" below.
if (process.env.EXPO_PUBLIC_LENS_LINK === "on") {
void enableLensLink(db, { allowInProduction: true });
}Rebuild the app (a development or release build — not Expo Go), install it, open it once. Then in Anchor Lens: Connect to an app → Open app from file, and pick
Android/media/<your app's package>/anchor-lens/<database>.anchorlensLens opens the app's database live. Edits in either app show up in the other.
How it works
enableLensLinkstarts a WebSocket server on 127.0.0.1, on a random port, and puts anInspectorAgenton the database behind it.- It makes a secret for this launch — 32 random bytes — and writes the port and the secret into the link file, sealed so that only Anchor Lens can read it.
- Lens reads the file, connects to
ws://127.0.0.1:<port>with React Native's own WebSocket, and proves it holds the secret with the inspector's HMAC challenge. The secret never crosses the connection. - From there it is an ordinary inspector session: the same protocol, capability checks and Model API
writes — validation, unique indexes, timestamps, the sync queue — as through
anchor-relay.
The file is rewritten on every launch, because the port and the secret change. It works only while the app is running; if Lens says the app closed, open the app and pick the file again.
Staying alive in the background
Android stops apps in the background to save power, and some phones — Xiaomi's especially — do it within seconds of switching away. So while the link is on, the app runs an Android foreground service with an ongoing notification (Anchor Lens Link on, then Anchor Lens connected), which is what Android lets an app use to keep running. Anchor Lens does the same while it is connected, so you can switch between the two.
It starts with the link, so call enableLensLink while the app is on screen: Android 12 and later
refuse to start one from the background. keepAlive: false turns it off, and link.keepAliveError
says why it could not start.
Two settings make it dependable. Put them on a QA screen:
import {
askBatteryUnrestricted,
askNotificationPermission,
backgroundStatus,
openBackgroundSettings,
} from "anchordb-lens-link";
const status = backgroundStatus(); // { notifications, batteryUnrestricted, keepingAlive, manufacturer, vendorSettings }
await askNotificationPermission(); // Android 13+: lets the notification show
askBatteryUnrestricted(); // Android's "let this app always run in the background?" dialog
if (status?.vendorSettings) openBackgroundSettings(); // Xiaomi: Autostart, and Battery saverOn a Xiaomi phone also turn on Autostart, set Battery saver to No restrictions, and lock the app in Recents.
The package adds FOREGROUND_SERVICE, FOREGROUND_SERVICE_SPECIAL_USE, POST_NOTIFICATIONS and
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS to the app's manifest, with a specialUse foreground service.
That suits a QA build; a Play Store build that shipped the package would have to justify them — one
more reason to keep it out of production.
Keep it out of production
A link exposes the database to Anchor Lens on the phone, so:
- Nothing happens unless the app calls
enableLensLink. Put the call behind a build flag. - In a release build — which includes a QA APK — it refuses to start without
allowInProduction: true. readOnly: truerefuses every write from Lens.link.close()stops the server and deletes the file.
What protects the database:
- Loopback only. The server listens on 127.0.0.1; nothing on the network can reach it. A web page in the phone's browser can reach 127.0.0.1, and is refused by its Origin before it gets further.
- A new secret every launch, proved over a single-use challenge, never sent.
- The seal makes the file unreadable and tamper-evident to other apps. It is not secrecy from someone who holds both the file and Anchor Lens, which carries the key — the two points above are what count.
API
enableLensLink(db, options?): Promise<LensLink>| Option | |
| --- | --- |
| allowInProduction | Required in a release build |
| readOnly | Refuse every write from Lens |
| anchorVersion, platform | Reported to Lens |
| keepAlive | Keep the app running in the background while the link is on. Default true |
| onConnectionsChange(count) | Lens connections opening and closing |
LensLink has port, fileName, filePath, connections, keepAliveError, agent and close(). Calling
enableLensLink again for the same database replaces the running link, so it is safe in an effect and
through Fast Refresh.
For a Lens client: readLensLink(fileText) returns { app, database, port, secret, … } or throws a
LensLinkError (not_a_link, tampered, unsupported, invalid) with a message worth showing, and
lensLinkUrl(link) is where to connect.
Requirements
- Android. The native module is an Expo module, so the app needs
expo(any Expo app has it; a bare React Native app needsexpo-modules-coreinstalled). iOS is not supported yet. anchordb1.3 or later, whose inspector accepts a shared secret.- Anchor Lens with Open app from file.
Bugs, support and feedback
Report a bug, ask for help or suggest a feature on the AnchorDB project page —
choose anchordb-lens-link as the package, and the reply comes by email.
Include the version (npm ls anchordb), where it runs, the smallest snippet that reproduces it, and
the full error.
