@bharper/atv-js 0.2.4 → 0.2.6
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/dist/index.d.ts.map +1 -1
- package/dist/index.js +56 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +65 -8
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC5G,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAChF,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -28,6 +28,7 @@ Object.defineProperty(exports, "HidCommand", { enumerable: true, get: function (
|
|
|
28
28
|
Object.defineProperty(exports, "MediaControlCommand", { enumerable: true, get: function () { return remote_1.MediaControlCommand; } });
|
|
29
29
|
var keyboard_1 = require("./companion/keyboard");
|
|
30
30
|
Object.defineProperty(exports, "KeyboardFocusState", { enumerable: true, get: function () { return keyboard_1.KeyboardFocusState; } });
|
|
31
|
+
const mdns_2 = require("./mdns");
|
|
31
32
|
const connection_1 = require("./companion/connection");
|
|
32
33
|
const protocol_1 = require("./companion/protocol");
|
|
33
34
|
const auth_1 = require("./companion/auth");
|
|
@@ -88,16 +89,65 @@ async function finishCompanionPairing(session, pin, displayName) {
|
|
|
88
89
|
}
|
|
89
90
|
return creds;
|
|
90
91
|
}
|
|
92
|
+
function errorMessage(error) {
|
|
93
|
+
if (error instanceof Error)
|
|
94
|
+
return error.message;
|
|
95
|
+
return String(error);
|
|
96
|
+
}
|
|
97
|
+
function matchesDevice(target, candidate) {
|
|
98
|
+
if (target.identifier && candidate.identifier === target.identifier)
|
|
99
|
+
return true;
|
|
100
|
+
if (candidate.address === target.address)
|
|
101
|
+
return true;
|
|
102
|
+
return candidate.name === target.name;
|
|
103
|
+
}
|
|
104
|
+
function mergeDiscoveredDevice(target, discovered) {
|
|
105
|
+
return {
|
|
106
|
+
...target,
|
|
107
|
+
...discovered,
|
|
108
|
+
properties: { ...target.properties, ...discovered.properties },
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
async function connectCompanion(device, companionCredentials) {
|
|
112
|
+
const connection = new connection_1.CompanionConnection(device.address, device.port);
|
|
113
|
+
const protocol = new protocol_1.CompanionProtocol(connection, companionCredentials);
|
|
114
|
+
connection.setListener(protocol);
|
|
115
|
+
await protocol.start();
|
|
116
|
+
return protocol;
|
|
117
|
+
}
|
|
118
|
+
async function discoverLatestDevice(device) {
|
|
119
|
+
const discovered = await (0, mdns_2.scan)(3000, false);
|
|
120
|
+
return discovered.find((candidate) => matchesDevice(device, candidate)) || null;
|
|
121
|
+
}
|
|
91
122
|
/**
|
|
92
123
|
* Connect to an Apple TV using stored credentials.
|
|
93
124
|
* Performs pair-verify and sets up encrypted Companion channel.
|
|
94
125
|
*/
|
|
95
126
|
async function connect(device, credentials) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
127
|
+
let activeDevice = device;
|
|
128
|
+
let protocol;
|
|
129
|
+
try {
|
|
130
|
+
protocol = await connectCompanion(activeDevice, credentials.companion);
|
|
131
|
+
}
|
|
132
|
+
catch (initialError) {
|
|
133
|
+
let discovered = null;
|
|
134
|
+
try {
|
|
135
|
+
discovered = await discoverLatestDevice(activeDevice);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
discovered = null;
|
|
139
|
+
}
|
|
140
|
+
if (!discovered || discovered.port === activeDevice.port) {
|
|
141
|
+
throw initialError;
|
|
142
|
+
}
|
|
143
|
+
activeDevice = mergeDiscoveredDevice(activeDevice, discovered);
|
|
144
|
+
try {
|
|
145
|
+
protocol = await connectCompanion(activeDevice, credentials.companion);
|
|
146
|
+
}
|
|
147
|
+
catch (retryError) {
|
|
148
|
+
throw new Error(`Companion connection failed on saved port ${device.port} and discovered port ${activeDevice.port}: ${errorMessage(retryError)}`, { cause: initialError instanceof Error ? initialError : undefined });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
101
151
|
// Post-connection initialization (order matters!)
|
|
102
152
|
// 1. Send system info
|
|
103
153
|
// Client ID is stored hex-encoded in credentials, decode to get the actual UUID bytes
|
|
@@ -133,7 +183,7 @@ async function connect(device, credentials) {
|
|
|
133
183
|
protocol.subscribeEvent('_iMC');
|
|
134
184
|
const conn = {
|
|
135
185
|
protocol,
|
|
136
|
-
device,
|
|
186
|
+
device: activeDevice,
|
|
137
187
|
credentials,
|
|
138
188
|
_keyboardFocusState: keyboard_2.KeyboardFocusState.Unknown,
|
|
139
189
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAkDH,kDAGC;AAKD,oDASC;AAMD,sDAeC;AAKD,wDAgBC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { HapCredentials, Credentials, parseCredentials, serializeCredentials } f
|
|
|
8
8
|
export { RemoteKey, HidCommand, MediaControlCommand } from './companion/remote';
|
|
9
9
|
export { KeyboardFocusState } from './companion/keyboard';
|
|
10
10
|
|
|
11
|
-
import { AppleTVDevice } from './mdns';
|
|
11
|
+
import { AppleTVDevice, scan as scanDevices } from './mdns';
|
|
12
12
|
import { CompanionConnection } from './companion/connection';
|
|
13
13
|
import { CompanionProtocol } from './companion/protocol';
|
|
14
14
|
import { CompanionPairSetupProcedure } from './companion/auth';
|
|
@@ -122,6 +122,41 @@ export interface AppleTVConnection {
|
|
|
122
122
|
_keyboardFocusState: KeyboardFocusState;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
function errorMessage(error: unknown): string {
|
|
126
|
+
if (error instanceof Error) return error.message;
|
|
127
|
+
return String(error);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function matchesDevice(target: AppleTVDevice, candidate: AppleTVDevice): boolean {
|
|
131
|
+
if (target.identifier && candidate.identifier === target.identifier) return true;
|
|
132
|
+
if (candidate.address === target.address) return true;
|
|
133
|
+
return candidate.name === target.name;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function mergeDiscoveredDevice(target: AppleTVDevice, discovered: AppleTVDevice): AppleTVDevice {
|
|
137
|
+
return {
|
|
138
|
+
...target,
|
|
139
|
+
...discovered,
|
|
140
|
+
properties: { ...target.properties, ...discovered.properties },
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function connectCompanion(
|
|
145
|
+
device: AppleTVDevice,
|
|
146
|
+
companionCredentials: string,
|
|
147
|
+
): Promise<CompanionProtocol> {
|
|
148
|
+
const connection = new CompanionConnection(device.address, device.port);
|
|
149
|
+
const protocol = new CompanionProtocol(connection, companionCredentials);
|
|
150
|
+
connection.setListener(protocol);
|
|
151
|
+
await protocol.start();
|
|
152
|
+
return protocol;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function discoverLatestDevice(device: AppleTVDevice): Promise<AppleTVDevice | null> {
|
|
156
|
+
const discovered = await scanDevices(3000, false);
|
|
157
|
+
return discovered.find((candidate) => matchesDevice(device, candidate)) || null;
|
|
158
|
+
}
|
|
159
|
+
|
|
125
160
|
/**
|
|
126
161
|
* Connect to an Apple TV using stored credentials.
|
|
127
162
|
* Performs pair-verify and sets up encrypted Companion channel.
|
|
@@ -130,12 +165,34 @@ export async function connect(
|
|
|
130
165
|
device: AppleTVDevice,
|
|
131
166
|
credentials: Credentials,
|
|
132
167
|
): Promise<AppleTVConnection> {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
168
|
+
let activeDevice = device;
|
|
169
|
+
let protocol: CompanionProtocol;
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
protocol = await connectCompanion(activeDevice, credentials.companion);
|
|
173
|
+
} catch (initialError) {
|
|
174
|
+
let discovered: AppleTVDevice | null = null;
|
|
175
|
+
try {
|
|
176
|
+
discovered = await discoverLatestDevice(activeDevice);
|
|
177
|
+
} catch {
|
|
178
|
+
discovered = null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (!discovered || discovered.port === activeDevice.port) {
|
|
182
|
+
throw initialError;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
activeDevice = mergeDiscoveredDevice(activeDevice, discovered);
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
protocol = await connectCompanion(activeDevice, credentials.companion);
|
|
189
|
+
} catch (retryError) {
|
|
190
|
+
throw new Error(
|
|
191
|
+
`Companion connection failed on saved port ${device.port} and discovered port ${activeDevice.port}: ${errorMessage(retryError)}`,
|
|
192
|
+
{ cause: initialError instanceof Error ? initialError : undefined },
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
139
196
|
|
|
140
197
|
// Post-connection initialization (order matters!)
|
|
141
198
|
// 1. Send system info
|
|
@@ -177,7 +234,7 @@ export async function connect(
|
|
|
177
234
|
|
|
178
235
|
const conn: AppleTVConnection = {
|
|
179
236
|
protocol,
|
|
180
|
-
device,
|
|
237
|
+
device: activeDevice,
|
|
181
238
|
credentials,
|
|
182
239
|
_keyboardFocusState: KeyboardFocusState.Unknown,
|
|
183
240
|
};
|