@buoy-gg/tv-remote 7.0.36 → 7.0.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,89 +1,61 @@
1
1
  # @buoy-gg/tv-remote
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/@buoy-gg/tv-remote?style=flat-square&labelColor=1c1c1c&color=10B981)](https://www.npmjs.com/package/@buoy-gg/tv-remote) [![npm downloads](https://img.shields.io/npm/dm/@buoy-gg/tv-remote?style=flat-square&labelColor=1c1c1c&color=10B981)](https://www.npmjs.com/package/@buoy-gg/tv-remote)
3
+ Record remote events received by a React Native TV app and inspect them in Buoy Desktop. Desktop can send supported host-side input and replay recorded sequences. The device package observes events; it does not inject hardware presses itself.
4
4
 
5
- **Press the TV remote from Buoy Desktop — drive your Apple TV / Android TV app's D-pad, record press sequences as macros, and replay them across every connected device.**
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @buoy-gg/core @buoy-gg/external-sync @buoy-gg/tv-remote
9
+ ```
6
10
 
7
- Part of [Buoy](https://github.com/Buoy-gg/buoy) — devtools that live inside your React Native app. Install it and the TV Remote panel lights up in Buoy Desktop for that device.
11
+ ## Account setup
8
12
 
9
- ## Install
13
+ Start in a development build with a Free or Pro Buoy account key. From the app directory:
10
14
 
11
15
  ```bash
12
- npm install @buoy-gg/core @buoy-gg/tv-remote
16
+ npx --package=@buoy-gg/core buoy login
13
17
  ```
14
18
 
19
+ For Expo, initialize Buoy with the key written to `.env.local`:
20
+
15
21
  ```tsx
16
- import { FloatingDevTools } from "@buoy-gg/core";
22
+ import { Buoy } from "@buoy-gg/core";
17
23
 
18
- export default function App() {
19
- return (
20
- <>
21
- {/* your app */}
22
- <FloatingDevTools headless /> {/* TV apps run headless — no bubble */}
23
- </>
24
- );
25
- }
24
+ Buoy.init({ licenseKey: process.env.EXPO_PUBLIC_BUOY_KEY });
26
25
  ```
27
26
 
28
- ## What this package does — and deliberately does not
29
-
30
- This package **only observes**. It captures the remote events your app receives
31
- (`up`/`down`/`left`/`right`/`select`/`menu`/`playPause`) and streams them to Buoy Desktop.
27
+ For React Native CLI, pass the key through your app's environment configuration; `.env.local` is not loaded automatically. Keep the menu inside the providers used by your app. Restart the development server after installing packages. See the [Quick Start](https://buoy.gg/buoy/latest/docs/quick-start) for the complete root component.
32
28
 
33
- **Presses are injected from the host**, by Buoy Desktop shelling out to `adb shell input keyevent`
34
- (Android TV) or `idb ui key` (Apple TV simulator). That is the only honest path:
29
+ ## Connect a TV app
35
30
 
36
- - On tvOS, the two things an app *can* do in-process are post the internal `onHWKeyEvent`
37
- notification (fires the JS event, but focus never moves) and `requestTVFocus` (jumps focus,
38
- but fires no event and traverses nothing). Each is half of a press, and the missing half is
39
- the half QA cares about.
40
- - On Android, directional focus navigation for unconsumed D-pad keys happens in `ViewRootImpl`,
41
- *above* the Activity — so an in-process `dispatchKeyEvent` would fire JS events **without
42
- moving focus** exactly on the screens that are broken.
31
+ Use a compatible react-native-tvos app and follow the [TV installation guide](https://buoy.gg/buoy/latest/docs/tv/installation). Mount the core integration after account initialization:
43
32
 
44
- Host-side injection goes through `InputManager` / the simulator's HID layer — the same pipeline
45
- as a physical remote, driving the real focus engine.
33
+ ```tsx
34
+ import { FloatingDevTools } from "@buoy-gg/core";
46
35
 
47
- The package also renders **nothing**. On Android TV any focusable view in an overlay becomes a
48
- D-pad stop in the host app's focus order, so a visible tool would alter the navigation it is
49
- supposed to be testing.
36
+ <FloatingDevTools headless />;
37
+ ```
50
38
 
51
- ## Support matrix
39
+ Keep the TV app headless so a focusable developer overlay does not interfere with its navigation. Open Desktop, sign in, select the device, and open the tool's panel. A phone build is not a substitute for testing TV behavior.
52
40
 
53
- | Target | Drive-able? | Via |
54
- |---|---|---|
55
- | Android TV emulator | ✅ full fidelity | `adb -s <serial> shell input keyevent` |
56
- | Android TV device | ✅ full fidelity | same, over `adb connect <ip>:5555` |
57
- | Apple TV simulator | ✅ arrows / select / menu — ❌ play-pause | `idb ui key --udid <udid>` |
58
- | Apple TV device | ❌ replay unsupported — **record only** | (future: an XCUITest `XCUIRemote` companion) |
41
+ ## Capture and replay
59
42
 
60
- Capture is pure JS and works on every target, including retail hardware — so the
61
- **record-on-retail** workflow holds: press the physical remote on a rack device, get a macro,
62
- replay it against emulators and simulators.
43
+ Arm recording in Desktop, press a short sequence on the physical or simulated remote, and compare the received events with the app's behavior. Disarm when done. Menu capture on tvOS is opt-in and is released on disarm.
63
44
 
64
- `idb` is not part of Xcode. Without it on `PATH` the Apple TV lane is disabled with an install
65
- hint (`brew install idb-companion` + `pipx install fb-idb`).
45
+ | Target | Host input support |
46
+ | --- | --- |
47
+ | Android TV emulator or authorized device | adb input key events; the host must be able to reach the target. |
48
+ | Apple TV simulator | idb arrows, select, and menu; play/pause is unsupported in this path. |
49
+ | Physical Apple TV | Record received events; host replay is unsupported. |
66
50
 
67
- ## API
51
+ The Apple TV simulator lane requires idb separately from Xcode. Follow Desktop diagnostics and the TV guide for host setup. Capture depends on supported TV event APIs and account access; it does not guarantee every OS-level remote event reaches JavaScript.
68
52
 
69
- Everything is driven from Buoy Desktop; these exports exist for custom integrations.
53
+ For custom integrations, exports include `arm`, `disarm`, `clear`, `setMenuCapture`, `getEventsSince`, `getState`, `subscribe`, and `tvRemoteSyncAdapter`. Check `getState().supported` before treating a platform as available.
70
54
 
71
- ```ts
72
- import {
73
- arm, // start capturing
74
- disarm, // stop capturing, hand the Menu key back to the platform
75
- clear,
76
- setMenuCapture, // tvOS: route Menu to JS (opt-in, always undone on disarm)
77
- getEventsSince, // (seq) => events newer than seq
78
- getState,
79
- subscribe,
80
- tvRemoteSyncAdapter, // auto-discovered by @buoy-gg/core
81
- } from "@buoy-gg/tv-remote";
82
- ```
55
+ [Full TV Remote guide](https://buoy.gg/buoy/latest/docs/tools/tv-remote)
83
56
 
84
- On non-TV platforms `getState().supported` is `false`, the native listener is never attached,
85
- and the package costs one boolean.
57
+ ## Desktop and MCP
86
58
 
87
- ## Docs
59
+ React Native connections require `@buoy-gg/external-sync`. Follow the [Desktop connection guide](https://buoy.gg/buoy/latest/docs/desktop), sign in to Desktop separately, and confirm the selected device. [MCP](https://buoy.gg/buoy/latest/docs/mcp) also needs a process account and Pro access.
88
60
 
89
- Full documentation: <https://buoy.gg/buoy/latest/docs/tools/tv-remote>
61
+ Device data can travel over your LAN to the configured broker. Account validation makes network requests. See [Telemetry](https://buoy.gg/buoy/latest/docs/telemetry) for data-flow details.
@@ -1,56 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- Object.defineProperty(exports, "arm", {
7
- enumerable: true,
8
- get: function () {
9
- return _tvEventStore.arm;
10
- }
11
- });
12
- Object.defineProperty(exports, "clear", {
13
- enumerable: true,
14
- get: function () {
15
- return _tvEventStore.clear;
16
- }
17
- });
18
- Object.defineProperty(exports, "disarm", {
19
- enumerable: true,
20
- get: function () {
21
- return _tvEventStore.disarm;
22
- }
23
- });
24
- Object.defineProperty(exports, "getEventsSince", {
25
- enumerable: true,
26
- get: function () {
27
- return _tvEventStore.getEventsSince;
28
- }
29
- });
30
- Object.defineProperty(exports, "getState", {
31
- enumerable: true,
32
- get: function () {
33
- return _tvEventStore.getState;
34
- }
35
- });
36
- Object.defineProperty(exports, "setMenuCapture", {
37
- enumerable: true,
38
- get: function () {
39
- return _tvEventStore.setMenuCapture;
40
- }
41
- });
42
- Object.defineProperty(exports, "subscribe", {
43
- enumerable: true,
44
- get: function () {
45
- return _tvEventStore.subscribe;
46
- }
47
- });
48
- Object.defineProperty(exports, "tvRemoteSyncAdapter", {
49
- enumerable: true,
50
- get: function () {
51
- return _tvRemoteSyncAdapter.tvRemoteSyncAdapter;
52
- }
53
- });
54
- var _tvRemoteSyncAdapter = require("./sync/tvRemoteSyncAdapter");
55
- var _tvEventStore = require("./store/tvEventStore");
56
- //# sourceMappingURL=index.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"arm",{enumerable:!0,get:function(){return _tvEventStore.arm}}),Object.defineProperty(exports,"clear",{enumerable:!0,get:function(){return _tvEventStore.clear}}),Object.defineProperty(exports,"disarm",{enumerable:!0,get:function(){return _tvEventStore.disarm}}),Object.defineProperty(exports,"getEventsSince",{enumerable:!0,get:function(){return _tvEventStore.getEventsSince}}),Object.defineProperty(exports,"getState",{enumerable:!0,get:function(){return _tvEventStore.getState}}),Object.defineProperty(exports,"setMenuCapture",{enumerable:!0,get:function(){return _tvEventStore.setMenuCapture}}),Object.defineProperty(exports,"subscribe",{enumerable:!0,get:function(){return _tvEventStore.subscribe}}),Object.defineProperty(exports,"tvRemoteSyncAdapter",{enumerable:!0,get:function(){return _tvRemoteSyncAdapter.tvRemoteSyncAdapter}});var _tvRemoteSyncAdapter=require("./sync/tvRemoteSyncAdapter"),_tvEventStore=require("./store/tvEventStore");
@@ -1,167 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.arm = arm;
7
- exports.clear = clear;
8
- exports.disarm = disarm;
9
- exports.getEventsSince = getEventsSince;
10
- exports.getState = getState;
11
- exports.setMenuCapture = setMenuCapture;
12
- exports.subscribe = subscribe;
13
- var ReactNative = _interopRequireWildcard(require("react-native"));
14
- function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
15
- /**
16
- * tvEventStore — the whole device-side half of the TV remote tool.
17
- *
18
- * CONTRACT: this store only ever OBSERVES. It never injects, synthesizes, or
19
- * fakes a remote press. Presses come from the host (Buoy Desktop shells out to
20
- * `adb shell input keyevent` / `idb ui key`), because those go through the real
21
- * platform focus engine; anything we could fake in-process would move focus
22
- * without firing events, or fire events without moving focus. See
23
- * TV_REMOTE_DRIVER_PLAN.md §2.
24
- *
25
- * It is also deliberately UI-less. On Android TV any focusable view we rendered
26
- * would become a D-pad stop in the host app's focus order, so the tool would
27
- * alter the navigation it is supposed to be replaying.
28
- *
29
- * Safe to ship in non-TV apps: the native event emitter is never touched unless
30
- * `Platform.isTV` is true, so the cost on a phone is one boolean.
31
- */
32
-
33
- /** One captured remote event, as it goes over the wire to the dashboard. */
34
-
35
- /**
36
- * Ring buffer depth. Replay polls `getEventsSince` every few dozen ms with a
37
- * ~2s budget per step, so 50 is many times more than any echo needs; it exists
38
- * so a human scrubbing the echo strip has some scrollback.
39
- */
40
- const MAX_EVENTS = 50;
41
-
42
- /**
43
- * Continuous gestures are not presses and are never recorded — the macro format
44
- * is discrete keys. Dropping them here keeps them out of the ring buffer so
45
- * they can't push real presses out of it during a replay.
46
- */
47
- const IGNORED_EVENT_TYPES = new Set(["pan", "swipeUp", "swipeDown", "swipeLeft", "swipeRight"]);
48
- /**
49
- * `TVEventHandler` / `TVEventControl` only exist on the react-native-tvos fork.
50
- * A namespace read (rather than a named import) keeps this module importable on
51
- * stock react-native, where those exports are absent.
52
- */
53
- const RN = ReactNative;
54
- const isTV = RN.Platform?.isTV === true;
55
- let events = [];
56
- let seq = 0;
57
- let armed = false;
58
- let menuCaptureArmed = false;
59
- let subscription = null;
60
- const listeners = new Set();
61
- function emitChange() {
62
- listeners.forEach(listener => {
63
- listener();
64
- });
65
- }
66
- function handleEvent(raw) {
67
- // Disarming removes the subscription, but don't take that on trust: a native
68
- // emitter that delivered one more event after `remove()` would land a stray
69
- // press in the buffer, and a stray press is exactly what a replay would
70
- // mistake for a step's echo.
71
- if (!armed) return;
72
- const event = raw;
73
- const eventType = event?.eventType;
74
- if (typeof eventType !== "string") return;
75
- if (IGNORED_EVENT_TYPES.has(eventType)) return;
76
-
77
- /**
78
- * Dedupe by ignoring key DOWN, never key UP. tvOS emits keyAction 1 (up)
79
- * ONLY — taps reach the gesture recognizer at StateEnded — so filtering to
80
- * "down" would swallow every tvOS event. Android's down-emit is
81
- * feature-flagged off by default, but dropping it here is the correct
82
- * invariant either way: one press must produce exactly one echo.
83
- */
84
- if (event?.eventKeyAction === 0) return;
85
- seq += 1;
86
- const next = {
87
- seq,
88
- t: Date.now(),
89
- eventType,
90
- eventKeyAction: event?.eventKeyAction
91
- };
92
- events = events.length >= MAX_EVENTS ? [...events.slice(1), next] : [...events, next];
93
- emitChange();
94
- }
95
-
96
- /** Start pushing remote events into the buffer. Idempotent. */
97
- function arm() {
98
- if (armed) return;
99
- armed = true;
100
- if (isTV && RN.TVEventHandler && !subscription) {
101
- subscription = RN.TVEventHandler.addListener(handleEvent);
102
- }
103
- emitChange();
104
- }
105
-
106
- /**
107
- * Stop capturing and hand the Menu key back to the platform. Every teardown
108
- * path funnels through here — leaving menu capture on would leave the app
109
- * unable to navigate back, which is an App Store behavior change.
110
- */
111
- function disarm() {
112
- if (subscription) {
113
- subscription.remove();
114
- subscription = null;
115
- }
116
- if (menuCaptureArmed) setMenuCapture(false);
117
- if (!armed) return;
118
- armed = false;
119
- emitChange();
120
- }
121
-
122
- /**
123
- * tvOS: route the Menu key to JS so it can be recorded, instead of letting it
124
- * pop the navigation stack (and background the app at the root). This changes
125
- * how the app under test behaves, so it is opt-in per recording session and is
126
- * always undone on disarm.
127
- */
128
- function setMenuCapture(on) {
129
- if (!isTV || RN.Platform.OS !== "ios" || !RN.TVEventControl) return;
130
- if (on === menuCaptureArmed) return;
131
- if (on) {
132
- RN.TVEventControl.enableTVMenuKey();
133
- } else {
134
- RN.TVEventControl.disableTVMenuKey();
135
- }
136
- menuCaptureArmed = on;
137
- emitChange();
138
- }
139
- function clear() {
140
- if (events.length === 0) return;
141
- events = [];
142
- emitChange();
143
- }
144
-
145
- /** Events strictly newer than `sinceSeq` — the replay echo cursor. */
146
- function getEventsSince(sinceSeq) {
147
- if (!Number.isFinite(sinceSeq)) return events.slice();
148
- return events.filter(event => event.seq > sinceSeq);
149
- }
150
- function getState() {
151
- return {
152
- supported: isTV,
153
- platform: RN.Platform?.OS ?? "unknown",
154
- captureArmed: armed,
155
- listening: subscription !== null,
156
- menuCaptureArmed,
157
- seq,
158
- recent: events.slice()
159
- };
160
- }
161
- function subscribe(listener) {
162
- listeners.add(listener);
163
- return () => {
164
- listeners.delete(listener);
165
- };
166
- }
167
- //# sourceMappingURL=tvEventStore.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.arm=arm,exports.clear=clear,exports.disarm=disarm,exports.getEventsSince=getEventsSince,exports.getState=getState,exports.setMenuCapture=setMenuCapture,exports.subscribe=subscribe;var ReactNative=_interopRequireWildcard(require("react-native"));function _interopRequireWildcard(e,t){if("function"==typeof WeakMap)var n=new WeakMap,r=new WeakMap;return(_interopRequireWildcard=function(e,t){if(!t&&e&&e.__esModule)return e;var i,s,a={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return a;if(i=t?r:n){if(i.has(e))return i.get(e);i.set(e,a)}for(const t in e)"default"!==t&&{}.hasOwnProperty.call(e,t)&&((s=(i=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,t))&&(s.get||s.set)?i(a,t,s):a[t]=e[t]);return a})(e,t)}const MAX_EVENTS=50,IGNORED_EVENT_TYPES=new Set(["pan","swipeUp","swipeDown","swipeLeft","swipeRight"]),RN=ReactNative,isTV=!0===RN.Platform?.isTV;let events=[],seq=0,armed=!1,menuCaptureArmed=!1,subscription=null;const listeners=new Set;function emitChange(){listeners.forEach(e=>{e()})}function handleEvent(e){if(!armed)return;const t=e,n=t?.eventType;if("string"!=typeof n)return;if(IGNORED_EVENT_TYPES.has(n))return;if(0===t?.eventKeyAction)return;seq+=1;const r={seq:seq,t:Date.now(),eventType:n,eventKeyAction:t?.eventKeyAction};events=events.length>=50?[...events.slice(1),r]:[...events,r],emitChange()}function arm(){armed||(armed=!0,isTV&&RN.TVEventHandler&&!subscription&&(subscription=RN.TVEventHandler.addListener(handleEvent)),emitChange())}function disarm(){subscription&&(subscription.remove(),subscription=null),menuCaptureArmed&&setMenuCapture(!1),armed&&(armed=!1,emitChange())}function setMenuCapture(e){isTV&&"ios"===RN.Platform.OS&&RN.TVEventControl&&e!==menuCaptureArmed&&(e?RN.TVEventControl.enableTVMenuKey():RN.TVEventControl.disableTVMenuKey(),menuCaptureArmed=e,emitChange())}function clear(){0!==events.length&&(events=[],emitChange())}function getEventsSince(e){return Number.isFinite(e)?events.filter(t=>t.seq>e):events.slice()}function getState(){return{supported:isTV,platform:RN.Platform?.OS??"unknown",captureArmed:armed,listening:null!==subscription,menuCaptureArmed:menuCaptureArmed,seq:seq,recent:events.slice()}}function subscribe(e){return listeners.add(e),()=>{listeners.delete(e)}}
@@ -1,57 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.tvRemoteSyncAdapter = void 0;
7
- var _tvEventStore = require("../store/tvEventStore");
8
- /**
9
- * tvRemoteSyncAdapter — streams captured TV remote events to Buoy Desktop via
10
- * @buoy-gg/external-sync.
11
- *
12
- * Structurally matches external-sync's `ToolSyncAdapter` WITHOUT importing the
13
- * package (same as every other tool's adapter). Auto-discovery in @buoy-gg/core
14
- * picks it up by export name and announces the "tv-remote" capability.
15
- *
16
- * `getEventsSince` exists because snapshots are throttled 200ms trailing-edge
17
- * per tool, which is too coarse to time a replay step's echo. Replay polls this
18
- * awaited action instead and gets the real latency.
19
- */
20
-
21
- const tvRemoteSyncAdapter = exports.tvRemoteSyncAdapter = {
22
- version: 1,
23
- getSnapshot() {
24
- return (0, _tvEventStore.getState)();
25
- },
26
- subscribe(onChange) {
27
- return (0, _tvEventStore.subscribe)(onChange);
28
- },
29
- actions: {
30
- arm() {
31
- (0, _tvEventStore.arm)();
32
- return (0, _tvEventStore.getState)();
33
- },
34
- disarm() {
35
- (0, _tvEventStore.disarm)();
36
- return (0, _tvEventStore.getState)();
37
- },
38
- /** Cursor-paged echo poll. `seq: 0` returns everything buffered. */
39
- getEventsSince(params) {
40
- const since = typeof params?.seq === "number" ? params.seq : 0;
41
- const state = (0, _tvEventStore.getState)();
42
- return {
43
- seq: state.seq,
44
- events: (0, _tvEventStore.getEventsSince)(since)
45
- };
46
- },
47
- setMenuCapture(params) {
48
- (0, _tvEventStore.setMenuCapture)(params?.on === true);
49
- return (0, _tvEventStore.getState)();
50
- },
51
- clear() {
52
- (0, _tvEventStore.clear)();
53
- return (0, _tvEventStore.getState)();
54
- }
55
- }
56
- };
57
- //# sourceMappingURL=tvRemoteSyncAdapter.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.tvRemoteSyncAdapter=void 0;var _tvEventStore=require("../store/tvEventStore");const tvRemoteSyncAdapter=exports.tvRemoteSyncAdapter={version:1,getSnapshot:()=>(0,_tvEventStore.getState)(),subscribe:t=>(0,_tvEventStore.subscribe)(t),actions:{arm:()=>((0,_tvEventStore.arm)(),(0,_tvEventStore.getState)()),disarm:()=>((0,_tvEventStore.disarm)(),(0,_tvEventStore.getState)()),getEventsSince(t){const e="number"==typeof t?.seq?t.seq:0;return{seq:(0,_tvEventStore.getState)().seq,events:(0,_tvEventStore.getEventsSince)(e)}},setMenuCapture:t=>((0,_tvEventStore.setMenuCapture)(!0===t?.on),(0,_tvEventStore.getState)()),clear:()=>((0,_tvEventStore.clear)(),(0,_tvEventStore.getState)())}};
@@ -1,23 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * @buoy-gg/tv-remote
5
- *
6
- * The device-side half of Buoy's TV remote driver: it CAPTURES the D-pad /
7
- * select / menu / play-pause events the app actually receives and streams them
8
- * to Buoy Desktop, which is where presses are injected from (adb / idb) and
9
- * where macros are recorded and replayed.
10
- *
11
- * This package renders nothing and injects nothing. See the README for why.
12
- */
13
-
14
- // =============================================================================
15
- // EXTERNAL SYNC (device → desktop dashboard)
16
- // =============================================================================
17
- export { tvRemoteSyncAdapter } from "./sync/tvRemoteSyncAdapter";
18
-
19
- // =============================================================================
20
- // CAPTURE STORE (arm/disarm + types)
21
- // =============================================================================
22
- export { arm, disarm, clear, setMenuCapture, getEventsSince, getState, subscribe } from "./store/tvEventStore";
23
- //# sourceMappingURL=index.js.map
1
+ "use strict";export{tvRemoteSyncAdapter}from"./sync/tvRemoteSyncAdapter";export{arm,disarm,clear,setMenuCapture,getEventsSince,getState,subscribe}from"./store/tvEventStore";
@@ -1,157 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * tvEventStore — the whole device-side half of the TV remote tool.
5
- *
6
- * CONTRACT: this store only ever OBSERVES. It never injects, synthesizes, or
7
- * fakes a remote press. Presses come from the host (Buoy Desktop shells out to
8
- * `adb shell input keyevent` / `idb ui key`), because those go through the real
9
- * platform focus engine; anything we could fake in-process would move focus
10
- * without firing events, or fire events without moving focus. See
11
- * TV_REMOTE_DRIVER_PLAN.md §2.
12
- *
13
- * It is also deliberately UI-less. On Android TV any focusable view we rendered
14
- * would become a D-pad stop in the host app's focus order, so the tool would
15
- * alter the navigation it is supposed to be replaying.
16
- *
17
- * Safe to ship in non-TV apps: the native event emitter is never touched unless
18
- * `Platform.isTV` is true, so the cost on a phone is one boolean.
19
- */
20
-
21
- import * as ReactNative from "react-native";
22
-
23
- /** One captured remote event, as it goes over the wire to the dashboard. */
24
-
25
- /**
26
- * Ring buffer depth. Replay polls `getEventsSince` every few dozen ms with a
27
- * ~2s budget per step, so 50 is many times more than any echo needs; it exists
28
- * so a human scrubbing the echo strip has some scrollback.
29
- */
30
- const MAX_EVENTS = 50;
31
-
32
- /**
33
- * Continuous gestures are not presses and are never recorded — the macro format
34
- * is discrete keys. Dropping them here keeps them out of the ring buffer so
35
- * they can't push real presses out of it during a replay.
36
- */
37
- const IGNORED_EVENT_TYPES = new Set(["pan", "swipeUp", "swipeDown", "swipeLeft", "swipeRight"]);
38
- /**
39
- * `TVEventHandler` / `TVEventControl` only exist on the react-native-tvos fork.
40
- * A namespace read (rather than a named import) keeps this module importable on
41
- * stock react-native, where those exports are absent.
42
- */
43
- const RN = ReactNative;
44
- const isTV = RN.Platform?.isTV === true;
45
- let events = [];
46
- let seq = 0;
47
- let armed = false;
48
- let menuCaptureArmed = false;
49
- let subscription = null;
50
- const listeners = new Set();
51
- function emitChange() {
52
- listeners.forEach(listener => {
53
- listener();
54
- });
55
- }
56
- function handleEvent(raw) {
57
- // Disarming removes the subscription, but don't take that on trust: a native
58
- // emitter that delivered one more event after `remove()` would land a stray
59
- // press in the buffer, and a stray press is exactly what a replay would
60
- // mistake for a step's echo.
61
- if (!armed) return;
62
- const event = raw;
63
- const eventType = event?.eventType;
64
- if (typeof eventType !== "string") return;
65
- if (IGNORED_EVENT_TYPES.has(eventType)) return;
66
-
67
- /**
68
- * Dedupe by ignoring key DOWN, never key UP. tvOS emits keyAction 1 (up)
69
- * ONLY — taps reach the gesture recognizer at StateEnded — so filtering to
70
- * "down" would swallow every tvOS event. Android's down-emit is
71
- * feature-flagged off by default, but dropping it here is the correct
72
- * invariant either way: one press must produce exactly one echo.
73
- */
74
- if (event?.eventKeyAction === 0) return;
75
- seq += 1;
76
- const next = {
77
- seq,
78
- t: Date.now(),
79
- eventType,
80
- eventKeyAction: event?.eventKeyAction
81
- };
82
- events = events.length >= MAX_EVENTS ? [...events.slice(1), next] : [...events, next];
83
- emitChange();
84
- }
85
-
86
- /** Start pushing remote events into the buffer. Idempotent. */
87
- export function arm() {
88
- if (armed) return;
89
- armed = true;
90
- if (isTV && RN.TVEventHandler && !subscription) {
91
- subscription = RN.TVEventHandler.addListener(handleEvent);
92
- }
93
- emitChange();
94
- }
95
-
96
- /**
97
- * Stop capturing and hand the Menu key back to the platform. Every teardown
98
- * path funnels through here — leaving menu capture on would leave the app
99
- * unable to navigate back, which is an App Store behavior change.
100
- */
101
- export function disarm() {
102
- if (subscription) {
103
- subscription.remove();
104
- subscription = null;
105
- }
106
- if (menuCaptureArmed) setMenuCapture(false);
107
- if (!armed) return;
108
- armed = false;
109
- emitChange();
110
- }
111
-
112
- /**
113
- * tvOS: route the Menu key to JS so it can be recorded, instead of letting it
114
- * pop the navigation stack (and background the app at the root). This changes
115
- * how the app under test behaves, so it is opt-in per recording session and is
116
- * always undone on disarm.
117
- */
118
- export function setMenuCapture(on) {
119
- if (!isTV || RN.Platform.OS !== "ios" || !RN.TVEventControl) return;
120
- if (on === menuCaptureArmed) return;
121
- if (on) {
122
- RN.TVEventControl.enableTVMenuKey();
123
- } else {
124
- RN.TVEventControl.disableTVMenuKey();
125
- }
126
- menuCaptureArmed = on;
127
- emitChange();
128
- }
129
- export function clear() {
130
- if (events.length === 0) return;
131
- events = [];
132
- emitChange();
133
- }
134
-
135
- /** Events strictly newer than `sinceSeq` — the replay echo cursor. */
136
- export function getEventsSince(sinceSeq) {
137
- if (!Number.isFinite(sinceSeq)) return events.slice();
138
- return events.filter(event => event.seq > sinceSeq);
139
- }
140
- export function getState() {
141
- return {
142
- supported: isTV,
143
- platform: RN.Platform?.OS ?? "unknown",
144
- captureArmed: armed,
145
- listening: subscription !== null,
146
- menuCaptureArmed,
147
- seq,
148
- recent: events.slice()
149
- };
150
- }
151
- export function subscribe(listener) {
152
- listeners.add(listener);
153
- return () => {
154
- listeners.delete(listener);
155
- };
156
- }
157
- //# sourceMappingURL=tvEventStore.js.map
1
+ "use strict";import*as ReactNative from"react-native";const MAX_EVENTS=50,IGNORED_EVENT_TYPES=new Set(["pan","swipeUp","swipeDown","swipeLeft","swipeRight"]),RN=ReactNative,isTV=!0===RN.Platform?.isTV;let events=[],seq=0,armed=!1,menuCaptureArmed=!1,subscription=null;const listeners=new Set;function emitChange(){listeners.forEach(e=>{e()})}function handleEvent(e){if(!armed)return;const t=e,n=t?.eventType;if("string"!=typeof n)return;if(IGNORED_EVENT_TYPES.has(n))return;if(0===t?.eventKeyAction)return;seq+=1;const r={seq:seq,t:Date.now(),eventType:n,eventKeyAction:t?.eventKeyAction};events=events.length>=50?[...events.slice(1),r]:[...events,r],emitChange()}export function arm(){armed||(armed=!0,isTV&&RN.TVEventHandler&&!subscription&&(subscription=RN.TVEventHandler.addListener(handleEvent)),emitChange())}export function disarm(){subscription&&(subscription.remove(),subscription=null),menuCaptureArmed&&setMenuCapture(!1),armed&&(armed=!1,emitChange())}export function setMenuCapture(e){isTV&&"ios"===RN.Platform.OS&&RN.TVEventControl&&e!==menuCaptureArmed&&(e?RN.TVEventControl.enableTVMenuKey():RN.TVEventControl.disableTVMenuKey(),menuCaptureArmed=e,emitChange())}export function clear(){0!==events.length&&(events=[],emitChange())}export function getEventsSince(e){return Number.isFinite(e)?events.filter(t=>t.seq>e):events.slice()}export function getState(){return{supported:isTV,platform:RN.Platform?.OS??"unknown",captureArmed:armed,listening:null!==subscription,menuCaptureArmed:menuCaptureArmed,seq:seq,recent:events.slice()}}export function subscribe(e){return listeners.add(e),()=>{listeners.delete(e)}}
@@ -1,53 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * tvRemoteSyncAdapter — streams captured TV remote events to Buoy Desktop via
5
- * @buoy-gg/external-sync.
6
- *
7
- * Structurally matches external-sync's `ToolSyncAdapter` WITHOUT importing the
8
- * package (same as every other tool's adapter). Auto-discovery in @buoy-gg/core
9
- * picks it up by export name and announces the "tv-remote" capability.
10
- *
11
- * `getEventsSince` exists because snapshots are throttled 200ms trailing-edge
12
- * per tool, which is too coarse to time a replay step's echo. Replay polls this
13
- * awaited action instead and gets the real latency.
14
- */
15
-
16
- import { arm, clear, disarm, getEventsSince, getState, setMenuCapture, subscribe } from "../store/tvEventStore";
17
- export const tvRemoteSyncAdapter = {
18
- version: 1,
19
- getSnapshot() {
20
- return getState();
21
- },
22
- subscribe(onChange) {
23
- return subscribe(onChange);
24
- },
25
- actions: {
26
- arm() {
27
- arm();
28
- return getState();
29
- },
30
- disarm() {
31
- disarm();
32
- return getState();
33
- },
34
- /** Cursor-paged echo poll. `seq: 0` returns everything buffered. */
35
- getEventsSince(params) {
36
- const since = typeof params?.seq === "number" ? params.seq : 0;
37
- const state = getState();
38
- return {
39
- seq: state.seq,
40
- events: getEventsSince(since)
41
- };
42
- },
43
- setMenuCapture(params) {
44
- setMenuCapture(params?.on === true);
45
- return getState();
46
- },
47
- clear() {
48
- clear();
49
- return getState();
50
- }
51
- }
52
- };
53
- //# sourceMappingURL=tvRemoteSyncAdapter.js.map
1
+ "use strict";import{arm,clear,disarm,getEventsSince,getState,setMenuCapture,subscribe}from"../store/tvEventStore";export const tvRemoteSyncAdapter={version:1,getSnapshot:()=>getState(),subscribe:e=>subscribe(e),actions:{arm:()=>(arm(),getState()),disarm:()=>(disarm(),getState()),getEventsSince(e){const t="number"==typeof e?.seq?e.seq:0;return{seq:getState().seq,events:getEventsSince(t)}},setMenuCapture:e=>(setMenuCapture(!0===e?.on),getState()),clear:()=>(clear(),getState())}};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buoy-gg/tv-remote",
3
- "version": "7.0.36",
3
+ "version": "7.0.38",
4
4
  "description": "TV remote capture for React Native TV apps — records the D-pad/select/menu events the app actually receives, so Buoy Desktop can drive and replay real remote presses. Part of Buoy devtools.",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -1 +0,0 @@
1
- {"version":3,"names":["_tvRemoteSyncAdapter","require","_tvEventStore"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAcA,IAAAA,oBAAA,GAAAC,OAAA;AAKA,IAAAC,aAAA,GAAAD,OAAA","ignoreList":[]}
@@ -1 +0,0 @@
1
- {"version":3,"names":["ReactNative","_interopRequireWildcard","require","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","MAX_EVENTS","IGNORED_EVENT_TYPES","Set","RN","isTV","Platform","events","seq","armed","menuCaptureArmed","subscription","listeners","emitChange","forEach","listener","handleEvent","raw","event","eventType","eventKeyAction","next","Date","now","length","slice","arm","TVEventHandler","addListener","disarm","remove","setMenuCapture","on","OS","TVEventControl","enableTVMenuKey","disableTVMenuKey","clear","getEventsSince","sinceSeq","Number","isFinite","filter","getState","supported","platform","captureArmed","listening","recent","subscribe","add","delete"],"sourceRoot":"../../../src","sources":["store/tvEventStore.ts"],"mappings":"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","ignoreList":[]}
@@ -1 +0,0 @@
1
- {"version":3,"names":["_tvEventStore","require","tvRemoteSyncAdapter","exports","version","getSnapshot","getState","subscribe","onChange","actions","arm","disarm","getEventsSince","params","since","seq","state","events","setMenuCapture","on","clear"],"sourceRoot":"../../../src","sources":["sync/tvRemoteSyncAdapter.ts"],"mappings":";;;;;;AAaA,IAAAA,aAAA,GAAAC,OAAA;AAbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAcO,MAAMC,mBAAmB,GAAAC,OAAA,CAAAD,mBAAA,GAAG;EACjCE,OAAO,EAAE,CAAC;EAEVC,WAAWA,CAAA,EAAkB;IAC3B,OAAO,IAAAC,sBAAQ,EAAC,CAAC;EACnB,CAAC;EAEDC,SAASA,CAACC,QAAoB,EAAc;IAC1C,OAAO,IAAAD,uBAAS,EAACC,QAAQ,CAAC;EAC5B,CAAC;EAEDC,OAAO,EAAE;IACPC,GAAGA,CAAA,EAAkB;MACnB,IAAAA,iBAAG,EAAC,CAAC;MACL,OAAO,IAAAJ,sBAAQ,EAAC,CAAC;IACnB,CAAC;IAEDK,MAAMA,CAAA,EAAkB;MACtB,IAAAA,oBAAM,EAAC,CAAC;MACR,OAAO,IAAAL,sBAAQ,EAAC,CAAC;IACnB,CAAC;IAED;IACAM,cAAcA,CAACC,MAAyB,EAGtC;MACA,MAAMC,KAAK,GAAG,OAAOD,MAAM,EAAEE,GAAG,KAAK,QAAQ,GAAGF,MAAM,CAACE,GAAG,GAAG,CAAC;MAC9D,MAAMC,KAAK,GAAG,IAAAV,sBAAQ,EAAC,CAAC;MACxB,OAAO;QAAES,GAAG,EAAEC,KAAK,CAACD,GAAG;QAAEE,MAAM,EAAE,IAAAL,4BAAc,EAACE,KAAK;MAAE,CAAC;IAC1D,CAAC;IAEDI,cAAcA,CAACL,MAAyB,EAAiB;MACvD,IAAAK,4BAAc,EAACL,MAAM,EAAEM,EAAE,KAAK,IAAI,CAAC;MACnC,OAAO,IAAAb,sBAAQ,EAAC,CAAC;IACnB,CAAC;IAEDc,KAAKA,CAAA,EAAkB;MACrB,IAAAA,mBAAK,EAAC,CAAC;MACP,OAAO,IAAAd,sBAAQ,EAAC,CAAC;IACnB;EACF;AACF,CAAC","ignoreList":[]}
@@ -1 +0,0 @@
1
- {"version":3,"names":["tvRemoteSyncAdapter","arm","disarm","clear","setMenuCapture","getEventsSince","getState","subscribe"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,SAASA,mBAAmB,QAAQ,4BAA4B;;AAEhE;AACA;AACA;AACA,SACEC,GAAG,EACHC,MAAM,EACNC,KAAK,EACLC,cAAc,EACdC,cAAc,EACdC,QAAQ,EACRC,SAAS,QACJ,sBAAsB","ignoreList":[]}
@@ -1 +0,0 @@
1
- {"version":3,"names":["ReactNative","MAX_EVENTS","IGNORED_EVENT_TYPES","Set","RN","isTV","Platform","events","seq","armed","menuCaptureArmed","subscription","listeners","emitChange","forEach","listener","handleEvent","raw","event","eventType","has","eventKeyAction","next","t","Date","now","length","slice","arm","TVEventHandler","addListener","disarm","remove","setMenuCapture","on","OS","TVEventControl","enableTVMenuKey","disableTVMenuKey","clear","getEventsSince","sinceSeq","Number","isFinite","filter","getState","supported","platform","captureArmed","listening","recent","subscribe","add","delete"],"sourceRoot":"../../../src","sources":["store/tvEventStore.ts"],"mappings":"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","ignoreList":[]}
@@ -1 +0,0 @@
1
- {"version":3,"names":["arm","clear","disarm","getEventsSince","getState","setMenuCapture","subscribe","tvRemoteSyncAdapter","version","getSnapshot","onChange","actions","params","since","seq","state","events","on"],"sourceRoot":"../../../src","sources":["sync/tvRemoteSyncAdapter.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SACEA,GAAG,EACHC,KAAK,EACLC,MAAM,EACNC,cAAc,EACdC,QAAQ,EACRC,cAAc,EACdC,SAAS,QAGJ,uBAAuB;AAE9B,OAAO,MAAMC,mBAAmB,GAAG;EACjCC,OAAO,EAAE,CAAC;EAEVC,WAAWA,CAAA,EAAkB;IAC3B,OAAOL,QAAQ,CAAC,CAAC;EACnB,CAAC;EAEDE,SAASA,CAACI,QAAoB,EAAc;IAC1C,OAAOJ,SAAS,CAACI,QAAQ,CAAC;EAC5B,CAAC;EAEDC,OAAO,EAAE;IACPX,GAAGA,CAAA,EAAkB;MACnBA,GAAG,CAAC,CAAC;MACL,OAAOI,QAAQ,CAAC,CAAC;IACnB,CAAC;IAEDF,MAAMA,CAAA,EAAkB;MACtBA,MAAM,CAAC,CAAC;MACR,OAAOE,QAAQ,CAAC,CAAC;IACnB,CAAC;IAED;IACAD,cAAcA,CAACS,MAAyB,EAGtC;MACA,MAAMC,KAAK,GAAG,OAAOD,MAAM,EAAEE,GAAG,KAAK,QAAQ,GAAGF,MAAM,CAACE,GAAG,GAAG,CAAC;MAC9D,MAAMC,KAAK,GAAGX,QAAQ,CAAC,CAAC;MACxB,OAAO;QAAEU,GAAG,EAAEC,KAAK,CAACD,GAAG;QAAEE,MAAM,EAAEb,cAAc,CAACU,KAAK;MAAE,CAAC;IAC1D,CAAC;IAEDR,cAAcA,CAACO,MAAyB,EAAiB;MACvDP,cAAc,CAACO,MAAM,EAAEK,EAAE,KAAK,IAAI,CAAC;MACnC,OAAOb,QAAQ,CAAC,CAAC;IACnB,CAAC;IAEDH,KAAKA,CAAA,EAAkB;MACrBA,KAAK,CAAC,CAAC;MACP,OAAOG,QAAQ,CAAC,CAAC;IACnB;EACF;AACF,CAAC","ignoreList":[]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAKjE,OAAO,EACL,GAAG,EACH,MAAM,EACN,KAAK,EACL,cAAc,EACd,cAAc,EACd,QAAQ,EACR,SAAS,GACV,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"tvEventStore.d.ts","sourceRoot":"","sources":["../../../src/store/tvEventStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAC;IACZ,+BAA+B;IAC/B,CAAC,EAAE,MAAM,CAAC;IACV,+GAA+G;IAC/G,SAAS,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,qEAAqE;IACrE,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB;;;;;OAKG;IACH,SAAS,EAAE,OAAO,CAAC;IACnB,0EAA0E;IAC1E,gBAAgB,EAAE,OAAO,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB;AAwFD,+DAA+D;AAC/D,wBAAgB,GAAG,IAAI,IAAI,CAO1B;AAED;;;;GAIG;AACH,wBAAgB,MAAM,IAAI,IAAI,CAS7B;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAUhD;AAED,wBAAgB,KAAK,IAAI,IAAI,CAI5B;AAED,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,EAAE,CAGhE;AAED,wBAAgB,QAAQ,IAAI,aAAa,CAUxC;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAK1D"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"tvRemoteSyncAdapter.d.ts","sourceRoot":"","sources":["../../../src/sync/tvRemoteSyncAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAQL,KAAK,aAAa,EAClB,KAAK,aAAa,EACnB,MAAM,uBAAuB,CAAC;AAE/B,eAAO,MAAM,mBAAmB;;mBAGf,aAAa;wBAIR,MAAM,IAAI,GAAG,MAAM,IAAI;;eAKlC,aAAa;kBAKV,aAAa;QAKvB,oEAAoE;gCAC5C;YAAE,GAAG,CAAC,EAAE,MAAM,CAAA;SAAE,GAAG;YACzC,GAAG,EAAE,MAAM,CAAC;YACZ,MAAM,EAAE,aAAa,EAAE,CAAC;SACzB;gCAMuB;YAAE,EAAE,CAAC,EAAE,OAAO,CAAA;SAAE,GAAG,aAAa;iBAK/C,aAAa;;CAKzB,CAAC"}