The default export, and the quick path - creates a DroidSock API instance. options.mode ("eager" or "lazy", default "eager"), options.context, and options.config are all optional. Also available under the explicit name createDroidSock (import { createDroidSock } from "@cldmv/droidsock") for callers who prefer it - both names are the exact same function.
Single-target operations - the module name (singular device) disambiguates them from the collection-wide operations on devices below. A device leaf, once created, is a persistent handle that outlives any one TCP connection: disconnect() only tears down the current socket, it does not forget the device - connect() on the same host:port later reconnects that exact same leaf, reusing whatever options it was created with, so a reference you're holding stays valid and you never have to re-supply host/port/options just to reconnect. remove() is the separate, explicit "forget this device" operation.
-
connect(host, port, options):host: Device IP address (IPv4 or IPv6)port: ADB port (default:5555)options.keyDir: Directory for RSA keys (default:~/.adb)
Connects to a device and returns its live leaf. Calling
connect()again for the samehost:portreuses the same leaf - if it's already connected, that connection is returned as-is; if it had disconnected, it's reconnected in place. Anoptionsargument passed on a later call only overrides the fields it provides (e.g. a differentkeyDir); anything omitted falls back to what the device was created with. The device is also reachable afterward directly off the api tree - not just via the valueconnect()returned - atapi.devices["<sanitized host_port>"], where a.inhost:portbecomes a single_and a:becomes a double__(the two would otherwise collide into indistinguishable runs of underscores for an IPv6 host), e.g.10.6.0.108:5555→api.devices["10_6_0_108__5555"]. Every device that's ever been connected lives there until explicitlyremove()d. -
disconnect(host, port): Tears down a specific device's connection without forgetting it (default port5555) - its leaf stays mounted and reconnectable. Returnstrueif a matching device was found,falseotherwise. Synchronous. -
remove(host, port): Disconnects (if needed) and unmounts a specific device's leaf entirely - the actual "forget this device" operation. Returnstrueif a matching device was found,falseotherwise. Async -awaitit.
Collection-wide operations, mounted alongside every device's own leaf at api.devices.<sanitized host_port>.
list(): Returns an array of the currently-connected device leaves. A known-but-disconnected device is not included.disconnect(): Takes no arguments - disconnects every known device (connected or not; a no-op for one that's already disconnected), keeping every leaf mounted for later reconnection. Returns the number disconnected. Synchronous. Throws if called with any argument, catching a mix-up with the single-targetdevice.disconnect(host, port).remove(): Takes no arguments - disconnects and unmounts every known device leaf. Returns the number removed. Async -awaitit. Throws if called with any argument, catching a mix-up with the single-targetdevice.remove(host, port).get(idOrLeaf): Looks up a device leaf - connected or currently disconnected - by"host:port"string (bracket an IPv6 host with a port, e.g."[2001:db8::1]:5555") or by the leaf object itself (as returned byconnect()). Returnsundefinedonly for a device that was never connected or has since beenremove()d.
isConnected(): Check connection status - always reflects the live socket state.disconnect(): Disconnect without forgetting this device - its leaf stays mounted atapi.devicesand can be reconnected later viadevice.connect(host, port). Synchronous.reconnect(options): Re-establishes the connection for this same leaf; a no-op if already connected.optionsoverrides only the fields it provides, falling back to whatever this device was created (or last reconnected) with. Async -awaitit. (device.connect(host, port, options)calls this automatically when the target is already known but disconnected - most callers won't need to call it directly.)remove(): Disconnects (if needed) and unmounts this device's leaf fromapi.devices- the same operation asdevice.remove(host, port), called on the leaf directly. Async -awaitit.
shell(command, options): Execute a shell command and return its outputstartStreamingShell(command, options): Start a streaming command (options.onData/onError/onEnd); returns a control object withstop()startInteractiveShell(command, options): Start an interactive command; returns a control object withsendInput(data)andstop()
ls(path): List directory via shell (ls -la)pwd(): Get current directorygetprop(property): Get a system property (all properties if omitted)getModel(): Get device modelgetAndroidVersion(): Get Android versiongetBattery(): Get battery status (dumpsys battery)screenshot(filename): Take a screenshot (screencap -p)logcat(options): Stream logcat - same streaming control object asstartStreamingShelltop(options): Streamtop -m 10keypress(key): Send a keyevent (input keyevent)launchApp(packageName, activity): Launch an app (am start)
push(localPath, remotePath, options): Experimental - real binary transfer via the ADB SYNC sub-protocol (legacy 32-bitSEND).options.onProgress,options.mode(default0o644). Not yet validated against a real device.pull(remotePath, localPath, options): Experimental - real binary transfer via the ADB SYNC sub-protocol (legacy 32-bitRECV).options.onProgress. Not yet validated against a real device.pushV2(localPath, remotePath, options)/pullV2(remotePath, localPath, options): Experimental - the 64-bitSEND_V2/RECV_V2SYNC variants, for files/listings beyond the legacy 32-bit ~2.14GB ceiling. Same options aspush/pull, plusoptions.compression("none"(default) or"brotli") for per-chunk compression - only usable against a device that also advertisedsendrecv_v2_brotli.lz4/zstdaren't implemented (tracked separately). Only usable against a device that advertised thesendrecv_v2feature. See #8.list(remotePath): List directory contents, preferring the binary-safe SYNCLISTcommand (experimental, not yet validated against a real device) and falling back to shellls -laparsing when the SYNC service isn't usable. A realLISTfailure (e.g. a missing path) is never masked by the fallback - it's rethrown as-is.listV2(remotePath): Experimental - the 64-bitLIST_V2SYNC variant. No shell fallback. Only usable against a device that advertised thels_v2feature.stat(remotePath): Get file/directory info via shell (rawstatoutput)statV2(remotePath): Experimental - binary-safe stat via the 64-bitSTAT_V2SYNC command, returning structured fields (mode/size/atime/mtime/ctime/uid/gid/nlink/dev/ino- the 64-bit fields asBigInt) instead of raw shell text. Only usable against a device that advertised thestat_v2feature.
For direct access to one specific listing implementation (bypassing the automatic SYNC-then-shell preference), call the underlying module functions directly: api.files.listSync(device.connection.socket, device.streamManager, remotePath) or api.files.listShell(...) with the same arguments.
reboot(mode): Experimental - reboots the device via the real ADBreboot:service - a distinct top-level service likeshell:/sync:, not a shell command.modeis""(normal, default),"bootloader","recovery","sideload","sideload-auto-reboot", or any other string for a vendor-specific target. Not yet validated against a real device.rebootBootloader()/rebootRecovery()/rebootSideload(): Shortcuts for the correspondingreboot(mode)call.
device.shell("reboot") still works unchanged for a plain reboot - it's just unable to reach bootloader/recovery/sideload, since those aren't real shell commands.
forward(devicePort, options): Experimental - theadb forward tcp:<localPort> tcp:<devicePort>equivalent. Listens on a local TCP port and bridges each accepted connection to a new ADB stream on the device'stcp:<devicePort>service. Returns{ localPort, close() }. Not yet validated against a real device.options.localPort(default0, letting the OS pick a free port)options.host(default"127.0.0.1")options.onError(error, localSocket): called on a per-connection bridging error
reverse(devicePort, hostPort, options): Experimental - theadb reverse tcp:<devicePort> tcp:<hostPort>equivalent. Registers the tunnel with the device (reverse:forward:tcp:<devicePort>;tcp:<hostPort>), then bridges each device-initiated connection to a new local TCP connection onhostPort. Returns{ devicePort, hostPort, close() }-close()also unregisters the tunnel viareverse:killforward:. Not yet validated against a real device.options.host(default"127.0.0.1")options.onError(error, deviceStream): called on a per-connection bridging error
install(localPath, options): Experimental - theadb install <local.apk>equivalent. Tries the modern streaming install (exec:cmd package install -S <size>, no on-device file at all) when the device advertised thecmdfeature during the CNXN handshake, falling back to the classic push-then-install flow (push the APK to a device temp directory, runpm install, remove the temp file regardless of outcome) otherwise, or if the streaming attempt fails partway through. Not yet validated against a real device.options.flags(default[]): flags passed topm installoptions.remoteDir(default"/data/local/tmp"): device directory to push into (classic flow only)options.onProgress: forwarded to the underlyingpush()call (classic flow only)
To use one path explicitly instead of the automatic try-streaming-then-fallback behavior, call the underlying module functions directly: api.install.streaming(device.connection.socket, device.streamManager, localPath, options) or api.install.classic(...) with the same arguments.