@basmilius/apple-companion-link 0.1.2 → 0.2.0

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 CHANGED
@@ -1,7 +1,6 @@
1
- export type { default as CompanionLinkPairing } from "./pairing";
2
- export type { default as CompanionLinkVerify } from "./verify";
3
- export type { HidCommandKey, MediaControlCommandKey } from "./const";
4
- export type { AttentionState, ButtonPressType, LaunchableApp, UserAccount } from "./types";
5
- export { HidCommand, MediaControlCommand } from "./const";
6
- export { convertAttentionState } from "./utils";
7
- export { default as CompanionLink } from "./protocol";
1
+ export { default as Protocol } from "./protocol";
2
+ export { default as Stream } from "./stream";
3
+ export { Pairing, Verify } from "./pairing";
4
+ export * from "./const";
5
+ export * from "./utils";
6
+ export type * from "./types";
package/dist/index.js CHANGED
@@ -1,3 +1,8 @@
1
+ // src/protocol.ts
2
+ import { randomInt as randomInt2 } from "node:crypto";
3
+ import { COMPANION_LINK_SERVICE, Context, waitFor } from "@basmilius/apple-common";
4
+ import { OPack as OPack2, Plist } from "@basmilius/apple-encoding";
5
+
1
6
  // src/const.ts
2
7
  var HidCommand = {
3
8
  Up: 1,
@@ -35,27 +40,8 @@ var MediaControlCommand = {
35
40
  GetCaptionSettings: 12,
36
41
  SetCaptionSettings: 13
37
42
  };
38
- // src/utils.ts
39
- function convertAttentionState(state) {
40
- switch (state) {
41
- case 1:
42
- return "asleep";
43
- case 2:
44
- return "screensaver";
45
- case 3:
46
- return "awake";
47
- case 4:
48
- return "idle";
49
- default:
50
- return "unknown";
51
- }
52
- }
53
- // src/protocol.ts
54
- import { randomBytes, randomInt as randomInt2 } from "node:crypto";
55
- import { reporter as reporter2, waitFor } from "@basmilius/apple-common";
56
- import { OPack as OPack2, Plist } from "@basmilius/apple-encoding";
57
43
 
58
- // src/messages.ts
44
+ // src/frame.ts
59
45
  var FrameType = {
60
46
  Unknown: 0,
61
47
  Noop: 1,
@@ -97,16 +83,19 @@ var PairFrameTypes = [
97
83
  ];
98
84
 
99
85
  // src/pairing.ts
100
- import { AccessoryPair } from "@basmilius/apple-common";
101
- class CompanionLinkPairing {
86
+ import { AccessoryPair, AccessoryVerify, hkdf } from "@basmilius/apple-common";
87
+ class Pairing {
102
88
  get internal() {
103
89
  return this.#internal;
104
90
  }
91
+ get stream() {
92
+ return this.#stream;
93
+ }
105
94
  #internal;
106
- #protocol;
95
+ #stream;
107
96
  constructor(protocol) {
108
- this.#internal = new AccessoryPair(this.#request.bind(this));
109
- this.#protocol = protocol;
97
+ this.#internal = new AccessoryPair(protocol.context, this.#request.bind(this));
98
+ this.#stream = protocol.stream;
110
99
  }
111
100
  async start() {
112
101
  await this.#internal.start();
@@ -119,7 +108,7 @@ class CompanionLinkPairing {
119
108
  }
120
109
  async#request(step, data) {
121
110
  const frameType = step === "m1" ? FrameType.PS_Start : FrameType.PS_Next;
122
- const [, response] = await this.#protocol.socket.exchange(frameType, {
111
+ const [, response] = await this.#stream.exchange(frameType, {
123
112
  _pd: data,
124
113
  _pwTy: 1
125
114
  });
@@ -130,24 +119,88 @@ class CompanionLinkPairing {
130
119
  }
131
120
  }
132
121
 
133
- // src/socket.ts
122
+ class Verify {
123
+ get internal() {
124
+ return this.#internal;
125
+ }
126
+ get stream() {
127
+ return this.#stream;
128
+ }
129
+ #internal;
130
+ #stream;
131
+ constructor(protocol) {
132
+ this.#internal = new AccessoryVerify(protocol.context, this.#request.bind(this));
133
+ this.#stream = protocol.stream;
134
+ }
135
+ async start(credentials) {
136
+ const keys = await this.#internal.start(credentials);
137
+ const accessoryToControllerKey = hkdf({
138
+ hash: "sha512",
139
+ key: keys.sharedSecret,
140
+ length: 32,
141
+ salt: Buffer.alloc(0),
142
+ info: Buffer.from("ServerEncrypt-main")
143
+ });
144
+ const controllerToAccessoryKey = hkdf({
145
+ hash: "sha512",
146
+ key: keys.sharedSecret,
147
+ length: 32,
148
+ salt: Buffer.alloc(0),
149
+ info: Buffer.from("ClientEncrypt-main")
150
+ });
151
+ return {
152
+ accessoryToControllerKey,
153
+ controllerToAccessoryKey,
154
+ pairingId: keys.pairingId,
155
+ sharedSecret: keys.sharedSecret
156
+ };
157
+ }
158
+ async#request(step, data) {
159
+ const frameType = step === "m1" ? FrameType.PV_Start : FrameType.PV_Next;
160
+ const [, response] = await this.#stream.exchange(frameType, {
161
+ _pd: data,
162
+ _auTy: 4
163
+ });
164
+ if (typeof response !== "object" || response === null) {
165
+ throw new Error("Invalid response from receiver.");
166
+ }
167
+ return response["_pd"];
168
+ }
169
+ }
170
+
171
+ // src/utils.ts
172
+ function convertAttentionState(state) {
173
+ switch (state) {
174
+ case 1:
175
+ return "asleep";
176
+ case 2:
177
+ return "screensaver";
178
+ case 3:
179
+ return "awake";
180
+ case 4:
181
+ return "idle";
182
+ default:
183
+ return "unknown";
184
+ }
185
+ }
186
+
187
+ // src/stream.ts
134
188
  import { randomInt } from "node:crypto";
135
- import { Chacha20, ENCRYPTION, EncryptionAwareConnection, reporter } from "@basmilius/apple-common";
189
+ import { Chacha20, ENCRYPTION, EncryptionAwareConnection } from "@basmilius/apple-common";
136
190
  import { OPack } from "@basmilius/apple-encoding";
137
- var HEADER_BYTES = 4;
191
+ var HEADER_SIZE = 4;
138
192
 
139
- class CompanionLinkSocket extends EncryptionAwareConnection {
140
- get #encryption() {
193
+ class Stream extends EncryptionAwareConnection {
194
+ get #encryptionState() {
141
195
  return this[ENCRYPTION];
142
196
  }
143
197
  #queue = {};
144
198
  #buffer = Buffer.alloc(0);
145
199
  #xid;
146
- constructor(address, port) {
147
- super(address, port);
200
+ constructor(context, address, port) {
201
+ super(context, address, port);
148
202
  this.#xid = randomInt(0, 2 ** 16);
149
- this.onData = this.onData.bind(this);
150
- this.on("data", this.onData);
203
+ this.on("data", this.#onData.bind(this));
151
204
  }
152
205
  async exchange(type, obj) {
153
206
  const _x = this.#xid;
@@ -174,67 +227,65 @@ class CompanionLinkSocket extends EncryptionAwareConnection {
174
227
  let data;
175
228
  if (this.isEncrypted) {
176
229
  const nonce = Buffer.alloc(12);
177
- nonce.writeBigUInt64LE(BigInt(this.#encryption.writeCount++), 0);
178
- const encrypted = Chacha20.encrypt(this.#encryption.writeKey, nonce, header, payload);
230
+ nonce.writeBigUInt64LE(BigInt(this.#encryptionState.writeCount++), 0);
231
+ const encrypted = Chacha20.encrypt(this.#encryptionState.writeKey, nonce, header, payload);
179
232
  data = Buffer.concat([header, encrypted.ciphertext, encrypted.authTag]);
180
233
  } else {
181
234
  data = Buffer.concat([header, payload]);
182
235
  }
183
- reporter.raw("Sending data frame...", this.isEncrypted, Buffer.from(data).toString("hex"), obj);
236
+ this.context.logger.raw("[companion-link]", "Sending data frame", this.isEncrypted, Buffer.from(data).toString("hex"), obj);
184
237
  try {
185
238
  return await this.write(data);
186
239
  } catch (err) {
187
- reporter.error("Error in Companion Link send()", err);
240
+ this.context.logger.error("[companion-link]", "Error in Companion Link send()", err);
188
241
  this.emit("error", err);
189
242
  }
190
243
  }
191
- async onData(buffer) {
192
- reporter.raw("Received data frame", buffer.toString("hex"));
193
- this.#buffer = Buffer.concat([this.#buffer, buffer]);
244
+ async#onData(data) {
245
+ this.#buffer = Buffer.concat([this.#buffer, data]);
194
246
  try {
195
- while (this.#buffer.byteLength >= HEADER_BYTES) {
196
- const header = this.#buffer.subarray(0, HEADER_BYTES);
247
+ while (this.#buffer.byteLength >= HEADER_SIZE) {
248
+ const header = this.#buffer.subarray(0, HEADER_SIZE);
197
249
  const payloadLength = header.readUintBE(1, 3);
198
- const totalLength = HEADER_BYTES + payloadLength;
250
+ const totalLength = HEADER_SIZE + payloadLength;
199
251
  if (this.#buffer.byteLength < totalLength) {
200
- reporter.warn(`Not enough data yet, waiting on the next frame.. needed=${totalLength} available=${this.#buffer.byteLength} receivedLength=${buffer.byteLength}`);
252
+ this.context.logger.warn("[companion-link]", `Data packet is too short needed=${totalLength} available=${this.#buffer.byteLength} receivedLength=${data.byteLength}`);
201
253
  return;
202
254
  }
203
- reporter.raw(`Frame found length=${totalLength} availableLength=${this.#buffer.byteLength} receivedLength=${buffer.byteLength}`);
204
- const frame = Buffer.from(this.#buffer.subarray(0, totalLength));
255
+ this.context.logger.raw("[companion-link]", `Received frame length=${totalLength} availableLength=${this.#buffer.byteLength} receivedLength=${data.byteLength}`);
256
+ let frame = Buffer.from(this.#buffer.subarray(0, totalLength));
205
257
  this.#buffer = this.#buffer.subarray(totalLength);
206
- reporter.raw(`Handle frame, ${this.#buffer.byteLength} bytes left...`);
207
- const data = await this.#decrypt(frame);
208
- let payload = data.subarray(4, totalLength);
209
- await this.#handle(header, payload);
258
+ this.context.logger.raw("[companion-link]", `Handle frame, ${this.#buffer.byteLength} bytes left...`);
259
+ if (this.isEncrypted) {
260
+ frame = this.#decrypt(frame);
261
+ }
262
+ const payload = frame.subarray(HEADER_SIZE, totalLength);
263
+ this.#handle(header, payload);
210
264
  }
211
265
  } catch (err) {
212
- reporter.error("Error in Companion Link onData handler", err);
266
+ this.context.logger.error("[companion-link]", "#onData()", err);
213
267
  this.emit("error", err);
214
268
  }
215
269
  }
216
- async#decrypt(data) {
217
- if (!this.isEncrypted) {
218
- return data;
219
- }
270
+ #decrypt(data) {
220
271
  const header = data.subarray(0, 4);
221
272
  const payloadLength = header.readUintBE(1, 3);
222
273
  const payload = data.subarray(4, 4 + payloadLength);
223
274
  const authTag = payload.subarray(payload.byteLength - 16);
224
275
  const ciphertext = payload.subarray(0, payload.byteLength - 16);
225
276
  const nonce = Buffer.alloc(12);
226
- nonce.writeBigUint64LE(BigInt(this.#encryption.readCount++), 0);
227
- const decrypted = Chacha20.decrypt(this.#encryption.readKey, nonce, header, ciphertext, authTag);
277
+ nonce.writeBigUint64LE(BigInt(this.#encryptionState.readCount++), 0);
278
+ const decrypted = Chacha20.decrypt(this.#encryptionState.readKey, nonce, header, ciphertext, authTag);
228
279
  return Buffer.concat([header, decrypted, authTag]);
229
280
  }
230
- async#handle(header, payload) {
281
+ #handle(header, payload) {
231
282
  const type = header.readInt8();
232
283
  if (!OPackFrameTypes.includes(type)) {
233
- reporter.warn("Packet not handled, no opack frame.");
284
+ this.context.logger.warn("[companion-link]", "Packet not handled, no opack frame.");
234
285
  return;
235
286
  }
236
287
  payload = OPack.decode(payload);
237
- reporter.raw("Decoded OPACK", { header, payload });
288
+ this.context.logger.raw("[companion-link]", "Decoded OPACK", { header, payload });
238
289
  if ("_x" in payload) {
239
290
  const _x = payload._x;
240
291
  if (_x in this.#queue) {
@@ -256,109 +307,72 @@ class CompanionLinkSocket extends EncryptionAwareConnection {
256
307
  resolve?.([header, payload]);
257
308
  delete this.#queue[_x];
258
309
  } else {
259
- reporter.warn("No handler for message", [header, payload]);
260
- }
261
- }
262
- }
263
-
264
- // src/verify.ts
265
- import { AccessoryVerify, hkdf } from "@basmilius/apple-common";
266
- class CompanionLinkVerify {
267
- #internal;
268
- #protocol;
269
- constructor(protocol) {
270
- this.#internal = new AccessoryVerify(this.#request.bind(this));
271
- this.#protocol = protocol;
272
- }
273
- async start(credentials) {
274
- const keys = await this.#internal.start(credentials);
275
- const accessoryToControllerKey = hkdf({
276
- hash: "sha512",
277
- key: keys.sharedSecret,
278
- length: 32,
279
- salt: Buffer.alloc(0),
280
- info: Buffer.from("ServerEncrypt-main")
281
- });
282
- const controllerToAccessoryKey = hkdf({
283
- hash: "sha512",
284
- key: keys.sharedSecret,
285
- length: 32,
286
- salt: Buffer.alloc(0),
287
- info: Buffer.from("ClientEncrypt-main")
288
- });
289
- return {
290
- accessoryToControllerKey,
291
- controllerToAccessoryKey,
292
- pairingId: keys.pairingId,
293
- sharedSecret: keys.sharedSecret
294
- };
295
- }
296
- async#request(step, data) {
297
- const frameType = step === "m1" ? FrameType.PV_Start : FrameType.PV_Next;
298
- const [, response] = await this.#protocol.socket.exchange(frameType, {
299
- _pd: data,
300
- _auTy: 4
301
- });
302
- if (typeof response !== "object" || response === null) {
303
- throw new Error("Invalid response from receiver.");
310
+ this.context.logger.warn("[companion-link]", "No handler for message", [header, payload]);
304
311
  }
305
- return response["_pd"];
306
312
  }
307
313
  }
308
314
 
309
315
  // src/protocol.ts
310
- class CompanionLink {
311
- get device() {
312
- return this.#device;
316
+ class Protocol {
317
+ get context() {
318
+ return this.#context;
313
319
  }
314
- get socket() {
315
- return this.#socket;
320
+ get discoveryResult() {
321
+ return this.#discoveryResult;
316
322
  }
317
323
  get pairing() {
318
324
  return this.#pairing;
319
325
  }
326
+ get stream() {
327
+ return this.#stream;
328
+ }
320
329
  get verify() {
321
330
  return this.#verify;
322
331
  }
323
- #device;
324
- #socket;
332
+ #context;
333
+ #discoveryResult;
325
334
  #pairing;
335
+ #stream;
326
336
  #verify;
327
- constructor(device) {
328
- this.#device = device;
329
- this.#socket = new CompanionLinkSocket(device.address, device.service.port);
330
- this.#pairing = new CompanionLinkPairing(this);
331
- this.#verify = new CompanionLinkVerify(this);
337
+ constructor(deviceId, discoveryResult) {
338
+ this.#context = new Context(deviceId.replace(`.${COMPANION_LINK_SERVICE}`, "").replace(".local", ""));
339
+ this.#discoveryResult = discoveryResult;
340
+ this.#stream = new Stream(this.#context, discoveryResult.address, discoveryResult.service.port);
341
+ this.#pairing = new Pairing(this);
342
+ this.#verify = new Verify(this);
332
343
  }
333
344
  async connect() {
334
- await this.#socket.connect();
345
+ await this.#stream.connect();
346
+ }
347
+ async destroy() {
348
+ await this.#stream.destroy();
335
349
  }
336
350
  async disconnect() {
337
- await this.#socket.disconnect();
351
+ await this.#stream.disconnect();
338
352
  }
339
353
  async fetchMediaControlStatus() {
340
- await this.#socket.exchange(FrameType.E_OPACK, {
354
+ await this.#stream.exchange(FrameType.E_OPACK, {
341
355
  _i: "FetchMediaControlStatus",
342
356
  _t: MessageType.Request,
343
357
  _c: {}
344
358
  });
345
359
  }
346
360
  async fetchNowPlayingInfo() {
347
- await this.#socket.exchange(FrameType.E_OPACK, {
361
+ await this.#stream.exchange(FrameType.E_OPACK, {
348
362
  _i: "FetchCurrentNowPlayingInfoEvent",
349
363
  _t: MessageType.Request,
350
364
  _c: {}
351
365
  });
352
366
  }
353
367
  async fetchSupportedActions() {
354
- await this.#socket.exchange(FrameType.E_OPACK, {
368
+ await this.#stream.exchange(FrameType.E_OPACK, {
355
369
  _i: "FetchSupportedActionsEvent",
356
370
  _t: MessageType.Request,
357
371
  _c: {}
358
372
  });
359
373
  }
360
374
  async getAttentionState() {
361
- const [, payload] = await this.#socket.exchange(FrameType.E_OPACK, {
375
+ const [, payload] = await this.#stream.exchange(FrameType.E_OPACK, {
362
376
  _i: "FetchAttentionState",
363
377
  _t: MessageType.Request,
364
378
  _c: {}
@@ -367,7 +381,7 @@ class CompanionLink {
367
381
  return convertAttentionState(_c.state);
368
382
  }
369
383
  async getLaunchableApps() {
370
- const [, payload] = await this.#socket.exchange(FrameType.E_OPACK, {
384
+ const [, payload] = await this.#stream.exchange(FrameType.E_OPACK, {
371
385
  _i: "FetchLaunchableApplicationsEvent",
372
386
  _t: MessageType.Request,
373
387
  _c: {}
@@ -379,7 +393,7 @@ class CompanionLink {
379
393
  }));
380
394
  }
381
395
  async getSiriRemoteInfo() {
382
- const [, payload] = await this.#socket.exchange(FrameType.E_OPACK, {
396
+ const [, payload] = await this.#stream.exchange(FrameType.E_OPACK, {
383
397
  _i: "FetchSiriRemoteInfo",
384
398
  _t: MessageType.Request,
385
399
  _c: {}
@@ -387,7 +401,7 @@ class CompanionLink {
387
401
  return Plist.parse(Buffer.from(payload["_c"]["SiriRemoteInfoKey"]).buffer);
388
402
  }
389
403
  async getUserAccounts() {
390
- const [, payload] = await this.#socket.exchange(FrameType.E_OPACK, {
404
+ const [, payload] = await this.#stream.exchange(FrameType.E_OPACK, {
391
405
  _i: "FetchUserAccountsEvent",
392
406
  _t: MessageType.Request,
393
407
  _c: {}
@@ -399,7 +413,7 @@ class CompanionLink {
399
413
  }));
400
414
  }
401
415
  async hidCommand(command, down = false) {
402
- await this.#socket.exchange(FrameType.E_OPACK, {
416
+ await this.#stream.exchange(FrameType.E_OPACK, {
403
417
  _i: "_hidC",
404
418
  _t: MessageType.Request,
405
419
  _c: {
@@ -409,7 +423,7 @@ class CompanionLink {
409
423
  });
410
424
  }
411
425
  async launchApp(bundleId) {
412
- await this.#socket.exchange(FrameType.E_OPACK, {
426
+ await this.#stream.exchange(FrameType.E_OPACK, {
413
427
  _i: "_launchApp",
414
428
  _t: MessageType.Request,
415
429
  _c: {
@@ -418,7 +432,7 @@ class CompanionLink {
418
432
  });
419
433
  }
420
434
  async launchUrl(url) {
421
- await this.#socket.exchange(FrameType.E_OPACK, {
435
+ await this.#stream.exchange(FrameType.E_OPACK, {
422
436
  _i: "_launchApp",
423
437
  _t: MessageType.Request,
424
438
  _c: {
@@ -427,7 +441,7 @@ class CompanionLink {
427
441
  });
428
442
  }
429
443
  async mediaControlCommand(command, content) {
430
- const [, payload] = await this.#socket.exchange(FrameType.E_OPACK, {
444
+ const [, payload] = await this.#stream.exchange(FrameType.E_OPACK, {
431
445
  _i: "_mcc",
432
446
  _t: MessageType.Request,
433
447
  _c: {
@@ -457,7 +471,7 @@ class CompanionLink {
457
471
  }
458
472
  }
459
473
  async switchUserAccount(accountId) {
460
- await this.#socket.exchange(FrameType.E_OPACK, {
474
+ await this.#stream.exchange(FrameType.E_OPACK, {
461
475
  _i: "SwitchUserAccountEvent",
462
476
  _t: MessageType.Request,
463
477
  _c: {
@@ -466,8 +480,8 @@ class CompanionLink {
466
480
  });
467
481
  }
468
482
  async _subscribe(event, fn) {
469
- this.#socket.on(event, fn);
470
- await this.#socket.send(FrameType.E_OPACK, {
483
+ this.#stream.on(event, fn);
484
+ await this.#stream.send(FrameType.E_OPACK, {
471
485
  _i: "_interest",
472
486
  _t: MessageType.Event,
473
487
  _c: {
@@ -476,13 +490,13 @@ class CompanionLink {
476
490
  });
477
491
  }
478
492
  async _unsubscribe(event, fn) {
479
- if (!this.socket.isConnected) {
493
+ if (!this.#stream.isConnected) {
480
494
  return;
481
495
  }
482
496
  if (fn) {
483
- this.#socket.off(event, fn);
497
+ this.#stream.off(event, fn);
484
498
  }
485
- await this.#socket.send(FrameType.E_OPACK, {
499
+ await this.#stream.send(FrameType.E_OPACK, {
486
500
  _i: "_interest",
487
501
  _t: MessageType.Event,
488
502
  _c: {
@@ -491,7 +505,7 @@ class CompanionLink {
491
505
  });
492
506
  }
493
507
  async _sessionStart() {
494
- const [, payload] = await this.#socket.exchange(FrameType.E_OPACK, {
508
+ const [, payload] = await this.#stream.exchange(FrameType.E_OPACK, {
495
509
  _i: "_sessionStart",
496
510
  _t: MessageType.Request,
497
511
  _btHP: false,
@@ -504,7 +518,7 @@ class CompanionLink {
504
518
  return objectOrFail(payload);
505
519
  }
506
520
  async _systemInfo(pairingId) {
507
- const [, payload] = await this.#socket.exchange(FrameType.E_OPACK, {
521
+ const [, payload] = await this.#stream.exchange(FrameType.E_OPACK, {
508
522
  _i: "_systemInfo",
509
523
  _t: MessageType.Request,
510
524
  _btHP: false,
@@ -512,7 +526,7 @@ class CompanionLink {
512
526
  _bf: 0,
513
527
  _cf: 512,
514
528
  _clFl: 128,
515
- _i: randomBytes(6).toString("hex"),
529
+ _i: "b561af32aea6",
516
530
  _idsID: pairingId.toString(),
517
531
  _pubID: "DA:6D:1E:D8:A0:4F",
518
532
  _sf: 1099511628032,
@@ -554,7 +568,7 @@ class CompanionLink {
554
568
  return objectOrFail(payload);
555
569
  }
556
570
  async _tiStart() {
557
- const [, payload] = await this.#socket.exchange(FrameType.E_OPACK, {
571
+ const [, payload] = await this.#stream.exchange(FrameType.E_OPACK, {
558
572
  _i: "_tiStart",
559
573
  _t: MessageType.Request,
560
574
  _btHP: false,
@@ -563,7 +577,7 @@ class CompanionLink {
563
577
  return objectOrFail(payload);
564
578
  }
565
579
  async _touchStart() {
566
- const [, payload] = await this.#socket.exchange(FrameType.E_OPACK, {
580
+ const [, payload] = await this.#stream.exchange(FrameType.E_OPACK, {
567
581
  _i: "_touchStart",
568
582
  _t: MessageType.Request,
569
583
  _btHP: false,
@@ -576,7 +590,7 @@ class CompanionLink {
576
590
  return objectOrFail(payload);
577
591
  }
578
592
  async _tvrcSessionStart() {
579
- const [, payload] = await this.#socket.exchange(FrameType.E_OPACK, {
593
+ const [, payload] = await this.#stream.exchange(FrameType.E_OPACK, {
580
594
  _i: "TVRCSessionStart",
581
595
  _t: MessageType.Request,
582
596
  _btHP: false,
@@ -590,12 +604,14 @@ function objectOrFail(obj) {
590
604
  if (typeof obj === "object") {
591
605
  return obj;
592
606
  }
593
- reporter2.error("Expected an object.", { obj });
594
607
  throw new Error("Expected an object.");
595
608
  }
596
609
  export {
597
610
  convertAttentionState,
611
+ Verify,
612
+ Stream,
613
+ Protocol,
614
+ Pairing,
598
615
  MediaControlCommand,
599
- HidCommand,
600
- CompanionLink
616
+ HidCommand
601
617
  };
package/dist/pairing.d.ts CHANGED
@@ -1,10 +1,19 @@
1
- import { type AccessoryCredentials, type AccessoryKeys, AccessoryPair } from "@basmilius/apple-common";
1
+ import { type AccessoryCredentials, type AccessoryKeys, AccessoryPair, AccessoryVerify } from "@basmilius/apple-common";
2
2
  import type Protocol from "./protocol";
3
- export default class CompanionLinkPairing {
3
+ import type Stream from "./stream";
4
+ export declare class Pairing {
4
5
  #private;
5
6
  get internal(): AccessoryPair;
7
+ get stream(): Stream;
6
8
  constructor(protocol: Protocol);
7
9
  start(): Promise<void>;
8
10
  pin(askPin: () => Promise<string>): Promise<AccessoryCredentials>;
9
11
  transient(): Promise<AccessoryKeys>;
10
12
  }
13
+ export declare class Verify {
14
+ #private;
15
+ get internal(): AccessoryVerify;
16
+ get stream(): Stream;
17
+ constructor(protocol: Protocol);
18
+ start(credentials: AccessoryCredentials): Promise<AccessoryKeys>;
19
+ }
@@ -1,17 +1,18 @@
1
- import { type DiscoveryResult } from "@basmilius/apple-common";
2
- import type { AttentionState, ButtonPressType, LaunchableApp, UserAccount } from "./types";
1
+ import { Context, type DiscoveryResult } from "@basmilius/apple-common";
3
2
  import { type HidCommandKey, type MediaControlCommandKey } from "./const";
4
- import Pairing from "./pairing";
5
- import Socket from "./socket";
6
- import Verify from "./verify";
7
- export default class CompanionLink {
3
+ import { Pairing, Verify } from "./pairing";
4
+ import type { AttentionState, ButtonPressType, LaunchableApp, UserAccount } from "./types";
5
+ import Stream from "./stream";
6
+ export default class Protocol {
8
7
  #private;
9
- get device(): DiscoveryResult;
10
- get socket(): Socket;
8
+ get context(): Context;
9
+ get discoveryResult(): DiscoveryResult;
11
10
  get pairing(): Pairing;
11
+ get stream(): Stream;
12
12
  get verify(): Verify;
13
- constructor(device: DiscoveryResult);
13
+ constructor(deviceId: string, discoveryResult: DiscoveryResult);
14
14
  connect(): Promise<void>;
15
+ destroy(): Promise<void>;
15
16
  disconnect(): Promise<void>;
16
17
  fetchMediaControlStatus(): Promise<void>;
17
18
  fetchNowPlayingInfo(): Promise<void>;
@@ -0,0 +1,7 @@
1
+ import { type Context, EncryptionAwareConnection } from "@basmilius/apple-common";
2
+ export default class Stream extends EncryptionAwareConnection<Record<string, [unknown]>> {
3
+ #private;
4
+ constructor(context: Context, address: string, port: number);
5
+ exchange(type: number, obj: Record<string, unknown>): Promise<[number, unknown]>;
6
+ send(type: number, obj: Record<string, unknown>): Promise<void>;
7
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@basmilius/apple-companion-link",
3
3
  "description": "Implementation of Apple's Companion Link in Node.js.",
4
- "version": "0.1.2",
4
+ "version": "0.2.0",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "author": {
@@ -40,8 +40,8 @@
40
40
  }
41
41
  },
42
42
  "dependencies": {
43
- "@basmilius/apple-common": "0.1.2",
44
- "@basmilius/apple-encoding": "0.1.2"
43
+ "@basmilius/apple-common": "0.2.0",
44
+ "@basmilius/apple-encoding": "0.2.0"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@basmilius/tools": "^2.23.0",
package/dist/socket.d.ts DELETED
@@ -1,8 +0,0 @@
1
- import { EncryptionAwareConnection } from "@basmilius/apple-common";
2
- export default class CompanionLinkSocket extends EncryptionAwareConnection<Record<string, [unknown]>> {
3
- #private;
4
- constructor(address: string, port: number);
5
- exchange(type: number, obj: Record<string, unknown>): Promise<[number, unknown]>;
6
- send(type: number, obj: Record<string, unknown>): Promise<void>;
7
- onData(buffer: Buffer): Promise<void>;
8
- }
package/dist/verify.d.ts DELETED
@@ -1,7 +0,0 @@
1
- import { type AccessoryCredentials, type AccessoryKeys } from "@basmilius/apple-common";
2
- import type Protocol from "./protocol";
3
- export default class CompanionLinkVerify {
4
- #private;
5
- constructor(protocol: Protocol);
6
- start(credentials: AccessoryCredentials): Promise<AccessoryKeys>;
7
- }
File without changes