@onekeyfe/hd-transport 1.2.0-alpha.3 → 1.2.0-alpha.31

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 (65) hide show
  1. package/README.md +1 -1
  2. package/__tests__/messages.test.js +142 -0
  3. package/__tests__/protocol-v2-ble-frame-writer.test.js +119 -0
  4. package/__tests__/protocol-v2-link-manager.test.js +389 -0
  5. package/__tests__/protocol-v2-usb-transport-base.test.js +330 -0
  6. package/__tests__/protocol-v2.test.js +555 -119
  7. package/dist/constants.d.ts +6 -3
  8. package/dist/constants.d.ts.map +1 -1
  9. package/dist/index.d.ts +981 -278
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +759 -247
  12. package/dist/protocols/index.d.ts +14 -5
  13. package/dist/protocols/index.d.ts.map +1 -1
  14. package/dist/protocols/v2/ble-frame-writer.d.ts +15 -0
  15. package/dist/protocols/v2/ble-frame-writer.d.ts.map +1 -0
  16. package/dist/protocols/v2/constants.d.ts +1 -0
  17. package/dist/protocols/v2/constants.d.ts.map +1 -1
  18. package/dist/protocols/v2/decode.d.ts +13 -2
  19. package/dist/protocols/v2/decode.d.ts.map +1 -1
  20. package/dist/protocols/v2/encode.d.ts +2 -3
  21. package/dist/protocols/v2/encode.d.ts.map +1 -1
  22. package/dist/protocols/v2/errors.d.ts +8 -0
  23. package/dist/protocols/v2/errors.d.ts.map +1 -0
  24. package/dist/protocols/v2/frame-assembler.d.ts.map +1 -1
  25. package/dist/protocols/v2/index.d.ts +2 -1
  26. package/dist/protocols/v2/index.d.ts.map +1 -1
  27. package/dist/protocols/v2/link-manager.d.ts +38 -0
  28. package/dist/protocols/v2/link-manager.d.ts.map +1 -0
  29. package/dist/protocols/v2/sequence-cursor.d.ts +5 -0
  30. package/dist/protocols/v2/sequence-cursor.d.ts.map +1 -0
  31. package/dist/protocols/v2/session.d.ts +19 -5
  32. package/dist/protocols/v2/session.d.ts.map +1 -1
  33. package/dist/protocols/v2/usb-transport-base.d.ts +32 -0
  34. package/dist/protocols/v2/usb-transport-base.d.ts.map +1 -0
  35. package/dist/serialization/protobuf/decode.d.ts.map +1 -1
  36. package/dist/types/messages.d.ts +523 -158
  37. package/dist/types/messages.d.ts.map +1 -1
  38. package/dist/types/transport.d.ts +13 -3
  39. package/dist/types/transport.d.ts.map +1 -1
  40. package/messages-protocol-v2.json +796 -620
  41. package/package.json +3 -3
  42. package/scripts/protobuf-build.sh +96 -310
  43. package/scripts/protobuf-patches/index.js +1 -0
  44. package/scripts/protobuf-types.js +19 -1
  45. package/src/constants.ts +29 -15
  46. package/src/index.ts +11 -1
  47. package/src/protocols/index.ts +39 -40
  48. package/src/protocols/v2/ble-frame-writer.ts +77 -0
  49. package/src/protocols/v2/constants.ts +1 -0
  50. package/src/protocols/v2/crc8.ts +1 -1
  51. package/src/protocols/v2/decode.ts +71 -37
  52. package/src/protocols/v2/encode.ts +2 -28
  53. package/src/protocols/v2/errors.ts +25 -0
  54. package/src/protocols/v2/frame-assembler.ts +6 -4
  55. package/src/protocols/v2/index.ts +2 -1
  56. package/src/protocols/v2/link-manager.ts +186 -0
  57. package/src/protocols/v2/sequence-cursor.ts +10 -0
  58. package/src/protocols/v2/session.ts +157 -201
  59. package/src/protocols/v2/usb-transport-base.ts +213 -0
  60. package/src/serialization/protobuf/decode.ts +4 -1
  61. package/src/types/messages.ts +623 -181
  62. package/src/types/transport.ts +13 -3
  63. package/dist/protocols/v2/debug.d.ts +0 -13
  64. package/dist/protocols/v2/debug.d.ts.map +0 -1
  65. package/src/protocols/v2/debug.ts +0 -26
@@ -0,0 +1,213 @@
1
+ import { ProtocolV2FrameAssembler } from './frame-assembler';
2
+ import { ProtocolV2LinkError, isProtocolV2LinkError } from './errors';
3
+ import { ProtocolV2LinkManager } from './link-manager';
4
+ import { getErrorMessage } from './session';
5
+
6
+ import type { MessageFromOneKey, TransportCallOptions } from '../../types';
7
+ import type { ProtocolV2CallContext, ProtocolV2Schemas, ProtocolV2SessionOptions } from './session';
8
+
9
+ export type ProtocolV2UsbTransportBaseOptions = {
10
+ router: number;
11
+ maxFrameBytes: number;
12
+ logPrefix: string;
13
+ };
14
+
15
+ type ProtocolV2UsbCancellation = {
16
+ generation: number;
17
+ reason?: string;
18
+ promise: Promise<string>;
19
+ cancel: (reason: string) => void;
20
+ };
21
+
22
+ export abstract class ProtocolV2UsbTransportBase<Key> {
23
+ private readonly protocolV2UsbLinks: ProtocolV2LinkManager<Key>;
24
+
25
+ private readonly protocolV2UsbAssemblers = new Map<Key, ProtocolV2FrameAssembler>();
26
+
27
+ private readonly protocolV2UsbGenerations = new Map<Key, number>();
28
+
29
+ private readonly protocolV2UsbCancellations = new Map<Key, ProtocolV2UsbCancellation>();
30
+
31
+ private readonly protocolV2UsbOptions: ProtocolV2UsbTransportBaseOptions;
32
+
33
+ protected constructor(options: ProtocolV2UsbTransportBaseOptions) {
34
+ this.protocolV2UsbOptions = options;
35
+ this.protocolV2UsbLinks = new ProtocolV2LinkManager<Key>({
36
+ getSchemas: () => this.getProtocolV2UsbSchemas(),
37
+ classifyError: error => (isProtocolV2LinkError(error) ? 'link-fatal' : 'recoverable'),
38
+ onLinkInvalidated: async (key, reason) => {
39
+ this.protocolV2UsbAssemblers.get(key)?.reset();
40
+ await this.resetProtocolV2UsbNativeLink(key, reason);
41
+ await this.onProtocolV2UsbLinkInvalidated(key, reason);
42
+ },
43
+ });
44
+ }
45
+
46
+ protected abstract getProtocolV2UsbSchemas(): ProtocolV2Schemas;
47
+
48
+ protected abstract getProtocolV2UsbLogger(): ProtocolV2SessionOptions['logger'];
49
+
50
+ protected abstract writeProtocolV2UsbPacket(
51
+ key: Key,
52
+ frame: Uint8Array,
53
+ context: ProtocolV2CallContext
54
+ ): Promise<void>;
55
+
56
+ protected abstract readProtocolV2UsbPacket(
57
+ key: Key,
58
+ context: ProtocolV2CallContext
59
+ ): Promise<Uint8Array>;
60
+
61
+ protected abstract resetProtocolV2UsbNativeLink(key: Key, reason: string): Promise<void>;
62
+
63
+ protected abstract createProtocolV2UsbTimeoutError(name: string, timeoutMs: number): Error;
64
+
65
+ protected onProtocolV2UsbLinkInvalidated(_key: Key, _reason: string): Promise<void> | void {
66
+ // Subclasses may clear protocol caches or emit platform-specific diagnostics.
67
+ }
68
+
69
+ protected async rotateProtocolV2UsbGeneration(key: Key, reason: string): Promise<number> {
70
+ await this.protocolV2UsbLinks.invalidateLink(key, reason);
71
+ const generation = (this.protocolV2UsbGenerations.get(key) ?? 0) + 1;
72
+ this.protocolV2UsbGenerations.set(key, generation);
73
+ this.protocolV2UsbCancellations.set(key, this.createProtocolV2UsbCancellation(generation));
74
+ this.protocolV2UsbAssemblers.set(
75
+ key,
76
+ new ProtocolV2FrameAssembler(this.protocolV2UsbOptions.maxFrameBytes)
77
+ );
78
+ return generation;
79
+ }
80
+
81
+ protected callProtocolV2Usb(
82
+ key: Key,
83
+ name: string,
84
+ data: Record<string, unknown>,
85
+ options?: TransportCallOptions
86
+ ): Promise<MessageFromOneKey> {
87
+ return this.protocolV2UsbLinks.call(
88
+ key,
89
+ () => this.createProtocolV2UsbAdapter(key),
90
+ name,
91
+ data,
92
+ options
93
+ );
94
+ }
95
+
96
+ protected invalidateProtocolV2UsbLink(key: Key, reason: string): Promise<void> {
97
+ return this.protocolV2UsbLinks.invalidateLink(key, reason);
98
+ }
99
+
100
+ protected invalidateAllProtocolV2UsbLinks(reason: string): Promise<void> {
101
+ return this.protocolV2UsbLinks.invalidateAllLinks(reason);
102
+ }
103
+
104
+ protected async disposeProtocolV2UsbLinks(reason: string): Promise<void> {
105
+ await this.protocolV2UsbLinks.dispose(reason);
106
+ this.protocolV2UsbAssemblers.clear();
107
+ this.protocolV2UsbGenerations.clear();
108
+ this.protocolV2UsbCancellations.clear();
109
+ }
110
+
111
+ private createProtocolV2UsbAdapter(key: Key) {
112
+ const generation = this.protocolV2UsbGenerations.get(key);
113
+ if (generation === undefined) {
114
+ throw new Error('Protocol V2 USB generation has not been initialized');
115
+ }
116
+ const cancellation = this.protocolV2UsbCancellations.get(key);
117
+ if (!cancellation || cancellation.generation !== generation) {
118
+ throw new Error('Protocol V2 USB cancellation state has not been initialized');
119
+ }
120
+
121
+ const assertCurrentGeneration = () => {
122
+ if (cancellation.reason) {
123
+ throw new ProtocolV2LinkError('generation', cancellation.reason);
124
+ }
125
+ if (this.protocolV2UsbGenerations.get(key) !== generation) {
126
+ throw new ProtocolV2LinkError(
127
+ 'generation',
128
+ 'Protocol V2 USB connection generation changed'
129
+ );
130
+ }
131
+ };
132
+
133
+ return {
134
+ router: this.protocolV2UsbOptions.router,
135
+ maxFrameBytes: this.protocolV2UsbOptions.maxFrameBytes,
136
+ generation,
137
+ prepareCall: () => {
138
+ assertCurrentGeneration();
139
+ },
140
+ writeFrame: async (frame: Uint8Array, context: ProtocolV2CallContext) => {
141
+ assertCurrentGeneration();
142
+ try {
143
+ await this.writeProtocolV2UsbPacket(key, frame, context);
144
+ } catch (error) {
145
+ throw this.createProtocolV2UsbIoError('write', error);
146
+ }
147
+ assertCurrentGeneration();
148
+ },
149
+ readFrame: async (context: ProtocolV2CallContext) => {
150
+ assertCurrentGeneration();
151
+ const assembler = this.getProtocolV2UsbAssembler(key);
152
+ let frame = assembler.push(new Uint8Array(0));
153
+ while (!frame) {
154
+ const packetRead = this.readProtocolV2UsbPacket(key, context)
155
+ .then(packet => ({ packet }))
156
+ .catch(error => {
157
+ throw this.createProtocolV2UsbIoError('read', error);
158
+ });
159
+ const cancelled = cancellation.promise.then(reason => ({ reason }));
160
+ const result = await Promise.race([packetRead, cancelled]);
161
+ if ('reason' in result) {
162
+ throw new ProtocolV2LinkError('generation', result.reason);
163
+ }
164
+ assertCurrentGeneration();
165
+ frame = assembler.push(result.packet);
166
+ }
167
+ assertCurrentGeneration();
168
+ return frame;
169
+ },
170
+ reset: (reason: string) => {
171
+ cancellation.cancel(reason);
172
+ this.protocolV2UsbAssemblers.get(key)?.reset();
173
+ },
174
+ logger: this.getProtocolV2UsbLogger(),
175
+ logPrefix: this.protocolV2UsbOptions.logPrefix,
176
+ createTimeoutError: (messageName: string, timeoutMs: number) =>
177
+ this.createProtocolV2UsbTimeoutError(messageName, timeoutMs),
178
+ };
179
+ }
180
+
181
+ private getProtocolV2UsbAssembler(key: Key): ProtocolV2FrameAssembler {
182
+ const assembler = this.protocolV2UsbAssemblers.get(key);
183
+ if (!assembler) {
184
+ throw new Error('Protocol V2 USB assembler has not been initialized');
185
+ }
186
+ return assembler;
187
+ }
188
+
189
+ private createProtocolV2UsbCancellation(generation: number): ProtocolV2UsbCancellation {
190
+ let resolveCancellation: (reason: string) => void = () => undefined;
191
+ const cancellation: ProtocolV2UsbCancellation = {
192
+ generation,
193
+ promise: new Promise(resolve => {
194
+ resolveCancellation = resolve;
195
+ }),
196
+ cancel: reason => {
197
+ if (cancellation.reason) return;
198
+ cancellation.reason = reason;
199
+ resolveCancellation(reason);
200
+ },
201
+ };
202
+ return cancellation;
203
+ }
204
+
205
+ private createProtocolV2UsbIoError(operation: 'read' | 'write', error: unknown) {
206
+ if (isProtocolV2LinkError(error)) return error;
207
+ return new ProtocolV2LinkError(
208
+ 'io',
209
+ `Protocol V2 USB ${operation} failed: ${getErrorMessage(error) || 'unknown error'}`,
210
+ error
211
+ );
212
+ }
213
+ }
@@ -70,7 +70,10 @@ function messageToJSON(Message: Message<Record<string, unknown>>, fields: Type['
70
70
  }
71
71
  // message type
72
72
  else if (field.resolvedType!.fields) {
73
- res[key] = messageToJSON(value, field.resolvedType!.fields);
73
+ // [compatibility]: absent optional sub-messages are not own properties
74
+ // of the decoded instance, so value is undefined here; decode them to
75
+ // null, matching the optional primitive-field convention above.
76
+ res[key] = value == null ? null : messageToJSON(value, (field.resolvedType as Type).fields);
74
77
  } else {
75
78
  throw new Error(`case not handled: ${key}`);
76
79
  }