@onekeyfe/hwk-adapter-core 1.1.26-alpha.10
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 +1079 -0
- package/dist/index.d.ts +1079 -0
- package/dist/index.js +606 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +552 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +54 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,606 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
CHAIN_FINGERPRINT_PATHS: () => CHAIN_FINGERPRINT_PATHS,
|
|
24
|
+
DEVICE: () => DEVICE,
|
|
25
|
+
DEVICE_EVENT: () => DEVICE_EVENT,
|
|
26
|
+
DeviceJobQueue: () => DeviceJobQueue,
|
|
27
|
+
EConnectorInteraction: () => EConnectorInteraction,
|
|
28
|
+
HardwareErrorCode: () => HardwareErrorCode,
|
|
29
|
+
SDK: () => SDK,
|
|
30
|
+
TypedEventEmitter: () => TypedEventEmitter,
|
|
31
|
+
UI_EVENT: () => UI_EVENT,
|
|
32
|
+
UI_REQUEST: () => UI_REQUEST,
|
|
33
|
+
UI_REQUEST_CANCELLED_TAG: () => UI_REQUEST_CANCELLED_TAG,
|
|
34
|
+
UI_REQUEST_DEFAULT_TIMEOUT_MS: () => UI_REQUEST_DEFAULT_TIMEOUT_MS,
|
|
35
|
+
UI_REQUEST_PREEMPTED_TAG: () => UI_REQUEST_PREEMPTED_TAG,
|
|
36
|
+
UI_REQUEST_TIMEOUT_TAG: () => UI_REQUEST_TIMEOUT_TAG,
|
|
37
|
+
UI_RESPONSE: () => UI_RESPONSE,
|
|
38
|
+
UiRequestRegistry: () => UiRequestRegistry,
|
|
39
|
+
batchCall: () => batchCall,
|
|
40
|
+
bytesToHex: () => bytesToHex2,
|
|
41
|
+
compareSemver: () => compareSemver,
|
|
42
|
+
createBridgedConnector: () => createBridgedConnector,
|
|
43
|
+
deriveDeviceFingerprint: () => deriveDeviceFingerprint,
|
|
44
|
+
enrichErrorMessage: () => enrichErrorMessage,
|
|
45
|
+
ensure0x: () => ensure0x,
|
|
46
|
+
failure: () => failure,
|
|
47
|
+
hexToBytes: () => hexToBytes,
|
|
48
|
+
padHex64: () => padHex64,
|
|
49
|
+
stripHex: () => stripHex,
|
|
50
|
+
success: () => success
|
|
51
|
+
});
|
|
52
|
+
module.exports = __toCommonJS(index_exports);
|
|
53
|
+
|
|
54
|
+
// src/types/errors.ts
|
|
55
|
+
var HardwareErrorCode = /* @__PURE__ */ ((HardwareErrorCode2) => {
|
|
56
|
+
HardwareErrorCode2[HardwareErrorCode2["UnknownError"] = 1e4] = "UnknownError";
|
|
57
|
+
HardwareErrorCode2[HardwareErrorCode2["UserRejected"] = 10001] = "UserRejected";
|
|
58
|
+
HardwareErrorCode2[HardwareErrorCode2["InvalidParams"] = 10002] = "InvalidParams";
|
|
59
|
+
HardwareErrorCode2[HardwareErrorCode2["OperationTimeout"] = 10003] = "OperationTimeout";
|
|
60
|
+
HardwareErrorCode2[HardwareErrorCode2["MethodNotSupported"] = 10004] = "MethodNotSupported";
|
|
61
|
+
HardwareErrorCode2[HardwareErrorCode2["DeviceNotFound"] = 10100] = "DeviceNotFound";
|
|
62
|
+
HardwareErrorCode2[HardwareErrorCode2["DeviceDisconnected"] = 10101] = "DeviceDisconnected";
|
|
63
|
+
HardwareErrorCode2[HardwareErrorCode2["DeviceBusy"] = 10102] = "DeviceBusy";
|
|
64
|
+
HardwareErrorCode2[HardwareErrorCode2["DeviceLocked"] = 10103] = "DeviceLocked";
|
|
65
|
+
HardwareErrorCode2[HardwareErrorCode2["DeviceNotInitialized"] = 10104] = "DeviceNotInitialized";
|
|
66
|
+
HardwareErrorCode2[HardwareErrorCode2["DeviceInBootloader"] = 10105] = "DeviceInBootloader";
|
|
67
|
+
HardwareErrorCode2[HardwareErrorCode2["DeviceMismatch"] = 10106] = "DeviceMismatch";
|
|
68
|
+
HardwareErrorCode2[HardwareErrorCode2["FirmwareTooOld"] = 10200] = "FirmwareTooOld";
|
|
69
|
+
HardwareErrorCode2[HardwareErrorCode2["FirmwareUpdateRequired"] = 10201] = "FirmwareUpdateRequired";
|
|
70
|
+
HardwareErrorCode2[HardwareErrorCode2["TransportError"] = 10300] = "TransportError";
|
|
71
|
+
HardwareErrorCode2[HardwareErrorCode2["BridgeNotFound"] = 10301] = "BridgeNotFound";
|
|
72
|
+
HardwareErrorCode2[HardwareErrorCode2["TransportNotAvailable"] = 10302] = "TransportNotAvailable";
|
|
73
|
+
HardwareErrorCode2[HardwareErrorCode2["DevicePermissionDenied"] = 10303] = "DevicePermissionDenied";
|
|
74
|
+
HardwareErrorCode2[HardwareErrorCode2["PinInvalid"] = 10400] = "PinInvalid";
|
|
75
|
+
HardwareErrorCode2[HardwareErrorCode2["PinCancelled"] = 10401] = "PinCancelled";
|
|
76
|
+
HardwareErrorCode2[HardwareErrorCode2["PassphraseRejected"] = 10402] = "PassphraseRejected";
|
|
77
|
+
HardwareErrorCode2[HardwareErrorCode2["AppNotOpen"] = 10500] = "AppNotOpen";
|
|
78
|
+
HardwareErrorCode2[HardwareErrorCode2["WrongApp"] = 10501] = "WrongApp";
|
|
79
|
+
HardwareErrorCode2[HardwareErrorCode2["AppTooOld"] = 10502] = "AppTooOld";
|
|
80
|
+
HardwareErrorCode2[HardwareErrorCode2["EvmBlindSigningRequired"] = 11e3] = "EvmBlindSigningRequired";
|
|
81
|
+
HardwareErrorCode2[HardwareErrorCode2["EvmClearSignPluginMissing"] = 11001] = "EvmClearSignPluginMissing";
|
|
82
|
+
HardwareErrorCode2[HardwareErrorCode2["EvmDataTooLarge"] = 11002] = "EvmDataTooLarge";
|
|
83
|
+
HardwareErrorCode2[HardwareErrorCode2["EvmTxTypeNotSupported"] = 11003] = "EvmTxTypeNotSupported";
|
|
84
|
+
HardwareErrorCode2[HardwareErrorCode2["SolanaBlindSigningRequired"] = 11100] = "SolanaBlindSigningRequired";
|
|
85
|
+
HardwareErrorCode2[HardwareErrorCode2["TronCustomContractRequired"] = 11200] = "TronCustomContractRequired";
|
|
86
|
+
HardwareErrorCode2[HardwareErrorCode2["TronDataSigningRequired"] = 11201] = "TronDataSigningRequired";
|
|
87
|
+
HardwareErrorCode2[HardwareErrorCode2["TronSignByHashRequired"] = 11202] = "TronSignByHashRequired";
|
|
88
|
+
HardwareErrorCode2[HardwareErrorCode2["BtcWalletPolicyHmacMismatch"] = 11300] = "BtcWalletPolicyHmacMismatch";
|
|
89
|
+
HardwareErrorCode2[HardwareErrorCode2["BtcUnexpectedState"] = 11301] = "BtcUnexpectedState";
|
|
90
|
+
return HardwareErrorCode2;
|
|
91
|
+
})(HardwareErrorCode || {});
|
|
92
|
+
|
|
93
|
+
// src/types/response.ts
|
|
94
|
+
function success(payload) {
|
|
95
|
+
return { success: true, payload };
|
|
96
|
+
}
|
|
97
|
+
function failure(code, error) {
|
|
98
|
+
return { success: false, payload: { error, code } };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// src/types/fingerprint.ts
|
|
102
|
+
var import_sha256 = require("@noble/hashes/sha256");
|
|
103
|
+
var import_utils = require("@noble/hashes/utils");
|
|
104
|
+
var CHAIN_FINGERPRINT_PATHS = {
|
|
105
|
+
evm: "m/44'/60'/0'/0/0",
|
|
106
|
+
// BTC: account-level path (3 levels), mainnet cointype 0.
|
|
107
|
+
// Cointype 1 (testnet) is rejected by some Ledger BTC App configurations.
|
|
108
|
+
btc: "m/44'/0'/0'",
|
|
109
|
+
sol: "m/44'/501'/0'",
|
|
110
|
+
tron: "m/44'/195'/0'/0/0"
|
|
111
|
+
};
|
|
112
|
+
function deriveDeviceFingerprint(value) {
|
|
113
|
+
return (0, import_utils.bytesToHex)((0, import_sha256.sha256)((0, import_utils.utf8ToBytes)(value))).slice(0, 16);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// src/events/device.ts
|
|
117
|
+
var DEVICE_EVENT = "DEVICE_EVENT";
|
|
118
|
+
var DEVICE = {
|
|
119
|
+
CONNECT: "device-connect",
|
|
120
|
+
DISCONNECT: "device-disconnect",
|
|
121
|
+
CHANGED: "device-changed"
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// src/events/ui-request.ts
|
|
125
|
+
var UI_EVENT = "UI_EVENT";
|
|
126
|
+
var UI_REQUEST = {
|
|
127
|
+
REQUEST_PIN: "ui-request-pin",
|
|
128
|
+
REQUEST_PASSPHRASE: "ui-request-passphrase",
|
|
129
|
+
REQUEST_PASSPHRASE_ON_DEVICE: "ui-request-passphrase-on-device",
|
|
130
|
+
REQUEST_BUTTON: "ui-request-button",
|
|
131
|
+
REQUEST_QR_DISPLAY: "ui-request-qr-display",
|
|
132
|
+
REQUEST_QR_SCAN: "ui-request-qr-scan",
|
|
133
|
+
REQUEST_DEVICE_PERMISSION: "ui-request-device-permission",
|
|
134
|
+
REQUEST_SELECT_DEVICE: "ui-request-select-device",
|
|
135
|
+
REQUEST_DEVICE_CONNECT: "ui-request-device-connect",
|
|
136
|
+
REQUEST_PREEMPTION: "ui-request-preemption",
|
|
137
|
+
CLOSE_UI_WINDOW: "ui-close",
|
|
138
|
+
DEVICE_PROGRESS: "ui-device_progress",
|
|
139
|
+
FIRMWARE_PROGRESS: "ui-firmware-progress",
|
|
140
|
+
FIRMWARE_TIP: "ui-firmware-tip"
|
|
141
|
+
};
|
|
142
|
+
var UI_RESPONSE = {
|
|
143
|
+
RECEIVE_PIN: "receive-pin",
|
|
144
|
+
RECEIVE_PASSPHRASE: "receive-passphrase",
|
|
145
|
+
RECEIVE_PASSPHRASE_ON_DEVICE: "receive-passphrase-on-device",
|
|
146
|
+
RECEIVE_QR_RESPONSE: "receive-qr-response",
|
|
147
|
+
RECEIVE_SELECT_DEVICE: "receive-select-device",
|
|
148
|
+
RECEIVE_DEVICE_CONNECT: "receive-device-connect",
|
|
149
|
+
RECEIVE_DEVICE_PERMISSION: "receive-device-permission",
|
|
150
|
+
RECEIVE_PREEMPTION: "receive-preemption",
|
|
151
|
+
CANCEL: "cancel"
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// src/events/sdk.ts
|
|
155
|
+
var SDK = {
|
|
156
|
+
DEVICE_STUCK: "device-stuck",
|
|
157
|
+
DEVICE_UNRESPONSIVE: "device-unresponsive",
|
|
158
|
+
DEVICE_RECOVERED: "device-recovered",
|
|
159
|
+
DEVICE_INTERACTION: "device-interaction"
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// src/utils/DeviceJobQueue.ts
|
|
163
|
+
var DeviceJobQueue = class {
|
|
164
|
+
constructor(deps) {
|
|
165
|
+
this._queues = /* @__PURE__ */ new Map();
|
|
166
|
+
this._active = /* @__PURE__ */ new Map();
|
|
167
|
+
/** Incremented on clear() so stale queued jobs can detect invalidation. */
|
|
168
|
+
this._generation = 0;
|
|
169
|
+
this._deps = deps ?? null;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Enqueue a job for a specific device.
|
|
173
|
+
* If a job is already running for this device, behavior depends on interruptibility:
|
|
174
|
+
* - 'none': new job queues silently (no preemption possible)
|
|
175
|
+
* - 'safe': current job is auto-cancelled, new job runs immediately after
|
|
176
|
+
* - 'confirm': emits REQUEST_PREEMPTION and waits for UI response
|
|
177
|
+
*/
|
|
178
|
+
async enqueue(deviceId, job, options = {}) {
|
|
179
|
+
const interruptibility = options.interruptibility ?? "confirm";
|
|
180
|
+
const active = this._active.get(deviceId);
|
|
181
|
+
if (active) {
|
|
182
|
+
switch (active.options.interruptibility) {
|
|
183
|
+
case "none":
|
|
184
|
+
break;
|
|
185
|
+
case "safe":
|
|
186
|
+
active.abortController.abort(new Error("Preempted by new operation"));
|
|
187
|
+
break;
|
|
188
|
+
case "confirm": {
|
|
189
|
+
if (this._deps?.uiRegistry.hasPending(UI_REQUEST.REQUEST_PREEMPTION)) {
|
|
190
|
+
throw Object.assign(
|
|
191
|
+
new Error(`Device busy: a preemption decision is already pending`),
|
|
192
|
+
{ hardwareErrorCode: "DEVICE_BUSY" }
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
const decision = await this._requestPreemptionDecision(deviceId, active, {
|
|
196
|
+
label: options.label,
|
|
197
|
+
interruptibility
|
|
198
|
+
});
|
|
199
|
+
switch (decision) {
|
|
200
|
+
case "cancel-current":
|
|
201
|
+
active.abortController.abort(new Error("Cancelled by user via preemption"));
|
|
202
|
+
break;
|
|
203
|
+
case "reject-new":
|
|
204
|
+
throw Object.assign(
|
|
205
|
+
new Error(`Device busy: ${active.options.label ?? "unknown operation"}`),
|
|
206
|
+
{ hardwareErrorCode: "DEVICE_BUSY" }
|
|
207
|
+
);
|
|
208
|
+
case "wait":
|
|
209
|
+
break;
|
|
210
|
+
default:
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const ac = new AbortController();
|
|
218
|
+
const prev = this._queues.get(deviceId) ?? Promise.resolve();
|
|
219
|
+
const gen = this._generation;
|
|
220
|
+
const next = prev.catch(() => {
|
|
221
|
+
}).then(async () => {
|
|
222
|
+
if (this._generation !== gen) {
|
|
223
|
+
throw new Error("Job cancelled: queue was cleared");
|
|
224
|
+
}
|
|
225
|
+
this._active.set(deviceId, {
|
|
226
|
+
options: { interruptibility, label: options.label },
|
|
227
|
+
abortController: ac,
|
|
228
|
+
startedAt: Date.now()
|
|
229
|
+
});
|
|
230
|
+
try {
|
|
231
|
+
return await job(ac.signal);
|
|
232
|
+
} finally {
|
|
233
|
+
this._active.delete(deviceId);
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
const tail = next.catch(() => {
|
|
237
|
+
});
|
|
238
|
+
this._queues.set(deviceId, tail);
|
|
239
|
+
tail.then(() => {
|
|
240
|
+
if (this._queues.get(deviceId) === tail) {
|
|
241
|
+
this._queues.delete(deviceId);
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
return next;
|
|
245
|
+
}
|
|
246
|
+
/** Manually cancel the active job on a device. Returns false if job is non-interruptible. */
|
|
247
|
+
cancelActive(deviceId) {
|
|
248
|
+
const active = this._active.get(deviceId);
|
|
249
|
+
if (!active) return false;
|
|
250
|
+
if (active.options.interruptibility === "none") return false;
|
|
251
|
+
active.abortController.abort(new Error("Manually cancelled"));
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
/** Force cancel regardless of interruptibility. Use for device stuck recovery. */
|
|
255
|
+
forceCancelActive(deviceId) {
|
|
256
|
+
const active = this._active.get(deviceId);
|
|
257
|
+
if (!active) return false;
|
|
258
|
+
active.abortController.abort(new Error("Force cancelled for recovery"));
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
/** Get info about the currently active job for a device, or null if idle. */
|
|
262
|
+
getActiveJob(deviceId) {
|
|
263
|
+
const active = this._active.get(deviceId);
|
|
264
|
+
if (!active) return null;
|
|
265
|
+
return {
|
|
266
|
+
label: active.options.label,
|
|
267
|
+
interruptibility: active.options.interruptibility,
|
|
268
|
+
startedAt: active.startedAt
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
clear() {
|
|
272
|
+
this._generation++;
|
|
273
|
+
for (const active of this._active.values()) {
|
|
274
|
+
active.abortController.abort(new Error("Queue cleared"));
|
|
275
|
+
}
|
|
276
|
+
this._active.clear();
|
|
277
|
+
this._queues.clear();
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Request preemption decision via UI request/response flow.
|
|
281
|
+
* Falls back to 'wait' if deps are not provided.
|
|
282
|
+
*/
|
|
283
|
+
async _requestPreemptionDecision(deviceId, active, newJob) {
|
|
284
|
+
if (!this._deps) return "wait";
|
|
285
|
+
const { emit, uiRegistry } = this._deps;
|
|
286
|
+
emit(UI_REQUEST.REQUEST_PREEMPTION, {
|
|
287
|
+
type: UI_REQUEST.REQUEST_PREEMPTION,
|
|
288
|
+
payload: {
|
|
289
|
+
deviceId,
|
|
290
|
+
currentJob: {
|
|
291
|
+
label: active.options.label,
|
|
292
|
+
interruptibility: active.options.interruptibility,
|
|
293
|
+
startedAt: active.startedAt
|
|
294
|
+
},
|
|
295
|
+
newJob
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
const response = await uiRegistry.wait(
|
|
299
|
+
UI_REQUEST.REQUEST_PREEMPTION
|
|
300
|
+
);
|
|
301
|
+
return response?.decision ?? "wait";
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
// src/types/connector.ts
|
|
306
|
+
var EConnectorInteraction = /* @__PURE__ */ ((EConnectorInteraction2) => {
|
|
307
|
+
EConnectorInteraction2["ConfirmOpenApp"] = "confirm-open-app";
|
|
308
|
+
EConnectorInteraction2["UnlockDevice"] = "unlock-device";
|
|
309
|
+
EConnectorInteraction2["ConfirmOnDevice"] = "confirm-on-device";
|
|
310
|
+
EConnectorInteraction2["InteractionComplete"] = "interaction-complete";
|
|
311
|
+
return EConnectorInteraction2;
|
|
312
|
+
})(EConnectorInteraction || {});
|
|
313
|
+
function createBridgedConnector(vendor, connectionType, bridge) {
|
|
314
|
+
const handlerMap = /* @__PURE__ */ new Map();
|
|
315
|
+
return {
|
|
316
|
+
connectionType,
|
|
317
|
+
searchDevices: () => bridge.searchDevices({ vendor }),
|
|
318
|
+
connect: (deviceId) => bridge.connect({ vendor, deviceId }),
|
|
319
|
+
disconnect: (sessionId) => bridge.disconnect({ vendor, sessionId }),
|
|
320
|
+
call: (sessionId, method, callParams) => bridge.call({ vendor, sessionId, method, callParams }),
|
|
321
|
+
cancel: (sessionId) => bridge.cancel({ vendor, sessionId }),
|
|
322
|
+
uiResponse: (response) => bridge.uiResponse({ vendor, response }),
|
|
323
|
+
on: (event, handler) => {
|
|
324
|
+
const bridgeHandler = (e) => {
|
|
325
|
+
if (e.type === event) {
|
|
326
|
+
handler(e.data);
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
let inner = handlerMap.get(event);
|
|
330
|
+
if (!inner) {
|
|
331
|
+
inner = /* @__PURE__ */ new Map();
|
|
332
|
+
handlerMap.set(event, inner);
|
|
333
|
+
}
|
|
334
|
+
inner.set(handler, bridgeHandler);
|
|
335
|
+
bridge.onEvent({ vendor }, bridgeHandler);
|
|
336
|
+
},
|
|
337
|
+
off: (event, handler) => {
|
|
338
|
+
const inner = handlerMap.get(event);
|
|
339
|
+
const bridgeHandler = inner?.get(handler);
|
|
340
|
+
if (!bridgeHandler || !inner) return;
|
|
341
|
+
bridge.offEvent({ vendor }, bridgeHandler);
|
|
342
|
+
inner.delete(handler);
|
|
343
|
+
if (inner.size === 0) handlerMap.delete(event);
|
|
344
|
+
},
|
|
345
|
+
reset: () => bridge.reset({ vendor })
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// src/utils/TypedEventEmitter.ts
|
|
350
|
+
var TypedEventEmitter = class {
|
|
351
|
+
constructor() {
|
|
352
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
353
|
+
this._listeners = /* @__PURE__ */ new Map();
|
|
354
|
+
}
|
|
355
|
+
on(event, listener) {
|
|
356
|
+
let set = this._listeners.get(event);
|
|
357
|
+
if (!set) {
|
|
358
|
+
set = /* @__PURE__ */ new Set();
|
|
359
|
+
this._listeners.set(event, set);
|
|
360
|
+
}
|
|
361
|
+
set.add(listener);
|
|
362
|
+
}
|
|
363
|
+
off(event, listener) {
|
|
364
|
+
const set = this._listeners.get(event);
|
|
365
|
+
if (set) {
|
|
366
|
+
set.delete(listener);
|
|
367
|
+
if (set.size === 0) this._listeners.delete(event);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
emit(event, data) {
|
|
371
|
+
const set = this._listeners.get(event);
|
|
372
|
+
if (set) {
|
|
373
|
+
for (const listener of set) listener(data);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
removeAllListeners() {
|
|
377
|
+
this._listeners.clear();
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
// src/utils/UiRequestRegistry.ts
|
|
382
|
+
var UI_REQUEST_DEFAULT_TIMEOUT_MS = 6e5;
|
|
383
|
+
var RESPONSE_TO_REQUEST = {
|
|
384
|
+
[UI_RESPONSE.RECEIVE_PIN]: UI_REQUEST.REQUEST_PIN,
|
|
385
|
+
[UI_RESPONSE.RECEIVE_PASSPHRASE]: UI_REQUEST.REQUEST_PASSPHRASE,
|
|
386
|
+
[UI_RESPONSE.RECEIVE_PASSPHRASE_ON_DEVICE]: UI_REQUEST.REQUEST_PASSPHRASE_ON_DEVICE,
|
|
387
|
+
[UI_RESPONSE.RECEIVE_SELECT_DEVICE]: UI_REQUEST.REQUEST_SELECT_DEVICE,
|
|
388
|
+
[UI_RESPONSE.RECEIVE_DEVICE_CONNECT]: UI_REQUEST.REQUEST_DEVICE_CONNECT,
|
|
389
|
+
[UI_RESPONSE.RECEIVE_DEVICE_PERMISSION]: UI_REQUEST.REQUEST_DEVICE_PERMISSION,
|
|
390
|
+
[UI_RESPONSE.RECEIVE_PREEMPTION]: UI_REQUEST.REQUEST_PREEMPTION
|
|
391
|
+
// RECEIVE_QR_RESPONSE maps to QR_DISPLAY or QR_SCAN — resolved dynamically below.
|
|
392
|
+
};
|
|
393
|
+
var UI_REQUEST_PREEMPTED_TAG = "UiRequestPreempted";
|
|
394
|
+
var UI_REQUEST_CANCELLED_TAG = "UiRequestCancelled";
|
|
395
|
+
var UI_REQUEST_TIMEOUT_TAG = "UiRequestTimeout";
|
|
396
|
+
var UiRequestRegistry = class {
|
|
397
|
+
constructor() {
|
|
398
|
+
this.pending = /* @__PURE__ */ new Map();
|
|
399
|
+
}
|
|
400
|
+
wait(requestType, options) {
|
|
401
|
+
const existing = this.pending.get(requestType);
|
|
402
|
+
if (existing) {
|
|
403
|
+
clearTimeout(existing.timer);
|
|
404
|
+
this.pending.delete(requestType);
|
|
405
|
+
existing.reject(
|
|
406
|
+
Object.assign(new Error(`UI request '${requestType}' was superseded by a new request`), {
|
|
407
|
+
_tag: UI_REQUEST_PREEMPTED_TAG
|
|
408
|
+
})
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
const timeoutMs = options?.timeoutMs ?? UI_REQUEST_DEFAULT_TIMEOUT_MS;
|
|
412
|
+
return new Promise((resolve, reject) => {
|
|
413
|
+
const timer = setTimeout(() => {
|
|
414
|
+
if (this.pending.get(requestType)?.timer === timer) {
|
|
415
|
+
this.pending.delete(requestType);
|
|
416
|
+
reject(
|
|
417
|
+
Object.assign(new Error(`UI request '${requestType}' timed out after ${timeoutMs}ms`), {
|
|
418
|
+
_tag: UI_REQUEST_TIMEOUT_TAG
|
|
419
|
+
})
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
}, timeoutMs);
|
|
423
|
+
this.pending.set(requestType, {
|
|
424
|
+
resolve,
|
|
425
|
+
reject,
|
|
426
|
+
timer
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
resolve(responseType, payload) {
|
|
431
|
+
let requestType = RESPONSE_TO_REQUEST[responseType];
|
|
432
|
+
if (responseType === UI_RESPONSE.RECEIVE_QR_RESPONSE) {
|
|
433
|
+
if (this.pending.has(UI_REQUEST.REQUEST_QR_DISPLAY)) {
|
|
434
|
+
requestType = UI_REQUEST.REQUEST_QR_DISPLAY;
|
|
435
|
+
} else if (this.pending.has(UI_REQUEST.REQUEST_QR_SCAN)) {
|
|
436
|
+
requestType = UI_REQUEST.REQUEST_QR_SCAN;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
if (!requestType) return;
|
|
440
|
+
const entry = this.pending.get(requestType);
|
|
441
|
+
if (!entry) return;
|
|
442
|
+
clearTimeout(entry.timer);
|
|
443
|
+
this.pending.delete(requestType);
|
|
444
|
+
entry.resolve(payload);
|
|
445
|
+
}
|
|
446
|
+
cancel(requestType) {
|
|
447
|
+
if (requestType) {
|
|
448
|
+
const entry = this.pending.get(requestType);
|
|
449
|
+
if (!entry) return;
|
|
450
|
+
clearTimeout(entry.timer);
|
|
451
|
+
this.pending.delete(requestType);
|
|
452
|
+
entry.reject(
|
|
453
|
+
Object.assign(new Error(`UI request '${requestType}' was cancelled`), {
|
|
454
|
+
_tag: UI_REQUEST_CANCELLED_TAG
|
|
455
|
+
})
|
|
456
|
+
);
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
for (const [type, entry] of this.pending) {
|
|
460
|
+
clearTimeout(entry.timer);
|
|
461
|
+
entry.reject(
|
|
462
|
+
Object.assign(new Error(`UI request '${type}' was cancelled`), {
|
|
463
|
+
_tag: UI_REQUEST_CANCELLED_TAG
|
|
464
|
+
})
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
this.pending.clear();
|
|
468
|
+
}
|
|
469
|
+
reset() {
|
|
470
|
+
this.cancel();
|
|
471
|
+
}
|
|
472
|
+
hasPending(requestType) {
|
|
473
|
+
return this.pending.has(requestType);
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
// src/utils/semver.ts
|
|
478
|
+
function compareSemver(a, b) {
|
|
479
|
+
const pa = a.split(".").map(Number);
|
|
480
|
+
const pb = b.split(".").map(Number);
|
|
481
|
+
for (let i = 0; i < 3; i++) {
|
|
482
|
+
const va = pa[i] ?? 0;
|
|
483
|
+
const vb = pb[i] ?? 0;
|
|
484
|
+
if (va < vb) return -1;
|
|
485
|
+
if (va > vb) return 1;
|
|
486
|
+
}
|
|
487
|
+
return 0;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// src/utils/hex.ts
|
|
491
|
+
var import_utils2 = require("@noble/hashes/utils");
|
|
492
|
+
function ensure0x(hex) {
|
|
493
|
+
return hex.startsWith("0x") ? hex : `0x${hex}`;
|
|
494
|
+
}
|
|
495
|
+
function stripHex(hex) {
|
|
496
|
+
return hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
497
|
+
}
|
|
498
|
+
function padHex64(hex) {
|
|
499
|
+
return `0x${stripHex(hex).padStart(64, "0")}`;
|
|
500
|
+
}
|
|
501
|
+
function hexToBytes(hex) {
|
|
502
|
+
return (0, import_utils2.hexToBytes)(stripHex(hex));
|
|
503
|
+
}
|
|
504
|
+
function bytesToHex2(bytes) {
|
|
505
|
+
return (0, import_utils2.bytesToHex)(bytes);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// src/utils/errorMessages.ts
|
|
509
|
+
function enrichErrorMessage(code, originalMessage) {
|
|
510
|
+
switch (code) {
|
|
511
|
+
case 10400 /* PinInvalid */:
|
|
512
|
+
return `${originalMessage}. Please re-enter your PIN.`;
|
|
513
|
+
case 10401 /* PinCancelled */:
|
|
514
|
+
return `${originalMessage}. PIN entry was cancelled.`;
|
|
515
|
+
case 10102 /* DeviceBusy */:
|
|
516
|
+
return `${originalMessage}. The device is in use by another application. Close other wallet apps and try again.`;
|
|
517
|
+
case 10101 /* DeviceDisconnected */:
|
|
518
|
+
return `${originalMessage}. Please reconnect the device and try again.`;
|
|
519
|
+
case 10103 /* DeviceLocked */:
|
|
520
|
+
return `${originalMessage}. Please unlock your device and try again.`;
|
|
521
|
+
case 10001 /* UserRejected */:
|
|
522
|
+
return `${originalMessage}. The request was rejected on the device.`;
|
|
523
|
+
case 10501 /* WrongApp */:
|
|
524
|
+
return `${originalMessage}. Please open the correct app on your device.`;
|
|
525
|
+
case 10500 /* AppNotOpen */:
|
|
526
|
+
return `${originalMessage}. The required app is not installed on the device.`;
|
|
527
|
+
case 10302 /* TransportNotAvailable */:
|
|
528
|
+
return `${originalMessage}. Ensure the device bridge/transport is available and running.`;
|
|
529
|
+
case 10200 /* FirmwareTooOld */:
|
|
530
|
+
return `${originalMessage}. Please update your device firmware.`;
|
|
531
|
+
case 10104 /* DeviceNotInitialized */:
|
|
532
|
+
return `${originalMessage}. The device may need to be set up first.`;
|
|
533
|
+
case 10003 /* OperationTimeout */:
|
|
534
|
+
return `${originalMessage}. The operation timed out. Please try again.`;
|
|
535
|
+
case 11e3 /* EvmBlindSigningRequired */:
|
|
536
|
+
return "Ledger: Blind signing not enabled in Ethereum app.";
|
|
537
|
+
case 11001 /* EvmClearSignPluginMissing */:
|
|
538
|
+
return "Ledger: Required plugin not installed (install via Ledger Live).";
|
|
539
|
+
case 11002 /* EvmDataTooLarge */:
|
|
540
|
+
return "Ledger: Transaction data too large for device memory.";
|
|
541
|
+
case 11003 /* EvmTxTypeNotSupported */:
|
|
542
|
+
return "Ledger: Transaction type not supported by current Ethereum app.";
|
|
543
|
+
case 10502 /* AppTooOld */:
|
|
544
|
+
return "Ledger: App out of date (update via Ledger Live).";
|
|
545
|
+
case 11100 /* SolanaBlindSigningRequired */:
|
|
546
|
+
return "Blind signing disabled in the Solana app.";
|
|
547
|
+
case 11200 /* TronCustomContractRequired */:
|
|
548
|
+
return "Custom Contracts setting disabled in the Tron app.";
|
|
549
|
+
case 11201 /* TronDataSigningRequired */:
|
|
550
|
+
return "Transactions Data setting disabled in the Tron app.";
|
|
551
|
+
case 11202 /* TronSignByHashRequired */:
|
|
552
|
+
return "Sign by Hash setting disabled in the Tron app.";
|
|
553
|
+
case 11300 /* BtcWalletPolicyHmacMismatch */:
|
|
554
|
+
return "Wallet policy not registered or HMAC mismatch.";
|
|
555
|
+
case 11301 /* BtcUnexpectedState */:
|
|
556
|
+
return "Signing aborted due to unexpected device state.";
|
|
557
|
+
default:
|
|
558
|
+
return originalMessage;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// src/utils/batchCall.ts
|
|
563
|
+
async function batchCall(params, callFn, onProgress) {
|
|
564
|
+
const results = [];
|
|
565
|
+
for (let i = 0; i < params.length; i++) {
|
|
566
|
+
const result = await callFn(params[i]);
|
|
567
|
+
if (!result.success) {
|
|
568
|
+
return result;
|
|
569
|
+
}
|
|
570
|
+
results.push(result.payload);
|
|
571
|
+
onProgress?.({ index: i, total: params.length });
|
|
572
|
+
}
|
|
573
|
+
return { success: true, payload: results };
|
|
574
|
+
}
|
|
575
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
576
|
+
0 && (module.exports = {
|
|
577
|
+
CHAIN_FINGERPRINT_PATHS,
|
|
578
|
+
DEVICE,
|
|
579
|
+
DEVICE_EVENT,
|
|
580
|
+
DeviceJobQueue,
|
|
581
|
+
EConnectorInteraction,
|
|
582
|
+
HardwareErrorCode,
|
|
583
|
+
SDK,
|
|
584
|
+
TypedEventEmitter,
|
|
585
|
+
UI_EVENT,
|
|
586
|
+
UI_REQUEST,
|
|
587
|
+
UI_REQUEST_CANCELLED_TAG,
|
|
588
|
+
UI_REQUEST_DEFAULT_TIMEOUT_MS,
|
|
589
|
+
UI_REQUEST_PREEMPTED_TAG,
|
|
590
|
+
UI_REQUEST_TIMEOUT_TAG,
|
|
591
|
+
UI_RESPONSE,
|
|
592
|
+
UiRequestRegistry,
|
|
593
|
+
batchCall,
|
|
594
|
+
bytesToHex,
|
|
595
|
+
compareSemver,
|
|
596
|
+
createBridgedConnector,
|
|
597
|
+
deriveDeviceFingerprint,
|
|
598
|
+
enrichErrorMessage,
|
|
599
|
+
ensure0x,
|
|
600
|
+
failure,
|
|
601
|
+
hexToBytes,
|
|
602
|
+
padHex64,
|
|
603
|
+
stripHex,
|
|
604
|
+
success
|
|
605
|
+
});
|
|
606
|
+
//# sourceMappingURL=index.js.map
|