@basmilius/apple-common 0.9.18 → 0.9.19

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.mts CHANGED
@@ -437,6 +437,30 @@ declare const RAOP_SERVICE = "_raop._tcp.local";
437
437
  //#region src/symbols.d.ts
438
438
  declare const ENCRYPTION: unique symbol;
439
439
  //#endregion
440
+ //#region src/recovery.d.ts
441
+ type EventMap$1 = {
442
+ recovering: [attempt: number];
443
+ recovered: [];
444
+ failed: [errors: Error[]];
445
+ };
446
+ type ConnectionRecoveryOptions = {
447
+ maxAttempts?: number;
448
+ baseDelay?: number;
449
+ maxDelay?: number;
450
+ useExponentialBackoff?: boolean;
451
+ reconnectInterval?: number;
452
+ onReconnect: () => Promise<void>;
453
+ };
454
+ declare class ConnectionRecovery extends EventEmitter<EventMap$1> {
455
+ #private;
456
+ constructor(options: ConnectionRecoveryOptions);
457
+ get isRecovering(): boolean;
458
+ get attempt(): number;
459
+ handleDisconnect(unexpected: boolean): void;
460
+ reset(): void;
461
+ dispose(): void;
462
+ }
463
+ //#endregion
440
464
  //#region src/timing.d.ts
441
465
  declare class TimingServer {
442
466
  #private;
@@ -457,6 +481,78 @@ declare function randomInt64(): bigint;
457
481
  declare function uint16ToBE(value: number): Buffer;
458
482
  declare function uint53ToLE(value: number): Buffer;
459
483
  //#endregion
484
+ //#region src/deviceModel.d.ts
485
+ declare enum DeviceModel {
486
+ Unknown = 0,
487
+ AppleTVGen2 = 1,
488
+ AppleTVGen3 = 2,
489
+ AppleTVHD = 3,
490
+ AppleTV4K = 4,
491
+ AppleTV4KGen2 = 5,
492
+ AppleTV4KGen3 = 6,
493
+ HomePod = 10,
494
+ HomePodMini = 11,
495
+ HomePodGen2 = 12,
496
+ AirPortExpress = 20,
497
+ AirPortExpressGen2 = 21
498
+ }
499
+ declare enum DeviceType {
500
+ Unknown = 0,
501
+ AppleTV = 1,
502
+ HomePod = 2,
503
+ AirPort = 3
504
+ }
505
+ declare const lookupDeviceModel: (identifier: string) => DeviceModel;
506
+ declare const getDeviceModelName: (model: DeviceModel) => string;
507
+ declare const getDeviceType: (model: DeviceModel) => DeviceType;
508
+ declare const isAppleTV: (model: DeviceModel) => boolean;
509
+ declare const isHomePod: (model: DeviceModel) => boolean;
510
+ declare const isAirPort: (model: DeviceModel) => boolean;
511
+ //#endregion
512
+ //#region src/errors.d.ts
513
+ declare class AppleProtocolError extends Error {
514
+ constructor(message: string);
515
+ }
516
+ declare class ConnectionError extends AppleProtocolError {
517
+ constructor(message: string);
518
+ }
519
+ declare class ConnectionTimeoutError extends ConnectionError {
520
+ constructor(message?: string);
521
+ }
522
+ declare class ConnectionClosedError extends ConnectionError {
523
+ constructor(message?: string);
524
+ }
525
+ declare class PairingError extends AppleProtocolError {
526
+ constructor(message: string);
527
+ }
528
+ declare class AuthenticationError extends PairingError {
529
+ constructor(message: string);
530
+ }
531
+ declare class CredentialsError extends PairingError {
532
+ constructor(message: string);
533
+ }
534
+ declare class CommandError extends AppleProtocolError {
535
+ constructor(message: string);
536
+ }
537
+ declare class SetupError extends AppleProtocolError {
538
+ constructor(message: string);
539
+ }
540
+ declare class DiscoveryError extends AppleProtocolError {
541
+ constructor(message: string);
542
+ }
543
+ declare class EncryptionError extends AppleProtocolError {
544
+ constructor(message: string);
545
+ }
546
+ declare class InvalidResponseError extends AppleProtocolError {
547
+ constructor(message: string);
548
+ }
549
+ declare class TimeoutError extends AppleProtocolError {
550
+ constructor(message: string);
551
+ }
552
+ declare class PlaybackError extends AppleProtocolError {
553
+ constructor(message: string);
554
+ }
555
+ //#endregion
460
556
  //#region src/audioSource.d.ts
461
557
  interface AudioSource {
462
558
  get duration(): number;
@@ -466,4 +562,4 @@ interface AudioSource {
466
562
  stop(): Promise<void>;
467
563
  }
468
564
  //#endregion
469
- export { AIRPLAY_SERVICE, AIRPLAY_TRANSIENT_PIN, type AccessoryCredentials, type AccessoryKeys, AccessoryPair, AccessoryVerify, type AirPlayFeatureFlagName, AirPlayFeatureFlags, type AudioSource, COMPANION_LINK_SERVICE, type CombinedDiscoveryResult, Connection, type ConnectionState, Context, Discovery, type DiscoveryResult, ENCRYPTION, EncryptionAwareConnection, EncryptionState, type EventMap, HTTP_TIMEOUT, JsonStorage, type Logger, type MdnsService, MemoryStorage, type PairingRequirement, type ProtocolType, RAOP_SERVICE, type Reporter, Storage, type StorageData, type StoredDevice, TimingServer, describeFlags, generateActiveRemoteId, generateDacpId, generateSessionId, getLocalIP, getMacAddress, getPairingRequirement, getProtocolVersion, hasFeatureFlag, isPasswordRequired, isRemoteControlSupported, multicast as mdnsMulticast, unicast as mdnsUnicast, parseFeatures, prompt, randomInt32, randomInt64, reporter, uint16ToBE, uint53ToLE, v4 as uuid, waitFor };
565
+ export { AIRPLAY_SERVICE, AIRPLAY_TRANSIENT_PIN, type AccessoryCredentials, type AccessoryKeys, AccessoryPair, AccessoryVerify, type AirPlayFeatureFlagName, AirPlayFeatureFlags, AppleProtocolError, type AudioSource, AuthenticationError, COMPANION_LINK_SERVICE, type CombinedDiscoveryResult, CommandError, Connection, ConnectionClosedError, ConnectionError, ConnectionRecovery, type ConnectionRecoveryOptions, type ConnectionState, ConnectionTimeoutError, Context, CredentialsError, DeviceModel, DeviceType, Discovery, DiscoveryError, type DiscoveryResult, ENCRYPTION, EncryptionAwareConnection, EncryptionError, EncryptionState, type EventMap, HTTP_TIMEOUT, InvalidResponseError, JsonStorage, type Logger, type MdnsService, MemoryStorage, PairingError, type PairingRequirement, PlaybackError, type ProtocolType, RAOP_SERVICE, type Reporter, SetupError, Storage, type StorageData, type StoredDevice, TimeoutError, TimingServer, describeFlags, generateActiveRemoteId, generateDacpId, generateSessionId, getDeviceModelName, getDeviceType, getLocalIP, getMacAddress, getPairingRequirement, getProtocolVersion, hasFeatureFlag, isAirPort, isAppleTV, isHomePod, isPasswordRequired, isRemoteControlSupported, lookupDeviceModel, multicast as mdnsMulticast, unicast as mdnsUnicast, parseFeatures, prompt, randomInt32, randomInt64, reporter, uint16ToBE, uint53ToLE, v4 as uuid, waitFor };
package/dist/index.mjs CHANGED
@@ -257,6 +257,93 @@ const AIRPLAY_SERVICE = "_airplay._tcp.local";
257
257
  const COMPANION_LINK_SERVICE = "_companion-link._tcp.local";
258
258
  const RAOP_SERVICE = "_raop._tcp.local";
259
259
 
260
+ //#endregion
261
+ //#region src/errors.ts
262
+ var AppleProtocolError = class extends Error {
263
+ constructor(message) {
264
+ super(message);
265
+ this.name = "AppleProtocolError";
266
+ }
267
+ };
268
+ var ConnectionError = class extends AppleProtocolError {
269
+ constructor(message) {
270
+ super(message);
271
+ this.name = "ConnectionError";
272
+ }
273
+ };
274
+ var ConnectionTimeoutError = class extends ConnectionError {
275
+ constructor(message = "Connection timed out.") {
276
+ super(message);
277
+ this.name = "ConnectionTimeoutError";
278
+ }
279
+ };
280
+ var ConnectionClosedError = class extends ConnectionError {
281
+ constructor(message = "Connection closed unexpectedly.") {
282
+ super(message);
283
+ this.name = "ConnectionClosedError";
284
+ }
285
+ };
286
+ var PairingError = class extends AppleProtocolError {
287
+ constructor(message) {
288
+ super(message);
289
+ this.name = "PairingError";
290
+ }
291
+ };
292
+ var AuthenticationError = class extends PairingError {
293
+ constructor(message) {
294
+ super(message);
295
+ this.name = "AuthenticationError";
296
+ }
297
+ };
298
+ var CredentialsError = class extends PairingError {
299
+ constructor(message) {
300
+ super(message);
301
+ this.name = "CredentialsError";
302
+ }
303
+ };
304
+ var CommandError = class extends AppleProtocolError {
305
+ constructor(message) {
306
+ super(message);
307
+ this.name = "CommandError";
308
+ }
309
+ };
310
+ var SetupError = class extends AppleProtocolError {
311
+ constructor(message) {
312
+ super(message);
313
+ this.name = "SetupError";
314
+ }
315
+ };
316
+ var DiscoveryError = class extends AppleProtocolError {
317
+ constructor(message) {
318
+ super(message);
319
+ this.name = "DiscoveryError";
320
+ }
321
+ };
322
+ var EncryptionError = class extends AppleProtocolError {
323
+ constructor(message) {
324
+ super(message);
325
+ this.name = "EncryptionError";
326
+ }
327
+ };
328
+ var InvalidResponseError = class extends AppleProtocolError {
329
+ constructor(message) {
330
+ super(message);
331
+ this.name = "InvalidResponseError";
332
+ }
333
+ };
334
+ var TimeoutError = class extends AppleProtocolError {
335
+ constructor(message) {
336
+ super(message);
337
+ this.name = "TimeoutError";
338
+ }
339
+ };
340
+ var PlaybackError = class extends AppleProtocolError {
341
+ constructor(message) {
342
+ super(message);
343
+ this.name = "PlaybackError";
344
+ }
345
+ };
346
+
260
347
  //#endregion
261
348
  //#region src/mdns.ts
262
349
  const MDNS_ADDRESS = "224.0.0.251";
@@ -321,10 +408,12 @@ function createQueryPackets(services, qtype = QueryType.PTR, unicastResponse = f
321
408
  }
322
409
  return packets;
323
410
  }
411
+ const MAX_POINTER_JUMPS = 128;
324
412
  const decodeQName = (buf, offset) => {
325
413
  const labels = [];
326
414
  let currentOffset = offset;
327
415
  let jumped = false;
416
+ let jumps = 0;
328
417
  let returnOffset = offset;
329
418
  while (currentOffset < buf.byteLength) {
330
419
  const length = buf[currentOffset];
@@ -333,6 +422,7 @@ const decodeQName = (buf, offset) => {
333
422
  break;
334
423
  }
335
424
  if ((length & 192) === 192) {
425
+ if (++jumps > MAX_POINTER_JUMPS) break;
336
426
  const pointer = (length & 63) << 8 | buf[currentOffset + 1];
337
427
  if (!jumped) returnOffset = currentOffset + 2;
338
428
  currentOffset = pointer;
@@ -713,7 +803,7 @@ var Discovery = class Discovery {
713
803
  tries--;
714
804
  await waitFor(timeout);
715
805
  }
716
- throw new Error("Device not found after several tries, aborting.");
806
+ throw new DiscoveryError(`Device '${id}' not found after several tries, aborting.`);
717
807
  }
718
808
  static clearCache() {
719
809
  Discovery.#cache.clear();
@@ -826,7 +916,7 @@ var Connection = class extends EventEmitter {
826
916
  }
827
917
  async connect() {
828
918
  if (this.#state === "connected") return;
829
- if (this.#state === "connecting") throw new Error("A connection is already being established.");
919
+ if (this.#state === "connecting") throw new ConnectionError("A connection is already being established.");
830
920
  this.#retryEnabled = true;
831
921
  this.#retryAttempt = 0;
832
922
  return this.#attemptConnect();
@@ -861,7 +951,7 @@ var Connection = class extends EventEmitter {
861
951
  }
862
952
  write(data) {
863
953
  if (!this.#socket || this.state !== "connected" || !this.#socket.writable) {
864
- this.#emitInternal("error", /* @__PURE__ */ new Error("Cannot write to a disconnected connection."));
954
+ this.#emitInternal("error", new ConnectionClosedError("Cannot write to a disconnected connection."));
865
955
  return;
866
956
  }
867
957
  this.#socket.write(data, (err) => {
@@ -942,7 +1032,7 @@ var Connection = class extends EventEmitter {
942
1032
  this.#context.logger.net(`Connection closed (${hadError ? "with error" : "normally"}).`);
943
1033
  }
944
1034
  this.#emitInternal("close", hadError);
945
- if (wasConnected && this.#retryEnabled && hadError) this.#scheduleRetry(/* @__PURE__ */ new Error("Connection closed unexpectedly."));
1035
+ if (wasConnected && this.#retryEnabled && hadError) this.#scheduleRetry(new ConnectionClosedError());
946
1036
  }
947
1037
  #onConnect() {
948
1038
  this.#state = "connected";
@@ -974,7 +1064,7 @@ var Connection = class extends EventEmitter {
974
1064
  }
975
1065
  #onTimeout() {
976
1066
  this.#context.logger.error("Connection timed out.");
977
- const err = /* @__PURE__ */ new Error("Connection timed out.");
1067
+ const err = new ConnectionTimeoutError();
978
1068
  this.#emitInternal("timeout");
979
1069
  if (this.#state === "connecting") this.#scheduleRetry(err);
980
1070
  else {
@@ -3176,7 +3266,7 @@ var AccessoryPair = class extends BasePairing {
3176
3266
  const m4 = await this.m4(m3);
3177
3267
  const m5 = await this.m5(m4);
3178
3268
  const m6 = await this.m6(m4, m5);
3179
- if (!m6) throw new Error("Pairing failed, could not get accessory keys.");
3269
+ if (!m6) throw new PairingError("Pairing failed, could not get accessory keys.");
3180
3270
  return m6;
3181
3271
  }
3182
3272
  async transient() {
@@ -3337,7 +3427,7 @@ var AccessoryPair = class extends BasePairing {
3337
3427
  accessoryIdentifier,
3338
3428
  accessoryLongTermPublicKey
3339
3429
  ]);
3340
- if (!Ed25519.verify(accessoryInfo, accessorySignature, accessoryLongTermPublicKey)) throw new Error("Invalid accessory signature.");
3430
+ if (!Ed25519.verify(accessoryInfo, accessorySignature, accessoryLongTermPublicKey)) throw new AuthenticationError("Invalid accessory signature.");
3341
3431
  return {
3342
3432
  accessoryIdentifier: accessoryIdentifier.toString(),
3343
3433
  accessoryLongTermPublicKey,
@@ -3410,13 +3500,13 @@ var AccessoryVerify = class extends BasePairing {
3410
3500
  const tlv = TLV8.decode(data);
3411
3501
  const accessoryIdentifier = tlv.get(TLV8.Value.Identifier);
3412
3502
  const accessorySignature = tlv.get(TLV8.Value.Signature);
3413
- if (accessoryIdentifier.toString() !== localAccessoryIdentifier) throw new Error(`Invalid accessory identifier. Expected ${accessoryIdentifier.toString()} to be ${localAccessoryIdentifier}.`);
3503
+ if (accessoryIdentifier.toString() !== localAccessoryIdentifier) throw new AuthenticationError(`Invalid accessory identifier. Expected ${accessoryIdentifier.toString()} to be ${localAccessoryIdentifier}.`);
3414
3504
  const accessoryInfo = Buffer.concat([
3415
3505
  m1.serverPublicKey,
3416
3506
  accessoryIdentifier,
3417
3507
  this.#ephemeralKeyPair.publicKey
3418
3508
  ]);
3419
- if (!Ed25519.verify(accessoryInfo, accessorySignature, longTermPublicKey)) throw new Error("Invalid accessory signature.");
3509
+ if (!Ed25519.verify(accessoryInfo, accessorySignature, longTermPublicKey)) throw new AuthenticationError("Invalid accessory signature.");
3420
3510
  return {
3421
3511
  serverEphemeralPublicKey: m1.serverPublicKey,
3422
3512
  sessionKey,
@@ -3463,6 +3553,112 @@ var AccessoryVerify = class extends BasePairing {
3463
3553
  //#region src/symbols.ts
3464
3554
  const ENCRYPTION = Symbol();
3465
3555
 
3556
+ //#endregion
3557
+ //#region src/recovery.ts
3558
+ var ConnectionRecovery = class extends EventEmitter {
3559
+ #options;
3560
+ #attempt = 0;
3561
+ #errors = [];
3562
+ #isRecovering = false;
3563
+ #isScheduledReconnecting = false;
3564
+ #retryTimeout;
3565
+ #reconnectInterval;
3566
+ #disposed = false;
3567
+ constructor(options) {
3568
+ super();
3569
+ this.#options = {
3570
+ maxAttempts: 3,
3571
+ baseDelay: 1e3,
3572
+ maxDelay: 3e4,
3573
+ useExponentialBackoff: true,
3574
+ reconnectInterval: 0,
3575
+ ...options
3576
+ };
3577
+ if (this.#options.reconnectInterval > 0) this.#startReconnectInterval();
3578
+ }
3579
+ get isRecovering() {
3580
+ return this.#isRecovering;
3581
+ }
3582
+ get attempt() {
3583
+ return this.#attempt;
3584
+ }
3585
+ handleDisconnect(unexpected) {
3586
+ if (this.#disposed || !unexpected) return;
3587
+ this.#stopReconnectInterval();
3588
+ this.#recover();
3589
+ }
3590
+ reset() {
3591
+ this.#attempt = 0;
3592
+ this.#errors = [];
3593
+ this.#isRecovering = false;
3594
+ if (this.#retryTimeout) {
3595
+ clearTimeout(this.#retryTimeout);
3596
+ this.#retryTimeout = void 0;
3597
+ }
3598
+ if (this.#options.reconnectInterval > 0) this.#startReconnectInterval();
3599
+ }
3600
+ dispose() {
3601
+ this.#disposed = true;
3602
+ this.#isRecovering = false;
3603
+ this.#isScheduledReconnecting = false;
3604
+ if (this.#retryTimeout) {
3605
+ clearTimeout(this.#retryTimeout);
3606
+ this.#retryTimeout = void 0;
3607
+ }
3608
+ this.#stopReconnectInterval();
3609
+ this.removeAllListeners();
3610
+ }
3611
+ #recover() {
3612
+ if (this.#isRecovering || this.#disposed) return;
3613
+ if (this.#attempt >= this.#options.maxAttempts) {
3614
+ this.emit("failed", this.#errors);
3615
+ return;
3616
+ }
3617
+ this.#isRecovering = true;
3618
+ this.#attempt++;
3619
+ this.emit("recovering", this.#attempt);
3620
+ const delay = this.#calculateDelay();
3621
+ this.#retryTimeout = setTimeout(async () => {
3622
+ this.#retryTimeout = void 0;
3623
+ try {
3624
+ await this.#options.onReconnect();
3625
+ this.#isRecovering = false;
3626
+ this.#attempt = 0;
3627
+ this.#errors = [];
3628
+ this.emit("recovered");
3629
+ if (this.#options.reconnectInterval > 0) this.#startReconnectInterval();
3630
+ } catch (err) {
3631
+ this.#isRecovering = false;
3632
+ this.#errors.push(err instanceof Error ? err : new Error(String(err)));
3633
+ this.#recover();
3634
+ }
3635
+ }, delay);
3636
+ }
3637
+ #calculateDelay() {
3638
+ if (!this.#options.useExponentialBackoff) return this.#options.baseDelay;
3639
+ const delay = this.#options.baseDelay * Math.pow(2, this.#attempt - 1);
3640
+ return Math.min(delay, this.#options.maxDelay);
3641
+ }
3642
+ #startReconnectInterval() {
3643
+ this.#stopReconnectInterval();
3644
+ this.#reconnectInterval = setInterval(async () => {
3645
+ if (this.#isRecovering || this.#disposed || this.#isScheduledReconnecting) return;
3646
+ this.#isScheduledReconnecting = true;
3647
+ try {
3648
+ await this.#options.onReconnect();
3649
+ } catch (_) {} finally {
3650
+ this.#isScheduledReconnecting = false;
3651
+ }
3652
+ }, this.#options.reconnectInterval);
3653
+ }
3654
+ #stopReconnectInterval() {
3655
+ if (this.#reconnectInterval) {
3656
+ clearInterval(this.#reconnectInterval);
3657
+ this.#reconnectInterval = void 0;
3658
+ }
3659
+ }
3660
+ };
3661
+
3466
3662
  //#endregion
3467
3663
  //#region src/timing.ts
3468
3664
  var TimingServer = class {
@@ -3485,13 +3681,18 @@ var TimingServer = class {
3485
3681
  }
3486
3682
  listen() {
3487
3683
  return new Promise((resolve, reject) => {
3488
- this.#socket.once("error", reject);
3489
- this.#socket.once("listening", () => {
3490
- this.#socket.removeListener("error", reject);
3684
+ const onError = (err) => {
3685
+ this.#socket.removeListener("listening", onListening);
3686
+ reject(err);
3687
+ };
3688
+ const onListening = () => {
3689
+ this.#socket.removeListener("error", onError);
3491
3690
  this.#onListening();
3492
3691
  resolve();
3493
- });
3494
- this.#socket.bind(0, resolve);
3692
+ };
3693
+ this.#socket.once("error", onError);
3694
+ this.#socket.once("listening", onListening);
3695
+ this.#socket.bind(0);
3495
3696
  });
3496
3697
  }
3497
3698
  #onConnect() {
@@ -3596,4 +3797,89 @@ function splitUInt53(number) {
3596
3797
  }
3597
3798
 
3598
3799
  //#endregion
3599
- export { AIRPLAY_SERVICE, AIRPLAY_TRANSIENT_PIN, AccessoryPair, AccessoryVerify, AirPlayFeatureFlags, COMPANION_LINK_SERVICE, Connection, Context, Discovery, ENCRYPTION, EncryptionAwareConnection, EncryptionState, HTTP_TIMEOUT, JsonStorage, MemoryStorage, RAOP_SERVICE, Storage, TimingServer, describeFlags, generateActiveRemoteId, generateDacpId, generateSessionId, getLocalIP, getMacAddress, getPairingRequirement, getProtocolVersion, hasFeatureFlag, isPasswordRequired, isRemoteControlSupported, multicast as mdnsMulticast, unicast as mdnsUnicast, parseFeatures, prompt, randomInt32, randomInt64, reporter, uint16ToBE, uint53ToLE, v4 as uuid, waitFor };
3800
+ //#region src/deviceModel.ts
3801
+ let DeviceModel = /* @__PURE__ */ function(DeviceModel) {
3802
+ DeviceModel[DeviceModel["Unknown"] = 0] = "Unknown";
3803
+ DeviceModel[DeviceModel["AppleTVGen2"] = 1] = "AppleTVGen2";
3804
+ DeviceModel[DeviceModel["AppleTVGen3"] = 2] = "AppleTVGen3";
3805
+ DeviceModel[DeviceModel["AppleTVHD"] = 3] = "AppleTVHD";
3806
+ DeviceModel[DeviceModel["AppleTV4K"] = 4] = "AppleTV4K";
3807
+ DeviceModel[DeviceModel["AppleTV4KGen2"] = 5] = "AppleTV4KGen2";
3808
+ DeviceModel[DeviceModel["AppleTV4KGen3"] = 6] = "AppleTV4KGen3";
3809
+ DeviceModel[DeviceModel["HomePod"] = 10] = "HomePod";
3810
+ DeviceModel[DeviceModel["HomePodMini"] = 11] = "HomePodMini";
3811
+ DeviceModel[DeviceModel["HomePodGen2"] = 12] = "HomePodGen2";
3812
+ DeviceModel[DeviceModel["AirPortExpress"] = 20] = "AirPortExpress";
3813
+ DeviceModel[DeviceModel["AirPortExpressGen2"] = 21] = "AirPortExpressGen2";
3814
+ return DeviceModel;
3815
+ }({});
3816
+ let DeviceType = /* @__PURE__ */ function(DeviceType) {
3817
+ DeviceType[DeviceType["Unknown"] = 0] = "Unknown";
3818
+ DeviceType[DeviceType["AppleTV"] = 1] = "AppleTV";
3819
+ DeviceType[DeviceType["HomePod"] = 2] = "HomePod";
3820
+ DeviceType[DeviceType["AirPort"] = 3] = "AirPort";
3821
+ return DeviceType;
3822
+ }({});
3823
+ const MODEL_IDENTIFIERS = {
3824
+ "AppleTV2,1": DeviceModel.AppleTVGen2,
3825
+ "AppleTV3,1": DeviceModel.AppleTVGen3,
3826
+ "AppleTV3,2": DeviceModel.AppleTVGen3,
3827
+ "AppleTV5,3": DeviceModel.AppleTVHD,
3828
+ "AppleTV6,2": DeviceModel.AppleTV4K,
3829
+ "AppleTV11,1": DeviceModel.AppleTV4KGen2,
3830
+ "AppleTV14,1": DeviceModel.AppleTV4KGen3,
3831
+ "AudioAccessory1,1": DeviceModel.HomePod,
3832
+ "AudioAccessory1,2": DeviceModel.HomePod,
3833
+ "AudioAccessory5,1": DeviceModel.HomePodMini,
3834
+ "AudioAccessorySingle5,1": DeviceModel.HomePodMini,
3835
+ "AudioAccessory6,1": DeviceModel.HomePodGen2,
3836
+ "AirPort4,107": DeviceModel.AirPortExpress,
3837
+ "AirPort10,115": DeviceModel.AirPortExpressGen2
3838
+ };
3839
+ const INTERNAL_NAMES = {
3840
+ "K66AP": DeviceModel.AppleTVGen2,
3841
+ "J33AP": DeviceModel.AppleTVGen3,
3842
+ "J33IAP": DeviceModel.AppleTVGen3,
3843
+ "J42dAP": DeviceModel.AppleTVHD,
3844
+ "J105aAP": DeviceModel.AppleTV4K,
3845
+ "J305AP": DeviceModel.AppleTV4KGen2,
3846
+ "J255AP": DeviceModel.AppleTV4KGen3,
3847
+ "B520AP": DeviceModel.HomePodMini
3848
+ };
3849
+ const MODEL_NAMES = {
3850
+ [DeviceModel.Unknown]: "Unknown",
3851
+ [DeviceModel.AppleTVGen2]: "Apple TV (2nd generation)",
3852
+ [DeviceModel.AppleTVGen3]: "Apple TV (3rd generation)",
3853
+ [DeviceModel.AppleTVHD]: "Apple TV HD",
3854
+ [DeviceModel.AppleTV4K]: "Apple TV 4K (1st generation)",
3855
+ [DeviceModel.AppleTV4KGen2]: "Apple TV 4K (2nd generation)",
3856
+ [DeviceModel.AppleTV4KGen3]: "Apple TV 4K (3rd generation)",
3857
+ [DeviceModel.HomePod]: "HomePod",
3858
+ [DeviceModel.HomePodMini]: "HomePod mini",
3859
+ [DeviceModel.HomePodGen2]: "HomePod (2nd generation)",
3860
+ [DeviceModel.AirPortExpress]: "AirPort Express",
3861
+ [DeviceModel.AirPortExpressGen2]: "AirPort Express (2nd generation)"
3862
+ };
3863
+ const MODEL_TYPES = {
3864
+ [DeviceModel.Unknown]: DeviceType.Unknown,
3865
+ [DeviceModel.AppleTVGen2]: DeviceType.AppleTV,
3866
+ [DeviceModel.AppleTVGen3]: DeviceType.AppleTV,
3867
+ [DeviceModel.AppleTVHD]: DeviceType.AppleTV,
3868
+ [DeviceModel.AppleTV4K]: DeviceType.AppleTV,
3869
+ [DeviceModel.AppleTV4KGen2]: DeviceType.AppleTV,
3870
+ [DeviceModel.AppleTV4KGen3]: DeviceType.AppleTV,
3871
+ [DeviceModel.HomePod]: DeviceType.HomePod,
3872
+ [DeviceModel.HomePodMini]: DeviceType.HomePod,
3873
+ [DeviceModel.HomePodGen2]: DeviceType.HomePod,
3874
+ [DeviceModel.AirPortExpress]: DeviceType.AirPort,
3875
+ [DeviceModel.AirPortExpressGen2]: DeviceType.AirPort
3876
+ };
3877
+ const lookupDeviceModel = (identifier) => MODEL_IDENTIFIERS[identifier] ?? INTERNAL_NAMES[identifier] ?? DeviceModel.Unknown;
3878
+ const getDeviceModelName = (model) => MODEL_NAMES[model] ?? "Unknown";
3879
+ const getDeviceType = (model) => MODEL_TYPES[model] ?? DeviceType.Unknown;
3880
+ const isAppleTV = (model) => getDeviceType(model) === DeviceType.AppleTV;
3881
+ const isHomePod = (model) => getDeviceType(model) === DeviceType.HomePod;
3882
+ const isAirPort = (model) => getDeviceType(model) === DeviceType.AirPort;
3883
+
3884
+ //#endregion
3885
+ export { AIRPLAY_SERVICE, AIRPLAY_TRANSIENT_PIN, AccessoryPair, AccessoryVerify, AirPlayFeatureFlags, AppleProtocolError, AuthenticationError, COMPANION_LINK_SERVICE, CommandError, Connection, ConnectionClosedError, ConnectionError, ConnectionRecovery, ConnectionTimeoutError, Context, CredentialsError, DeviceModel, DeviceType, Discovery, DiscoveryError, ENCRYPTION, EncryptionAwareConnection, EncryptionError, EncryptionState, HTTP_TIMEOUT, InvalidResponseError, JsonStorage, MemoryStorage, PairingError, PlaybackError, RAOP_SERVICE, SetupError, Storage, TimeoutError, TimingServer, describeFlags, generateActiveRemoteId, generateDacpId, generateSessionId, getDeviceModelName, getDeviceType, getLocalIP, getMacAddress, getPairingRequirement, getProtocolVersion, hasFeatureFlag, isAirPort, isAppleTV, isHomePod, isPasswordRequired, isRemoteControlSupported, lookupDeviceModel, multicast as mdnsMulticast, unicast as mdnsUnicast, parseFeatures, prompt, randomInt32, randomInt64, reporter, uint16ToBE, uint53ToLE, v4 as uuid, waitFor };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@basmilius/apple-common",
3
3
  "description": "Common features shared across various apple protocol packages.",
4
- "version": "0.9.18",
4
+ "version": "0.9.19",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "author": {
@@ -45,8 +45,8 @@
45
45
  }
46
46
  },
47
47
  "dependencies": {
48
- "@basmilius/apple-encoding": "0.9.18",
49
- "@basmilius/apple-encryption": "0.9.18"
48
+ "@basmilius/apple-encoding": "0.9.19",
49
+ "@basmilius/apple-encryption": "0.9.19"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/bun": "^1.3.11",