@ukeyfe/hardware-transport 1.1.13

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 (72) hide show
  1. package/.eslintrc +24 -0
  2. package/README.md +29 -0
  3. package/__tests__/build-receive.test.js +117 -0
  4. package/__tests__/decode-features.test.js +72 -0
  5. package/__tests__/encode-decode-basic.test.js +272 -0
  6. package/__tests__/encode-decode.test.js +532 -0
  7. package/__tests__/messages.test.js +86 -0
  8. package/dist/constants.d.ts +6 -0
  9. package/dist/constants.d.ts.map +1 -0
  10. package/dist/index.d.ts +5203 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +942 -0
  13. package/dist/serialization/index.d.ts +6 -0
  14. package/dist/serialization/index.d.ts.map +1 -0
  15. package/dist/serialization/protobuf/decode.d.ts +6 -0
  16. package/dist/serialization/protobuf/decode.d.ts.map +1 -0
  17. package/dist/serialization/protobuf/encode.d.ts +5 -0
  18. package/dist/serialization/protobuf/encode.d.ts.map +1 -0
  19. package/dist/serialization/protobuf/index.d.ts +4 -0
  20. package/dist/serialization/protobuf/index.d.ts.map +1 -0
  21. package/dist/serialization/protobuf/messages.d.ts +11 -0
  22. package/dist/serialization/protobuf/messages.d.ts.map +1 -0
  23. package/dist/serialization/protocol/decode.d.ts +11 -0
  24. package/dist/serialization/protocol/decode.d.ts.map +1 -0
  25. package/dist/serialization/protocol/encode.d.ts +11 -0
  26. package/dist/serialization/protocol/encode.d.ts.map +1 -0
  27. package/dist/serialization/protocol/index.d.ts +3 -0
  28. package/dist/serialization/protocol/index.d.ts.map +1 -0
  29. package/dist/serialization/receive.d.ts +8 -0
  30. package/dist/serialization/receive.d.ts.map +1 -0
  31. package/dist/serialization/send.d.ts +7 -0
  32. package/dist/serialization/send.d.ts.map +1 -0
  33. package/dist/types/index.d.ts +3 -0
  34. package/dist/types/index.d.ts.map +1 -0
  35. package/dist/types/messages.d.ts +3762 -0
  36. package/dist/types/messages.d.ts.map +1 -0
  37. package/dist/types/transport.d.ts +62 -0
  38. package/dist/types/transport.d.ts.map +1 -0
  39. package/dist/utils/highlevel-checks.d.ts +10 -0
  40. package/dist/utils/highlevel-checks.d.ts.map +1 -0
  41. package/dist/utils/logBlockCommand.d.ts +2 -0
  42. package/dist/utils/logBlockCommand.d.ts.map +1 -0
  43. package/dist/utils/protobuf.d.ts +2 -0
  44. package/dist/utils/protobuf.d.ts.map +1 -0
  45. package/jest.config.js +7 -0
  46. package/package.json +31 -0
  47. package/protocol.md +21 -0
  48. package/scripts/protobuf-build.sh +58 -0
  49. package/scripts/protobuf-patches/TxAck.js +44 -0
  50. package/scripts/protobuf-patches/TxInputType.js +49 -0
  51. package/scripts/protobuf-patches/TxOutputType.js +50 -0
  52. package/scripts/protobuf-patches/index.js +274 -0
  53. package/scripts/protobuf-types.js +283 -0
  54. package/src/constants.ts +8 -0
  55. package/src/index.ts +41 -0
  56. package/src/serialization/index.ts +8 -0
  57. package/src/serialization/protobuf/decode.ts +95 -0
  58. package/src/serialization/protobuf/encode.ts +79 -0
  59. package/src/serialization/protobuf/index.ts +3 -0
  60. package/src/serialization/protobuf/messages.ts +37 -0
  61. package/src/serialization/protocol/decode.ts +48 -0
  62. package/src/serialization/protocol/encode.ts +59 -0
  63. package/src/serialization/protocol/index.ts +2 -0
  64. package/src/serialization/receive.ts +18 -0
  65. package/src/serialization/send.ts +56 -0
  66. package/src/types/index.ts +2 -0
  67. package/src/types/messages.ts +4864 -0
  68. package/src/types/transport.ts +71 -0
  69. package/src/utils/highlevel-checks.ts +88 -0
  70. package/src/utils/logBlockCommand.ts +1 -0
  71. package/src/utils/protobuf.ts +24 -0
  72. package/tsconfig.json +11 -0
@@ -0,0 +1,274 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const UINT_TYPE = 'UintType';
5
+
6
+ // type rule fixes, ideally it should not be here
7
+ const RULE_PATCH = {
8
+ 'MultisigRedeemScriptType.nodes': 'optional', // its valid to be undefined according to implementation/tests
9
+ 'MultisigRedeemScriptType.address_n': 'optional', // its valid to be undefined according to implementation/tests
10
+ 'TxRequestDetailsType.request_index': 'required',
11
+ 'TxRequest.request_type': 'required',
12
+ 'TxRequest.details': 'required',
13
+ 'TxAckPaymentRequest.memos': 'optional', // protobuf repeated bytes are always optional (fallback to [])
14
+ 'CardanoPoolOwnerType.staking_key_path': 'optional',
15
+ 'CardanoPoolOwner.staking_key_path': 'optional',
16
+ 'CardanoTxCertificateType.path': 'optional',
17
+ 'CardanoTxCertificate.path': 'optional',
18
+ 'CardanoTxInputType.address_n': 'optional',
19
+ 'CardanoTxWithdrawal.path': 'optional',
20
+ 'CardanoNativeScript.scripts': 'optional',
21
+ 'CardanoNativeScript.key_path': 'optional',
22
+ 'CardanoTxRequiredSigner.key_path': 'optional',
23
+ 'Success.message': 'required', // didn't find use case where it's not sent
24
+ 'SignedIdentity.address': 'required',
25
+ 'EosAuthorizationKey.key': 'required', // its valid to be undefined according to implementation/tests
26
+ 'EosAuthorizationKey.type': 'optional', // its valid to be undefined according to implementation/tests
27
+ 'EosAuthorizationKey.address_n': 'optional', // its valid to be undefined according to implementation/tests
28
+ 'EthereumAddress.address': 'required', // address is transformed from legacy type _old_address
29
+ // TODO: Features should be union: bootloader|normal
30
+ // fields below are marked as required because of backward compatibility (suite implementation)
31
+ 'Features.vendor': 'required',
32
+ 'Features.bootloader_mode': 'required',
33
+ 'Features.device_id': 'required',
34
+ 'Features.major_version': 'required',
35
+ 'Features.minor_version': 'required',
36
+ 'Features.patch_version': 'required',
37
+ 'Features.pin_protection': 'required',
38
+ 'Features.passphrase_protection': 'required',
39
+ 'Features.language': 'required',
40
+ 'Features.label': 'required',
41
+ 'Features.initialized': 'required',
42
+ 'Features.revision': 'required',
43
+ 'Features.bootloader_hash': 'required',
44
+ 'Features.imported': 'required',
45
+ 'Features.unlocked': 'required',
46
+ 'Features.firmware_present': 'required',
47
+ 'Features.needs_backup': 'required',
48
+ 'Features.flags': 'required',
49
+ 'Features.fw_major': 'required',
50
+ 'Features.fw_minor': 'required',
51
+ 'Features.fw_patch': 'required',
52
+ 'Features.fw_vendor': 'required',
53
+ 'Features.model': 'required',
54
+ 'Features.unfinished_backup': 'required',
55
+ 'Features.no_backup': 'required',
56
+ 'Features.recovery_mode': 'required',
57
+ 'Features.backup_type': 'required',
58
+ 'Features.sd_card_present': 'required',
59
+ 'Features.sd_protection': 'required',
60
+ 'Features.wipe_code_protection': 'required',
61
+ 'Features.session_id': 'required',
62
+ 'Features.passphrase_always_on_device': 'required',
63
+ 'Features.safety_checks': 'required',
64
+ 'Features.auto_lock_delay_ms': 'required',
65
+ 'Features.display_rotation': 'required',
66
+ 'Features.experimental_features': 'required',
67
+ 'GetOwnershipProof.ownership_ids': 'optional', // protobuf repeated bytes are always optional (fallback to [])
68
+ 'NEMTransactionCommon.address_n': 'optional', // no address_n in multisig
69
+ 'NEMTransfer.mosaics': 'optional', // its valid to be undefined according to implementation/tests
70
+ 'NEMMosaicDefinition.networks': 'optional', // never used according to implementation/tests
71
+ 'NEMAggregateModification.modifications': 'optional', // its valid to be undefined according to implementation/tests
72
+ 'StellarAssetType.code': 'required',
73
+ 'StellarPathPaymentStrictReceiveOp.paths': 'optional', // its valid to be undefined according to implementation/tests
74
+ 'StellarPathPaymentStrictSendOp.paths': 'optional', // its valid to be undefined according to implementation/tests
75
+ };
76
+
77
+ // custom types IN to trezor
78
+ // protobuf lib will handle the translation to required type
79
+ // connect or other 3rd party libs are using compatible types (string as number etc...)
80
+ const TYPE_PATCH = {
81
+ 'Features.bootloader_mode': 'boolean | null',
82
+ 'Features.device_id': 'string | null',
83
+ 'Features.pin_protection': 'boolean | null',
84
+ 'Features.passphrase_protection': 'boolean | null',
85
+ 'Features.language': 'string | null',
86
+ 'Features.label': 'string | null',
87
+ 'Features.initialized': 'boolean | null',
88
+ 'Features.revision': 'string | null',
89
+ 'Features.bootloader_hash': 'string | null',
90
+ 'Features.imported': 'boolean | null',
91
+ 'Features.unlocked': 'boolean | null',
92
+ 'Features.firmware_present': 'boolean | null',
93
+ 'Features.needs_backup': 'boolean | null',
94
+ 'Features.flags': 'number | null',
95
+ 'Features.fw_major': 'number | null',
96
+ 'Features.fw_minor': 'number | null',
97
+ 'Features.fw_patch': 'number | null',
98
+ 'Features.fw_vendor': 'string | null',
99
+ 'Features.unfinished_backup': 'boolean | null',
100
+ 'Features.no_backup': 'boolean | null',
101
+ 'Features.recovery_mode': 'boolean | null',
102
+ 'Features.backup_type': 'BackupType | null',
103
+ 'Features.sd_card_present': 'boolean | null',
104
+ 'Features.sd_protection': 'boolean | null',
105
+ 'Features.wipe_code_protection': 'boolean | null',
106
+ 'Features.session_id': 'string | null',
107
+ 'Features.passphrase_always_on_device': 'boolean | null',
108
+ 'Features.safety_checks': 'SafetyCheckLevel | null',
109
+ 'Features.auto_lock_delay_ms': 'number | null',
110
+ 'Features.display_rotation': 'number | null',
111
+ 'Features.experimental_features': 'boolean | null',
112
+ 'Features.ukey_device_type': 'string | null',
113
+ 'Features.ukey_se_type': 'string | null',
114
+ 'Features.ukey_se01_state': 'string | null',
115
+ 'Features.ukey_se02_state': 'string | null',
116
+ 'Features.ukey_se03_state': 'string | null',
117
+ 'Features.ukey_se04_state': 'string | null',
118
+ 'HDNodePathType.node': 'HDNodeType | string',
119
+ 'FirmwareUpload.payload': 'Buffer | ArrayBuffer',
120
+ 'EthereumGetAddress.encoded_network': 'ArrayBuffer',
121
+ 'EthereumDefinitions.encoded_network': 'ArrayBuffer',
122
+ 'EthereumDefinitions.encoded_token': 'ArrayBuffer',
123
+ 'EthereumSignMessage.encoded_network': 'ArrayBuffer',
124
+ 'EthereumSignTypedHash.encoded_network': 'ArrayBuffer',
125
+ 'CardanoCatalystRegistrationParametersType.nonce': UINT_TYPE,
126
+ 'CardanoPoolParametersType.pledge': UINT_TYPE,
127
+ 'CardanoPoolParametersType.cost': UINT_TYPE,
128
+ 'CardanoPoolParametersType.margin_numerator': UINT_TYPE,
129
+ 'CardanoPoolParametersType.margin_denominator': UINT_TYPE,
130
+ 'CardanoTxCertificate.deposit': UINT_TYPE,
131
+ 'CardanoSignTxInit.ttl': UINT_TYPE,
132
+ 'CardanoSignTxInit.validity_interval_start': UINT_TYPE,
133
+ 'CardanoSignTxInit.total_collateral': UINT_TYPE,
134
+ 'CardanoToken.mint_amount': UINT_TYPE,
135
+ 'CardanoNativeScript.invalid_before': UINT_TYPE,
136
+ 'CardanoNativeScript.invalid_hereafter': UINT_TYPE,
137
+ 'EosAsset.symbol': 'string',
138
+ 'EosPermissionLevel.actor': 'string',
139
+ 'EosPermissionLevel.permission': 'string',
140
+ 'EosAuthorizationKey.key': 'string',
141
+ 'EosActionCommon.account': 'string',
142
+ 'EosActionCommon.name': 'string',
143
+ 'EosActionTransfer.sender': 'string',
144
+ 'EosActionTransfer.receiver': 'string',
145
+ 'EosActionDelegate.sender': 'string',
146
+ 'EosActionDelegate.receiver': 'string',
147
+ 'EosActionUndelegate.sender': 'string',
148
+ 'EosActionUndelegate.receiver': 'string',
149
+ 'EosActionRefund.owner': 'string',
150
+ 'EosActionBuyRam.payer': 'string',
151
+ 'EosActionBuyRam.receiver': 'string',
152
+ 'EosActionBuyRamBytes.payer': 'string',
153
+ 'EosActionBuyRamBytes.receiver': 'string',
154
+ 'EosActionSellRam.account': 'string',
155
+ 'EosActionVoteProducer.voter': 'string',
156
+ 'EosActionVoteProducer.proxy': 'string',
157
+ 'EosActionVoteProducer.producers': 'string',
158
+ 'EosActionUpdateAuth.account': 'string',
159
+ 'EosActionUpdateAuth.permission': 'string',
160
+ 'EosActionUpdateAuth.parent': 'string',
161
+ 'EosActionDeleteAuth.account': 'string',
162
+ 'EosActionDeleteAuth.permission': 'string',
163
+ 'EosActionLinkAuth.account': 'string',
164
+ 'EosActionLinkAuth.code': 'string',
165
+ 'EosActionLinkAuth.type': 'string',
166
+ 'EosActionLinkAuth.requirement': 'string',
167
+ 'EosActionUnlinkAuth.account': 'string',
168
+ 'EosActionUnlinkAuth.code': 'string',
169
+ 'EosActionUnlinkAuth.type': 'string',
170
+ 'EosActionNewAccount.creator': 'string',
171
+ 'EosActionNewAccount.name': 'string',
172
+ 'ResetDevice.backup_type': 'string | number', // BackupType is a enum. in Features displayed as string, in resetDevice method param accepted as number
173
+ 'StellarAssetType.type': '0 | 1 | 2',
174
+ 'StellarSignTx.sequence_number': UINT_TYPE,
175
+ 'StellarSignTx.memo_id': 'string',
176
+ 'StellarSignTx.memo_hash': 'Buffer | string',
177
+ 'StellarCreateAccountOp.starting_balance': UINT_TYPE,
178
+ 'StellarPathPaymentStrictReceiveOp.send_max': UINT_TYPE,
179
+ 'StellarPathPaymentStrictReceiveOp.destination_amount': UINT_TYPE,
180
+ 'StellarPathPaymentStrictSendOp.send_amount': UINT_TYPE,
181
+ 'StellarPathPaymentStrictSendOp.destination_min': UINT_TYPE,
182
+ 'StellarManageSellOfferOp.offer_id': UINT_TYPE,
183
+ 'StellarManageBuyOfferOp.offer_id': UINT_TYPE,
184
+ 'StellarSetOptionsOp.master_weight': UINT_TYPE,
185
+ 'StellarSetOptionsOp.low_threshold': UINT_TYPE,
186
+ 'StellarSetOptionsOp.medium_threshold': UINT_TYPE,
187
+ 'StellarSetOptionsOp.high_threshold': UINT_TYPE,
188
+ 'StellarSetOptionsOp.signer_key': 'Buffer | string',
189
+ 'StellarChangeTrustOp.limit': UINT_TYPE,
190
+ 'StellarManageDataOp.value': 'Buffer | string',
191
+ 'StellarBumpSequenceOp.bump_to': UINT_TYPE,
192
+ 'TezosContractID.tag': 'number',
193
+ 'TezosContractID.hash': 'Uint8Array',
194
+ 'TezosRevealOp.source': 'Uint8Array',
195
+ 'TezosRevealOp.public_key': 'Uint8Array',
196
+ 'TezosParametersManager.set_delegate': 'Uint8Array',
197
+ 'TezosTransactionOp.source': 'Uint8Array',
198
+ 'TezosTransactionOp.parameters': 'number[]',
199
+ 'TezosOriginationOp.source': 'Uint8Array',
200
+ 'TezosOriginationOp.delegate': 'Uint8Array',
201
+ 'TezosOriginationOp.script': 'string | number[]',
202
+ 'TezosDelegationOp.source': 'Uint8Array',
203
+ 'TezosDelegationOp.delegate': 'Uint8Array',
204
+ 'TezosSignTx.branch': 'Uint8Array',
205
+ 'TonSignMessage.ton_amount': UINT_TYPE,
206
+ 'TonSignMessage.jetton_amount': UINT_TYPE,
207
+ 'TonSignMessage.fwd_fee': UINT_TYPE,
208
+ 'TonSignMessage.expire_at': UINT_TYPE,
209
+ 'TonSignMessage.ext_ton_amount': UINT_TYPE,
210
+ 'TonSignProof.expire_at': UINT_TYPE,
211
+ };
212
+
213
+ const DEFINITION_PATCH = {
214
+ TxInputType: fs.readFileSync(path.join(__dirname, './TxInputType.js'), 'utf8'),
215
+ TxOutputType: fs.readFileSync(path.join(__dirname, './TxOutputType.js'), 'utf8'),
216
+ TxAck: fs.readFileSync(path.join(__dirname, './TxAck.js'), 'utf8'),
217
+ };
218
+
219
+ // skip unnecessary types
220
+ const SKIP = [
221
+ 'MessageType', // connect uses custom definition
222
+ 'TransactionType', // connect uses custom definition
223
+ 'TxInput', // declared in TxInputType patch
224
+ 'TxOutput', // declared in TxOutputType patch
225
+ // not implemented
226
+ 'CosiCommit',
227
+ 'CosiCommitment',
228
+ 'CosiSign',
229
+ 'CosiSignature',
230
+ 'DebugSwipeDirection',
231
+ 'DebugLinkDecision',
232
+ 'DebugLinkLayout',
233
+ 'DebugLinkReseedRandom',
234
+ 'DebugLinkRecordScreen',
235
+ 'DebugLinkGetState',
236
+ 'DebugLinkState',
237
+ 'DebugLinkStop',
238
+ 'DebugLinkLog',
239
+ 'DebugLinkMemoryRead',
240
+ 'DebugLinkMemory',
241
+ 'DebugLinkMemoryWrite',
242
+ 'DebugLinkFlashErase',
243
+ 'DebugLinkEraseSdCard',
244
+ 'DebugLinkWatchLayout',
245
+ 'LoadDevice',
246
+ 'DebugMoneroDiagRequest',
247
+ 'DebugMoneroDiagAck',
248
+ 'WebAuthnListResidentCredentials',
249
+ 'WebAuthnAddResidentCredential',
250
+ 'WebAuthnRemoveResidentCredential',
251
+ 'WebAuthnCredential',
252
+ 'WebAuthnCredentials',
253
+ 'wire_in',
254
+ 'wire_out',
255
+ 'wire_debug_in',
256
+ 'wire_debug_out',
257
+ 'wire_tiny',
258
+ 'wire_bootloader',
259
+ 'wire_no_fsm',
260
+ 'bitcoin_only',
261
+ 'has_bitcoin_only_values',
262
+ 'unstable',
263
+ 'wire_type',
264
+ 'experimental',
265
+ 'include_in_bitcoin_only',
266
+ ];
267
+
268
+ module.exports = {
269
+ RULE_PATCH,
270
+ TYPE_PATCH,
271
+ DEFINITION_PATCH,
272
+ SKIP,
273
+ UINT_TYPE,
274
+ };
@@ -0,0 +1,283 @@
1
+ /* eslint-disable react-hooks/rules-of-hooks */
2
+ /* eslint-disable import/no-unresolved */
3
+ // flowtype only
4
+ // flowtype doesn't have `enum` declarations like typescript
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ const json = require('../messages.json');
10
+ const { RULE_PATCH, TYPE_PATCH, DEFINITION_PATCH, SKIP, UINT_TYPE } = require('./protobuf-patches');
11
+
12
+ const args = process.argv.slice(2);
13
+
14
+ const isTypescript = args.includes('typescript');
15
+
16
+ // proto types to javascript types
17
+ const FIELD_TYPES = {
18
+ uint32: 'number',
19
+ uint64: 'number',
20
+ sint32: 'number',
21
+ sint64: 'number',
22
+ bool: 'boolean',
23
+ bytes: 'string',
24
+ // 'bytes': 'Uint8Array | number[] | Buffer | string', // protobuf will handle conversion
25
+ };
26
+
27
+ const types = []; // { type: 'enum | message', name: string, value: string[], exact?: boolean };
28
+
29
+ // enums used as keys (string), used as values (number) by default
30
+ const ENUM_KEYS = [
31
+ 'InputScriptType',
32
+ 'OutputScriptType',
33
+ 'RequestType',
34
+ 'BackupType',
35
+ 'Capability',
36
+ 'SafetyCheckLevel',
37
+ 'ButtonRequestType',
38
+ 'PinMatrixRequestType',
39
+ 'WordRequestType',
40
+ ];
41
+
42
+ const parseEnumTypescript = (itemName, item) => {
43
+ const value = [];
44
+ const IS_KEY = ENUM_KEYS.includes(itemName);
45
+ // declare enum
46
+ if (IS_KEY) {
47
+ value.push(`export enum Enum_${itemName} {`);
48
+ } else {
49
+ value.push(`export enum ${itemName} {`);
50
+ }
51
+
52
+ // declare fields
53
+ Object.entries(item.values).forEach(([name, id]) => {
54
+ value.push(` ${name} = ${id},`);
55
+ });
56
+ // close enum declaration
57
+ value.push('}');
58
+
59
+ if (IS_KEY) {
60
+ value.push(`export type ${itemName} = keyof typeof Enum_${itemName};`);
61
+ }
62
+ // empty line
63
+ value.push('');
64
+
65
+ types.push({
66
+ type: 'enum',
67
+ name: itemName,
68
+ value: value.join('\n'),
69
+ });
70
+ };
71
+
72
+ const parseEnum = (itemName, item) => {
73
+ if (isTypescript) return parseEnumTypescript(itemName, item);
74
+ const value = [];
75
+ // declare enum
76
+ value.push(`export const Enum_${itemName} = Object.freeze({`);
77
+ // declare fields
78
+ Object.entries(item.values).forEach(([name, id]) => {
79
+ value.push(` ${name}: ${id},`);
80
+ });
81
+ // close enum declaration
82
+ value.push('});');
83
+ // declare enum type using Keys or Values
84
+ const KEY = ENUM_KEYS.includes(itemName) ? 'Keys' : 'Values';
85
+ value.push(`export type ${itemName} = $${KEY}<typeof Enum_${itemName}>;`);
86
+ // empty line
87
+ value.push('');
88
+
89
+ types.push({
90
+ type: 'enum',
91
+ name: itemName,
92
+ value: value.join('\n'),
93
+ });
94
+ };
95
+
96
+ const useDefinition = def => {
97
+ // remove flow overhead
98
+ const clean = def.replace(/\/\/ @flow/, '').replace(/\/\/ @overhead-start(.*)@overhead-end/s, '');
99
+
100
+ if (isTypescript) {
101
+ // use typescript variant
102
+ // replace flowtype $Exact declaration: {| foo: 1 |} => { foo: 1 }
103
+ // replace flowtype spread with typescript union: { ...T, foo: 1 } => T & { foo: 1 }, see TxInputType patch
104
+ return clean
105
+ .replace(/\/\/ @typescript-variant:/, '')
106
+ .replace(/\/\/ @flowtype-variant(.*)/, '')
107
+ .replace(/{\|/gi, '{')
108
+ .replace(/\|}/gi, '}')
109
+ .replace(/\{\n.*.\.{3}(.*?),/g, '$1 & {');
110
+ }
111
+ return clean.replace(/\/\/ @typescript-variant(.*)/, '').replace(/\/\/ @flowtype-variant:/, '');
112
+ };
113
+
114
+ const parseMessage = (messageName, message, depth = 0) => {
115
+ if (messageName === 'google') return;
116
+ const value = [];
117
+ // add comment line
118
+ if (!depth) value.push(`// ${messageName}`);
119
+ // declare nested enums
120
+
121
+ // declare nested values
122
+ if (message.nested) {
123
+ Object.keys(message.nested).map(item => parseMessage(item, message.nested[item], depth + 1));
124
+ }
125
+
126
+ if (message.values) {
127
+ return parseEnum(messageName, message);
128
+ }
129
+ if (!message.fields || !Object.keys(message.fields).length) {
130
+ // few types are just empty objects, make it one line
131
+ value.push(`export type ${messageName} = {};`);
132
+ value.push('');
133
+ } else {
134
+ // find patch
135
+ const definition = DEFINITION_PATCH[messageName];
136
+ if (definition) {
137
+ // replace whole declaration
138
+ value.push(useDefinition(definition));
139
+ } else {
140
+ // declare type
141
+ value.push(`export type ${messageName} = {`);
142
+ Object.keys(message.fields).forEach(fieldName => {
143
+ const field = message.fields[fieldName];
144
+ const fieldKey = `${messageName}.${fieldName}`;
145
+ // find patch for "rule"
146
+ const fieldRule = RULE_PATCH[fieldKey] || field.rule;
147
+ const rule = fieldRule === 'required' || fieldRule === 'repeated' ? ': ' : '?: ';
148
+ // find patch for "type"
149
+ let type = TYPE_PATCH[fieldKey] || FIELD_TYPES[field.type] || field.type;
150
+ // automatically convert all amount and fee fields to UINT_TYPE
151
+ if (['amount', 'fee'].includes(fieldName)) {
152
+ type = UINT_TYPE;
153
+ }
154
+ // array
155
+ if (field.rule === 'repeated') {
156
+ type = type.split('|').length > 1 ? `Array<${type}>` : `${type}[]`;
157
+ }
158
+ value.push(` ${fieldName}${rule}${type};`);
159
+ });
160
+ // close type declaration
161
+ value.push('};');
162
+ // empty line
163
+ value.push('');
164
+ }
165
+ }
166
+ // type doest have to be e
167
+ const exact = message.fields && Object.values(message.fields).find(f => f.rule === 'required');
168
+ types.push({
169
+ type: 'message',
170
+ name: messageName,
171
+ value: value.join('\n'),
172
+ exact,
173
+ });
174
+ };
175
+
176
+ // top level messages and nested messages
177
+ Object.keys(json.nested).map(e => parseMessage(e, json.nested[e]));
178
+
179
+ // types needs reordering (used before defined)
180
+ const ORDER = {
181
+ BinanceCoin: 'BinanceInputOutput',
182
+ HDNodeType: 'HDNodePathType',
183
+ CardanoAssetGroupType: 'CardanoTxOutputType',
184
+ CardanoTokenType: 'CardanoAssetGroupType',
185
+ TxAck: 'TxAckInputWrapper',
186
+ EthereumFieldType: 'EthereumStructMember',
187
+ EthereumDataType: 'EthereumFieldType',
188
+ PaymentRequestMemo: 'TxAckPaymentRequest',
189
+ };
190
+
191
+ Object.keys(ORDER).forEach(key => {
192
+ // find indexes
193
+ const indexA = types.findIndex(t => t && t.name === key);
194
+ const indexB = types.findIndex(t => t && t.name === ORDER[key]);
195
+ const prevA = types[indexA];
196
+ // replace values
197
+ delete types[indexA];
198
+ types.splice(indexB, 0, prevA);
199
+ });
200
+
201
+ // skip not needed types
202
+ SKIP.forEach(key => {
203
+ const index = types.findIndex(t => t && t.name === key);
204
+ delete types[index];
205
+ });
206
+
207
+ // create content from types
208
+ const content = types.flatMap(t => (t ? [t.value] : [])).join('\n');
209
+
210
+ const lines = []; // string[]
211
+ if (!isTypescript) lines.push('// @flow');
212
+ lines.push('// This file is auto generated from data/messages/message.json');
213
+ lines.push('');
214
+ lines.push('// custom type uint32/64 may be represented as string');
215
+ lines.push(`export type ${UINT_TYPE} = string | number;`);
216
+ lines.push('');
217
+ lines.push(content);
218
+
219
+ // create custom definition
220
+ if (!isTypescript) {
221
+ lines.push('// custom connect definitions');
222
+ lines.push('export type MessageType = {');
223
+ types
224
+ .flatMap(t => (t && t.type === 'message' ? [t] : []))
225
+ .forEach(t => {
226
+ if (t.exact) {
227
+ lines.push(` ${t.name}: $Exact<${t.name}>;`);
228
+ } else {
229
+ lines.push(` ${t.name}: ${t.name};`);
230
+ }
231
+ // lines.push(' ' + t.name + ': $Exact<' + t.name + '>;');
232
+ });
233
+ lines.push('};');
234
+
235
+ // additional types utilities
236
+ lines.push(`
237
+ export type MessageKey = $Keys<MessageType>;
238
+
239
+ export type MessageResponse<T: MessageKey> = {
240
+ type: T;
241
+ message: $ElementType<MessageType, T>;
242
+ };
243
+
244
+ export type TypedCall = <T: MessageKey, R: MessageKey>(
245
+ type: T,
246
+ resType: R,
247
+ message?: $ElementType<MessageType, T>
248
+ ) => Promise<MessageResponse<R>>;
249
+ `);
250
+ } else {
251
+ lines.push('// custom connect definitions');
252
+ lines.push('export type MessageType = {');
253
+ types
254
+ .flatMap(t => (t && t.type === 'message' ? [t] : []))
255
+ .forEach(t => {
256
+ lines.push(` ${t.name}: ${t.name};`);
257
+ });
258
+ lines.push('};');
259
+
260
+ // additional types utilities
261
+ lines.push(`
262
+ export type MessageKey = keyof MessageType;
263
+
264
+ export type MessageResponse<T extends MessageKey> = {
265
+ type: T;
266
+ message: MessageType[T];
267
+ };
268
+
269
+ export type TypedCall = <T extends MessageKey, R extends MessageKey>(
270
+ type: T,
271
+ resType: R,
272
+ message?: MessageType[T],
273
+ ) => Promise<MessageResponse<R>>;
274
+ `);
275
+ }
276
+
277
+ // save to file
278
+ const filePath = isTypescript
279
+ ? path.join(__dirname, '../src/types/messages.ts')
280
+ : path.join(__dirname, '../protobuf.js');
281
+ fs.writeFile(filePath, lines.join('\n'), err => {
282
+ if (err) return console.log(err);
283
+ });
@@ -0,0 +1,8 @@
1
+ export const MESSAGE_TOP_CHAR = 0x003f;
2
+ export const MESSAGE_HEADER_BYTE = 0x23;
3
+ export const HEADER_SIZE = 1 + 1 + 4 + 2;
4
+ export const BUFFER_SIZE = 63;
5
+ /**
6
+ * exclude ?##
7
+ */
8
+ export const COMMON_HEADER_SIZE = 6;
package/src/index.ts ADDED
@@ -0,0 +1,41 @@
1
+ import * as protobuf from 'protobufjs/light';
2
+ import * as Long from 'long';
3
+ import {
4
+ buildBuffers,
5
+ buildEncodeBuffers,
6
+ buildOne,
7
+ decodeProtocol,
8
+ parseConfigure,
9
+ receiveOne,
10
+ } from './serialization';
11
+ import * as check from './utils/highlevel-checks';
12
+
13
+ protobuf.util.Long = Long;
14
+ protobuf.configure();
15
+
16
+ export type {
17
+ Transport,
18
+ AcquireInput,
19
+ UKeyDeviceInfo,
20
+ UKeyMobileDeviceInfo,
21
+ UKeyDeviceInfoWithSession,
22
+ MessageFromUKey,
23
+ LowlevelTransportSharedPlugin,
24
+ LowLevelDevice,
25
+ } from './types';
26
+
27
+ export { Messages } from './types';
28
+ export * from './types/messages';
29
+ export * from './utils/logBlockCommand';
30
+
31
+ export * from './constants';
32
+
33
+ export default {
34
+ check,
35
+ buildOne,
36
+ buildBuffers,
37
+ buildEncodeBuffers,
38
+ receiveOne,
39
+ parseConfigure,
40
+ decodeProtocol,
41
+ };
@@ -0,0 +1,8 @@
1
+ import { parseConfigure } from './protobuf';
2
+
3
+ export * from './send';
4
+ export * from './receive';
5
+
6
+ export * as decodeProtocol from './protocol/decode';
7
+
8
+ export { parseConfigure };