@onekeyfe/hd-shared 1.2.0-alpha.143 → 1.2.0-alpha.145

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.
@@ -8,6 +8,10 @@ export declare const ONEKEY_WEBUSB_FILTER: {
8
8
  vendorId: number;
9
9
  productId: number;
10
10
  }[];
11
+ export declare const ONEKEY_PROTOCOL_V2_USB_IDS: readonly [{
12
+ readonly vendorId: 4617;
13
+ readonly productId: 20300;
14
+ }];
11
15
  type WebUsbIdentityDescriptor = {
12
16
  vendorId?: number;
13
17
  productId?: number;
@@ -47,6 +51,14 @@ export declare const ONEKEY_WRITE_CHARACTERISTIC_UUID = "00000002-0000-1000-8000
47
51
  export declare const ONEKEY_NOTIFY_CHARACTERISTIC_UUID = "00000003-0000-1000-8000-00805f9b34fb";
48
52
  export declare const isHeaderChunk: (chunk: Buffer | Uint8Array) => boolean;
49
53
  export declare const isOnekeyDevice: (name: string | null, id?: string) => boolean;
54
+ export declare const inferProtocolHintFromUsbId: (vendorId?: number | null, productId?: number | null) => "V2" | undefined;
55
+ type UsbDevicePathInput = {
56
+ serialNumber?: string | null;
57
+ vendorId?: number;
58
+ productId?: number;
59
+ productName?: string | null;
60
+ };
61
+ export declare const resolveOneKeyUsbDevicePath: (device: UsbDevicePathInput) => string | undefined;
50
62
  type BluetoothDeviceIdentity = {
51
63
  id?: string;
52
64
  name?: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";AAEA,eAAO,MAAM,yBAAyB;;;CAG5B,CAAC;AAEX,MAAM,MAAM,uBAAuB,GACjC,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,OAAO,yBAAyB,CAAC,CAAC;AAE7E,eAAO,MAAM,oBAAoB;;;GAOhC,CAAC;AAEF,KAAK,wBAAwB,GAAG;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC,CAAC;AAIF,eAAO,MAAM,yBAAyB,eAAgB,wBAAwB,KAAG,OAQhF,CAAC;AAMF,eAAO,MAAM,2BAA2B,mDAS9B,CAAC;AAMX,eAAO,MAAM,8BAA8B,qBAGjC,CAAC;AAGX,oBAAY,qBAAqB;IAE/B,UAAU,uBAAuB;IACjC,iBAAiB,8BAA8B;IAC/C,aAAa,0BAA0B;IACvC,kBAAkB,+BAA+B;IACjD,cAAc,2BAA2B;IACzC,oBAAoB,iCAAiC;IAGrD,mBAAmB,gCAAgC;IACnD,oBAAoB,iCAAiC;IAGrD,aAAa,0BAA0B;IACvC,oBAAoB,iCAAiC;IAGrD,uBAAuB,oCAAoC;IAC3D,sBAAsB,mCAAmC;IAGzD,mBAAmB,gCAAgC;IACnD,mBAAmB,gCAAgC;IACnD,oBAAoB,iCAAiC;IACrD,iBAAiB,8BAA8B;IAG/C,iBAAiB,8BAA8B;IAC/C,oBAAoB,iCAAiC;IACrD,eAAe,4BAA4B;IAC3C,mBAAmB,gCAAgC;IACnD,qBAAqB,kCAAkC;IACvD,sBAAsB,mCAAmC;IACzD,qBAAqB,kCAAkC;IACvD,wBAAwB,qCAAqC;CAC9D;AAED,eAAO,MAAM,mBAAmB,yCAAyC,CAAC;AAC1E,eAAO,MAAM,gCAAgC,yCAAyC,CAAC;AACvF,eAAO,MAAM,iCAAiC,yCAAyC,CAAC;AAIxF,eAAO,MAAM,aAAa,UAAW,MAAM,GAAG,UAAU,KAAG,OAa1D,CAAC;AAkBF,eAAO,MAAM,cAAc,SAAU,MAAM,GAAG,IAAI,OAAO,MAAM,KAAG,OAuBjE,CAAC;AAEF,KAAK,uBAAuB,GAAG;IAC7B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC;CACxD,CAAC;AAIF,eAAO,MAAM,gBAAgB,UAAW,MAAM,GAAG,IAAI,WACP,CAAC;AAE/C,eAAO,MAAM,yBAAyB,SAAU,MAAM,KAAG,YAAY,MAAM,CAc1E,CAAC;AAEF,eAAO,MAAM,mBAAmB,eAClB,MAAM,GAAG,IAAI,GAAG,SAAS,WAC5B,YAAY,MAAM,CAAC,YACgB,CAAC;AAkC/C,eAAO,MAAM,6BAA6B,WAAY,MAAM,GAAG,IAAI,YAWlE,CAAC;AAEF,eAAO,MAAM,oCAAoC,UAAW,MAAM,WAejE,CAAC;AAEF,eAAO,MAAM,6BAA6B,iBAC1B,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,IAAI,GAAG,SAAS,YAIhE,CAAC;AAEJ,eAAO,MAAM,uBAAuB,2CAKjC,uBAAuB,KAAG,OAiB5B,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -7,6 +7,11 @@ declare const ONEKEY_WEBUSB_FILTER: {
7
7
  vendorId: number;
8
8
  productId: number;
9
9
  }[];
10
+ /** USB IDs whose first probe should be Protocol V2. Shared Pro/Touch PIDs stay unhinted. */
11
+ declare const ONEKEY_PROTOCOL_V2_USB_IDS: readonly [{
12
+ readonly vendorId: 4617;
13
+ readonly productId: 20300;
14
+ }];
10
15
  type WebUsbIdentityDescriptor = {
11
16
  vendorId?: number;
12
17
  productId?: number;
@@ -54,6 +59,14 @@ declare const ONEKEY_WRITE_CHARACTERISTIC_UUID = "00000002-0000-1000-8000-00805f
54
59
  declare const ONEKEY_NOTIFY_CHARACTERISTIC_UUID = "00000003-0000-1000-8000-00805f9b34fb";
55
60
  declare const isHeaderChunk: (chunk: Buffer | Uint8Array) => boolean;
56
61
  declare const isOnekeyDevice: (name: string | null, id?: string) => boolean;
62
+ declare const inferProtocolHintFromUsbId: (vendorId?: number | null, productId?: number | null) => "V2" | undefined;
63
+ type UsbDevicePathInput = {
64
+ serialNumber?: string | null;
65
+ vendorId?: number;
66
+ productId?: number;
67
+ productName?: string | null;
68
+ };
69
+ declare const resolveOneKeyUsbDevicePath: (device: UsbDevicePathInput) => string | undefined;
57
70
  type BluetoothDeviceIdentity = {
58
71
  id?: string;
59
72
  name?: string | null;
@@ -531,4 +544,4 @@ declare enum EDeviceType {
531
544
  Neo = "neo"
532
545
  }
533
546
 
534
- export { CreateErrorByMessage, CreateHardwareErrorByBridgeError, Deferred, EDeviceType, EFirmwareType, EOneKeyBleMessageKeys, HardwareError$1 as ERRORS, ERROR_CODES_REQUIRE_DISCONNECT, ERROR_CODES_REQUIRE_RELEASE, HARDWARE_CONNECT_PROTOCOL, HardwareConnectProtocol, HardwareError, HardwareErrorCode, HardwareErrorCodeMessage, IHardwareError, ONEKEY_NOTIFY_CHARACTERISTIC_UUID, ONEKEY_SERVICE_UUID, ONEKEY_WEBUSB_FILTER, ONEKEY_WRITE_CHARACTERISTIC_UUID, TypedError, createDefectiveFirmwareError, createDeferred, createDeprecatedHardwareError, createDeviceNotSupportMethodError, createKnownBleUuidAliases, createNeedUpgradeFirmwareHardwareError, createNewFirmwareForceUpdateHardwareError, createNewFirmwareUnReleaseHardwareError, hasOnekeyCommunicationService, isHeaderChunk, isKnownTrezorWebUsbDevice, isOnekeyBluetoothDevice, isOnekeyDevice, isPro2FindMyAdvertisementName, matchesKnownBleUuid, normalizeBleUuid, normalizePro2FindMyAdvertisementName, serializeError, wait };
547
+ export { CreateErrorByMessage, CreateHardwareErrorByBridgeError, Deferred, EDeviceType, EFirmwareType, EOneKeyBleMessageKeys, HardwareError$1 as ERRORS, ERROR_CODES_REQUIRE_DISCONNECT, ERROR_CODES_REQUIRE_RELEASE, HARDWARE_CONNECT_PROTOCOL, HardwareConnectProtocol, HardwareError, HardwareErrorCode, HardwareErrorCodeMessage, IHardwareError, ONEKEY_NOTIFY_CHARACTERISTIC_UUID, ONEKEY_PROTOCOL_V2_USB_IDS, ONEKEY_SERVICE_UUID, ONEKEY_WEBUSB_FILTER, ONEKEY_WRITE_CHARACTERISTIC_UUID, TypedError, createDefectiveFirmwareError, createDeferred, createDeprecatedHardwareError, createDeviceNotSupportMethodError, createKnownBleUuidAliases, createNeedUpgradeFirmwareHardwareError, createNewFirmwareForceUpdateHardwareError, createNewFirmwareUnReleaseHardwareError, hasOnekeyCommunicationService, inferProtocolHintFromUsbId, isHeaderChunk, isKnownTrezorWebUsbDevice, isOnekeyBluetoothDevice, isOnekeyDevice, isPro2FindMyAdvertisementName, matchesKnownBleUuid, normalizeBleUuid, normalizePro2FindMyAdvertisementName, resolveOneKeyUsbDevicePath, serializeError, wait };
package/dist/index.js CHANGED
@@ -399,6 +399,7 @@ const ONEKEY_WEBUSB_FILTER = [
399
399
  { vendorId: 0x1209, productId: 0x4f4b },
400
400
  { vendorId: 0x1209, productId: 0x4f4c },
401
401
  ];
402
+ const ONEKEY_PROTOCOL_V2_USB_IDS = [{ vendorId: 0x1209, productId: 0x4f4c }];
402
403
  const TREZOR_WEBUSB_MANUFACTURER_NAMES = new Set(['trezor', 'trezor company', 'satoshilabs']);
403
404
  const isKnownTrezorWebUsbDevice = (descriptor) => {
404
405
  var _a;
@@ -495,12 +496,36 @@ const isOnekeyDevice = (name, id) => {
495
496
  return true;
496
497
  if (normalizedName.startsWith('touch ') ||
497
498
  normalizedName.startsWith('pro ') ||
498
- normalizedName.startsWith('pro2 ') ||
499
- normalizedName.startsWith('neo ')) {
499
+ normalizedName.startsWith('pro2') ||
500
+ normalizedName.startsWith('neo')) {
501
+ return true;
502
+ }
503
+ const compactName = compactBleName(normalizedName);
504
+ if (PRO2_COMPACT_NAME_PATTERN.test(compactName) || NEO_COMPACT_NAME_PATTERN.test(compactName)) {
500
505
  return true;
501
506
  }
502
507
  return isOneKeyShortName(normalizedName);
503
508
  };
509
+ const inferProtocolHintFromUsbId = (vendorId, productId) => ONEKEY_PROTOCOL_V2_USB_IDS.some(id => id.vendorId === vendorId && id.productId === productId)
510
+ ? 'V2'
511
+ : undefined;
512
+ const resolveOneKeyUsbDevicePath = (device) => {
513
+ var _a, _b, _c, _d;
514
+ const serial = (_a = device.serialNumber) === null || _a === void 0 ? void 0 : _a.trim();
515
+ if (serial)
516
+ return serial;
517
+ if (device.vendorId == null && device.productId == null && !device.productName) {
518
+ return undefined;
519
+ }
520
+ const vendorId = ((_b = device.vendorId) !== null && _b !== void 0 ? _b : 0).toString(16).padStart(4, '0');
521
+ const productId = ((_c = device.productId) !== null && _c !== void 0 ? _c : 0).toString(16).padStart(4, '0');
522
+ const product = ((_d = device.productName) !== null && _d !== void 0 ? _d : 'onekey')
523
+ .trim()
524
+ .toLowerCase()
525
+ .replace(/\s+/g, '-')
526
+ .replace(/[^a-z0-9-]/g, '');
527
+ return `usb-${vendorId}-${productId}-${product || 'onekey'}`;
528
+ };
504
529
  const BLUETOOTH_BASE_UUID_SUFFIX = '00001000800000805f9b34fb';
505
530
  const normalizeBleUuid = (uuid) => (uuid !== null && uuid !== void 0 ? uuid : '').replace(/-/g, '').toLowerCase();
506
531
  const createKnownBleUuidAliases = (uuid) => {
@@ -520,6 +545,7 @@ const matchesKnownBleUuid = (actualUuid, aliases) => aliases.has(normalizeBleUui
520
545
  const ONEKEY_COMMUNICATION_SERVICE_ALIASES = createKnownBleUuidAliases(ONEKEY_SERVICE_UUID);
521
546
  const FIDO_SERVICE_ALIASES = createKnownBleUuidAliases('0000fffd-0000-1000-8000-00805f9b34fb');
522
547
  const PRO2_COMPACT_NAME_PATTERN = /^(?:onekey)?pro2[a-f0-9]{4}$/i;
548
+ const NEO_COMPACT_NAME_PATTERN = /^(?:onekey)?neo[a-f0-9]{4}$/i;
523
549
  const FIND_MY_COMPACT_SUFFIXES = [
524
550
  'findemy',
525
551
  'findem',
@@ -669,6 +695,7 @@ exports.HardwareError = HardwareError;
669
695
  exports.HardwareErrorCode = HardwareErrorCode;
670
696
  exports.HardwareErrorCodeMessage = HardwareErrorCodeMessage;
671
697
  exports.ONEKEY_NOTIFY_CHARACTERISTIC_UUID = ONEKEY_NOTIFY_CHARACTERISTIC_UUID;
698
+ exports.ONEKEY_PROTOCOL_V2_USB_IDS = ONEKEY_PROTOCOL_V2_USB_IDS;
672
699
  exports.ONEKEY_SERVICE_UUID = ONEKEY_SERVICE_UUID;
673
700
  exports.ONEKEY_WEBUSB_FILTER = ONEKEY_WEBUSB_FILTER;
674
701
  exports.ONEKEY_WRITE_CHARACTERISTIC_UUID = ONEKEY_WRITE_CHARACTERISTIC_UUID;
@@ -682,6 +709,7 @@ exports.createNeedUpgradeFirmwareHardwareError = createNeedUpgradeFirmwareHardwa
682
709
  exports.createNewFirmwareForceUpdateHardwareError = createNewFirmwareForceUpdateHardwareError;
683
710
  exports.createNewFirmwareUnReleaseHardwareError = createNewFirmwareUnReleaseHardwareError;
684
711
  exports.hasOnekeyCommunicationService = hasOnekeyCommunicationService;
712
+ exports.inferProtocolHintFromUsbId = inferProtocolHintFromUsbId;
685
713
  exports.isHeaderChunk = isHeaderChunk;
686
714
  exports.isKnownTrezorWebUsbDevice = isKnownTrezorWebUsbDevice;
687
715
  exports.isOnekeyBluetoothDevice = isOnekeyBluetoothDevice;
@@ -690,5 +718,6 @@ exports.isPro2FindMyAdvertisementName = isPro2FindMyAdvertisementName;
690
718
  exports.matchesKnownBleUuid = matchesKnownBleUuid;
691
719
  exports.normalizeBleUuid = normalizeBleUuid;
692
720
  exports.normalizePro2FindMyAdvertisementName = normalizePro2FindMyAdvertisementName;
721
+ exports.resolveOneKeyUsbDevicePath = resolveOneKeyUsbDevicePath;
693
722
  exports.serializeError = serializeError;
694
723
  exports.wait = wait;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-shared",
3
- "version": "1.2.0-alpha.143",
3
+ "version": "1.2.0-alpha.145",
4
4
  "description": "Hardware SDK's shared tool library",
5
5
  "keywords": [
6
6
  "Hardware-SDK",
@@ -26,5 +26,5 @@
26
26
  "lint": "eslint .",
27
27
  "lint:fix": "eslint . --fix"
28
28
  },
29
- "gitHead": "17a4c59d984da31727aaabc2d2e59d988ec9e734"
29
+ "gitHead": "9a136f881865c15e603ef271ae820c2b5a991dcc"
30
30
  }
@@ -1,12 +1,14 @@
1
1
  import {
2
2
  createKnownBleUuidAliases,
3
3
  hasOnekeyCommunicationService,
4
+ inferProtocolHintFromUsbId,
4
5
  isKnownTrezorWebUsbDevice,
5
6
  isOnekeyBluetoothDevice,
6
7
  isOnekeyDevice,
7
8
  isPro2FindMyAdvertisementName,
8
9
  matchesKnownBleUuid,
9
10
  normalizePro2FindMyAdvertisementName,
11
+ resolveOneKeyUsbDevicePath,
10
12
  } from './constants';
11
13
 
12
14
  describe('hardware device identity filters', () => {
@@ -14,6 +16,9 @@ describe('hardware device identity filters', () => {
14
16
  expect(isOnekeyDevice('Touch A1B2')).toBe(true);
15
17
  expect(isOnekeyDevice('Pro A1B2')).toBe(true);
16
18
  expect(isOnekeyDevice('Neo A1B2')).toBe(true);
19
+ expect(isOnekeyDevice('Pro2A1B2')).toBe(true);
20
+ expect(isOnekeyDevice('OneKeyPro2A1B2')).toBe(true);
21
+ expect(isOnekeyDevice('Neo22D8')).toBe(true);
17
22
  expect(isOnekeyDevice('K1234')).toBe(true);
18
23
  expect(isOnekeyDevice('S8')).toBe(true);
19
24
  });
@@ -136,6 +141,32 @@ describe('hardware device identity filters', () => {
136
141
  expect(hasOnekeyCommunicationService(['abcd0001-1234-5678-9012-abcdefabcdef'])).toBe(false);
137
142
  });
138
143
 
144
+ it('hints Protocol V2 from the current Pro2/Neo USB ID only', () => {
145
+ expect(inferProtocolHintFromUsbId(0x1209, 0x4f4c)).toBe('V2');
146
+ expect(inferProtocolHintFromUsbId(0x1209, 0x53c1)).toBeUndefined();
147
+ expect(inferProtocolHintFromUsbId(0x1209, 0x4f4a)).toBeUndefined();
148
+ expect(inferProtocolHintFromUsbId(0x1209, 0x4f4b)).toBeUndefined();
149
+ });
150
+
151
+ it('uses the USB serial when present and synthesizes a path when firmware omits it', () => {
152
+ expect(
153
+ resolveOneKeyUsbDevicePath({
154
+ vendorId: 0x1209,
155
+ productId: 0x4f4c,
156
+ productName: 'OneKey Pro 2',
157
+ serialNumber: 'PRO2-SERIAL',
158
+ })
159
+ ).toBe('PRO2-SERIAL');
160
+ expect(
161
+ resolveOneKeyUsbDevicePath({
162
+ vendorId: 0x1209,
163
+ productId: 0x4f4c,
164
+ productName: 'OneKey Neo',
165
+ serialNumber: '',
166
+ })
167
+ ).toBe('usb-1209-4f4c-onekey-neo');
168
+ });
169
+
139
170
  it('only filters WebUSB descriptors that are explicitly identified as Trezor', () => {
140
171
  expect(
141
172
  isKnownTrezorWebUsbDevice({
package/src/constants.ts CHANGED
@@ -13,10 +13,13 @@ export const ONEKEY_WEBUSB_FILTER = [
13
13
  { vendorId: 0x1209, productId: 0x53c1 }, // Classic/Classic1s/Mini/Pro/Touch firmware and legacy Pro2; keep for existing devices
14
14
  { vendorId: 0x1209, productId: 0x4f4a }, // Pro bootloader, Touch bootloader, Pro2
15
15
  { vendorId: 0x1209, productId: 0x4f4b }, // Pro/Touch firmware (Trezor not implemented), Pro2
16
- { vendorId: 0x1209, productId: 0x4f4c }, // Pro board and Pro2 with the new firmware PID
16
+ { vendorId: 0x1209, productId: 0x4f4c }, // Pro2 / Neo current firmware, all modes
17
17
  // { vendorId: 0x1209, productId: 0x4f50 }, // Touch Board
18
18
  ];
19
19
 
20
+ /** USB IDs whose first probe should be Protocol V2. Shared Pro/Touch PIDs stay unhinted. */
21
+ export const ONEKEY_PROTOCOL_V2_USB_IDS = [{ vendorId: 0x1209, productId: 0x4f4c }] as const;
22
+
20
23
  type WebUsbIdentityDescriptor = {
21
24
  vendorId?: number;
22
25
  productId?: number;
@@ -152,14 +155,47 @@ export const isOnekeyDevice = (name: string | null, id?: string): boolean => {
152
155
  if (
153
156
  normalizedName.startsWith('touch ') ||
154
157
  normalizedName.startsWith('pro ') ||
155
- normalizedName.startsWith('pro2 ') ||
156
- normalizedName.startsWith('neo ')
158
+ normalizedName.startsWith('pro2') ||
159
+ normalizedName.startsWith('neo')
157
160
  ) {
158
161
  return true;
159
162
  }
163
+ const compactName = compactBleName(normalizedName);
164
+ if (PRO2_COMPACT_NAME_PATTERN.test(compactName) || NEO_COMPACT_NAME_PATTERN.test(compactName)) {
165
+ return true;
166
+ }
160
167
  return isOneKeyShortName(normalizedName);
161
168
  };
162
169
 
170
+ export const inferProtocolHintFromUsbId = (vendorId?: number | null, productId?: number | null) =>
171
+ ONEKEY_PROTOCOL_V2_USB_IDS.some(id => id.vendorId === vendorId && id.productId === productId)
172
+ ? ('V2' as const)
173
+ : undefined;
174
+
175
+ type UsbDevicePathInput = {
176
+ serialNumber?: string | null;
177
+ vendorId?: number;
178
+ productId?: number;
179
+ productName?: string | null;
180
+ };
181
+
182
+ export const resolveOneKeyUsbDevicePath = (device: UsbDevicePathInput): string | undefined => {
183
+ const serial = device.serialNumber?.trim();
184
+ if (serial) return serial;
185
+ if (device.vendorId == null && device.productId == null && !device.productName) {
186
+ return undefined;
187
+ }
188
+
189
+ const vendorId = (device.vendorId ?? 0).toString(16).padStart(4, '0');
190
+ const productId = (device.productId ?? 0).toString(16).padStart(4, '0');
191
+ const product = (device.productName ?? 'onekey')
192
+ .trim()
193
+ .toLowerCase()
194
+ .replace(/\s+/g, '-')
195
+ .replace(/[^a-z0-9-]/g, '');
196
+ return `usb-${vendorId}-${productId}-${product || 'onekey'}`;
197
+ };
198
+
163
199
  type BluetoothDeviceIdentity = {
164
200
  id?: string;
165
201
  name?: string | null;
@@ -196,6 +232,7 @@ export const matchesKnownBleUuid = (
196
232
  const ONEKEY_COMMUNICATION_SERVICE_ALIASES = createKnownBleUuidAliases(ONEKEY_SERVICE_UUID);
197
233
  const FIDO_SERVICE_ALIASES = createKnownBleUuidAliases('0000fffd-0000-1000-8000-00805f9b34fb');
198
234
  const PRO2_COMPACT_NAME_PATTERN = /^(?:onekey)?pro2[a-f0-9]{4}$/i;
235
+ const NEO_COMPACT_NAME_PATTERN = /^(?:onekey)?neo[a-f0-9]{4}$/i;
199
236
  const FIND_MY_COMPACT_SUFFIXES = [
200
237
  'findemy',
201
238
  'findem',