From e0c2ddbf725ee0185ba9fada4a2c66520ed7bbbc Mon Sep 17 00:00:00 2001 From: Shinrai Date: Sat, 3 Oct 2026 16:56:06 -0700 Subject: [PATCH 1/3] docs(changelog): backfill release notes for v1.0.0 through v2.1.6 Adds a per-version changelog under docs/changelog/v1/ and v2/ for every shipped release, written from the published npm tarballs (1.x-2.1.0) and from each release commit's diff (2.1.1 onward). Breaking changes that shipped in minor or patch releases are called out with upgrade steps. v2.1.1 onward were released on GitHub but have not reached npm. --- docs/changelog/v1/v1.0.0.md | 65 ++++++++++++++++++++++++ docs/changelog/v1/v1.1.0.md | 49 ++++++++++++++++++ docs/changelog/v1/v1.2.0.md | 58 ++++++++++++++++++++++ docs/changelog/v1/v1.3.0.md | 36 ++++++++++++++ docs/changelog/v1/v1.4.0.md | 39 +++++++++++++++ docs/changelog/v1/v1.5.0.md | 33 +++++++++++++ docs/changelog/v1/v1.5.1.md | 72 +++++++++++++++++++++++++++ docs/changelog/v1/v1.5.2.md | 54 ++++++++++++++++++++ docs/changelog/v1/v1.5.3.md | 36 ++++++++++++++ docs/changelog/v1/v1.5.4.md | 51 +++++++++++++++++++ docs/changelog/v1/v1.5.5.md | 53 ++++++++++++++++++++ docs/changelog/v2/v2.0.0.md | 78 +++++++++++++++++++++++++++++ docs/changelog/v2/v2.1.0.md | 99 +++++++++++++++++++++++++++++++++++++ docs/changelog/v2/v2.1.1.md | 64 ++++++++++++++++++++++++ docs/changelog/v2/v2.1.2.md | 31 ++++++++++++ docs/changelog/v2/v2.1.3.md | 42 ++++++++++++++++ docs/changelog/v2/v2.1.4.md | 48 ++++++++++++++++++ docs/changelog/v2/v2.1.5.md | 40 +++++++++++++++ docs/changelog/v2/v2.1.6.md | 35 +++++++++++++ 19 files changed, 983 insertions(+) create mode 100644 docs/changelog/v1/v1.0.0.md create mode 100644 docs/changelog/v1/v1.1.0.md create mode 100644 docs/changelog/v1/v1.2.0.md create mode 100644 docs/changelog/v1/v1.3.0.md create mode 100644 docs/changelog/v1/v1.4.0.md create mode 100644 docs/changelog/v1/v1.5.0.md create mode 100644 docs/changelog/v1/v1.5.1.md create mode 100644 docs/changelog/v1/v1.5.2.md create mode 100644 docs/changelog/v1/v1.5.3.md create mode 100644 docs/changelog/v1/v1.5.4.md create mode 100644 docs/changelog/v1/v1.5.5.md create mode 100644 docs/changelog/v2/v2.0.0.md create mode 100644 docs/changelog/v2/v2.1.0.md create mode 100644 docs/changelog/v2/v2.1.1.md create mode 100644 docs/changelog/v2/v2.1.2.md create mode 100644 docs/changelog/v2/v2.1.3.md create mode 100644 docs/changelog/v2/v2.1.4.md create mode 100644 docs/changelog/v2/v2.1.5.md create mode 100644 docs/changelog/v2/v2.1.6.md diff --git a/docs/changelog/v1/v1.0.0.md b/docs/changelog/v1/v1.0.0.md new file mode 100644 index 0000000..a0ff5c6 --- /dev/null +++ b/docs/changelog/v1/v1.0.0.md @@ -0,0 +1,65 @@ +# @cldmv/node-android-tv-remote v1.0.0 Changelog + +**Release Date**: July 2025 +**Release Type**: Initial release + +--- + +## Overview + +Version 1.0.0 is the first release of `@cldmv/node-android-tv-remote`, a Node.js library for controlling Android TV and Fire TV devices over ADB. It exposes a single factory function that returns a remote with connection management, remote-control key presses, long presses, and keyboard input, built on `adbkit`. + +--- + +## ✨ Features + +### Remote factory + +`require("@cldmv/node-android-tv-remote")` exports a factory function that takes a `RemoteConfig` and returns a remote. Supported options are `ip`, `port` (default `5555`), `inputDevice` (default `/dev/input/event0`, used for long presses), `autoConnect` (default `true`), `autoDisconnect` (default `true`), `disconnectTimeout` (seconds of inactivity before auto-disconnect, default `10`), and `quiet` (default `true`, suppresses connection logging). + +### Connection management + +- `connect()` and `disconnect()` support both promise and Node-style callback usage. +- Commands connect on demand when `autoConnect` is enabled, and the inactivity timer disconnects after `disconnectTimeout` seconds when `autoDisconnect` is enabled. +- An "already connected" / "already disconnected" response from ADB is treated as success rather than an error. +- Connection failures print guidance for unauthorized devices (accept the authorization prompt on the TV). + +### Remote control keys + +`press.()` sends the matching Android keycode for each entry in `src/data/remote-keys.json`: `home`, `back`, `menu`, `ok`, `select`, `up`, `down`, `left`, `right`, `play`, `pause`, `playPause`, `stop`, `next`, `previous`, `fastForward`, `rewind`, `volumeUp`, `volumeDown`, `volumeMute`, `channelUp`, `channelDown`, `info`, `guide`, `settings`, `apps`, `caption`, `bookmark`, `help`, `power`, `input`, `mute`, `search`, and `number0` through `number9`. `press.long.()` sends the same key as a long press via `sendevent` against the configured `inputDevice`. + +### Keyboard input + +- `keyboard.text(text)` types a string with `input text`. +- `keyboard.key(name, { forceKeycode })` and `keyboard.key.()` send a single key, using text input for single characters and falling back to the Android keycode otherwise. `keyboard.key..keycode()` always sends the keycode. +- `keyboard.key.shift.()` and `keyboard.key.shift..keycode()` send the shifted variant. +- `inputKeycode(code)` sends a raw Android keycode. + +### Device settings helper + +`handleSettings(mode, [overrideQuiet])` reads (`"get"`) or writes (`"set"`) the `screen_off_timeout`, `sleep_timeout`, and `stay_on_while_plugged_in` Android settings so the device stays awake. + +### ADB install check + +A `postinstall` script checks for `adb` on the `PATH` and prints install instructions for Windows, macOS, and Linux when it is missing. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.0.0.md](./v1.0.0.md) — this changelog. +- README with ADB installation instructions, usage, API summary, and supported-device table. +- `docs/KEYBOARD_KEYS.md` and `docs/KEYCODES.md` key reference lists. + +--- + +## 🔧 Dependencies + +- `adbkit` 2.11.1 +- `jest` ^30.0.5 (dev) + +--- + +## Upgrade notes + +Initial release — nothing to upgrade from. diff --git a/docs/changelog/v1/v1.1.0.md b/docs/changelog/v1/v1.1.0.md new file mode 100644 index 0000000..656b3fa --- /dev/null +++ b/docs/changelog/v1/v1.1.0.md @@ -0,0 +1,49 @@ +# @cldmv/node-android-tv-remote v1.1.0 Changelog + +**Release Date**: July 2025 +**Release Type**: Minor + +--- + +## Overview + +Version 1.1.0 makes the directional keys work reliably, improves the guidance printed when an ADB connection fails, and adds an interactive device-setup script. + +No breaking changes. All v1.0.0 configuration and usage is fully compatible. + +--- + +## ✨ Features + +### `press.up/down/left/right` map to the D-pad keycodes + +`press.up()`, `press.down()`, `press.left()`, and `press.right()` (and their `press.long.*` forms) now send `dpadUp`, `dpadDown`, `dpadLeft`, and `dpadRight` explicitly. In v1.0.0 these looked up keycodes named `up`/`down`/`left`/`right` directly. + +### Better connection-failure guidance + +- Authentication failures (`failed to authenticate`, in addition to `device unauthorized`) now print extra recovery steps: reconnect or reboot the TV, remove the device from the authorized ADB list, and toggle ADB Debugging off and on. +- A refused connection (`actively refused` / `No connection could be made`) prints the steps for enabling Developer Options and ADB Debugging on Android TV and Fire TV. + +### Interactive device setup + +- `npm run setup-device` runs `scripts/setup-device.js`, which prompts for the device IP and port, applies the keep-awake settings, ensures the device is awake, and returns it to the home screen. +- `src/lib/adb/setup.js` adds an `AndroidTVSetup` helper used by the setup script and the test scripts. It is an internal helper, not part of the package's main export. + +--- + +## 🔧 CI & tooling + +- `test/connect-readall.js` now drives `AndroidTVSetup` instead of carrying its own copy of the settings logic. +- New `test/interactive-remote.js` script for manually exercising the remote buttons against a device. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.1.0.md](./v1.1.0.md) — this changelog. + +--- + +## Upgrade notes + +No breaking changes — drop-in for v1.0.0. diff --git a/docs/changelog/v1/v1.2.0.md b/docs/changelog/v1/v1.2.0.md new file mode 100644 index 0000000..ac95688 --- /dev/null +++ b/docs/changelog/v1/v1.2.0.md @@ -0,0 +1,58 @@ +# @cldmv/node-android-tv-remote v1.2.0 Changelog + +**Release Date**: July 2025 +**Release Type**: Minor + +--- + +## Overview + +Version 1.2.0 adds a persistent, self-healing ADB connection (heartbeat plus periodic connection checks) and connection-status helpers. It also changes two defaults in a way that is not backward compatible, even though it shipped as a minor release. + +--- + +## ✨ Features + +### Persistent connection with heartbeat and auto-reconnect + +New `RemoteConfig` options: + +- `maintainConnection` (default `true`) — keep the ADB connection alive while connected. +- `heartbeatInterval` (default `30000` ms) — how often a no-op shell command (`echo heartbeat`) is sent. +- `connectionCheckInterval` (default `30000` ms) — how often the device list is checked; if the device has dropped out of `adb devices`, the remote attempts to reconnect. + +The timers start on `connect()` and stop on `disconnect()`. + +### Connection status helpers + +- `getConnectionStatus([liveCheck])` resolves to `"connected"` or `"disconnected"` from internal state, or, with `liveCheck` set to `true`, queries `adb devices` and can also resolve to `"unknown"` if the query fails. +- `isConnected` reports the module's internal connection state without a live check. It is exposed as a function in this release, so call it as `remote.isConnected()`. + +--- + +## 💥 Breaking Changes + +This release shipped as a minor version but changes default behaviour. + +- **`autoDisconnect` now defaults to `false`.** In v1.0.0 and v1.1.0 the connection was dropped after `disconnectTimeout` seconds of inactivity unless disabled; now it stays open unless you pass `autoDisconnect: true`. +- **The remote now keeps timers running while connected.** With `maintainConnection` on by default, the heartbeat and connection-check intervals stay active after `connect()`, which can keep a Node process from exiting on its own until `disconnect()` is called. + +Upgrade steps: pass `autoDisconnect: true` to keep the previous idle-disconnect behaviour, pass `maintainConnection: false` to disable the heartbeat and reconnect timers, and make sure scripts call `remote.disconnect()` before they are expected to exit. + +--- + +## 🔧 CI & tooling + +- `test/interactive-remote.js` now uses the main remote module instead of the `AndroidTVSetup` helper. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.2.0.md](./v1.2.0.md) — this changelog. + +--- + +## Upgrade notes + +Not a pure drop-in for v1.1.0: review the `autoDisconnect` default and the new keep-alive timers described under Breaking Changes. Code that sets `autoDisconnect` explicitly and calls `disconnect()` when finished is unaffected. diff --git a/docs/changelog/v1/v1.3.0.md b/docs/changelog/v1/v1.3.0.md new file mode 100644 index 0000000..8e8ae26 --- /dev/null +++ b/docs/changelog/v1/v1.3.0.md @@ -0,0 +1,36 @@ +# @cldmv/node-android-tv-remote v1.3.0 Changelog + +**Release Date**: July 2025 +**Release Type**: Minor + +--- + +## Overview + +Version 1.3.0 expands the `press` interface with numpad, paging, and media keys. + +No breaking changes. All v1.2.0 configuration and usage is fully compatible. + +--- + +## ✨ Features + +### Numpad, paging, and media keys on `press` + +`src/data/remote-keys.json` gains 34 entries, each available as `press.()` and `press.long.()`: + +- Numpad: `numpad0` through `numpad9`, `numpadDivide`, `numpadMultiply`, `numpadSubtract`, `numpadAdd`, `numpadDot`, `numpadComma`, `numpadEnter`, `numpadEquals`, `numpadLeftParen`, `numpadRightParen` +- Paging: `pageUp`, `pageDown` +- Media: `mediaPlay`, `mediaPause`, `mediaClose`, `mediaEject`, `mediaRecord`, `mediaSkipForward`, `mediaSkipBackward`, `mediaStepForward`, `mediaStepBackward`, `mediaAudioTrack`, `mediaTopMenu` + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.3.0.md](./v1.3.0.md) — this changelog. + +--- + +## Upgrade notes + +No breaking changes — drop-in for v1.2.0. diff --git a/docs/changelog/v1/v1.4.0.md b/docs/changelog/v1/v1.4.0.md new file mode 100644 index 0000000..307121f --- /dev/null +++ b/docs/changelog/v1/v1.4.0.md @@ -0,0 +1,39 @@ +# @cldmv/node-android-tv-remote v1.4.0 Changelog + +**Release Date**: July 2025 +**Release Type**: Minor + +--- + +## Overview + +Version 1.4.0 makes the remote aware of a device that is already connected, so creating a remote against a connected device no longer starts from a stale "disconnected" state. + +No breaking changes. All v1.3.0 configuration and usage is fully compatible. + +--- + +## ✨ Features + +### Already-connected detection + +- When a remote is created, it runs a live `getConnectionStatus(true)` check; if the device is already connected, internal state is set to connected and the heartbeat and connection-check timers start. +- `connect()` now returns immediately when the remote already believes it is connected, instead of calling ADB again. + +--- + +## 🔧 CI & tooling + +- `test/connect-readall.js` checks whether the setup helper is already connected before calling `connect()`. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.4.0.md](./v1.4.0.md) — this changelog. + +--- + +## Upgrade notes + +No breaking changes — drop-in for v1.3.0. diff --git a/docs/changelog/v1/v1.5.0.md b/docs/changelog/v1/v1.5.0.md new file mode 100644 index 0000000..437cafd --- /dev/null +++ b/docs/changelog/v1/v1.5.0.md @@ -0,0 +1,33 @@ +# @cldmv/node-android-tv-remote v1.5.0 Changelog + +**Release Date**: July 2025 +**Release Type**: Minor + +--- + +## Overview + +Version 1.5.0 adds two introspection methods to the remote returned by `createRemote()`, so callers can discover which keyboard keys and press commands the live API exposes. Two new key names (`wakeup`, `enter`) are also added to the press command list. + +No breaking changes. All v1.4.0 configuration and usage is fully compatible. + +--- + +## ✨ Features + +- **`remote.getKeyboardKeys()`** — returns the names of every function on `remote.keyboard.key` (for example `"a"`, `"enter"`, `"space"`). It inspects the live object, so it always matches the real API surface, and it excludes the `keycode` and `shift` sub-objects. +- **`remote.getPressCommands()`** — returns the names of every press command on `remote.press`, including aliases, excluding `long`. +- **New press keys `wakeup` and `enter`** added to `src/data/remote-keys.json`. +- **API surface test** — `test/api-surface.test.js` covers both new methods. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.5.0.md](./v1.5.0.md) — this changelog. + +--- + +## Upgrade notes + +No breaking changes — drop-in for v1.4.0. diff --git a/docs/changelog/v1/v1.5.1.md b/docs/changelog/v1/v1.5.1.md new file mode 100644 index 0000000..35cfec1 --- /dev/null +++ b/docs/changelog/v1/v1.5.1.md @@ -0,0 +1,72 @@ +# @cldmv/node-android-tv-remote v1.5.1 Changelog + +**Release Date**: July 2025 +**Release Type**: Patch + +--- + +## Overview + +Version 1.5.1 adds five streaming-service keycodes and a `recall` press key, validates the `ip` option up front, and fixes the order of initialization inside the `createRemote()` factory. It also changes `isConnected` from a method to a plain property, which breaks callers of `remote.isConnected()` despite the patch version number — see Breaking Changes. + +--- + +## 💥 Breaking Changes + +### `isConnected` stopped being a method (shipped despite being a patch) + +In v1.5.0 `remote.isConnected` was a function; in v1.5.1 it is the boolean returned by `isConnected()` evaluated once, when `createRemote()` runs. Calling `remote.isConnected()` now throws `TypeError: remote.isConnected is not a function`, and the property is a fixed snapshot (`false` at creation) that never updates. v1.5.2 turns it into a live getter, but it remains a property, so the call form stays broken. + +Before (v1.5.0): + +```js +if (remote.isConnected()) { + // ... +} +``` + +After (v1.5.2 or later): + +```js +if (remote.isConnected) { + // ... +} +``` + +For a check against the device itself, use `await remote.getConnectionStatus(true)`. + +### `createRemote()` throws without `ip` + +The factory now throws `Error("Missing required 'ip' property in RemoteConfig.")` when called with no config, a non-object, or a config without `ip`. + +Before: `createRemote()` and `createRemote({})` were accepted. + +After: always pass `{ ip: "192.168.1.50" }` (plus any other options). + +--- + +## ✨ Features + +- **New keycodes** `azmNetflix` (290), `azmPrime` (291), `azmDirecttv` (292), `azmPeacock` (296) and `azmGuide` (297) in `src/data/keycodes.json`, exposed as press keys in `remote-keys.json`. +- **New press key `recall`.** +- **Type checking** — `src/lib/android-tv-remote.js` is now checked with `// @ts-check`, with typed `connect`, `disconnect` and `inputKeycode` signatures and usage examples in the JSDoc. + +--- + +## 🐛 Bug Fixes + +### Initial connection check runs after configuration is read + +The on-creation "already connected" check was declared at the top of the factory, before the connection state and options it reads had been set up, so its errors were swallowed by the surrounding `try`/`catch` and the check never took effect. It now runs after the configuration is parsed. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.5.1.md](./v1.5.1.md) — this changelog. + +--- + +## Upgrade notes + +Replace every `remote.isConnected()` call with the property form `remote.isConnected` and make sure `ip` is always supplied. Move straight to v1.5.2 so the property reflects live state. diff --git a/docs/changelog/v1/v1.5.2.md b/docs/changelog/v1/v1.5.2.md new file mode 100644 index 0000000..aea3411 --- /dev/null +++ b/docs/changelog/v1/v1.5.2.md @@ -0,0 +1,54 @@ +# @cldmv/node-android-tv-remote v1.5.2 Changelog + +**Release Date**: July 2025 +**Release Type**: Patch + +--- + +## Overview + +Version 1.5.2 makes `isConnected` a getter property, so it reflects the current connection state instead of the snapshot taken at creation in v1.5.1. It is a one-line change, but it settles the property form that broke `remote.isConnected()` callers in v1.5.1. + +--- + +## 💥 Breaking Changes + +### `isConnected` is a getter, not a method (shipped despite being a patch) + +`remote.isConnected` is now a getter that returns the module's tracked connection state. Code written against v1.5.0 or earlier that calls it as a function fails with `TypeError: remote.isConnected is not a function`. + +Before (v1.5.0 and earlier): + +```js +if (remote.isConnected()) { + // ... +} +``` + +After: + +```js +if (remote.isConnected) { + // ... +} +``` + +The value is the internal state, not a live check. `await remote.getConnectionStatus(true)` queries `adb devices`. + +--- + +## 🐛 Bug Fixes + +- `remote.isConnected` now tracks connect and disconnect events over the life of the remote instead of staying at its creation-time value. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.5.2.md](./v1.5.2.md) — this changelog. + +--- + +## Upgrade notes + +Drop the parentheses on every `isConnected` call. Otherwise drop-in for v1.5.1. diff --git a/docs/changelog/v1/v1.5.3.md b/docs/changelog/v1/v1.5.3.md new file mode 100644 index 0000000..17c16ae --- /dev/null +++ b/docs/changelog/v1/v1.5.3.md @@ -0,0 +1,36 @@ +# @cldmv/node-android-tv-remote v1.5.3 Changelog + +**Release Date**: July 2025 +**Release Type**: Patch + +--- + +## Overview + +Version 1.5.3 keeps the internal connection state in sync when a live connection check runs, and fixes the interactive test script to use the factory API. + +No breaking changes. All v1.5.2 configuration and usage is fully compatible. + +--- + +## 🐛 Bug Fixes + +### `getConnectionStatus(true)` updates the tracked state + +A live check (`await remote.getConnectionStatus(true)`) now sets the internal connected flag to match what `adb devices` reports, and clears it if the check fails. Before, a live check could report `"connected"` or `"disconnected"` while `remote.isConnected` kept its previous value. + +### Interactive test script + +`test/interactive-remote.js` now calls `createRemote({ ip, port })` and then `remote.connect()`, instead of calling `connect({ ip, port })` on the module export. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.5.3.md](./v1.5.3.md) — this changelog. + +--- + +## Upgrade notes + +No breaking changes — drop-in for v1.5.2. diff --git a/docs/changelog/v1/v1.5.4.md b/docs/changelog/v1/v1.5.4.md new file mode 100644 index 0000000..c036017 --- /dev/null +++ b/docs/changelog/v1/v1.5.4.md @@ -0,0 +1,51 @@ +# @cldmv/node-android-tv-remote v1.5.4 Changelog + +**Release Date**: July 2025 +**Release Type**: Patch + +--- + +## Overview + +Version 1.5.4 changes how connection errors are surfaced. `connect()` and `disconnect()` no longer terminate the host process for every failure, and they now resolve with values. Because those return values and error paths changed in a patch release, callers that relied on the old behavior should read Breaking Changes. + +--- + +## 💥 Breaking Changes + +### Connection errors no longer always call `process.exit(1)` (shipped despite being a patch) + +Through v1.5.3, any error handled by the internal `handleDisconnectError()` ended with `process.exit(1)`. In v1.5.4 only the two cases with onboarding instructions still exit the process: an unauthorized or unauthenticated device, and a refused connection. Every other connect or disconnect error is logged and the promise resolves with the `Error` object itself rather than rejecting. + +Before: a failed `connect()` with, say, a timeout killed the process, so code after `await remote.connect()` never ran on failure. + +After: `await remote.connect()` can return with `connected` still false, and the resolved value is an `Error`. + +```js +const result = await remote.connect(); +if (result instanceof Error) { + // handle the failure; the promise did not reject +} +``` + +### `connect()` and `disconnect()` resolve `true` in the already-connected and already-disconnected cases + +Those two branches previously resolved `undefined`; they now resolve `true`. A normal successful `connect()` still resolves `undefined`. Code that compared the result to `undefined` should be updated. + +--- + +## ✨ Features + +- **`scripts/test-keycodes.js`** — a helper script for exercising keycodes against a device. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.5.4.md](./v1.5.4.md) — this changelog. + +--- + +## Upgrade notes + +Audit anything that awaits `connect()` or `disconnect()`: check the resolved value for an `Error`, and do not assume a failure stops the process. diff --git a/docs/changelog/v1/v1.5.5.md b/docs/changelog/v1/v1.5.5.md new file mode 100644 index 0000000..e8f5a74 --- /dev/null +++ b/docs/changelog/v1/v1.5.5.md @@ -0,0 +1,53 @@ +# @cldmv/node-android-tv-remote v1.5.5 Changelog + +**Release Date**: July 2025 +**Release Type**: Patch + +--- + +## Overview + +Version 1.5.5 exposes `remote.initPromise`, which settles with the result of the connection attempt made when `createRemote()` runs. That attempt now connects the device if it is not already connected. Because it runs at creation and can reject, treat this as a behavior change despite the patch number. + +--- + +## 💥 Breaking Changes + +### Initialization connects automatically, and a failed attempt rejects `initPromise` (shipped despite being a patch) + +When `createRemote()` is called it checks the device with a live status check. In v1.5.4 and earlier a "not connected" result did nothing and errors were ignored. In v1.5.5 a not-connected result calls `connect()`, and the outcome goes to `initPromise`: it resolves when connected and rejects with `Error("Failed to connect to device on initialization.")` (or the underlying error) otherwise. This runs regardless of the `autoConnect` option. + +A rejected promise with no handler is an unhandled rejection, which terminates the process on current Node.js versions. Callers that create a remote while the device is unreachable should attach a handler: + +```js +const remote = createRemote({ ip: "192.168.1.50" }); +remote.initPromise.catch((err) => { + console.error("TV not reachable:", err.message); +}); +``` + +--- + +## ✨ Features + +- **`remote.initPromise`** — `Promise` that resolves if the initial connection succeeds and rejects if it fails. + +```js +remote.initPromise + .then(() => remote.press.home()) + .catch((err) => { + /* ... */ + }); +``` + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.5.5.md](./v1.5.5.md) — this changelog. + +--- + +## Upgrade notes + +Always attach a `.catch()` to `remote.initPromise` (or `await` it inside `try`/`catch`) whenever the device may be offline when the remote is created. diff --git a/docs/changelog/v2/v2.0.0.md b/docs/changelog/v2/v2.0.0.md new file mode 100644 index 0000000..058d75f --- /dev/null +++ b/docs/changelog/v2/v2.0.0.md @@ -0,0 +1,78 @@ +# @cldmv/node-android-tv-remote v2.0.0 Changelog + +**Release Date**: October 2025 +**Release Type**: Major + +--- + +## Overview + +Version 2.0.0 turns the library into an ES module with a CommonJS entry, moves from the unmaintained `adbkit` 2.x to `@devicefarmer/adbkit` 3.x, and replaces console output with an event-driven model. Every remote is now an event source: operations report through structured `log` events and failures through structured `error` events, instead of printing to the console or exiting the process. + +The command surface (`press`, `keyboard`, `inputKeycode`, `handleSettings`, `connect` / `disconnect`) carries over from 1.5.x. What changes is how the package is loaded, how it reports, and how initialization behaves. + +--- + +## 💥 Breaking Changes + +### ES module package with an `exports` map + +`package.json` now sets `"type": "module"` and an `exports` map (`import` → `index.mjs`, `require` → `index.cjs`) in place of `"main": "src/lib/android-tv-remote.js"`. Source files were renamed from `.js` to `.mjs`. + +- `import createRemote from "@cldmv/node-android-tv-remote"` and `require("@cldmv/node-android-tv-remote")` both return the `createRemote` factory. +- Deep imports of internal files (for example `.../src/lib/android-tv-remote.js`) no longer resolve; import from the package root. +- The CommonJS entry loads `index.mjs` through `require()`, which only works on Node.js versions with `require(esm)` (^20.19.0 or >=22.12.0). On older Node.js, load the package with `import()`. (v2.1.7 later made this fail with a clear message.) + +### Console output replaced by `log` and `error` events + +The library no longer writes to the console or calls `process.exit()`. Each remote exposes `on`, `off` and `once` (all chainable) and `emit`, and reports through two events: + +- `log` — `{ level, message, source, timestamp, data? }`, with `level` one of `info`, `warn`, `error` or `debug`. Suppressed when `quiet` is true (the default), apart from errors. +- `error` — `{ error, source, message, timestamp }`. + +The emitter is a Node.js `EventEmitter`, so an `error` event with no listener attached throws. Attach an `error` listener on every remote: + +```js +import createRemote from "@cldmv/node-android-tv-remote"; + +const remote = createRemote({ ip: "192.168.1.100" }); +remote.on("log", (e) => console.log(`[${e.level}] ${e.source}: ${e.message}`)); +remote.on("error", (e) => console.error(e.source, e.error.message)); + +await remote.press.home(); +``` + +### `autoConnect: false` no longer connects at creation + +In 1.5.5, `createRemote()` started connecting at creation even with `autoConnect: false`. Initialization now honours the option: with `autoConnect: false`, `initPromise` resolves immediately and nothing connects until `connect()` is called. + +--- + +## ✨ Features + +- **`createAndroidTVRemote(config)`** — an async factory that resolves once initialization has finished; also available as `createRemote.create`. Exported by name from the ESM entry. +- **`connectTimeout`** option (default `10000` ms) bounds each ADB connection attempt, and initialization times out instead of hanging when a device never answers. +- **`AndroidTVSetup`** is exported from the package entry (ESM and CommonJS) for device-setup scripting. +- Clearer onboarding messages, sent as `log` events, for unauthorized devices and refused connections. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v2/v2.0.0.md](./v2.0.0.md) — this changelog. +- README — new key-features list, ESM and CommonJS usage, an event-driven usage guide, the event data shapes, and lists of the main methods, event methods and properties. + +--- + +## 🔧 Dependencies + +- `adbkit` 2.11.1 → `@devicefarmer/adbkit` ^3.3.8 (maintained fork, same ADB protocol). + +--- + +## Upgrade notes + +1. Load the package from its root with `import` (any supported Node.js) or `require` (Node.js ^20.19.0 or >=22.12.0); remove deep imports of internal files. +2. Attach an `error` listener to every remote, and a `log` listener if you relied on the console output. +3. If you passed `autoConnect: false`, call `connect()` yourself before sending commands (the commands still auto-connect only when `autoConnect` is true). +4. Optionally switch to `await createAndroidTVRemote(config)` to get a remote that has finished initializing. diff --git a/docs/changelog/v2/v2.1.0.md b/docs/changelog/v2/v2.1.0.md new file mode 100644 index 0000000..54b12de --- /dev/null +++ b/docs/changelog/v2/v2.1.0.md @@ -0,0 +1,99 @@ +# @cldmv/node-android-tv-remote v2.1.0 Changelog + +**Release Date**: October 2025 +**Release Type**: Minor + +--- + +## Overview + +Version 2.1.0 adds screen capture, device power and boot management, and a reworked keyboard API. Screenshots come back as PNG streams (optionally resized through `sharp`) or are saved to disk, and new `ensureAwake()`, `reboot()` and `waitBootComplete()` methods manage the device's power state. + +The release also changes the API shape in ways that break existing callers despite the minor version number: `createRemote()` is now async, `handleSettings()` became `setSettings()`, `keyboard.key` was cut down to typeable characters only, and `AndroidTVSetup` is no longer exported. Each is covered under **Breaking Changes** below. + +--- + +## ✨ Features + +### Screen capture: `screencap()`, `thumbnail()` and `lastScreencapData` + +- `screencap({ width?, height?, filepath? })` captures the screen. Without `filepath` it resolves to a PNG stream; with `filepath` it saves the image in the background and resolves when the save has been started. `width` / `height` resize through `sharp`; without them the ADB PNG stream is piped straight through, skipping image processing. +- `thumbnail({ width = 240, height?, filepath? })` calls `screencap()` with a 240 px default width. +- `lastScreencapData` holds the most recent processed screenshot stream. +- Concurrent calls each get their own ADB stream, and progress is reported through `screencap-start`, `screencap-captured`, `screencap-processing`, `screencap-ready`, `screencap-saved` and `screencap-complete` events. + +### Power and boot management + +- `ensureAwake()` checks the device's power state, wakes it if needed and resolves `true` when it is ready. +- `reboot()` reboots the device through ADB's native reboot. +- `waitBootComplete(timeout = 60000)` resolves `true` once the device has finished booting. +- New `scripts/wake-tv.mjs` utility. + +### Keyboard character map + +`keyboard.key` is now built from a new `src/data/keyboard-keys.json` map of 71 typeable characters (letters, digits, symbols and control characters), and `keyboard.key.shift` holds shifted variants only for the 47 keys whose output actually changes with shift. `.keycode()` methods are created only where a keycode exists. + +--- + +## 💥 Breaking Changes + +All of the following shipped in a minor release. + +### `createRemote()` returns a Promise + +`createRemote()` is now an `async` function that resolves to the remote once it is initialized, so `createAndroidTVRemote()` becomes a plain alias. Code that used the return value directly breaks: + +```js +// 2.0.x +const remote = createRemote({ ip: "192.168.1.100" }); + +// 2.1.0 +const remote = await createRemote({ ip: "192.168.1.100" }); +``` + +This applies to the CommonJS entry too: `require("@cldmv/node-android-tv-remote")` returns the async factory. + +### `handleSettings(mode, overrideQuiet)` renamed to `setSettings(mode = "set")` + +`handleSettings` is gone. Call `remote.setSettings()` to apply the recommended settings, or `remote.setSettings("get")` to read the current values. + +### `keyboard.key` holds typeable characters only + +In 2.0.x, `keyboard.key` exposed every Android keycode (273 keys, including remote buttons such as `home`, `back`, `power` and the D-pad), each with a `shift` variant and a `.keycode()` method. In 2.1.0 it holds only the 71 typeable characters, `keyboard.key.shift` only the 47 characters that change with shift, and shifted keys no longer have `.keycode()` methods (ADB can't send a keycode combination). Move remote-button calls to `remote.press.()`, and send shifted characters through `keyboard.key.shift.()` or `keyboard.text()`. + +### `AndroidTVSetup` is no longer exported + +The `AndroidTVSetup` helper and its source file (`src/lib/adb/setup.mjs`) were removed, along with its named export from both entries. + +### New native dependency and Node.js floor + +`sharp` ^0.34.4 is now a runtime dependency, so installation pulls a platform-specific native binary. `package.json` declares `engines.node` `^18.17.0 || ^20.3.0 || >=21.0.0`, and the package now publishes only `src/`, `scripts/`, the two entry files and the README (`files`), so the `test/` and `docs/` folders no longer ship in the npm package. + +--- + +## 🐛 Bug Fixes + +- Remote-control buttons no longer appear in the `keyboard` namespace, and invalid shift-keycode methods are no longer generated. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v2/v2.1.0.md](./v2.1.0.md) — this changelog. +- README — documents screen capture, device management (`ensureAwake`, `reboot`, `waitBootComplete`), async initialization and the keyboard model. + +--- + +## 🔧 Dependencies + +- Added `sharp` ^0.34.4 (runtime) for screenshot resizing. + +--- + +## Upgrade notes + +1. `await` every `createRemote()` call (ESM and CommonJS). +2. Replace `handleSettings(mode)` with `setSettings(mode)`; the `"get"` mode is unchanged, and `"set"` is the default. +3. Move remote-button calls from `keyboard.key.