@bharper/atv-js 0.2.3

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.
Files changed (86) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +80 -0
  3. package/dist/airplay/auth.d.ts +24 -0
  4. package/dist/airplay/auth.d.ts.map +1 -0
  5. package/dist/airplay/auth.js +195 -0
  6. package/dist/airplay/auth.js.map +1 -0
  7. package/dist/bplist.d.ts +19 -0
  8. package/dist/bplist.d.ts.map +1 -0
  9. package/dist/bplist.js +141 -0
  10. package/dist/bplist.js.map +1 -0
  11. package/dist/companion/auth.d.ts +34 -0
  12. package/dist/companion/auth.d.ts.map +1 -0
  13. package/dist/companion/auth.js +119 -0
  14. package/dist/companion/auth.js.map +1 -0
  15. package/dist/companion/connection.d.ts +50 -0
  16. package/dist/companion/connection.d.ts.map +1 -0
  17. package/dist/companion/connection.js +170 -0
  18. package/dist/companion/connection.js.map +1 -0
  19. package/dist/companion/keyboard.d.ts +39 -0
  20. package/dist/companion/keyboard.d.ts.map +1 -0
  21. package/dist/companion/keyboard.js +127 -0
  22. package/dist/companion/keyboard.js.map +1 -0
  23. package/dist/companion/pairing_keepalive.d.ts +4 -0
  24. package/dist/companion/pairing_keepalive.d.ts.map +1 -0
  25. package/dist/companion/pairing_keepalive.js +68 -0
  26. package/dist/companion/pairing_keepalive.js.map +1 -0
  27. package/dist/companion/protocol.d.ts +64 -0
  28. package/dist/companion/protocol.d.ts.map +1 -0
  29. package/dist/companion/protocol.js +246 -0
  30. package/dist/companion/protocol.js.map +1 -0
  31. package/dist/companion/remote.d.ts +75 -0
  32. package/dist/companion/remote.d.ts.map +1 -0
  33. package/dist/companion/remote.js +142 -0
  34. package/dist/companion/remote.js.map +1 -0
  35. package/dist/crypto/chacha20.d.ts +27 -0
  36. package/dist/crypto/chacha20.d.ts.map +1 -0
  37. package/dist/crypto/chacha20.js +88 -0
  38. package/dist/crypto/chacha20.js.map +1 -0
  39. package/dist/crypto/hkdf.d.ts +6 -0
  40. package/dist/crypto/hkdf.d.ts.map +1 -0
  41. package/dist/crypto/hkdf.js +45 -0
  42. package/dist/crypto/hkdf.js.map +1 -0
  43. package/dist/index.d.ts +85 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +191 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/mdns.d.ts +20 -0
  48. package/dist/mdns.d.ts.map +1 -0
  49. package/dist/mdns.js +165 -0
  50. package/dist/mdns.js.map +1 -0
  51. package/dist/opack.d.ts +21 -0
  52. package/dist/opack.d.ts.map +1 -0
  53. package/dist/opack.js +350 -0
  54. package/dist/opack.js.map +1 -0
  55. package/dist/pairing/credentials.d.ts +23 -0
  56. package/dist/pairing/credentials.d.ts.map +1 -0
  57. package/dist/pairing/credentials.js +31 -0
  58. package/dist/pairing/credentials.js.map +1 -0
  59. package/dist/pairing/srp.d.ts +54 -0
  60. package/dist/pairing/srp.d.ts.map +1 -0
  61. package/dist/pairing/srp.js +221 -0
  62. package/dist/pairing/srp.js.map +1 -0
  63. package/dist/pairing/tlv.d.ts +26 -0
  64. package/dist/pairing/tlv.d.ts.map +1 -0
  65. package/dist/pairing/tlv.js +68 -0
  66. package/dist/pairing/tlv.js.map +1 -0
  67. package/examples/pair.ts +103 -0
  68. package/examples/remote.ts +212 -0
  69. package/package.json +33 -0
  70. package/src/airplay/auth.ts +207 -0
  71. package/src/bplist.ts +136 -0
  72. package/src/companion/auth.ts +141 -0
  73. package/src/companion/connection.ts +161 -0
  74. package/src/companion/keyboard.ts +155 -0
  75. package/src/companion/pairing_keepalive.ts +75 -0
  76. package/src/companion/protocol.ts +253 -0
  77. package/src/companion/remote.ts +151 -0
  78. package/src/crypto/chacha20.ts +93 -0
  79. package/src/crypto/hkdf.ts +18 -0
  80. package/src/index.ts +248 -0
  81. package/src/mdns.ts +198 -0
  82. package/src/opack.ts +299 -0
  83. package/src/pairing/credentials.ts +44 -0
  84. package/src/pairing/srp.ts +234 -0
  85. package/src/pairing/tlv.ts +64 -0
  86. package/tsconfig.json +19 -0
@@ -0,0 +1,246 @@
1
+ "use strict";
2
+ /**
3
+ * Companion protocol message dispatch layer.
4
+ * Port of pyatv/protocols/companion/protocol.py.
5
+ *
6
+ * Messages are OPACK-encoded with structure:
7
+ * { _i: identifier, _t: messageType, _c: content, _x: transactionId }
8
+ */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.CompanionProtocol = exports.MessageType = void 0;
44
+ const events_1 = require("events");
45
+ const connection_1 = require("./connection");
46
+ const opack = __importStar(require("../opack"));
47
+ const srp_1 = require("../pairing/srp");
48
+ const credentials_1 = require("../pairing/credentials");
49
+ const auth_1 = require("./auth");
50
+ var MessageType;
51
+ (function (MessageType) {
52
+ MessageType[MessageType["Event"] = 1] = "Event";
53
+ MessageType[MessageType["Request"] = 2] = "Request";
54
+ MessageType[MessageType["Response"] = 3] = "Response";
55
+ })(MessageType || (exports.MessageType = MessageType = {}));
56
+ const DEFAULT_TIMEOUT = 5000;
57
+ class CompanionProtocol {
58
+ connection;
59
+ xid = Math.floor(Math.random() * 0x10000); // Random starting xid like pyatv
60
+ pendingRequests = new Map();
61
+ pendingAuth = new Map(); // keyed by frame type
62
+ eventListeners = new Map();
63
+ events = new events_1.EventEmitter();
64
+ srp;
65
+ credentialString;
66
+ _onConnectionLost;
67
+ constructor(connection, credentialString) {
68
+ this.connection = connection;
69
+ this.srp = new srp_1.SRPAuthHandler();
70
+ this.credentialString = credentialString;
71
+ }
72
+ set onConnectionLost(handler) {
73
+ this._onConnectionLost = handler;
74
+ }
75
+ // ---- FrameListener interface ----
76
+ frameReceived(frameType, payload) {
77
+ // Auth frames (PS_*, PV_*)
78
+ if (frameType >= connection_1.FrameType.PS_Start && frameType <= connection_1.FrameType.PV_Next) {
79
+ this.handleAuthFrame(frameType, payload);
80
+ return;
81
+ }
82
+ // OPACK frames
83
+ if (frameType === connection_1.FrameType.E_OPACK || frameType === connection_1.FrameType.U_OPACK || frameType === connection_1.FrameType.P_OPACK) {
84
+ if (payload.length === 0)
85
+ return;
86
+ const { value } = opack.unpack(payload);
87
+ this.handleOpack(frameType, value);
88
+ }
89
+ }
90
+ connectionLost(error) {
91
+ // Reject all pending requests
92
+ for (const [, pending] of this.pendingRequests) {
93
+ clearTimeout(pending.timer);
94
+ pending.reject(new Error('Connection lost'));
95
+ }
96
+ this.pendingRequests.clear();
97
+ for (const [, pending] of this.pendingAuth) {
98
+ clearTimeout(pending.timer);
99
+ pending.reject(new Error('Connection lost'));
100
+ }
101
+ this.pendingAuth.clear();
102
+ if (this._onConnectionLost)
103
+ this._onConnectionLost(error);
104
+ }
105
+ // ---- Auth frame handling ----
106
+ handleAuthFrame(frameType, payload) {
107
+ if (payload.length === 0)
108
+ return;
109
+ const { value } = opack.unpack(payload);
110
+ const data = value;
111
+ // Auth responses come as the next frame type after the request
112
+ // PV_Start(5) → response comes as PV_Next(6), PS_Start(3) → PS_Next(4)
113
+ const pending = this.pendingAuth.get(frameType);
114
+ if (pending) {
115
+ clearTimeout(pending.timer);
116
+ this.pendingAuth.delete(frameType);
117
+ pending.resolve(data);
118
+ }
119
+ }
120
+ /**
121
+ * Exchange an auth frame and wait for the response.
122
+ */
123
+ async exchangeAuth(frameType, data, timeout = DEFAULT_TIMEOUT) {
124
+ // Response frame type: for PS_Start(3)→PS_Next(4), PV_Start(5)→PV_Next(6)
125
+ // For PS_Next(4)→PS_Next(4), PV_Next(6)→PV_Next(6)
126
+ let responseType;
127
+ if (frameType === connection_1.FrameType.PS_Start) {
128
+ responseType = connection_1.FrameType.PS_Next;
129
+ }
130
+ else if (frameType === connection_1.FrameType.PV_Start) {
131
+ responseType = connection_1.FrameType.PV_Next;
132
+ }
133
+ else {
134
+ responseType = frameType; // PS_Next → PS_Next, PV_Next → PV_Next
135
+ }
136
+ return new Promise((resolve, reject) => {
137
+ const timer = setTimeout(() => {
138
+ this.pendingAuth.delete(responseType);
139
+ reject(new Error(`Auth exchange timeout for frame type ${frameType}`));
140
+ }, timeout);
141
+ this.pendingAuth.set(responseType, { resolve, reject, timer });
142
+ this.connection.send(frameType, opack.pack(data));
143
+ });
144
+ }
145
+ // ---- OPACK message handling ----
146
+ handleOpack(frameType, data) {
147
+ const messageType = data._t;
148
+ if (messageType === MessageType.Event) {
149
+ const eventName = data._i;
150
+ const content = (data._c || {});
151
+ const listeners = this.eventListeners.get(eventName);
152
+ if (listeners) {
153
+ for (const listener of listeners) {
154
+ try {
155
+ listener(content);
156
+ }
157
+ catch { }
158
+ }
159
+ }
160
+ this.events.emit(eventName, content);
161
+ }
162
+ else if (messageType === MessageType.Response) {
163
+ const xid = data._x;
164
+ const pending = this.pendingRequests.get(xid);
165
+ if (pending) {
166
+ clearTimeout(pending.timer);
167
+ this.pendingRequests.delete(xid);
168
+ pending.resolve(data);
169
+ }
170
+ }
171
+ }
172
+ /**
173
+ * Send an OPACK request and wait for the response.
174
+ */
175
+ async exchangeOpack(data, frameType = connection_1.FrameType.E_OPACK, timeout = DEFAULT_TIMEOUT) {
176
+ const xid = this.xid++;
177
+ data._x = xid;
178
+ return new Promise((resolve, reject) => {
179
+ const timer = setTimeout(() => {
180
+ this.pendingRequests.delete(xid);
181
+ reject(new Error(`OPACK exchange timeout for xid ${xid}`));
182
+ }, timeout);
183
+ this.pendingRequests.set(xid, { resolve, reject, timer });
184
+ this.connection.send(frameType, opack.pack(data));
185
+ });
186
+ }
187
+ /**
188
+ * Send an OPACK event (no response expected).
189
+ */
190
+ sendEvent(identifier, content) {
191
+ const data = {
192
+ _i: identifier,
193
+ _t: MessageType.Event,
194
+ _c: content,
195
+ _x: this.xid++,
196
+ };
197
+ this.connection.send(connection_1.FrameType.E_OPACK, opack.pack(data));
198
+ }
199
+ /**
200
+ * Send an OPACK request with standard message structure.
201
+ */
202
+ async sendCommand(identifier, content = {}, timeout = DEFAULT_TIMEOUT) {
203
+ const data = {
204
+ _i: identifier,
205
+ _t: MessageType.Request,
206
+ _c: content,
207
+ };
208
+ return this.exchangeOpack(data, connection_1.FrameType.E_OPACK, timeout);
209
+ }
210
+ /**
211
+ * Register a listener for a specific event name.
212
+ */
213
+ listenTo(eventName, listener) {
214
+ const existing = this.eventListeners.get(eventName) || [];
215
+ existing.push(listener);
216
+ this.eventListeners.set(eventName, existing);
217
+ }
218
+ /**
219
+ * Subscribe to device events.
220
+ */
221
+ async subscribeEvent(eventName) {
222
+ this.sendEvent('_interest', { _regEvents: [eventName] });
223
+ }
224
+ // ---- Connection lifecycle ----
225
+ /**
226
+ * Start the protocol: connect, verify credentials if available, enable encryption.
227
+ */
228
+ async start() {
229
+ await this.connection.connect();
230
+ if (this.credentialString) {
231
+ const credentials = (0, credentials_1.parseCredentials)(this.credentialString);
232
+ await this.setupEncryption(credentials);
233
+ }
234
+ }
235
+ async setupEncryption(credentials) {
236
+ const verifier = new auth_1.CompanionPairVerifyProcedure(this, this.srp, credentials);
237
+ await verifier.verifyCredentials();
238
+ const [outputKey, inputKey] = verifier.encryptionKeys();
239
+ this.connection.enableEncryption(outputKey, inputKey);
240
+ }
241
+ close() {
242
+ this.connection.close();
243
+ }
244
+ }
245
+ exports.CompanionProtocol = CompanionProtocol;
246
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/companion/protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Remote control via Companion protocol HID and media control commands.
3
+ * Port of pyatv/protocols/companion/api.py + __init__.py remote control.
4
+ */
5
+ import { CompanionProtocol } from './protocol';
6
+ /** HID command values matching pyatv's HidCommand enum. */
7
+ export declare enum HidCommand {
8
+ Up = 1,
9
+ Down = 2,
10
+ Left = 3,
11
+ Right = 4,
12
+ Menu = 5,
13
+ Select = 6,
14
+ Home = 7,
15
+ VolumeUp = 8,
16
+ VolumeDown = 9,
17
+ Siri = 10,
18
+ Screensaver = 11,
19
+ Sleep = 12,
20
+ Wake = 13,
21
+ PlayPause = 14,
22
+ ChannelIncrement = 15,
23
+ ChannelDecrement = 16,
24
+ Guide = 17,
25
+ PageUp = 18,
26
+ PageDown = 19
27
+ }
28
+ /** Media control command values matching pyatv's MediaControlCommand enum. */
29
+ export declare enum MediaControlCommand {
30
+ Play = 1,
31
+ Pause = 2,
32
+ NextTrack = 3,
33
+ PreviousTrack = 4,
34
+ GetVolume = 5,
35
+ SetVolume = 6,
36
+ SkipBy = 7
37
+ }
38
+ /** Named remote keys. */
39
+ export declare enum RemoteKey {
40
+ Up = "up",
41
+ Down = "down",
42
+ Left = "left",
43
+ Right = "right",
44
+ Select = "select",
45
+ Menu = "menu",
46
+ TopMenu = "top_menu",
47
+ Home = "home",
48
+ HomeHold = "home_hold",
49
+ PlayPause = "play_pause",
50
+ Next = "next",
51
+ Previous = "previous",
52
+ SkipForward = "skip_forward",
53
+ SkipBackward = "skip_backward",
54
+ VolumeUp = "volume_up",
55
+ VolumeDown = "volume_down",
56
+ Guide = "guide"
57
+ }
58
+ /**
59
+ * Send a media control command.
60
+ */
61
+ export declare function sendMediaControl(protocol: CompanionProtocol, command: MediaControlCommand, args?: Record<string, unknown>): Promise<void>;
62
+ /**
63
+ * Send a remote control key press. Handles HID keys, media control keys,
64
+ * and long-press keys automatically.
65
+ */
66
+ export declare function sendKeyPress(protocol: CompanionProtocol, key: RemoteKey | string): Promise<void>;
67
+ /**
68
+ * Send a HID button down event only (for long press behavior).
69
+ */
70
+ export declare function sendKeyDown(protocol: CompanionProtocol, key: RemoteKey | string): Promise<void>;
71
+ /**
72
+ * Send a HID button up event only (to release a held button).
73
+ */
74
+ export declare function sendKeyUp(protocol: CompanionProtocol, key: RemoteKey | string): Promise<void>;
75
+ //# sourceMappingURL=remote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../src/companion/remote.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C,2DAA2D;AAC3D,oBAAY,UAAU;IACpB,EAAE,IAAI;IACN,IAAI,IAAI;IACR,IAAI,IAAI;IACR,KAAK,IAAI;IACT,IAAI,IAAI;IACR,MAAM,IAAI;IACV,IAAI,IAAI;IACR,QAAQ,IAAI;IACZ,UAAU,IAAI;IACd,IAAI,KAAK;IACT,WAAW,KAAK;IAChB,KAAK,KAAK;IACV,IAAI,KAAK;IACT,SAAS,KAAK;IACd,gBAAgB,KAAK;IACrB,gBAAgB,KAAK;IACrB,KAAK,KAAK;IACV,MAAM,KAAK;IACX,QAAQ,KAAK;CACd;AAED,8EAA8E;AAC9E,oBAAY,mBAAmB;IAC7B,IAAI,IAAI;IACR,KAAK,IAAI;IACT,SAAS,IAAI;IACb,aAAa,IAAI;IACjB,SAAS,IAAI;IACb,SAAS,IAAI;IACb,MAAM,IAAI;CACX;AAED,yBAAyB;AACzB,oBAAY,SAAS;IACnB,EAAE,OAAO;IACT,IAAI,SAAS;IACb,IAAI,SAAS;IACb,KAAK,UAAU;IACf,MAAM,WAAW;IACjB,IAAI,SAAS;IACb,OAAO,aAAa;IACpB,IAAI,SAAS;IACb,QAAQ,cAAc;IACtB,SAAS,eAAe;IACxB,IAAI,SAAS;IACb,QAAQ,aAAa;IACrB,WAAW,iBAAiB;IAC5B,YAAY,kBAAkB;IAC9B,QAAQ,cAAc;IACtB,UAAU,gBAAgB;IAC1B,KAAK,UAAU;CAChB;AA6BD;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,EAAE,mBAAmB,EAC5B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,IAAI,CAAC,CAEf;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBtG;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMrG;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMnG"}
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ /**
3
+ * Remote control via Companion protocol HID and media control commands.
4
+ * Port of pyatv/protocols/companion/api.py + __init__.py remote control.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.RemoteKey = exports.MediaControlCommand = exports.HidCommand = void 0;
8
+ exports.sendMediaControl = sendMediaControl;
9
+ exports.sendKeyPress = sendKeyPress;
10
+ exports.sendKeyDown = sendKeyDown;
11
+ exports.sendKeyUp = sendKeyUp;
12
+ /** HID command values matching pyatv's HidCommand enum. */
13
+ var HidCommand;
14
+ (function (HidCommand) {
15
+ HidCommand[HidCommand["Up"] = 1] = "Up";
16
+ HidCommand[HidCommand["Down"] = 2] = "Down";
17
+ HidCommand[HidCommand["Left"] = 3] = "Left";
18
+ HidCommand[HidCommand["Right"] = 4] = "Right";
19
+ HidCommand[HidCommand["Menu"] = 5] = "Menu";
20
+ HidCommand[HidCommand["Select"] = 6] = "Select";
21
+ HidCommand[HidCommand["Home"] = 7] = "Home";
22
+ HidCommand[HidCommand["VolumeUp"] = 8] = "VolumeUp";
23
+ HidCommand[HidCommand["VolumeDown"] = 9] = "VolumeDown";
24
+ HidCommand[HidCommand["Siri"] = 10] = "Siri";
25
+ HidCommand[HidCommand["Screensaver"] = 11] = "Screensaver";
26
+ HidCommand[HidCommand["Sleep"] = 12] = "Sleep";
27
+ HidCommand[HidCommand["Wake"] = 13] = "Wake";
28
+ HidCommand[HidCommand["PlayPause"] = 14] = "PlayPause";
29
+ HidCommand[HidCommand["ChannelIncrement"] = 15] = "ChannelIncrement";
30
+ HidCommand[HidCommand["ChannelDecrement"] = 16] = "ChannelDecrement";
31
+ HidCommand[HidCommand["Guide"] = 17] = "Guide";
32
+ HidCommand[HidCommand["PageUp"] = 18] = "PageUp";
33
+ HidCommand[HidCommand["PageDown"] = 19] = "PageDown";
34
+ })(HidCommand || (exports.HidCommand = HidCommand = {}));
35
+ /** Media control command values matching pyatv's MediaControlCommand enum. */
36
+ var MediaControlCommand;
37
+ (function (MediaControlCommand) {
38
+ MediaControlCommand[MediaControlCommand["Play"] = 1] = "Play";
39
+ MediaControlCommand[MediaControlCommand["Pause"] = 2] = "Pause";
40
+ MediaControlCommand[MediaControlCommand["NextTrack"] = 3] = "NextTrack";
41
+ MediaControlCommand[MediaControlCommand["PreviousTrack"] = 4] = "PreviousTrack";
42
+ MediaControlCommand[MediaControlCommand["GetVolume"] = 5] = "GetVolume";
43
+ MediaControlCommand[MediaControlCommand["SetVolume"] = 6] = "SetVolume";
44
+ MediaControlCommand[MediaControlCommand["SkipBy"] = 7] = "SkipBy";
45
+ })(MediaControlCommand || (exports.MediaControlCommand = MediaControlCommand = {}));
46
+ /** Named remote keys. */
47
+ var RemoteKey;
48
+ (function (RemoteKey) {
49
+ RemoteKey["Up"] = "up";
50
+ RemoteKey["Down"] = "down";
51
+ RemoteKey["Left"] = "left";
52
+ RemoteKey["Right"] = "right";
53
+ RemoteKey["Select"] = "select";
54
+ RemoteKey["Menu"] = "menu";
55
+ RemoteKey["TopMenu"] = "top_menu";
56
+ RemoteKey["Home"] = "home";
57
+ RemoteKey["HomeHold"] = "home_hold";
58
+ RemoteKey["PlayPause"] = "play_pause";
59
+ RemoteKey["Next"] = "next";
60
+ RemoteKey["Previous"] = "previous";
61
+ RemoteKey["SkipForward"] = "skip_forward";
62
+ RemoteKey["SkipBackward"] = "skip_backward";
63
+ RemoteKey["VolumeUp"] = "volume_up";
64
+ RemoteKey["VolumeDown"] = "volume_down";
65
+ RemoteKey["Guide"] = "guide";
66
+ })(RemoteKey || (exports.RemoteKey = RemoteKey = {}));
67
+ const KEY_TO_HID = {
68
+ [RemoteKey.Up]: HidCommand.Up,
69
+ [RemoteKey.Down]: HidCommand.Down,
70
+ [RemoteKey.Left]: HidCommand.Left,
71
+ [RemoteKey.Right]: HidCommand.Right,
72
+ [RemoteKey.Select]: HidCommand.Select,
73
+ [RemoteKey.Menu]: HidCommand.Menu,
74
+ [RemoteKey.TopMenu]: HidCommand.Menu,
75
+ [RemoteKey.Home]: HidCommand.Home,
76
+ [RemoteKey.HomeHold]: HidCommand.Home,
77
+ [RemoteKey.PlayPause]: HidCommand.PlayPause,
78
+ [RemoteKey.VolumeUp]: HidCommand.VolumeUp,
79
+ [RemoteKey.VolumeDown]: HidCommand.VolumeDown,
80
+ [RemoteKey.Guide]: HidCommand.Guide,
81
+ };
82
+ /** Keys that are media control commands rather than HID. */
83
+ const KEY_TO_MEDIA = {
84
+ [RemoteKey.Next]: MediaControlCommand.NextTrack,
85
+ [RemoteKey.Previous]: MediaControlCommand.PreviousTrack,
86
+ };
87
+ /** Keys that require a long press (hold down, delay, release). */
88
+ const LONG_PRESS_KEYS = new Set([RemoteKey.HomeHold]);
89
+ const LONG_PRESS_DELAY_MS = 1000;
90
+ /**
91
+ * Send a media control command.
92
+ */
93
+ async function sendMediaControl(protocol, command, args) {
94
+ await protocol.sendCommand('_mcc', { _mcc: command, ...(args || {}) });
95
+ }
96
+ /**
97
+ * Send a remote control key press. Handles HID keys, media control keys,
98
+ * and long-press keys automatically.
99
+ */
100
+ async function sendKeyPress(protocol, key) {
101
+ // Media control keys
102
+ const mediaCommand = KEY_TO_MEDIA[key];
103
+ if (mediaCommand !== undefined) {
104
+ await sendMediaControl(protocol, mediaCommand);
105
+ return;
106
+ }
107
+ const hidCommand = KEY_TO_HID[key];
108
+ if (hidCommand === undefined) {
109
+ throw new Error(`Unknown remote key: ${key}`);
110
+ }
111
+ if (LONG_PRESS_KEYS.has(key)) {
112
+ // Long press: hold down, wait, release
113
+ await protocol.sendCommand('_hidC', { _hBtS: 1, _hidC: hidCommand });
114
+ await new Promise((r) => setTimeout(r, LONG_PRESS_DELAY_MS));
115
+ await protocol.sendCommand('_hidC', { _hBtS: 2, _hidC: hidCommand });
116
+ return;
117
+ }
118
+ // Normal press: down + up
119
+ await protocol.sendCommand('_hidC', { _hBtS: 1, _hidC: hidCommand });
120
+ await protocol.sendCommand('_hidC', { _hBtS: 2, _hidC: hidCommand });
121
+ }
122
+ /**
123
+ * Send a HID button down event only (for long press behavior).
124
+ */
125
+ async function sendKeyDown(protocol, key) {
126
+ const hidCommand = KEY_TO_HID[key];
127
+ if (hidCommand === undefined) {
128
+ throw new Error(`Unknown remote key: ${key}`);
129
+ }
130
+ await protocol.sendCommand('_hidC', { _hBtS: 1, _hidC: hidCommand });
131
+ }
132
+ /**
133
+ * Send a HID button up event only (to release a held button).
134
+ */
135
+ async function sendKeyUp(protocol, key) {
136
+ const hidCommand = KEY_TO_HID[key];
137
+ if (hidCommand === undefined) {
138
+ throw new Error(`Unknown remote key: ${key}`);
139
+ }
140
+ await protocol.sendCommand('_hidC', { _hBtS: 2, _hidC: hidCommand });
141
+ }
142
+ //# sourceMappingURL=remote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote.js","sourceRoot":"","sources":["../../src/companion/remote.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * ChaCha20-Poly1305 AEAD encryption with counter-based nonces.
3
+ * Uses @noble/ciphers for pure JS implementation (works in Electron).
4
+ */
5
+ declare const AUTH_TAG_LENGTH = 16;
6
+ export { AUTH_TAG_LENGTH };
7
+ export declare class Chacha20Cipher {
8
+ private outKey;
9
+ private inKey;
10
+ private outCounter;
11
+ private inCounter;
12
+ private nonceLength;
13
+ constructor(outKey: Buffer, inKey: Buffer, nonceLength?: number);
14
+ private padNonce;
15
+ private getOutNonce;
16
+ private getInNonce;
17
+ encrypt(data: Buffer, nonce?: Buffer, aad?: Buffer): Buffer;
18
+ decrypt(data: Buffer, nonce?: Buffer, aad?: Buffer): Buffer;
19
+ }
20
+ /**
21
+ * 8-byte counter variant: nonce = [4 zero bytes][8-byte LE counter].
22
+ * Used for pairing steps with explicit nonces like "PS-Msg05", "PV-Msg02".
23
+ */
24
+ export declare class Chacha20Cipher8byteNonce extends Chacha20Cipher {
25
+ constructor(outKey: Buffer, inKey: Buffer);
26
+ }
27
+ //# sourceMappingURL=chacha20.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chacha20.d.ts","sourceRoot":"","sources":["../../src/crypto/chacha20.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,QAAA,MAAM,eAAe,KAAK,CAAC;AAE3B,OAAO,EAAE,eAAe,EAAE,CAAC;AAE3B,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,WAAW,CAAS;gBAEhB,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,SAAK;IAM3D,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM;IAe3D,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM;CAc5D;AAED;;;GAGG;AACH,qBAAa,wBAAyB,SAAQ,cAAc;gBAC9C,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAG1C"}
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ /**
3
+ * ChaCha20-Poly1305 AEAD encryption with counter-based nonces.
4
+ * Uses @noble/ciphers for pure JS implementation (works in Electron).
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.Chacha20Cipher8byteNonce = exports.Chacha20Cipher = exports.AUTH_TAG_LENGTH = void 0;
8
+ const chacha_js_1 = require("@noble/ciphers/chacha.js");
9
+ const NONCE_LENGTH = 12;
10
+ const AUTH_TAG_LENGTH = 16;
11
+ exports.AUTH_TAG_LENGTH = AUTH_TAG_LENGTH;
12
+ class Chacha20Cipher {
13
+ outKey;
14
+ inKey;
15
+ outCounter = 0;
16
+ inCounter = 0;
17
+ nonceLength;
18
+ constructor(outKey, inKey, nonceLength = 12) {
19
+ this.outKey = outKey;
20
+ this.inKey = inKey;
21
+ this.nonceLength = nonceLength;
22
+ }
23
+ padNonce(nonce) {
24
+ if (nonce.length >= NONCE_LENGTH)
25
+ return nonce;
26
+ const padded = Buffer.alloc(NONCE_LENGTH);
27
+ nonce.copy(padded, NONCE_LENGTH - nonce.length);
28
+ return padded;
29
+ }
30
+ getOutNonce() {
31
+ const nonce = Buffer.alloc(this.nonceLength);
32
+ writeLECounter(nonce, this.outCounter, this.nonceLength);
33
+ return this.nonceLength !== NONCE_LENGTH ? this.padNonce(nonce) : nonce;
34
+ }
35
+ getInNonce() {
36
+ const nonce = Buffer.alloc(this.nonceLength);
37
+ writeLECounter(nonce, this.inCounter, this.nonceLength);
38
+ return this.nonceLength !== NONCE_LENGTH ? this.padNonce(nonce) : nonce;
39
+ }
40
+ encrypt(data, nonce, aad) {
41
+ let useNonce;
42
+ if (nonce === undefined) {
43
+ useNonce = this.getOutNonce();
44
+ this.outCounter++;
45
+ }
46
+ else {
47
+ useNonce = nonce.length < NONCE_LENGTH ? this.padNonce(nonce) : nonce;
48
+ }
49
+ // Use @noble/ciphers chacha20-poly1305 (pure JS, works in Electron)
50
+ const cipher = (0, chacha_js_1.chacha20poly1305)(this.outKey, useNonce, aad);
51
+ const encrypted = cipher.encrypt(data);
52
+ return Buffer.from(encrypted);
53
+ }
54
+ decrypt(data, nonce, aad) {
55
+ let useNonce;
56
+ if (nonce === undefined) {
57
+ useNonce = this.getInNonce();
58
+ this.inCounter++;
59
+ }
60
+ else {
61
+ useNonce = nonce.length < NONCE_LENGTH ? this.padNonce(nonce) : nonce;
62
+ }
63
+ // Use @noble/ciphers chacha20-poly1305 (pure JS, works in Electron)
64
+ const decipher = (0, chacha_js_1.chacha20poly1305)(this.inKey, useNonce, aad);
65
+ const decrypted = decipher.decrypt(data);
66
+ return Buffer.from(decrypted);
67
+ }
68
+ }
69
+ exports.Chacha20Cipher = Chacha20Cipher;
70
+ /**
71
+ * 8-byte counter variant: nonce = [4 zero bytes][8-byte LE counter].
72
+ * Used for pairing steps with explicit nonces like "PS-Msg05", "PV-Msg02".
73
+ */
74
+ class Chacha20Cipher8byteNonce extends Chacha20Cipher {
75
+ constructor(outKey, inKey) {
76
+ super(outKey, inKey, 8);
77
+ }
78
+ }
79
+ exports.Chacha20Cipher8byteNonce = Chacha20Cipher8byteNonce;
80
+ function writeLECounter(buf, counter, length) {
81
+ // Use BigInt to avoid JavaScript's 32-bit limit on bit operations
82
+ let c = BigInt(counter);
83
+ for (let i = 0; i < length && i < 8; i++) {
84
+ buf[i] = Number(c & 0xffn);
85
+ c >>= 8n;
86
+ }
87
+ }
88
+ //# sourceMappingURL=chacha20.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chacha20.js","sourceRoot":"","sources":["../../src/crypto/chacha20.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * HKDF-SHA512 key derivation.
3
+ * Port of pyatv/auth/hap_srp.py hkdf_expand().
4
+ */
5
+ export declare function hkdfExpand(salt: string, info: string, sharedSecret: Buffer): Buffer;
6
+ //# sourceMappingURL=hkdf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hkdf.d.ts","sourceRoot":"","sources":["../../src/crypto/hkdf.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAUnF"}