@ledgerhq/device-transport-kit-web-ble 1.3.0 → 1.3.2

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.
@@ -1,2 +1,2 @@
1
- import{DeviceDisconnectedWhileSendingError as o,DeviceNotInitializedError as h,SendApduTimeoutError as l}from"@ledgerhq/device-management-kit";import{Left as c,Maybe as n,Right as f}from"purify-ts";import{BehaviorSubject as _}from"rxjs";const u=8;class w{_dependencies;_apduFrameSegmenter=n.empty();_apduSenderFactory;_apduReceiverFactory;_apduFrameReceiver;_logger;_mtuNegotiated$=new _(!1);_notificationsReady=!1;_mtuRequestInProgress=!1;_pendingResponseResolver=n.empty();constructor(t,e){this._dependencies={writeCharacteristic:t.writeCharacteristic,notifyCharacteristic:t.notifyCharacteristic},this._apduSenderFactory=t.apduSenderFactory,this._apduReceiverFactory=t.apduReceiverFactory,this._apduFrameReceiver=t.apduReceiverFactory(),this._logger=e("WebBleApduSender")}async sendApdu(t,e,i){try{const a=Math.max(1800,i??0);await this._waitUntilMtuNegotiated(a)}catch(a){return c(a)}if(!this._isGattConnected())return this._markLinkUnavailable(),c(new o("GATT not connected"));if(this._apduFrameSegmenter.isNothing())return c(new h("Unknown MTU / sender not ready"));let r;const s=new Promise(a=>{this._pendingResponseResolver=n.of(p=>{r&&clearTimeout(r),a(p)})}),d=this._apduFrameSegmenter.map(a=>a.getFrames(t)).orDefault([]);for(const a of d)try{await this._writeToGattCharacteristic(a.getRawData().slice().buffer)}catch(p){const m=e?"Frame write failed during expected drop":"Frame write failed";this._logger[e?"debug":"error"](m,{data:{e:p}}),this._failPendingSend(new o("Write failed"));break}return i&&(r=setTimeout(()=>{this._logger.debug("[sendApdu] Abort timeout triggered"),this._pendingResponseResolver.map(a=>a(c(new l("Abort timeout"))))},i)),s}closeConnection(){try{this._failPendingSend(new o("Connection closed")),this._notificationsReady&&(this._dependencies.notifyCharacteristic.removeEventListener("characteristicvaluechanged",this._handleNotification),this._dependencies.notifyCharacteristic.stopNotifications().catch(()=>{}),this._notificationsReady=!1),this._dependencies.notifyCharacteristic.service.device.gatt?.disconnect()}catch{this._logger.error("Failed to disconnect from device")}finally{this._mtuNegotiated$.next(!1),this._apduFrameSegmenter=n.empty()}}getDependencies(){return this._dependencies}setDependencies(t){this._failPendingSend(new o("Link changed"));try{this._notificationsReady&&(this._dependencies.notifyCharacteristic.removeEventListener("characteristicvaluechanged",this._handleNotification),this._dependencies.notifyCharacteristic.stopNotifications().catch(()=>{}))}catch{}this._notificationsReady=!1,this._mtuNegotiated$.next(!1),this._apduFrameSegmenter=n.empty(),this._pendingResponseResolver=n.empty(),this._dependencies=t,this._apduFrameReceiver=this._apduReceiverFactory()}async setupConnection(){const t=this._dependencies.notifyCharacteristic;this._notificationsReady||(await t.startNotifications(),this._logger.debug("Notify armed",{data:{notifyUuid:this._dependencies.notifyCharacteristic.uuid,writeUuid:this._dependencies.writeCharacteristic.uuid,props:this._dependencies.writeCharacteristic.properties}}),this._notificationsReady=!0,t.addEventListener("characteristicvaluechanged",this._handleNotification)),await this._sleep(120),this._mtuRequestInProgress=!0,this._mtuNegotiated$.next(!1),this._apduFrameSegmenter=n.empty();const e=new Uint8Array([u,0,0,0,0]);try{await this._writeToGattCharacteristic(e.buffer),await Promise.race([new Promise((i,r)=>{const s=setTimeout(()=>r(new Error("MTU negotiation timeout")),2e3),d=this._mtuNegotiated$.subscribe(a=>{a&&(clearTimeout(s),d.unsubscribe(),i())})}),this._sleep(2300).then(()=>{if(!this._isGattConnected())throw new o("Link dropped during MTU")})])}catch(i){try{t.removeEventListener("characteristicvaluechanged",this._handleNotification),await t.stopNotifications().catch(()=>{})}finally{this._notificationsReady=!1,this._mtuNegotiated$.next(!1),this._apduFrameSegmenter=n.empty()}throw i}finally{this._mtuRequestInProgress=!1}}_isGattConnected(){try{return!!this._dependencies.notifyCharacteristic.service.device.gatt?.connected}catch{return!1}}_isGattDisconnectedError(t){const e=t,i=(typeof e=="object"&&e!==null&&"name"in e?e.name??"":"").toString(),r=(typeof e=="object"&&e!==null&&"message"in e?e.message??"":"").toString().toLowerCase();return i==="NetworkError"||r.includes("gatt server is disconnected")||r.includes("not connected")||r.includes("cannot perform gatt operations")}_failPendingSend(t){this._pendingResponseResolver.map(e=>e(c(t))),this._pendingResponseResolver=n.empty()}_markLinkUnavailable(){this._notificationsReady&&(this._dependencies.notifyCharacteristic.removeEventListener("characteristicvaluechanged",this._handleNotification),this._dependencies.notifyCharacteristic.stopNotifications().catch(()=>{}),this._notificationsReady=!1),this._mtuNegotiated$.next(!1),this._apduFrameSegmenter=n.empty(),this._pendingResponseResolver=n.empty()}async _sleep(t){return new Promise(e=>setTimeout(e,t))}_handleNotification=t=>{const e=t.target;if(!e.value)return;const i=new Uint8Array(e.value.buffer);if(!this._mtuNegotiated$.value){if(!this._mtuRequestInProgress){this._logger.debug("Dropping pre-handshake frame",{data:{data:i}});return}if(i.length<6||i[0]!==u){this._logger.debug("Non-MTU frame during handshake; dropping",{data:{data:i}});return}this._handleMtuNegotiationFrame(i);return}this._handleApduFrame(i)};_handleMtuNegotiationFrame(t){const e=t[5];if(e===void 0||!Number.isFinite(e)||e<=0)throw new Error("MTU negotiation failed: invalid MTU");const i=e;this._apduFrameSegmenter=n.of(this._apduSenderFactory({frameSize:i})),this._mtuNegotiated$.next(!0)}_handleApduFrame(t){this._apduFrameReceiver.handleFrame(t).map(e=>e.map(i=>{this._logger.debug("Received APDU",{data:{resp:i}}),this._pendingResponseResolver.map(r=>r(f(i))),this._pendingResponseResolver=n.empty()})).mapLeft(e=>{this._pendingResponseResolver.map(i=>i(c(e))),this._pendingResponseResolver=n.empty()})}async _writeToGattCharacteristic(t){const e=this._dependencies.writeCharacteristic;if(!this._isGattConnected())throw this._markLinkUnavailable(),new o("GATT not connected");const i=typeof e.writeValueWithoutResponse=="function",r=typeof e.writeValueWithResponse=="function";if(e.properties.writeWithoutResponse&&i)try{await e.writeValueWithoutResponse(t);return}catch(s){if(this._isGattDisconnectedError(s)||!this._isGattConnected())throw this._markLinkUnavailable(),new o("Write failed")}if(e.properties.write&&r){await e.writeValueWithResponse(t);return}throw new Error("No supported write method for characteristic")}async _waitUntilMtuNegotiated(t=2e3){if(!(this._notificationsReady&&this._mtuNegotiated$.value&&this._isGattConnected()))return new Promise((e,i)=>{const r=this._mtuNegotiated$.subscribe(d=>{d&&this._notificationsReady&&this._isGattConnected()&&(clearTimeout(s),r.unsubscribe(),e())}),s=setTimeout(()=>{r.unsubscribe(),i(new h("Link not ready"))},t);this._notificationsReady&&this._mtuNegotiated$.value&&this._isGattConnected()&&(clearTimeout(s),r.unsubscribe(),e())})}}export{u as MTU_OP,w as WebBleApduSender};
1
+ import{DeviceDisconnectedWhileSendingError as o,DeviceNotInitializedError as h,formatApduReceivedLog as l,formatApduSentLog as f,SendApduTimeoutError as _}from"@ledgerhq/device-management-kit";import{Left as c,Maybe as n,Right as g}from"purify-ts";import{BehaviorSubject as v}from"rxjs";const u=8;class S{_dependencies;_apduFrameSegmenter=n.empty();_apduSenderFactory;_apduReceiverFactory;_apduFrameReceiver;_logger;_mtuNegotiated$=new v(!1);_notificationsReady=!1;_mtuRequestInProgress=!1;_pendingResponseResolver=n.empty();constructor(t,e){this._dependencies={writeCharacteristic:t.writeCharacteristic,notifyCharacteristic:t.notifyCharacteristic},this._apduSenderFactory=t.apduSenderFactory,this._apduReceiverFactory=t.apduReceiverFactory,this._apduFrameReceiver=t.apduReceiverFactory(),this._logger=e("WebBleApduSender")}async sendApdu(t,e,i){try{const a=Math.max(1800,i??0);await this._waitUntilMtuNegotiated(a)}catch(a){return c(a)}if(!this._isGattConnected())return this._markLinkUnavailable(),c(new o("GATT not connected"));if(this._apduFrameSegmenter.isNothing())return c(new h("Unknown MTU / sender not ready"));let r;const s=new Promise(a=>{this._pendingResponseResolver=n.of(p=>{r&&clearTimeout(r),a(p)})}),d=this._apduFrameSegmenter.map(a=>a.getFrames(t)).orDefault([]);for(const a of d)try{await this._writeToGattCharacteristic(a.getRawData().slice().buffer)}catch(p){const m=e?"Frame write failed during expected drop":"Frame write failed";this._logger[e?"debug":"error"](m,{data:{e:p}}),this._failPendingSend(new o("Write failed"));break}return this._logger.debug(f(t)),i&&(r=setTimeout(()=>{this._logger.debug("[sendApdu] Abort timeout triggered"),this._pendingResponseResolver.map(a=>a(c(new _("Abort timeout"))))},i)),s}closeConnection(){try{this._failPendingSend(new o("Connection closed")),this._notificationsReady&&(this._dependencies.notifyCharacteristic.removeEventListener("characteristicvaluechanged",this._handleNotification),this._dependencies.notifyCharacteristic.stopNotifications().catch(()=>{}),this._notificationsReady=!1),this._dependencies.notifyCharacteristic.service.device.gatt?.disconnect()}catch{this._logger.error("Failed to disconnect from device")}finally{this._mtuNegotiated$.next(!1),this._apduFrameSegmenter=n.empty()}}getDependencies(){return this._dependencies}setDependencies(t){this._failPendingSend(new o("Link changed"));try{this._notificationsReady&&(this._dependencies.notifyCharacteristic.removeEventListener("characteristicvaluechanged",this._handleNotification),this._dependencies.notifyCharacteristic.stopNotifications().catch(()=>{}))}catch{}this._notificationsReady=!1,this._mtuNegotiated$.next(!1),this._apduFrameSegmenter=n.empty(),this._pendingResponseResolver=n.empty(),this._dependencies=t,this._apduFrameReceiver=this._apduReceiverFactory()}async setupConnection(){const t=this._dependencies.notifyCharacteristic;this._notificationsReady||(await t.startNotifications(),this._logger.debug("Notify armed",{data:{notifyUuid:this._dependencies.notifyCharacteristic.uuid,writeUuid:this._dependencies.writeCharacteristic.uuid,props:this._dependencies.writeCharacteristic.properties}}),this._notificationsReady=!0,t.addEventListener("characteristicvaluechanged",this._handleNotification)),await this._sleep(120),this._mtuRequestInProgress=!0,this._mtuNegotiated$.next(!1),this._apduFrameSegmenter=n.empty();const e=new Uint8Array([u,0,0,0,0]);try{await this._writeToGattCharacteristic(e.buffer),await Promise.race([new Promise((i,r)=>{const s=setTimeout(()=>r(new Error("MTU negotiation timeout")),2e3),d=this._mtuNegotiated$.subscribe(a=>{a&&(clearTimeout(s),d.unsubscribe(),i())})}),this._sleep(2300).then(()=>{if(!this._isGattConnected())throw new o("Link dropped during MTU")})])}catch(i){try{t.removeEventListener("characteristicvaluechanged",this._handleNotification),await t.stopNotifications().catch(()=>{})}finally{this._notificationsReady=!1,this._mtuNegotiated$.next(!1),this._apduFrameSegmenter=n.empty()}throw i}finally{this._mtuRequestInProgress=!1}}_isGattConnected(){try{return!!this._dependencies.notifyCharacteristic.service.device.gatt?.connected}catch{return!1}}_isGattDisconnectedError(t){const e=t,i=(typeof e=="object"&&e!==null&&"name"in e?e.name??"":"").toString(),r=(typeof e=="object"&&e!==null&&"message"in e?e.message??"":"").toString().toLowerCase();return i==="NetworkError"||r.includes("gatt server is disconnected")||r.includes("not connected")||r.includes("cannot perform gatt operations")}_failPendingSend(t){this._pendingResponseResolver.map(e=>e(c(t))),this._pendingResponseResolver=n.empty()}_markLinkUnavailable(){this._notificationsReady&&(this._dependencies.notifyCharacteristic.removeEventListener("characteristicvaluechanged",this._handleNotification),this._dependencies.notifyCharacteristic.stopNotifications().catch(()=>{}),this._notificationsReady=!1),this._mtuNegotiated$.next(!1),this._apduFrameSegmenter=n.empty(),this._pendingResponseResolver=n.empty()}async _sleep(t){return new Promise(e=>setTimeout(e,t))}_handleNotification=t=>{const e=t.target;if(!e.value)return;const i=new Uint8Array(e.value.buffer);if(!this._mtuNegotiated$.value){if(!this._mtuRequestInProgress){this._logger.debug("Dropping pre-handshake frame",{data:{data:i}});return}if(i.length<6||i[0]!==u){this._logger.debug("Non-MTU frame during handshake; dropping",{data:{data:i}});return}this._handleMtuNegotiationFrame(i);return}this._handleApduFrame(i)};_handleMtuNegotiationFrame(t){const e=t[5];if(e===void 0||!Number.isFinite(e)||e<=0)throw new Error("MTU negotiation failed: invalid MTU");const i=e;this._apduFrameSegmenter=n.of(this._apduSenderFactory({frameSize:i})),this._mtuNegotiated$.next(!0)}_handleApduFrame(t){this._apduFrameReceiver.handleFrame(t).map(e=>e.map(i=>{this._logger.debug(l(i)),this._pendingResponseResolver.map(r=>r(g(i))),this._pendingResponseResolver=n.empty()})).mapLeft(e=>{this._pendingResponseResolver.map(i=>i(c(e))),this._pendingResponseResolver=n.empty()})}async _writeToGattCharacteristic(t){const e=this._dependencies.writeCharacteristic;if(!this._isGattConnected())throw this._markLinkUnavailable(),new o("GATT not connected");const i=typeof e.writeValueWithoutResponse=="function",r=typeof e.writeValueWithResponse=="function";if(e.properties.writeWithoutResponse&&i)try{await e.writeValueWithoutResponse(t);return}catch(s){if(this._isGattDisconnectedError(s)||!this._isGattConnected())throw this._markLinkUnavailable(),new o("Write failed")}if(e.properties.write&&r){await e.writeValueWithResponse(t);return}throw new Error("No supported write method for characteristic")}async _waitUntilMtuNegotiated(t=2e3){if(!(this._notificationsReady&&this._mtuNegotiated$.value&&this._isGattConnected()))return new Promise((e,i)=>{const r=this._mtuNegotiated$.subscribe(d=>{d&&this._notificationsReady&&this._isGattConnected()&&(clearTimeout(s),r.unsubscribe(),e())}),s=setTimeout(()=>{r.unsubscribe(),i(new h("Link not ready"))},t);this._notificationsReady&&this._mtuNegotiated$.value&&this._isGattConnected()&&(clearTimeout(s),r.unsubscribe(),e())})}}export{u as MTU_OP,S as WebBleApduSender};
2
2
  //# sourceMappingURL=WebBleApduSender.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/api/transport/WebBleApduSender.ts"],
4
- "sourcesContent": ["import {\n type ApduReceiverService,\n type ApduReceiverServiceFactory,\n type ApduResponse,\n type ApduSenderService,\n type ApduSenderServiceFactory,\n type DeviceApduSender,\n DeviceDisconnectedWhileSendingError,\n DeviceNotInitializedError,\n type DmkError,\n type LoggerPublisherService,\n SendApduTimeoutError,\n} from \"@ledgerhq/device-management-kit\";\nimport { type Either, Left, Maybe, Right } from \"purify-ts\";\nimport { BehaviorSubject } from \"rxjs\";\n\nexport type WebBleApduSenderDependencies = {\n writeCharacteristic: BluetoothRemoteGATTCharacteristic;\n notifyCharacteristic: BluetoothRemoteGATTCharacteristic;\n};\n\nexport const MTU_OP = 0x08;\n\nexport class WebBleApduSender\n implements DeviceApduSender<WebBleApduSenderDependencies>\n{\n private _dependencies: WebBleApduSenderDependencies;\n private _apduFrameSegmenter: Maybe<ApduSenderService> = Maybe.empty();\n private _apduSenderFactory: ApduSenderServiceFactory;\n private _apduReceiverFactory: ApduReceiverServiceFactory;\n private _apduFrameReceiver: ApduReceiverService;\n private _logger: LoggerPublisherService;\n\n private _mtuNegotiated$ = new BehaviorSubject<boolean>(false);\n private _notificationsReady = false;\n private _mtuRequestInProgress = false;\n\n private _pendingResponseResolver: Maybe<\n (r: Either<DmkError, ApduResponse>) => void\n > = Maybe.empty();\n\n constructor(\n initialDependencies: WebBleApduSenderDependencies & {\n apduSenderFactory: ApduSenderServiceFactory;\n apduReceiverFactory: ApduReceiverServiceFactory;\n },\n loggerFactory: (tag: string) => LoggerPublisherService,\n ) {\n this._dependencies = {\n writeCharacteristic: initialDependencies.writeCharacteristic,\n notifyCharacteristic: initialDependencies.notifyCharacteristic,\n };\n this._apduSenderFactory = initialDependencies.apduSenderFactory;\n this._apduReceiverFactory = initialDependencies.apduReceiverFactory;\n this._apduFrameReceiver = initialDependencies.apduReceiverFactory();\n this._logger = loggerFactory(\"WebBleApduSender\");\n }\n\n public async sendApdu(\n apdu: Uint8Array,\n triggersDisconnection?: boolean,\n abortTimeout?: number,\n ): Promise<Either<DmkError, ApduResponse>> {\n try {\n const waitBudget = Math.max(1800, abortTimeout ?? 0);\n await this._waitUntilMtuNegotiated(waitBudget);\n } catch (e) {\n return Left(e as DmkError);\n }\n\n if (!this._isGattConnected()) {\n this._markLinkUnavailable();\n return Left(\n new DeviceDisconnectedWhileSendingError(\n \"GATT not connected\",\n ) as unknown as DmkError,\n );\n }\n\n if (this._apduFrameSegmenter.isNothing()) {\n return Left(\n new DeviceNotInitializedError(\n \"Unknown MTU / sender not ready\",\n ) as unknown as DmkError,\n );\n }\n\n let timeoutHandle: ReturnType<typeof setTimeout> | undefined;\n const responsePromise = new Promise<Either<DmkError, ApduResponse>>(\n (resolve) => {\n this._pendingResponseResolver = Maybe.of((result) => {\n if (timeoutHandle) clearTimeout(timeoutHandle);\n resolve(result);\n });\n },\n );\n\n const frames = this._apduFrameSegmenter\n .map((segmenter) => segmenter.getFrames(apdu))\n .orDefault([]);\n\n for (const frame of frames) {\n try {\n await this._writeToGattCharacteristic(\n frame.getRawData().slice().buffer,\n );\n } catch (e) {\n const msg = triggersDisconnection\n ? \"Frame write failed during expected drop\"\n : \"Frame write failed\";\n this._logger[triggersDisconnection ? \"debug\" : \"error\"](msg, {\n data: { e },\n });\n this._failPendingSend(\n new DeviceDisconnectedWhileSendingError(\"Write failed\"),\n );\n break;\n }\n }\n\n if (abortTimeout) {\n timeoutHandle = setTimeout(() => {\n this._logger.debug(\"[sendApdu] Abort timeout triggered\");\n this._pendingResponseResolver.map((resolve) =>\n resolve(Left(new SendApduTimeoutError(\"Abort timeout\"))),\n );\n }, abortTimeout);\n }\n\n return responsePromise;\n }\n\n public closeConnection(): void {\n try {\n this._failPendingSend(\n new DeviceDisconnectedWhileSendingError(\"Connection closed\"),\n );\n if (this._notificationsReady) {\n this._dependencies.notifyCharacteristic.removeEventListener(\n \"characteristicvaluechanged\",\n this._handleNotification,\n );\n this._dependencies.notifyCharacteristic\n .stopNotifications()\n .catch(() => {});\n this._notificationsReady = false;\n }\n this._dependencies.notifyCharacteristic.service.device.gatt?.disconnect();\n } catch {\n this._logger.error(\"Failed to disconnect from device\");\n } finally {\n this._mtuNegotiated$.next(false);\n this._apduFrameSegmenter = Maybe.empty();\n }\n }\n\n public getDependencies(): WebBleApduSenderDependencies {\n return this._dependencies;\n }\n\n public setDependencies(deps: WebBleApduSenderDependencies): void {\n this._failPendingSend(\n new DeviceDisconnectedWhileSendingError(\"Link changed\"),\n );\n\n try {\n if (this._notificationsReady) {\n this._dependencies.notifyCharacteristic.removeEventListener(\n \"characteristicvaluechanged\",\n this._handleNotification,\n );\n this._dependencies.notifyCharacteristic\n .stopNotifications()\n .catch(() => {});\n }\n } catch {\n // ignore\n }\n\n this._notificationsReady = false;\n this._mtuNegotiated$.next(false);\n this._apduFrameSegmenter = Maybe.empty();\n this._pendingResponseResolver = Maybe.empty();\n\n this._dependencies = deps;\n this._apduFrameReceiver = this._apduReceiverFactory();\n }\n\n public async setupConnection(): Promise<void> {\n const notifyCharacteristic = this._dependencies.notifyCharacteristic;\n if (!this._notificationsReady) {\n await notifyCharacteristic.startNotifications();\n this._logger.debug(\"Notify armed\", {\n data: {\n notifyUuid: this._dependencies.notifyCharacteristic.uuid,\n writeUuid: this._dependencies.writeCharacteristic.uuid,\n props: this._dependencies.writeCharacteristic.properties,\n },\n });\n this._notificationsReady = true;\n notifyCharacteristic.addEventListener(\n \"characteristicvaluechanged\",\n this._handleNotification,\n );\n }\n\n // Avoids possible drops on the very first notification if we write immediately\n await this._sleep(120);\n\n this._mtuRequestInProgress = true;\n this._mtuNegotiated$.next(false);\n this._apduFrameSegmenter = Maybe.empty();\n\n const mtuRequestFrame = new Uint8Array([MTU_OP, 0, 0, 0, 0]);\n\n try {\n await this._writeToGattCharacteristic(mtuRequestFrame.buffer);\n\n await Promise.race([\n new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(\n () => reject(new Error(\"MTU negotiation timeout\")),\n 2000,\n );\n const sub = this._mtuNegotiated$.subscribe((ready) => {\n if (ready) {\n clearTimeout(timeout);\n sub.unsubscribe();\n resolve();\n }\n });\n }),\n this._sleep(2300).then(() => {\n if (!this._isGattConnected()) {\n throw new DeviceDisconnectedWhileSendingError(\n \"Link dropped during MTU\",\n );\n }\n }),\n ]);\n } catch (e) {\n try {\n notifyCharacteristic.removeEventListener(\n \"characteristicvaluechanged\",\n this._handleNotification,\n );\n await notifyCharacteristic.stopNotifications().catch(() => {});\n } finally {\n this._notificationsReady = false;\n this._mtuNegotiated$.next(false);\n this._apduFrameSegmenter = Maybe.empty();\n }\n throw e;\n } finally {\n this._mtuRequestInProgress = false;\n }\n }\n\n private _isGattConnected(): boolean {\n try {\n return !!this._dependencies.notifyCharacteristic.service.device.gatt\n ?.connected;\n } catch {\n return false;\n }\n }\n\n private _isGattDisconnectedError(e: unknown): boolean {\n const err = e as Error | { name?: string; message?: string };\n const name = (\n typeof err === \"object\" && err !== null && \"name\" in err\n ? (err.name ?? \"\")\n : \"\"\n ).toString();\n const msg = (\n typeof err === \"object\" && err !== null && \"message\" in err\n ? (err.message ?? \"\")\n : \"\"\n )\n .toString()\n .toLowerCase();\n return (\n name === \"NetworkError\" ||\n msg.includes(\"gatt server is disconnected\") ||\n msg.includes(\"not connected\") ||\n msg.includes(\"cannot perform gatt operations\")\n );\n }\n\n private _failPendingSend(err: DmkError) {\n this._pendingResponseResolver.map((resolve) => resolve(Left(err)));\n this._pendingResponseResolver = Maybe.empty();\n }\n\n private _markLinkUnavailable(): void {\n if (this._notificationsReady) {\n this._dependencies.notifyCharacteristic.removeEventListener(\n \"characteristicvaluechanged\",\n this._handleNotification,\n );\n this._dependencies.notifyCharacteristic\n .stopNotifications()\n .catch(() => {});\n this._notificationsReady = false;\n }\n\n this._mtuNegotiated$.next(false);\n this._apduFrameSegmenter = Maybe.empty();\n this._pendingResponseResolver = Maybe.empty();\n }\n\n private async _sleep(ms: number) {\n return new Promise((r) => setTimeout(r, ms));\n }\n\n private _handleNotification = (event: Event) => {\n const characteristic = event.target as BluetoothRemoteGATTCharacteristic;\n if (!characteristic.value) return;\n const data = new Uint8Array(characteristic.value.buffer);\n\n if (!this._mtuNegotiated$.value) {\n if (!this._mtuRequestInProgress) {\n this._logger.debug(\"Dropping pre-handshake frame\", { data: { data } });\n return;\n }\n if (data.length < 6 || data[0] !== MTU_OP) {\n this._logger.debug(\"Non-MTU frame during handshake; dropping\", {\n data: { data },\n });\n return;\n }\n this._handleMtuNegotiationFrame(data);\n return;\n }\n\n this._handleApduFrame(data);\n };\n\n private _handleMtuNegotiationFrame(mtuResponseBuffer: Uint8Array) {\n const ledgerMtu = mtuResponseBuffer[5];\n if (\n ledgerMtu === undefined ||\n !Number.isFinite(ledgerMtu) ||\n ledgerMtu <= 0\n ) {\n throw new Error(\"MTU negotiation failed: invalid MTU\");\n }\n\n const frameSize = ledgerMtu;\n this._apduFrameSegmenter = Maybe.of(this._apduSenderFactory({ frameSize }));\n this._mtuNegotiated$.next(true);\n }\n\n private _handleApduFrame(incomingFrame: Uint8Array) {\n this._apduFrameReceiver\n .handleFrame(incomingFrame)\n .map((maybeResponse) =>\n maybeResponse.map((resp) => {\n this._logger.debug(\"Received APDU\", { data: { resp } });\n this._pendingResponseResolver.map((resolve) => resolve(Right(resp)));\n this._pendingResponseResolver = Maybe.empty();\n }),\n )\n .mapLeft((err) => {\n this._pendingResponseResolver.map((resolve) => resolve(Left(err)));\n this._pendingResponseResolver = Maybe.empty();\n });\n }\n\n private async _writeToGattCharacteristic(buf: ArrayBuffer) {\n const ch = this._dependencies.writeCharacteristic;\n\n if (!this._isGattConnected()) {\n this._markLinkUnavailable();\n throw new DeviceDisconnectedWhileSendingError(\"GATT not connected\");\n }\n\n const hasWnr = typeof ch.writeValueWithoutResponse === \"function\";\n const hasWr = typeof ch.writeValueWithResponse === \"function\";\n\n // Prefer WNR for Ledger throughput\n if (ch.properties.writeWithoutResponse && hasWnr) {\n try {\n await ch.writeValueWithoutResponse(buf);\n return;\n } catch (e) {\n if (this._isGattDisconnectedError(e) || !this._isGattConnected()) {\n this._markLinkUnavailable();\n throw new DeviceDisconnectedWhileSendingError(\"Write failed\");\n }\n // otherwise, try WR\n }\n }\n\n if (ch.properties.write && hasWr) {\n await ch.writeValueWithResponse(buf);\n return;\n }\n\n throw new Error(\"No supported write method for characteristic\");\n }\n\n private async _waitUntilMtuNegotiated(maxMs = 2000): Promise<void> {\n if (\n this._notificationsReady &&\n this._mtuNegotiated$.value &&\n this._isGattConnected()\n )\n return;\n\n return new Promise<void>((resolve, reject) => {\n const subscription = this._mtuNegotiated$.subscribe((ready) => {\n if (!ready) return;\n if (this._notificationsReady && this._isGattConnected()) {\n clearTimeout(timer);\n subscription.unsubscribe();\n resolve();\n }\n });\n\n const timer = setTimeout(() => {\n subscription.unsubscribe();\n reject(new DeviceNotInitializedError(\"Link not ready\"));\n }, maxMs);\n\n if (\n this._notificationsReady &&\n this._mtuNegotiated$.value &&\n this._isGattConnected()\n ) {\n clearTimeout(timer);\n subscription.unsubscribe();\n resolve();\n }\n });\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["DeviceDisconnectedWhileSendingError", "DeviceNotInitializedError", "SendApduTimeoutError", "Left", "Maybe", "Right", "BehaviorSubject", "MTU_OP", "WebBleApduSender", "initialDependencies", "loggerFactory", "apdu", "triggersDisconnection", "abortTimeout", "waitBudget", "e", "timeoutHandle", "responsePromise", "resolve", "result", "frames", "segmenter", "frame", "msg", "deps", "notifyCharacteristic", "mtuRequestFrame", "reject", "timeout", "sub", "ready", "err", "name", "ms", "r", "event", "characteristic", "data", "mtuResponseBuffer", "ledgerMtu", "frameSize", "incomingFrame", "maybeResponse", "resp", "buf", "ch", "hasWnr", "hasWr", "maxMs", "subscription", "timer"]
4
+ "sourcesContent": ["import {\n type ApduReceiverService,\n type ApduReceiverServiceFactory,\n type ApduResponse,\n type ApduSenderService,\n type ApduSenderServiceFactory,\n type DeviceApduSender,\n DeviceDisconnectedWhileSendingError,\n DeviceNotInitializedError,\n type DmkError,\n formatApduReceivedLog,\n formatApduSentLog,\n type LoggerPublisherService,\n SendApduTimeoutError,\n} from \"@ledgerhq/device-management-kit\";\nimport { type Either, Left, Maybe, Right } from \"purify-ts\";\nimport { BehaviorSubject } from \"rxjs\";\n\nexport type WebBleApduSenderDependencies = {\n writeCharacteristic: BluetoothRemoteGATTCharacteristic;\n notifyCharacteristic: BluetoothRemoteGATTCharacteristic;\n};\n\nexport const MTU_OP = 0x08;\n\nexport class WebBleApduSender\n implements DeviceApduSender<WebBleApduSenderDependencies>\n{\n private _dependencies: WebBleApduSenderDependencies;\n private _apduFrameSegmenter: Maybe<ApduSenderService> = Maybe.empty();\n private _apduSenderFactory: ApduSenderServiceFactory;\n private _apduReceiverFactory: ApduReceiverServiceFactory;\n private _apduFrameReceiver: ApduReceiverService;\n private _logger: LoggerPublisherService;\n\n private _mtuNegotiated$ = new BehaviorSubject<boolean>(false);\n private _notificationsReady = false;\n private _mtuRequestInProgress = false;\n\n private _pendingResponseResolver: Maybe<\n (r: Either<DmkError, ApduResponse>) => void\n > = Maybe.empty();\n\n constructor(\n initialDependencies: WebBleApduSenderDependencies & {\n apduSenderFactory: ApduSenderServiceFactory;\n apduReceiverFactory: ApduReceiverServiceFactory;\n },\n loggerFactory: (tag: string) => LoggerPublisherService,\n ) {\n this._dependencies = {\n writeCharacteristic: initialDependencies.writeCharacteristic,\n notifyCharacteristic: initialDependencies.notifyCharacteristic,\n };\n this._apduSenderFactory = initialDependencies.apduSenderFactory;\n this._apduReceiverFactory = initialDependencies.apduReceiverFactory;\n this._apduFrameReceiver = initialDependencies.apduReceiverFactory();\n this._logger = loggerFactory(\"WebBleApduSender\");\n }\n\n public async sendApdu(\n apdu: Uint8Array,\n triggersDisconnection?: boolean,\n abortTimeout?: number,\n ): Promise<Either<DmkError, ApduResponse>> {\n try {\n const waitBudget = Math.max(1800, abortTimeout ?? 0);\n await this._waitUntilMtuNegotiated(waitBudget);\n } catch (e) {\n return Left(e as DmkError);\n }\n\n if (!this._isGattConnected()) {\n this._markLinkUnavailable();\n return Left(\n new DeviceDisconnectedWhileSendingError(\n \"GATT not connected\",\n ) as unknown as DmkError,\n );\n }\n\n if (this._apduFrameSegmenter.isNothing()) {\n return Left(\n new DeviceNotInitializedError(\n \"Unknown MTU / sender not ready\",\n ) as unknown as DmkError,\n );\n }\n\n let timeoutHandle: ReturnType<typeof setTimeout> | undefined;\n const responsePromise = new Promise<Either<DmkError, ApduResponse>>(\n (resolve) => {\n this._pendingResponseResolver = Maybe.of((result) => {\n if (timeoutHandle) clearTimeout(timeoutHandle);\n resolve(result);\n });\n },\n );\n\n const frames = this._apduFrameSegmenter\n .map((segmenter) => segmenter.getFrames(apdu))\n .orDefault([]);\n\n for (const frame of frames) {\n try {\n await this._writeToGattCharacteristic(\n frame.getRawData().slice().buffer,\n );\n } catch (e) {\n const msg = triggersDisconnection\n ? \"Frame write failed during expected drop\"\n : \"Frame write failed\";\n this._logger[triggersDisconnection ? \"debug\" : \"error\"](msg, {\n data: { e },\n });\n this._failPendingSend(\n new DeviceDisconnectedWhileSendingError(\"Write failed\"),\n );\n break;\n }\n }\n this._logger.debug(formatApduSentLog(apdu));\n\n if (abortTimeout) {\n timeoutHandle = setTimeout(() => {\n this._logger.debug(\"[sendApdu] Abort timeout triggered\");\n this._pendingResponseResolver.map((resolve) =>\n resolve(Left(new SendApduTimeoutError(\"Abort timeout\"))),\n );\n }, abortTimeout);\n }\n\n return responsePromise;\n }\n\n public closeConnection(): void {\n try {\n this._failPendingSend(\n new DeviceDisconnectedWhileSendingError(\"Connection closed\"),\n );\n if (this._notificationsReady) {\n this._dependencies.notifyCharacteristic.removeEventListener(\n \"characteristicvaluechanged\",\n this._handleNotification,\n );\n this._dependencies.notifyCharacteristic\n .stopNotifications()\n .catch(() => {});\n this._notificationsReady = false;\n }\n this._dependencies.notifyCharacteristic.service.device.gatt?.disconnect();\n } catch {\n this._logger.error(\"Failed to disconnect from device\");\n } finally {\n this._mtuNegotiated$.next(false);\n this._apduFrameSegmenter = Maybe.empty();\n }\n }\n\n public getDependencies(): WebBleApduSenderDependencies {\n return this._dependencies;\n }\n\n public setDependencies(deps: WebBleApduSenderDependencies): void {\n this._failPendingSend(\n new DeviceDisconnectedWhileSendingError(\"Link changed\"),\n );\n\n try {\n if (this._notificationsReady) {\n this._dependencies.notifyCharacteristic.removeEventListener(\n \"characteristicvaluechanged\",\n this._handleNotification,\n );\n this._dependencies.notifyCharacteristic\n .stopNotifications()\n .catch(() => {});\n }\n } catch {\n // ignore\n }\n\n this._notificationsReady = false;\n this._mtuNegotiated$.next(false);\n this._apduFrameSegmenter = Maybe.empty();\n this._pendingResponseResolver = Maybe.empty();\n\n this._dependencies = deps;\n this._apduFrameReceiver = this._apduReceiverFactory();\n }\n\n public async setupConnection(): Promise<void> {\n const notifyCharacteristic = this._dependencies.notifyCharacteristic;\n if (!this._notificationsReady) {\n await notifyCharacteristic.startNotifications();\n this._logger.debug(\"Notify armed\", {\n data: {\n notifyUuid: this._dependencies.notifyCharacteristic.uuid,\n writeUuid: this._dependencies.writeCharacteristic.uuid,\n props: this._dependencies.writeCharacteristic.properties,\n },\n });\n this._notificationsReady = true;\n notifyCharacteristic.addEventListener(\n \"characteristicvaluechanged\",\n this._handleNotification,\n );\n }\n\n // Avoids possible drops on the very first notification if we write immediately\n await this._sleep(120);\n\n this._mtuRequestInProgress = true;\n this._mtuNegotiated$.next(false);\n this._apduFrameSegmenter = Maybe.empty();\n\n const mtuRequestFrame = new Uint8Array([MTU_OP, 0, 0, 0, 0]);\n\n try {\n await this._writeToGattCharacteristic(mtuRequestFrame.buffer);\n\n await Promise.race([\n new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(\n () => reject(new Error(\"MTU negotiation timeout\")),\n 2000,\n );\n const sub = this._mtuNegotiated$.subscribe((ready) => {\n if (ready) {\n clearTimeout(timeout);\n sub.unsubscribe();\n resolve();\n }\n });\n }),\n this._sleep(2300).then(() => {\n if (!this._isGattConnected()) {\n throw new DeviceDisconnectedWhileSendingError(\n \"Link dropped during MTU\",\n );\n }\n }),\n ]);\n } catch (e) {\n try {\n notifyCharacteristic.removeEventListener(\n \"characteristicvaluechanged\",\n this._handleNotification,\n );\n await notifyCharacteristic.stopNotifications().catch(() => {});\n } finally {\n this._notificationsReady = false;\n this._mtuNegotiated$.next(false);\n this._apduFrameSegmenter = Maybe.empty();\n }\n throw e;\n } finally {\n this._mtuRequestInProgress = false;\n }\n }\n\n private _isGattConnected(): boolean {\n try {\n return !!this._dependencies.notifyCharacteristic.service.device.gatt\n ?.connected;\n } catch {\n return false;\n }\n }\n\n private _isGattDisconnectedError(e: unknown): boolean {\n const err = e as Error | { name?: string; message?: string };\n const name = (\n typeof err === \"object\" && err !== null && \"name\" in err\n ? (err.name ?? \"\")\n : \"\"\n ).toString();\n const msg = (\n typeof err === \"object\" && err !== null && \"message\" in err\n ? (err.message ?? \"\")\n : \"\"\n )\n .toString()\n .toLowerCase();\n return (\n name === \"NetworkError\" ||\n msg.includes(\"gatt server is disconnected\") ||\n msg.includes(\"not connected\") ||\n msg.includes(\"cannot perform gatt operations\")\n );\n }\n\n private _failPendingSend(err: DmkError) {\n this._pendingResponseResolver.map((resolve) => resolve(Left(err)));\n this._pendingResponseResolver = Maybe.empty();\n }\n\n private _markLinkUnavailable(): void {\n if (this._notificationsReady) {\n this._dependencies.notifyCharacteristic.removeEventListener(\n \"characteristicvaluechanged\",\n this._handleNotification,\n );\n this._dependencies.notifyCharacteristic\n .stopNotifications()\n .catch(() => {});\n this._notificationsReady = false;\n }\n\n this._mtuNegotiated$.next(false);\n this._apduFrameSegmenter = Maybe.empty();\n this._pendingResponseResolver = Maybe.empty();\n }\n\n private async _sleep(ms: number) {\n return new Promise((r) => setTimeout(r, ms));\n }\n\n private _handleNotification = (event: Event) => {\n const characteristic = event.target as BluetoothRemoteGATTCharacteristic;\n if (!characteristic.value) return;\n const data = new Uint8Array(characteristic.value.buffer);\n\n if (!this._mtuNegotiated$.value) {\n if (!this._mtuRequestInProgress) {\n this._logger.debug(\"Dropping pre-handshake frame\", { data: { data } });\n return;\n }\n if (data.length < 6 || data[0] !== MTU_OP) {\n this._logger.debug(\"Non-MTU frame during handshake; dropping\", {\n data: { data },\n });\n return;\n }\n this._handleMtuNegotiationFrame(data);\n return;\n }\n\n this._handleApduFrame(data);\n };\n\n private _handleMtuNegotiationFrame(mtuResponseBuffer: Uint8Array) {\n const ledgerMtu = mtuResponseBuffer[5];\n if (\n ledgerMtu === undefined ||\n !Number.isFinite(ledgerMtu) ||\n ledgerMtu <= 0\n ) {\n throw new Error(\"MTU negotiation failed: invalid MTU\");\n }\n\n const frameSize = ledgerMtu;\n this._apduFrameSegmenter = Maybe.of(this._apduSenderFactory({ frameSize }));\n this._mtuNegotiated$.next(true);\n }\n\n private _handleApduFrame(incomingFrame: Uint8Array) {\n this._apduFrameReceiver\n .handleFrame(incomingFrame)\n .map((maybeResponse) =>\n maybeResponse.map((resp) => {\n this._logger.debug(formatApduReceivedLog(resp));\n this._pendingResponseResolver.map((resolve) => resolve(Right(resp)));\n this._pendingResponseResolver = Maybe.empty();\n }),\n )\n .mapLeft((err) => {\n this._pendingResponseResolver.map((resolve) => resolve(Left(err)));\n this._pendingResponseResolver = Maybe.empty();\n });\n }\n\n private async _writeToGattCharacteristic(buf: ArrayBuffer) {\n const ch = this._dependencies.writeCharacteristic;\n\n if (!this._isGattConnected()) {\n this._markLinkUnavailable();\n throw new DeviceDisconnectedWhileSendingError(\"GATT not connected\");\n }\n\n const hasWnr = typeof ch.writeValueWithoutResponse === \"function\";\n const hasWr = typeof ch.writeValueWithResponse === \"function\";\n\n // Prefer WNR for Ledger throughput\n if (ch.properties.writeWithoutResponse && hasWnr) {\n try {\n await ch.writeValueWithoutResponse(buf);\n return;\n } catch (e) {\n if (this._isGattDisconnectedError(e) || !this._isGattConnected()) {\n this._markLinkUnavailable();\n throw new DeviceDisconnectedWhileSendingError(\"Write failed\");\n }\n // otherwise, try WR\n }\n }\n\n if (ch.properties.write && hasWr) {\n await ch.writeValueWithResponse(buf);\n return;\n }\n\n throw new Error(\"No supported write method for characteristic\");\n }\n\n private async _waitUntilMtuNegotiated(maxMs = 2000): Promise<void> {\n if (\n this._notificationsReady &&\n this._mtuNegotiated$.value &&\n this._isGattConnected()\n )\n return;\n\n return new Promise<void>((resolve, reject) => {\n const subscription = this._mtuNegotiated$.subscribe((ready) => {\n if (!ready) return;\n if (this._notificationsReady && this._isGattConnected()) {\n clearTimeout(timer);\n subscription.unsubscribe();\n resolve();\n }\n });\n\n const timer = setTimeout(() => {\n subscription.unsubscribe();\n reject(new DeviceNotInitializedError(\"Link not ready\"));\n }, maxMs);\n\n if (\n this._notificationsReady &&\n this._mtuNegotiated$.value &&\n this._isGattConnected()\n ) {\n clearTimeout(timer);\n subscription.unsubscribe();\n resolve();\n }\n });\n }\n}\n"],
5
+ "mappings": "AAAA,OAOE,uCAAAA,EACA,6BAAAC,EAEA,yBAAAC,EACA,qBAAAC,EAEA,wBAAAC,MACK,kCACP,OAAsB,QAAAC,EAAM,SAAAC,EAAO,SAAAC,MAAa,YAChD,OAAS,mBAAAC,MAAuB,OAOzB,MAAMC,EAAS,EAEf,MAAMC,CAEb,CACU,cACA,oBAAgDJ,EAAM,MAAM,EAC5D,mBACA,qBACA,mBACA,QAEA,gBAAkB,IAAIE,EAAyB,EAAK,EACpD,oBAAsB,GACtB,sBAAwB,GAExB,yBAEJF,EAAM,MAAM,EAEhB,YACEK,EAIAC,EACA,CACA,KAAK,cAAgB,CACnB,oBAAqBD,EAAoB,oBACzC,qBAAsBA,EAAoB,oBAC5C,EACA,KAAK,mBAAqBA,EAAoB,kBAC9C,KAAK,qBAAuBA,EAAoB,oBAChD,KAAK,mBAAqBA,EAAoB,oBAAoB,EAClE,KAAK,QAAUC,EAAc,kBAAkB,CACjD,CAEA,MAAa,SACXC,EACAC,EACAC,EACyC,CACzC,GAAI,CACF,MAAMC,EAAa,KAAK,IAAI,KAAMD,GAAgB,CAAC,EACnD,MAAM,KAAK,wBAAwBC,CAAU,CAC/C,OAASC,EAAG,CACV,OAAOZ,EAAKY,CAAa,CAC3B,CAEA,GAAI,CAAC,KAAK,iBAAiB,EACzB,YAAK,qBAAqB,EACnBZ,EACL,IAAIL,EACF,oBACF,CACF,EAGF,GAAI,KAAK,oBAAoB,UAAU,EACrC,OAAOK,EACL,IAAIJ,EACF,gCACF,CACF,EAGF,IAAIiB,EACJ,MAAMC,EAAkB,IAAI,QACzBC,GAAY,CACX,KAAK,yBAA2Bd,EAAM,GAAIe,GAAW,CAC/CH,GAAe,aAAaA,CAAa,EAC7CE,EAAQC,CAAM,CAChB,CAAC,CACH,CACF,EAEMC,EAAS,KAAK,oBACjB,IAAKC,GAAcA,EAAU,UAAUV,CAAI,CAAC,EAC5C,UAAU,CAAC,CAAC,EAEf,UAAWW,KAASF,EAClB,GAAI,CACF,MAAM,KAAK,2BACTE,EAAM,WAAW,EAAE,MAAM,EAAE,MAC7B,CACF,OAASP,EAAG,CACV,MAAMQ,EAAMX,EACR,0CACA,qBACJ,KAAK,QAAQA,EAAwB,QAAU,OAAO,EAAEW,EAAK,CAC3D,KAAM,CAAE,EAAAR,CAAE,CACZ,CAAC,EACD,KAAK,iBACH,IAAIjB,EAAoC,cAAc,CACxD,EACA,KACF,CAEF,YAAK,QAAQ,MAAMG,EAAkBU,CAAI,CAAC,EAEtCE,IACFG,EAAgB,WAAW,IAAM,CAC/B,KAAK,QAAQ,MAAM,oCAAoC,EACvD,KAAK,yBAAyB,IAAKE,GACjCA,EAAQf,EAAK,IAAID,EAAqB,eAAe,CAAC,CAAC,CACzD,CACF,EAAGW,CAAY,GAGVI,CACT,CAEO,iBAAwB,CAC7B,GAAI,CACF,KAAK,iBACH,IAAInB,EAAoC,mBAAmB,CAC7D,EACI,KAAK,sBACP,KAAK,cAAc,qBAAqB,oBACtC,6BACA,KAAK,mBACP,EACA,KAAK,cAAc,qBAChB,kBAAkB,EAClB,MAAM,IAAM,CAAC,CAAC,EACjB,KAAK,oBAAsB,IAE7B,KAAK,cAAc,qBAAqB,QAAQ,OAAO,MAAM,WAAW,CAC1E,MAAQ,CACN,KAAK,QAAQ,MAAM,kCAAkC,CACvD,QAAE,CACA,KAAK,gBAAgB,KAAK,EAAK,EAC/B,KAAK,oBAAsBM,EAAM,MAAM,CACzC,CACF,CAEO,iBAAgD,CACrD,OAAO,KAAK,aACd,CAEO,gBAAgBoB,EAA0C,CAC/D,KAAK,iBACH,IAAI1B,EAAoC,cAAc,CACxD,EAEA,GAAI,CACE,KAAK,sBACP,KAAK,cAAc,qBAAqB,oBACtC,6BACA,KAAK,mBACP,EACA,KAAK,cAAc,qBAChB,kBAAkB,EAClB,MAAM,IAAM,CAAC,CAAC,EAErB,MAAQ,CAER,CAEA,KAAK,oBAAsB,GAC3B,KAAK,gBAAgB,KAAK,EAAK,EAC/B,KAAK,oBAAsBM,EAAM,MAAM,EACvC,KAAK,yBAA2BA,EAAM,MAAM,EAE5C,KAAK,cAAgBoB,EACrB,KAAK,mBAAqB,KAAK,qBAAqB,CACtD,CAEA,MAAa,iBAAiC,CAC5C,MAAMC,EAAuB,KAAK,cAAc,qBAC3C,KAAK,sBACR,MAAMA,EAAqB,mBAAmB,EAC9C,KAAK,QAAQ,MAAM,eAAgB,CACjC,KAAM,CACJ,WAAY,KAAK,cAAc,qBAAqB,KACpD,UAAW,KAAK,cAAc,oBAAoB,KAClD,MAAO,KAAK,cAAc,oBAAoB,UAChD,CACF,CAAC,EACD,KAAK,oBAAsB,GAC3BA,EAAqB,iBACnB,6BACA,KAAK,mBACP,GAIF,MAAM,KAAK,OAAO,GAAG,EAErB,KAAK,sBAAwB,GAC7B,KAAK,gBAAgB,KAAK,EAAK,EAC/B,KAAK,oBAAsBrB,EAAM,MAAM,EAEvC,MAAMsB,EAAkB,IAAI,WAAW,CAACnB,EAAQ,EAAG,EAAG,EAAG,CAAC,CAAC,EAE3D,GAAI,CACF,MAAM,KAAK,2BAA2BmB,EAAgB,MAAM,EAE5D,MAAM,QAAQ,KAAK,CACjB,IAAI,QAAc,CAACR,EAASS,IAAW,CACrC,MAAMC,EAAU,WACd,IAAMD,EAAO,IAAI,MAAM,yBAAyB,CAAC,EACjD,GACF,EACME,EAAM,KAAK,gBAAgB,UAAWC,GAAU,CAChDA,IACF,aAAaF,CAAO,EACpBC,EAAI,YAAY,EAChBX,EAAQ,EAEZ,CAAC,CACH,CAAC,EACD,KAAK,OAAO,IAAI,EAAE,KAAK,IAAM,CAC3B,GAAI,CAAC,KAAK,iBAAiB,EACzB,MAAM,IAAIpB,EACR,yBACF,CAEJ,CAAC,CACH,CAAC,CACH,OAASiB,EAAG,CACV,GAAI,CACFU,EAAqB,oBACnB,6BACA,KAAK,mBACP,EACA,MAAMA,EAAqB,kBAAkB,EAAE,MAAM,IAAM,CAAC,CAAC,CAC/D,QAAE,CACA,KAAK,oBAAsB,GAC3B,KAAK,gBAAgB,KAAK,EAAK,EAC/B,KAAK,oBAAsBrB,EAAM,MAAM,CACzC,CACA,MAAMW,CACR,QAAE,CACA,KAAK,sBAAwB,EAC/B,CACF,CAEQ,kBAA4B,CAClC,GAAI,CACF,MAAO,CAAC,CAAC,KAAK,cAAc,qBAAqB,QAAQ,OAAO,MAC5D,SACN,MAAQ,CACN,MAAO,EACT,CACF,CAEQ,yBAAyBA,EAAqB,CACpD,MAAMgB,EAAMhB,EACNiB,GACJ,OAAOD,GAAQ,UAAYA,IAAQ,MAAQ,SAAUA,EAChDA,EAAI,MAAQ,GACb,IACJ,SAAS,EACLR,GACJ,OAAOQ,GAAQ,UAAYA,IAAQ,MAAQ,YAAaA,EACnDA,EAAI,SAAW,GAChB,IAEH,SAAS,EACT,YAAY,EACf,OACEC,IAAS,gBACTT,EAAI,SAAS,6BAA6B,GAC1CA,EAAI,SAAS,eAAe,GAC5BA,EAAI,SAAS,gCAAgC,CAEjD,CAEQ,iBAAiBQ,EAAe,CACtC,KAAK,yBAAyB,IAAKb,GAAYA,EAAQf,EAAK4B,CAAG,CAAC,CAAC,EACjE,KAAK,yBAA2B3B,EAAM,MAAM,CAC9C,CAEQ,sBAA6B,CAC/B,KAAK,sBACP,KAAK,cAAc,qBAAqB,oBACtC,6BACA,KAAK,mBACP,EACA,KAAK,cAAc,qBAChB,kBAAkB,EAClB,MAAM,IAAM,CAAC,CAAC,EACjB,KAAK,oBAAsB,IAG7B,KAAK,gBAAgB,KAAK,EAAK,EAC/B,KAAK,oBAAsBA,EAAM,MAAM,EACvC,KAAK,yBAA2BA,EAAM,MAAM,CAC9C,CAEA,MAAc,OAAO6B,EAAY,CAC/B,OAAO,IAAI,QAASC,GAAM,WAAWA,EAAGD,CAAE,CAAC,CAC7C,CAEQ,oBAAuBE,GAAiB,CAC9C,MAAMC,EAAiBD,EAAM,OAC7B,GAAI,CAACC,EAAe,MAAO,OAC3B,MAAMC,EAAO,IAAI,WAAWD,EAAe,MAAM,MAAM,EAEvD,GAAI,CAAC,KAAK,gBAAgB,MAAO,CAC/B,GAAI,CAAC,KAAK,sBAAuB,CAC/B,KAAK,QAAQ,MAAM,+BAAgC,CAAE,KAAM,CAAE,KAAAC,CAAK,CAAE,CAAC,EACrE,MACF,CACA,GAAIA,EAAK,OAAS,GAAKA,EAAK,CAAC,IAAM9B,EAAQ,CACzC,KAAK,QAAQ,MAAM,2CAA4C,CAC7D,KAAM,CAAE,KAAA8B,CAAK,CACf,CAAC,EACD,MACF,CACA,KAAK,2BAA2BA,CAAI,EACpC,MACF,CAEA,KAAK,iBAAiBA,CAAI,CAC5B,EAEQ,2BAA2BC,EAA+B,CAChE,MAAMC,EAAYD,EAAkB,CAAC,EACrC,GACEC,IAAc,QACd,CAAC,OAAO,SAASA,CAAS,GAC1BA,GAAa,EAEb,MAAM,IAAI,MAAM,qCAAqC,EAGvD,MAAMC,EAAYD,EAClB,KAAK,oBAAsBnC,EAAM,GAAG,KAAK,mBAAmB,CAAE,UAAAoC,CAAU,CAAC,CAAC,EAC1E,KAAK,gBAAgB,KAAK,EAAI,CAChC,CAEQ,iBAAiBC,EAA2B,CAClD,KAAK,mBACF,YAAYA,CAAa,EACzB,IAAKC,GACJA,EAAc,IAAKC,GAAS,CAC1B,KAAK,QAAQ,MAAM3C,EAAsB2C,CAAI,CAAC,EAC9C,KAAK,yBAAyB,IAAKzB,GAAYA,EAAQb,EAAMsC,CAAI,CAAC,CAAC,EACnE,KAAK,yBAA2BvC,EAAM,MAAM,CAC9C,CAAC,CACH,EACC,QAAS2B,GAAQ,CAChB,KAAK,yBAAyB,IAAKb,GAAYA,EAAQf,EAAK4B,CAAG,CAAC,CAAC,EACjE,KAAK,yBAA2B3B,EAAM,MAAM,CAC9C,CAAC,CACL,CAEA,MAAc,2BAA2BwC,EAAkB,CACzD,MAAMC,EAAK,KAAK,cAAc,oBAE9B,GAAI,CAAC,KAAK,iBAAiB,EACzB,WAAK,qBAAqB,EACpB,IAAI/C,EAAoC,oBAAoB,EAGpE,MAAMgD,EAAS,OAAOD,EAAG,2BAA8B,WACjDE,EAAQ,OAAOF,EAAG,wBAA2B,WAGnD,GAAIA,EAAG,WAAW,sBAAwBC,EACxC,GAAI,CACF,MAAMD,EAAG,0BAA0BD,CAAG,EACtC,MACF,OAAS7B,EAAG,CACV,GAAI,KAAK,yBAAyBA,CAAC,GAAK,CAAC,KAAK,iBAAiB,EAC7D,WAAK,qBAAqB,EACpB,IAAIjB,EAAoC,cAAc,CAGhE,CAGF,GAAI+C,EAAG,WAAW,OAASE,EAAO,CAChC,MAAMF,EAAG,uBAAuBD,CAAG,EACnC,MACF,CAEA,MAAM,IAAI,MAAM,8CAA8C,CAChE,CAEA,MAAc,wBAAwBI,EAAQ,IAAqB,CACjE,GACE,OAAK,qBACL,KAAK,gBAAgB,OACrB,KAAK,iBAAiB,GAIxB,OAAO,IAAI,QAAc,CAAC9B,EAASS,IAAW,CAC5C,MAAMsB,EAAe,KAAK,gBAAgB,UAAWnB,GAAU,CACxDA,GACD,KAAK,qBAAuB,KAAK,iBAAiB,IACpD,aAAaoB,CAAK,EAClBD,EAAa,YAAY,EACzB/B,EAAQ,EAEZ,CAAC,EAEKgC,EAAQ,WAAW,IAAM,CAC7BD,EAAa,YAAY,EACzBtB,EAAO,IAAI5B,EAA0B,gBAAgB,CAAC,CACxD,EAAGiD,CAAK,EAGN,KAAK,qBACL,KAAK,gBAAgB,OACrB,KAAK,iBAAiB,IAEtB,aAAaE,CAAK,EAClBD,EAAa,YAAY,EACzB/B,EAAQ,EAEZ,CAAC,CACH,CACF",
6
+ "names": ["DeviceDisconnectedWhileSendingError", "DeviceNotInitializedError", "formatApduReceivedLog", "formatApduSentLog", "SendApduTimeoutError", "Left", "Maybe", "Right", "BehaviorSubject", "MTU_OP", "WebBleApduSender", "initialDependencies", "loggerFactory", "apdu", "triggersDisconnection", "abortTimeout", "waitBudget", "e", "timeoutHandle", "responsePromise", "resolve", "result", "frames", "segmenter", "frame", "msg", "deps", "notifyCharacteristic", "mtuRequestFrame", "reject", "timeout", "sub", "ready", "err", "name", "ms", "r", "event", "characteristic", "data", "mtuResponseBuffer", "ledgerMtu", "frameSize", "incomingFrame", "maybeResponse", "resp", "buf", "ch", "hasWnr", "hasWr", "maxMs", "subscription", "timer"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{Maybe as B,Right as L}from"purify-ts";import{afterEach as V,beforeEach as x,describe as S,expect as n,it as u,vi as t}from"vitest";import{MTU_OP as h,WebBleApduSender as U}from"./WebBleApduSender";class W{subscribers=[];tag;constructor(r,o){this.subscribers=r,this.tag=o}debug=t.fn();info=t.fn();warn=t.fn();error=t.fn()}function p(){const e=t.fn(),r=t.fn().mockResolvedValue(void 0);return{service:{device:{gatt:{connected:!0,disconnect:e}}},uuid:"mock-uuid",properties:{broadcast:!1,read:!1,writeWithoutResponse:!1,write:!1,notify:!1,indicate:!1,authenticatedSignedWrites:!1,reliableWrite:!1,writableAuxiliaries:!1},getDescriptor:t.fn().mockResolvedValue(void 0),getDescriptors:t.fn().mockResolvedValue([]),startNotifications:t.fn().mockResolvedValue(void 0),addEventListener:t.fn(),removeEventListener:t.fn(),stopNotifications:r,writeValueWithResponse:t.fn().mockResolvedValue(void 0),writeValueWithoutResponse:t.fn().mockResolvedValue(void 0),readValue:t.fn().mockResolvedValue(new DataView(new ArrayBuffer(0))),writeValue:t.fn().mockResolvedValue(void 0),dispatchEvent:t.fn(),oncharacteristicvaluechanged:null}}let d,a,C,b,E,s;const v=()=>new Promise(e=>setImmediate(e)),m=e=>new Promise(r=>setTimeout(r,e));x(()=>{d=p(),a=p(),d.properties.write=!0,C=t.fn().mockReturnValue({getFrames:e=>[{getRawData:()=>e}]}),b=t.fn().mockReturnValue({handleFrame:t.fn(e=>L(B.of({data:new Uint8Array([144,0])})))}),E=e=>new W([],e),s=new U({writeCharacteristic:d,notifyCharacteristic:a,apduSenderFactory:C,apduReceiverFactory:b},E)});V(()=>{t.restoreAllMocks()});S("WebBleApduSender",()=>{u("getDependencies returns initial chars",()=>{const e=s.getDependencies();n(e.writeCharacteristic).toBe(d),n(e.notifyCharacteristic).toBe(a)}),u("setupConnection negotiates MTU and listens",async()=>{const e=s.setupConnection();n(a.startNotifications).toHaveBeenCalled(),await v();const o=a.addEventListener.mock.calls.filter(([l])=>l==="characteristicvaluechanged")[0];if(!o)throw new Error("No event registered for 'characteristicvaluechanged'");const i=o[1];await m(150);const c=new Uint8Array([h,0,0,0,0,32]).buffer;i({target:{value:{buffer:c}}}),await n(e).resolves.toBeUndefined()}),u("sendApdu writes frames and resolves on notification",async()=>{const e=s.setupConnection();await v();const r=a.addEventListener.mock.calls.find(([w])=>w==="characteristicvaluechanged");if(!r)throw new Error("No event registered for 'characteristicvaluechanged'");const o=r[1];await m(150),o({target:{value:{buffer:new Uint8Array([h,0,0,0,0,32]).buffer}}}),await e;const i=new Uint8Array([1,2,3]),c=s.sendApdu(i);await v(),n(d.writeValueWithResponse).toHaveBeenCalled();const l=d.writeValueWithResponse.mock.calls.at(-1)?.[0];n(l).toBeInstanceOf(ArrayBuffer),n(Array.from(new Uint8Array(l))).toEqual(Array.from(i));const f=a.addEventListener.mock.calls.filter(([w])=>w==="characteristicvaluechanged"),g=f[f.length-1];if(!g)throw new Error("No APDU handler registered.");const[,R]=g,k=new Uint8Array([144,0]).buffer;R({target:{value:{buffer:k}}});const y=await c;n(y.isRight()).toBe(!0);const A=y.extract();n(A).toHaveProperty("data"),n(A.data).toEqual(new Uint8Array([144,0]))}),u("closeConnection calls disconnect",()=>{s.closeConnection(),n(a.service.device.gatt.disconnect).toHaveBeenCalled()}),u("setDependencies swaps characteristics and resets link (does not arm)",async()=>{const e=s.setupConnection();await v();const r=a.addEventListener.mock.calls.find(([f])=>f==="characteristicvaluechanged");if(!r)throw new Error("No event registered for 'characteristicvaluechanged'");const o=r[1];await m(150),o({target:{value:{buffer:new Uint8Array([h,0,0,0,0,32]).buffer}}}),await e;const i=p(),c=p();c.properties.write=!0,s.setDependencies({writeCharacteristic:c,notifyCharacteristic:i}),n(a.removeEventListener).toHaveBeenCalledWith("characteristicvaluechanged",n.any(Function)),n(i.startNotifications).not.toHaveBeenCalled(),n(i.addEventListener).not.toHaveBeenCalled();const l=s.getDependencies();n(l.notifyCharacteristic).toBe(i),n(l.writeCharacteristic).toBe(c)})});
1
+ import{Maybe as B,Right as x}from"purify-ts";import{afterEach as L,beforeEach as V,describe as S,expect as n,it as u,vi as t}from"vitest";import{MTU_OP as h,WebBleApduSender as U}from"./WebBleApduSender";class W{subscribers=[];tag;constructor(r,o){this.subscribers=r,this.tag=o}debug=t.fn();info=t.fn();warn=t.fn();error=t.fn()}function p(){const e=t.fn(),r=t.fn().mockResolvedValue(void 0);return{service:{device:{gatt:{connected:!0,disconnect:e}}},uuid:"mock-uuid",properties:{broadcast:!1,read:!1,writeWithoutResponse:!1,write:!1,notify:!1,indicate:!1,authenticatedSignedWrites:!1,reliableWrite:!1,writableAuxiliaries:!1},getDescriptor:t.fn().mockResolvedValue(void 0),getDescriptors:t.fn().mockResolvedValue([]),startNotifications:t.fn().mockResolvedValue(void 0),addEventListener:t.fn(),removeEventListener:t.fn(),stopNotifications:r,writeValueWithResponse:t.fn().mockResolvedValue(void 0),writeValueWithoutResponse:t.fn().mockResolvedValue(void 0),readValue:t.fn().mockResolvedValue(new DataView(new ArrayBuffer(0))),writeValue:t.fn().mockResolvedValue(void 0),dispatchEvent:t.fn(),oncharacteristicvaluechanged:null}}let d,a,C,b,E,s;const v=()=>new Promise(e=>setImmediate(e)),m=e=>new Promise(r=>setTimeout(r,e));V(()=>{d=p(),a=p(),d.properties.write=!0,C=t.fn().mockReturnValue({getFrames:e=>[{getRawData:()=>e}]}),b=t.fn().mockReturnValue({handleFrame:t.fn(e=>x(B.of({data:new Uint8Array([144,0]),statusCode:new Uint8Array([144,0])})))}),E=e=>new W([],e),s=new U({writeCharacteristic:d,notifyCharacteristic:a,apduSenderFactory:C,apduReceiverFactory:b},E)});L(()=>{t.restoreAllMocks()});S("WebBleApduSender",()=>{u("getDependencies returns initial chars",()=>{const e=s.getDependencies();n(e.writeCharacteristic).toBe(d),n(e.notifyCharacteristic).toBe(a)}),u("setupConnection negotiates MTU and listens",async()=>{const e=s.setupConnection();n(a.startNotifications).toHaveBeenCalled(),await v();const o=a.addEventListener.mock.calls.filter(([l])=>l==="characteristicvaluechanged")[0];if(!o)throw new Error("No event registered for 'characteristicvaluechanged'");const i=o[1];await m(150);const c=new Uint8Array([h,0,0,0,0,32]).buffer;i({target:{value:{buffer:c}}}),await n(e).resolves.toBeUndefined()}),u("sendApdu writes frames and resolves on notification",async()=>{const e=s.setupConnection();await v();const r=a.addEventListener.mock.calls.find(([w])=>w==="characteristicvaluechanged");if(!r)throw new Error("No event registered for 'characteristicvaluechanged'");const o=r[1];await m(150),o({target:{value:{buffer:new Uint8Array([h,0,0,0,0,32]).buffer}}}),await e;const i=new Uint8Array([1,2,3]),c=s.sendApdu(i);await v(),n(d.writeValueWithResponse).toHaveBeenCalled();const l=d.writeValueWithResponse.mock.calls.at(-1)?.[0];n(l).toBeInstanceOf(ArrayBuffer),n(Array.from(new Uint8Array(l))).toEqual(Array.from(i));const f=a.addEventListener.mock.calls.filter(([w])=>w==="characteristicvaluechanged"),g=f[f.length-1];if(!g)throw new Error("No APDU handler registered.");const[,R]=g,k=new Uint8Array([144,0]).buffer;R({target:{value:{buffer:k}}});const y=await c;n(y.isRight()).toBe(!0);const A=y.extract();n(A).toHaveProperty("data"),n(A.data).toEqual(new Uint8Array([144,0]))}),u("closeConnection calls disconnect",()=>{s.closeConnection(),n(a.service.device.gatt.disconnect).toHaveBeenCalled()}),u("setDependencies swaps characteristics and resets link (does not arm)",async()=>{const e=s.setupConnection();await v();const r=a.addEventListener.mock.calls.find(([f])=>f==="characteristicvaluechanged");if(!r)throw new Error("No event registered for 'characteristicvaluechanged'");const o=r[1];await m(150),o({target:{value:{buffer:new Uint8Array([h,0,0,0,0,32]).buffer}}}),await e;const i=p(),c=p();c.properties.write=!0,s.setDependencies({writeCharacteristic:c,notifyCharacteristic:i}),n(a.removeEventListener).toHaveBeenCalledWith("characteristicvaluechanged",n.any(Function)),n(i.startNotifications).not.toHaveBeenCalled(),n(i.addEventListener).not.toHaveBeenCalled();const l=s.getDependencies();n(l.notifyCharacteristic).toBe(i),n(l.writeCharacteristic).toBe(c)})});
2
2
  //# sourceMappingURL=WebBleApduSender.test.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/api/transport/WebBleApduSender.test.ts"],
4
- "sourcesContent": ["/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n type ApduReceiverServiceFactory,\n type ApduResponse,\n type ApduSenderServiceFactory,\n type LoggerPublisherService,\n} from \"@ledgerhq/device-management-kit\";\nimport { Maybe, Right } from \"purify-ts\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport { MTU_OP, WebBleApduSender } from \"./WebBleApduSender\";\n\ntype EventListener = (event: Event) => void;\nclass LoggerStub implements LoggerPublisherService {\n subscribers: any[] = [];\n tag: string;\n constructor(subs: any[], tag: string) {\n this.subscribers = subs;\n this.tag = tag;\n }\n debug = vi.fn();\n info = vi.fn();\n warn = vi.fn();\n error = vi.fn();\n}\n\nfunction makeCharacteristic() {\n const disconnect = vi.fn();\n const stopNotifications = vi.fn().mockResolvedValue(undefined);\n return {\n service: { device: { gatt: { connected: true, disconnect } } },\n uuid: \"mock-uuid\",\n properties: {\n broadcast: false,\n read: false,\n writeWithoutResponse: false,\n write: false,\n notify: false,\n indicate: false,\n authenticatedSignedWrites: false,\n reliableWrite: false,\n writableAuxiliaries: false,\n },\n getDescriptor: vi.fn().mockResolvedValue(undefined),\n getDescriptors: vi.fn().mockResolvedValue([]),\n startNotifications: vi.fn().mockResolvedValue(undefined),\n addEventListener: vi.fn(),\n removeEventListener: vi.fn(),\n stopNotifications,\n writeValueWithResponse: vi.fn().mockResolvedValue(undefined),\n writeValueWithoutResponse: vi.fn().mockResolvedValue(undefined),\n readValue: vi.fn().mockResolvedValue(new DataView(new ArrayBuffer(0))),\n writeValue: vi.fn().mockResolvedValue(undefined),\n dispatchEvent: vi.fn(),\n oncharacteristicvaluechanged: null,\n };\n}\n\nlet writeChar: any;\nlet notifyChar: any;\nlet apduSenderFactory: ApduSenderServiceFactory;\nlet apduReceiverFactory: ApduReceiverServiceFactory;\nlet loggerFactory: (tag: string) => LoggerPublisherService;\nlet sender: WebBleApduSender;\n\nconst flushPromises = () =>\n new Promise<void>((resolve) => setImmediate(resolve));\nconst wait = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));\n\nbeforeEach(() => {\n writeChar = makeCharacteristic();\n notifyChar = makeCharacteristic();\n\n // it requires the characteristic to advertise \"write\" or \"writeWithoutResponse\" to pick a write mode\n writeChar.properties.write = true;\n\n // class calls getRawData().slice().buffer, return a Uint8Array\n apduSenderFactory = vi.fn().mockReturnValue({\n getFrames: (apdu: Uint8Array) => [{ getRawData: () => apdu }],\n });\n\n apduReceiverFactory = vi.fn().mockReturnValue({\n handleFrame: vi.fn((_frame: Uint8Array) =>\n Right(Maybe.of({ data: new Uint8Array([0x90, 0x00]) } as ApduResponse)),\n ),\n });\n\n loggerFactory = (tag: string) => new LoggerStub([], tag);\n\n sender = new WebBleApduSender(\n {\n writeCharacteristic: writeChar,\n notifyCharacteristic: notifyChar,\n apduSenderFactory,\n apduReceiverFactory,\n },\n loggerFactory,\n );\n});\n\nafterEach(() => {\n vi.restoreAllMocks();\n});\n\ndescribe(\"WebBleApduSender\", () => {\n it(\"getDependencies returns initial chars\", () => {\n const deps = sender.getDependencies();\n expect(deps.writeCharacteristic).toBe(writeChar);\n expect(deps.notifyCharacteristic).toBe(notifyChar);\n });\n\n it(\"setupConnection negotiates MTU and listens\", async () => {\n // when\n const promise = sender.setupConnection();\n\n // then\n expect(notifyChar.startNotifications).toHaveBeenCalled();\n await flushPromises();\n\n const filteredCalls = (\n notifyChar.addEventListener.mock.calls as [string, EventListener][]\n ).filter(([event]) => event === \"characteristicvaluechanged\");\n\n const firstCall = filteredCalls[0];\n if (!firstCall) {\n throw new Error(\"No event registered for 'characteristicvaluechanged'\");\n }\n const handler = firstCall[1];\n\n // wait for the internal sleep so the handshake flag is set\n await wait(150);\n\n const mtuBuf = new Uint8Array([MTU_OP, 0, 0, 0, 0, 0x20]).buffer;\n\n handler({ target: { value: { buffer: mtuBuf } } } as unknown as Event);\n\n await expect(promise).resolves.toBeUndefined();\n });\n\n it(\"sendApdu writes frames and resolves on notification\", async () => {\n // given\n const setupPromise = sender.setupConnection();\n await flushPromises();\n\n const mtuCall = (\n notifyChar.addEventListener.mock.calls as [string, EventListener][]\n ).find(([event]) => event === \"characteristicvaluechanged\");\n if (!mtuCall)\n throw new Error(\"No event registered for 'characteristicvaluechanged'\");\n\n const mtuHandler = mtuCall[1];\n\n // wait past the handshake delay, then send the proper MTU frame\n await wait(150);\n mtuHandler({\n target: {\n value: { buffer: new Uint8Array([MTU_OP, 0, 0, 0, 0, 0x20]).buffer },\n },\n } as unknown as Event);\n\n await setupPromise;\n\n const apduCmd = new Uint8Array([0x01, 0x02, 0x03]);\n\n // when\n const promise = sender.sendApdu(apduCmd);\n\n // then check that the last write matches the APDU bytes\n await flushPromises();\n expect(writeChar.writeValueWithResponse).toHaveBeenCalled();\n\n const lastArg = writeChar.writeValueWithResponse.mock.calls.at(\n -1,\n )?.[0] as ArrayBuffer;\n expect(lastArg).toBeInstanceOf(ArrayBuffer);\n expect(Array.from(new Uint8Array(lastArg))).toEqual(Array.from(apduCmd));\n\n const filteredCalls = (\n notifyChar.addEventListener.mock.calls as [string, EventListener][]\n ).filter(([event]) => event === \"characteristicvaluechanged\");\n const lastCall = filteredCalls[filteredCalls.length - 1];\n if (!lastCall) throw new Error(\"No APDU handler registered.\");\n\n const [, apduHandler] = lastCall;\n\n // when\n const respBuf = new Uint8Array([0x90, 0x00]).buffer;\n apduHandler({ target: { value: { buffer: respBuf } } } as unknown as Event);\n\n // then\n const result = await promise;\n expect(result.isRight()).toBe(true);\n const extractedResult = result.extract();\n expect(extractedResult).toHaveProperty(\"data\");\n expect((extractedResult as ApduResponse).data).toEqual(\n new Uint8Array([0x90, 0x00]),\n );\n });\n\n it(\"closeConnection calls disconnect\", () => {\n sender.closeConnection();\n expect(notifyChar.service.device.gatt.disconnect).toHaveBeenCalled();\n });\n\n it(\"setDependencies swaps characteristics and resets link (does not arm)\", async () => {\n // given\n const setupPromise = sender.setupConnection();\n await flushPromises();\n\n const mtuCall = (\n notifyChar.addEventListener.mock.calls as [string, EventListener][]\n ).find(([event]) => event === \"characteristicvaluechanged\");\n if (!mtuCall)\n throw new Error(\"No event registered for 'characteristicvaluechanged'\");\n const mtuHandler = mtuCall[1];\n\n await wait(150);\n mtuHandler({\n target: {\n value: { buffer: new Uint8Array([MTU_OP, 0, 0, 0, 0, 0x20]).buffer },\n },\n } as unknown as Event);\n await setupPromise;\n\n const newNotify = makeCharacteristic();\n const newWrite = makeCharacteristic();\n newWrite.properties.write = true;\n\n // when\n sender.setDependencies({\n writeCharacteristic:\n newWrite as unknown as BluetoothRemoteGATTCharacteristic,\n notifyCharacteristic:\n newNotify as unknown as BluetoothRemoteGATTCharacteristic,\n });\n\n // then\n expect(notifyChar.removeEventListener).toHaveBeenCalledWith(\n \"characteristicvaluechanged\",\n expect.any(Function),\n );\n expect(newNotify.startNotifications).not.toHaveBeenCalled();\n expect(newNotify.addEventListener).not.toHaveBeenCalled();\n\n const deps = sender.getDependencies();\n expect(deps.notifyCharacteristic).toBe(newNotify);\n expect(deps.writeCharacteristic).toBe(newWrite);\n });\n});\n"],
5
- "mappings": "AASA,OAAS,SAAAA,EAAO,SAAAC,MAAa,YAC7B,OAAS,aAAAC,EAAW,cAAAC,EAAY,YAAAC,EAAU,UAAAC,EAAQ,MAAAC,EAAI,MAAAC,MAAU,SAEhE,OAAS,UAAAC,EAAQ,oBAAAC,MAAwB,qBAGzC,MAAMC,CAA6C,CACjD,YAAqB,CAAC,EACtB,IACA,YAAYC,EAAaC,EAAa,CACpC,KAAK,YAAcD,EACnB,KAAK,IAAMC,CACb,CACA,MAAQL,EAAG,GAAG,EACd,KAAOA,EAAG,GAAG,EACb,KAAOA,EAAG,GAAG,EACb,MAAQA,EAAG,GAAG,CAChB,CAEA,SAASM,GAAqB,CAC5B,MAAMC,EAAaP,EAAG,GAAG,EACnBQ,EAAoBR,EAAG,GAAG,EAAE,kBAAkB,MAAS,EAC7D,MAAO,CACL,QAAS,CAAE,OAAQ,CAAE,KAAM,CAAE,UAAW,GAAM,WAAAO,CAAW,CAAE,CAAE,EAC7D,KAAM,YACN,WAAY,CACV,UAAW,GACX,KAAM,GACN,qBAAsB,GACtB,MAAO,GACP,OAAQ,GACR,SAAU,GACV,0BAA2B,GAC3B,cAAe,GACf,oBAAqB,EACvB,EACA,cAAeP,EAAG,GAAG,EAAE,kBAAkB,MAAS,EAClD,eAAgBA,EAAG,GAAG,EAAE,kBAAkB,CAAC,CAAC,EAC5C,mBAAoBA,EAAG,GAAG,EAAE,kBAAkB,MAAS,EACvD,iBAAkBA,EAAG,GAAG,EACxB,oBAAqBA,EAAG,GAAG,EAC3B,kBAAAQ,EACA,uBAAwBR,EAAG,GAAG,EAAE,kBAAkB,MAAS,EAC3D,0BAA2BA,EAAG,GAAG,EAAE,kBAAkB,MAAS,EAC9D,UAAWA,EAAG,GAAG,EAAE,kBAAkB,IAAI,SAAS,IAAI,YAAY,CAAC,CAAC,CAAC,EACrE,WAAYA,EAAG,GAAG,EAAE,kBAAkB,MAAS,EAC/C,cAAeA,EAAG,GAAG,EACrB,6BAA8B,IAChC,CACF,CAEA,IAAIS,EACAC,EACAC,EACAC,EACAC,EACAC,EAEJ,MAAMC,EAAgB,IACpB,IAAI,QAAeC,GAAY,aAAaA,CAAO,CAAC,EAChDC,EAAQC,GAAe,IAAI,QAAe,GAAM,WAAW,EAAGA,CAAE,CAAC,EAEvEtB,EAAW,IAAM,CACfa,EAAYH,EAAmB,EAC/BI,EAAaJ,EAAmB,EAGhCG,EAAU,WAAW,MAAQ,GAG7BE,EAAoBX,EAAG,GAAG,EAAE,gBAAgB,CAC1C,UAAYmB,GAAqB,CAAC,CAAE,WAAY,IAAMA,CAAK,CAAC,CAC9D,CAAC,EAEDP,EAAsBZ,EAAG,GAAG,EAAE,gBAAgB,CAC5C,YAAaA,EAAG,GAAIoB,GAClB1B,EAAMD,EAAM,GAAG,CAAE,KAAM,IAAI,WAAW,CAAC,IAAM,CAAI,CAAC,CAAE,CAAiB,CAAC,CACxE,CACF,CAAC,EAEDoB,EAAiBR,GAAgB,IAAIF,EAAW,CAAC,EAAGE,CAAG,EAEvDS,EAAS,IAAIZ,EACX,CACE,oBAAqBO,EACrB,qBAAsBC,EACtB,kBAAAC,EACA,oBAAAC,CACF,EACAC,CACF,CACF,CAAC,EAEDlB,EAAU,IAAM,CACdK,EAAG,gBAAgB,CACrB,CAAC,EAEDH,EAAS,mBAAoB,IAAM,CACjCE,EAAG,wCAAyC,IAAM,CAChD,MAAMsB,EAAOP,EAAO,gBAAgB,EACpChB,EAAOuB,EAAK,mBAAmB,EAAE,KAAKZ,CAAS,EAC/CX,EAAOuB,EAAK,oBAAoB,EAAE,KAAKX,CAAU,CACnD,CAAC,EAEDX,EAAG,6CAA8C,SAAY,CAE3D,MAAMuB,EAAUR,EAAO,gBAAgB,EAGvChB,EAAOY,EAAW,kBAAkB,EAAE,iBAAiB,EACvD,MAAMK,EAAc,EAMpB,MAAMQ,EAHJb,EAAW,iBAAiB,KAAK,MACjC,OAAO,CAAC,CAACc,CAAK,IAAMA,IAAU,4BAA4B,EAE5B,CAAC,EACjC,GAAI,CAACD,EACH,MAAM,IAAI,MAAM,sDAAsD,EAExE,MAAME,EAAUF,EAAU,CAAC,EAG3B,MAAMN,EAAK,GAAG,EAEd,MAAMS,EAAS,IAAI,WAAW,CAACzB,EAAQ,EAAG,EAAG,EAAG,EAAG,EAAI,CAAC,EAAE,OAE1DwB,EAAQ,CAAE,OAAQ,CAAE,MAAO,CAAE,OAAQC,CAAO,CAAE,CAAE,CAAqB,EAErE,MAAM5B,EAAOwB,CAAO,EAAE,SAAS,cAAc,CAC/C,CAAC,EAEDvB,EAAG,sDAAuD,SAAY,CAEpE,MAAM4B,EAAeb,EAAO,gBAAgB,EAC5C,MAAMC,EAAc,EAEpB,MAAMa,EACJlB,EAAW,iBAAiB,KAAK,MACjC,KAAK,CAAC,CAACc,CAAK,IAAMA,IAAU,4BAA4B,EAC1D,GAAI,CAACI,EACH,MAAM,IAAI,MAAM,sDAAsD,EAExE,MAAMC,EAAaD,EAAQ,CAAC,EAG5B,MAAMX,EAAK,GAAG,EACdY,EAAW,CACT,OAAQ,CACN,MAAO,CAAE,OAAQ,IAAI,WAAW,CAAC5B,EAAQ,EAAG,EAAG,EAAG,EAAG,EAAI,CAAC,EAAE,MAAO,CACrE,CACF,CAAqB,EAErB,MAAM0B,EAEN,MAAMG,EAAU,IAAI,WAAW,CAAC,EAAM,EAAM,CAAI,CAAC,EAG3CR,EAAUR,EAAO,SAASgB,CAAO,EAGvC,MAAMf,EAAc,EACpBjB,EAAOW,EAAU,sBAAsB,EAAE,iBAAiB,EAE1D,MAAMsB,EAAUtB,EAAU,uBAAuB,KAAK,MAAM,GAC1D,EACF,IAAI,CAAC,EACLX,EAAOiC,CAAO,EAAE,eAAe,WAAW,EAC1CjC,EAAO,MAAM,KAAK,IAAI,WAAWiC,CAAO,CAAC,CAAC,EAAE,QAAQ,MAAM,KAAKD,CAAO,CAAC,EAEvE,MAAME,EACJtB,EAAW,iBAAiB,KAAK,MACjC,OAAO,CAAC,CAACc,CAAK,IAAMA,IAAU,4BAA4B,EACtDS,EAAWD,EAAcA,EAAc,OAAS,CAAC,EACvD,GAAI,CAACC,EAAU,MAAM,IAAI,MAAM,6BAA6B,EAE5D,KAAM,CAAC,CAAEC,CAAW,EAAID,EAGlBE,EAAU,IAAI,WAAW,CAAC,IAAM,CAAI,CAAC,EAAE,OAC7CD,EAAY,CAAE,OAAQ,CAAE,MAAO,CAAE,OAAQC,CAAQ,CAAE,CAAE,CAAqB,EAG1E,MAAMC,EAAS,MAAMd,EACrBxB,EAAOsC,EAAO,QAAQ,CAAC,EAAE,KAAK,EAAI,EAClC,MAAMC,EAAkBD,EAAO,QAAQ,EACvCtC,EAAOuC,CAAe,EAAE,eAAe,MAAM,EAC7CvC,EAAQuC,EAAiC,IAAI,EAAE,QAC7C,IAAI,WAAW,CAAC,IAAM,CAAI,CAAC,CAC7B,CACF,CAAC,EAEDtC,EAAG,mCAAoC,IAAM,CAC3Ce,EAAO,gBAAgB,EACvBhB,EAAOY,EAAW,QAAQ,OAAO,KAAK,UAAU,EAAE,iBAAiB,CACrE,CAAC,EAEDX,EAAG,uEAAwE,SAAY,CAErF,MAAM4B,EAAeb,EAAO,gBAAgB,EAC5C,MAAMC,EAAc,EAEpB,MAAMa,EACJlB,EAAW,iBAAiB,KAAK,MACjC,KAAK,CAAC,CAACc,CAAK,IAAMA,IAAU,4BAA4B,EAC1D,GAAI,CAACI,EACH,MAAM,IAAI,MAAM,sDAAsD,EACxE,MAAMC,EAAaD,EAAQ,CAAC,EAE5B,MAAMX,EAAK,GAAG,EACdY,EAAW,CACT,OAAQ,CACN,MAAO,CAAE,OAAQ,IAAI,WAAW,CAAC5B,EAAQ,EAAG,EAAG,EAAG,EAAG,EAAI,CAAC,EAAE,MAAO,CACrE,CACF,CAAqB,EACrB,MAAM0B,EAEN,MAAMW,EAAYhC,EAAmB,EAC/BiC,EAAWjC,EAAmB,EACpCiC,EAAS,WAAW,MAAQ,GAG5BzB,EAAO,gBAAgB,CACrB,oBACEyB,EACF,qBACED,CACJ,CAAC,EAGDxC,EAAOY,EAAW,mBAAmB,EAAE,qBACrC,6BACAZ,EAAO,IAAI,QAAQ,CACrB,EACAA,EAAOwC,EAAU,kBAAkB,EAAE,IAAI,iBAAiB,EAC1DxC,EAAOwC,EAAU,gBAAgB,EAAE,IAAI,iBAAiB,EAExD,MAAMjB,EAAOP,EAAO,gBAAgB,EACpChB,EAAOuB,EAAK,oBAAoB,EAAE,KAAKiB,CAAS,EAChDxC,EAAOuB,EAAK,mBAAmB,EAAE,KAAKkB,CAAQ,CAChD,CAAC,CACH,CAAC",
4
+ "sourcesContent": ["/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n type ApduReceiverServiceFactory,\n type ApduResponse,\n type ApduSenderServiceFactory,\n type LoggerPublisherService,\n} from \"@ledgerhq/device-management-kit\";\nimport { Maybe, Right } from \"purify-ts\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport { MTU_OP, WebBleApduSender } from \"./WebBleApduSender\";\n\ntype EventListener = (event: Event) => void;\nclass LoggerStub implements LoggerPublisherService {\n subscribers: any[] = [];\n tag: string;\n constructor(subs: any[], tag: string) {\n this.subscribers = subs;\n this.tag = tag;\n }\n debug = vi.fn();\n info = vi.fn();\n warn = vi.fn();\n error = vi.fn();\n}\n\nfunction makeCharacteristic() {\n const disconnect = vi.fn();\n const stopNotifications = vi.fn().mockResolvedValue(undefined);\n return {\n service: { device: { gatt: { connected: true, disconnect } } },\n uuid: \"mock-uuid\",\n properties: {\n broadcast: false,\n read: false,\n writeWithoutResponse: false,\n write: false,\n notify: false,\n indicate: false,\n authenticatedSignedWrites: false,\n reliableWrite: false,\n writableAuxiliaries: false,\n },\n getDescriptor: vi.fn().mockResolvedValue(undefined),\n getDescriptors: vi.fn().mockResolvedValue([]),\n startNotifications: vi.fn().mockResolvedValue(undefined),\n addEventListener: vi.fn(),\n removeEventListener: vi.fn(),\n stopNotifications,\n writeValueWithResponse: vi.fn().mockResolvedValue(undefined),\n writeValueWithoutResponse: vi.fn().mockResolvedValue(undefined),\n readValue: vi.fn().mockResolvedValue(new DataView(new ArrayBuffer(0))),\n writeValue: vi.fn().mockResolvedValue(undefined),\n dispatchEvent: vi.fn(),\n oncharacteristicvaluechanged: null,\n };\n}\n\nlet writeChar: any;\nlet notifyChar: any;\nlet apduSenderFactory: ApduSenderServiceFactory;\nlet apduReceiverFactory: ApduReceiverServiceFactory;\nlet loggerFactory: (tag: string) => LoggerPublisherService;\nlet sender: WebBleApduSender;\n\nconst flushPromises = () =>\n new Promise<void>((resolve) => setImmediate(resolve));\nconst wait = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));\n\nbeforeEach(() => {\n writeChar = makeCharacteristic();\n notifyChar = makeCharacteristic();\n\n // it requires the characteristic to advertise \"write\" or \"writeWithoutResponse\" to pick a write mode\n writeChar.properties.write = true;\n\n // class calls getRawData().slice().buffer, return a Uint8Array\n apduSenderFactory = vi.fn().mockReturnValue({\n getFrames: (apdu: Uint8Array) => [{ getRawData: () => apdu }],\n });\n\n apduReceiverFactory = vi.fn().mockReturnValue({\n handleFrame: vi.fn((_frame: Uint8Array) =>\n Right(\n Maybe.of({\n data: new Uint8Array([0x90, 0x00]),\n statusCode: new Uint8Array([0x90, 0x00]),\n } as ApduResponse),\n ),\n ),\n });\n\n loggerFactory = (tag: string) => new LoggerStub([], tag);\n\n sender = new WebBleApduSender(\n {\n writeCharacteristic: writeChar,\n notifyCharacteristic: notifyChar,\n apduSenderFactory,\n apduReceiverFactory,\n },\n loggerFactory,\n );\n});\n\nafterEach(() => {\n vi.restoreAllMocks();\n});\n\ndescribe(\"WebBleApduSender\", () => {\n it(\"getDependencies returns initial chars\", () => {\n const deps = sender.getDependencies();\n expect(deps.writeCharacteristic).toBe(writeChar);\n expect(deps.notifyCharacteristic).toBe(notifyChar);\n });\n\n it(\"setupConnection negotiates MTU and listens\", async () => {\n // when\n const promise = sender.setupConnection();\n\n // then\n expect(notifyChar.startNotifications).toHaveBeenCalled();\n await flushPromises();\n\n const filteredCalls = (\n notifyChar.addEventListener.mock.calls as [string, EventListener][]\n ).filter(([event]) => event === \"characteristicvaluechanged\");\n\n const firstCall = filteredCalls[0];\n if (!firstCall) {\n throw new Error(\"No event registered for 'characteristicvaluechanged'\");\n }\n const handler = firstCall[1];\n\n // wait for the internal sleep so the handshake flag is set\n await wait(150);\n\n const mtuBuf = new Uint8Array([MTU_OP, 0, 0, 0, 0, 0x20]).buffer;\n\n handler({ target: { value: { buffer: mtuBuf } } } as unknown as Event);\n\n await expect(promise).resolves.toBeUndefined();\n });\n\n it(\"sendApdu writes frames and resolves on notification\", async () => {\n // given\n const setupPromise = sender.setupConnection();\n await flushPromises();\n\n const mtuCall = (\n notifyChar.addEventListener.mock.calls as [string, EventListener][]\n ).find(([event]) => event === \"characteristicvaluechanged\");\n if (!mtuCall)\n throw new Error(\"No event registered for 'characteristicvaluechanged'\");\n\n const mtuHandler = mtuCall[1];\n\n // wait past the handshake delay, then send the proper MTU frame\n await wait(150);\n mtuHandler({\n target: {\n value: { buffer: new Uint8Array([MTU_OP, 0, 0, 0, 0, 0x20]).buffer },\n },\n } as unknown as Event);\n\n await setupPromise;\n\n const apduCmd = new Uint8Array([0x01, 0x02, 0x03]);\n\n // when\n const promise = sender.sendApdu(apduCmd);\n\n // then check that the last write matches the APDU bytes\n await flushPromises();\n expect(writeChar.writeValueWithResponse).toHaveBeenCalled();\n\n const lastArg = writeChar.writeValueWithResponse.mock.calls.at(\n -1,\n )?.[0] as ArrayBuffer;\n expect(lastArg).toBeInstanceOf(ArrayBuffer);\n expect(Array.from(new Uint8Array(lastArg))).toEqual(Array.from(apduCmd));\n\n const filteredCalls = (\n notifyChar.addEventListener.mock.calls as [string, EventListener][]\n ).filter(([event]) => event === \"characteristicvaluechanged\");\n const lastCall = filteredCalls[filteredCalls.length - 1];\n if (!lastCall) throw new Error(\"No APDU handler registered.\");\n\n const [, apduHandler] = lastCall;\n\n // when\n const respBuf = new Uint8Array([0x90, 0x00]).buffer;\n apduHandler({ target: { value: { buffer: respBuf } } } as unknown as Event);\n\n // then\n const result = await promise;\n expect(result.isRight()).toBe(true);\n const extractedResult = result.extract();\n expect(extractedResult).toHaveProperty(\"data\");\n expect((extractedResult as ApduResponse).data).toEqual(\n new Uint8Array([0x90, 0x00]),\n );\n });\n\n it(\"closeConnection calls disconnect\", () => {\n sender.closeConnection();\n expect(notifyChar.service.device.gatt.disconnect).toHaveBeenCalled();\n });\n\n it(\"setDependencies swaps characteristics and resets link (does not arm)\", async () => {\n // given\n const setupPromise = sender.setupConnection();\n await flushPromises();\n\n const mtuCall = (\n notifyChar.addEventListener.mock.calls as [string, EventListener][]\n ).find(([event]) => event === \"characteristicvaluechanged\");\n if (!mtuCall)\n throw new Error(\"No event registered for 'characteristicvaluechanged'\");\n const mtuHandler = mtuCall[1];\n\n await wait(150);\n mtuHandler({\n target: {\n value: { buffer: new Uint8Array([MTU_OP, 0, 0, 0, 0, 0x20]).buffer },\n },\n } as unknown as Event);\n await setupPromise;\n\n const newNotify = makeCharacteristic();\n const newWrite = makeCharacteristic();\n newWrite.properties.write = true;\n\n // when\n sender.setDependencies({\n writeCharacteristic:\n newWrite as unknown as BluetoothRemoteGATTCharacteristic,\n notifyCharacteristic:\n newNotify as unknown as BluetoothRemoteGATTCharacteristic,\n });\n\n // then\n expect(notifyChar.removeEventListener).toHaveBeenCalledWith(\n \"characteristicvaluechanged\",\n expect.any(Function),\n );\n expect(newNotify.startNotifications).not.toHaveBeenCalled();\n expect(newNotify.addEventListener).not.toHaveBeenCalled();\n\n const deps = sender.getDependencies();\n expect(deps.notifyCharacteristic).toBe(newNotify);\n expect(deps.writeCharacteristic).toBe(newWrite);\n });\n});\n"],
5
+ "mappings": "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",
6
6
  "names": ["Maybe", "Right", "afterEach", "beforeEach", "describe", "expect", "it", "vi", "MTU_OP", "WebBleApduSender", "LoggerStub", "subs", "tag", "makeCharacteristic", "disconnect", "stopNotifications", "writeChar", "notifyChar", "apduSenderFactory", "apduReceiverFactory", "loggerFactory", "sender", "flushPromises", "resolve", "wait", "ms", "apdu", "_frame", "deps", "promise", "firstCall", "event", "handler", "mtuBuf", "setupPromise", "mtuCall", "mtuHandler", "apduCmd", "lastArg", "filteredCalls", "lastCall", "apduHandler", "respBuf", "result", "extractedResult", "newNotify", "newWrite"]
7
7
  }
@@ -1,53 +1,57 @@
1
1
  {
2
- "name": "@ledgerhq/device-transport-kit-web-ble",
3
- "version": "1.3.0",
4
- "license": "Apache-2.0",
5
- "private": false,
2
+ "dependencies": {
3
+ "@sentry/minimal": "catalog:",
4
+ "purify-ts": "catalog:",
5
+ "uuid": "catalog:"
6
+ },
7
+ "devDependencies": {
8
+ "@ledgerhq/device-management-kit": "workspace:^",
9
+ "@ledgerhq/eslint-config-dsdk": "workspace:^",
10
+ "@ledgerhq/ldmk-tool": "workspace:^",
11
+ "@ledgerhq/prettier-config-dsdk": "workspace:^",
12
+ "@ledgerhq/tsconfig-dsdk": "workspace:^",
13
+ "@ledgerhq/vitest-config-dmk": "workspace:^",
14
+ "@types/uuid": "catalog:",
15
+ "@types/web-bluetooth": "catalog:",
16
+ "rxjs": "catalog:",
17
+ "ts-node": "catalog:"
18
+ },
6
19
  "exports": {
7
20
  ".": {
8
- "types": "./lib/types/index.d.ts",
9
- "import": "./lib/esm/index.js"
21
+ "import": "./lib/esm/index.js",
22
+ "types": "./lib/types/index.d.ts"
10
23
  }
11
24
  },
12
25
  "files": [
13
26
  "./lib",
14
27
  "package.json"
15
28
  ],
29
+ "license": "Apache-2.0",
30
+ "name": "@ledgerhq/device-transport-kit-web-ble",
31
+ "peerDependencies": {
32
+ "@ledgerhq/device-management-kit": "workspace:^",
33
+ "rxjs": "catalog:"
34
+ },
35
+ "private": false,
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/LedgerHQ/device-sdk-ts.git"
39
+ },
16
40
  "scripts": {
17
- "prebuild": "rimraf lib",
18
41
  "build": "pnpm ldmk-tool build --entryPoints src/index.ts,src/**/*.ts --tsconfig tsconfig.prod.json --platform web",
19
42
  "dev": "concurrently \"pnpm watch:builds\" \"pnpm watch:types\"",
20
- "watch:builds": "pnpm ldmk-tool watch --entryPoints src/index.ts,src/**/*.ts --tsconfig tsconfig.prod.json --platform web",
21
- "watch:types": "concurrently \"tsc --watch -p tsconfig.prod.json\" \"tsc-alias --watch -p tsconfig.prod.json\"",
22
43
  "lint": "eslint",
23
44
  "lint:fix": "pnpm lint --fix",
24
45
  "postpack": "find . -name '*.tgz' -exec cp {} ../../../dist/ \\; ",
46
+ "prebuild": "rimraf lib",
25
47
  "prettier": "prettier . --check",
26
48
  "prettier:fix": "prettier . --write",
27
- "typecheck": "tsc --noEmit",
28
49
  "test": "vitest run",
50
+ "test:coverage": "vitest run --coverage",
29
51
  "test:watch": "vitest",
30
- "test:coverage": "vitest run --coverage"
31
- },
32
- "dependencies": {
33
- "@sentry/minimal": "catalog:",
34
- "purify-ts": "catalog:",
35
- "uuid": "catalog:"
36
- },
37
- "devDependencies": {
38
- "@ledgerhq/device-management-kit": "workspace:*",
39
- "@ledgerhq/ldmk-tool": "workspace:*",
40
- "@ledgerhq/eslint-config-dsdk": "workspace:*",
41
- "@ledgerhq/prettier-config-dsdk": "workspace:*",
42
- "@ledgerhq/tsconfig-dsdk": "workspace:*",
43
- "@ledgerhq/vitest-config-dmk": "workspace:*",
44
- "@types/uuid": "catalog:",
45
- "@types/web-bluetooth": "catalog:",
46
- "rxjs": "catalog:",
47
- "ts-node": "catalog:"
52
+ "typecheck": "tsc --noEmit",
53
+ "watch:builds": "pnpm ldmk-tool watch --entryPoints src/index.ts,src/**/*.ts --tsconfig tsconfig.prod.json --platform web",
54
+ "watch:types": "concurrently \"tsc --watch -p tsconfig.prod.json\" \"tsc-alias --watch -p tsconfig.prod.json\""
48
55
  },
49
- "peerDependencies": {
50
- "@ledgerhq/device-management-kit": "workspace:*",
51
- "rxjs": "catalog:"
52
- }
56
+ "version": "1.3.2"
53
57
  }
@@ -1 +1 @@
1
- {"version":3,"file":"WebBleApduSender.d.ts","sourceRoot":"","sources":["../../../../src/api/transport/WebBleApduSender.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,0BAA0B,EAC/B,KAAK,YAAY,EAEjB,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EAGrB,KAAK,QAAQ,EACb,KAAK,sBAAsB,EAE5B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,KAAK,MAAM,EAAsB,MAAM,WAAW,CAAC;AAG5D,MAAM,MAAM,4BAA4B,GAAG;IACzC,mBAAmB,EAAE,iCAAiC,CAAC;IACvD,oBAAoB,EAAE,iCAAiC,CAAC;CACzD,CAAC;AAEF,eAAO,MAAM,MAAM,IAAO,CAAC;AAE3B,qBAAa,gBACX,YAAW,gBAAgB,CAAC,4BAA4B,CAAC;IAEzD,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,mBAAmB,CAA2C;IACtE,OAAO,CAAC,kBAAkB,CAA2B;IACrD,OAAO,CAAC,oBAAoB,CAA6B;IACzD,OAAO,CAAC,kBAAkB,CAAsB;IAChD,OAAO,CAAC,OAAO,CAAyB;IAExC,OAAO,CAAC,eAAe,CAAuC;IAC9D,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,qBAAqB,CAAS;IAEtC,OAAO,CAAC,wBAAwB,CAEd;gBAGhB,mBAAmB,EAAE,4BAA4B,GAAG;QAClD,iBAAiB,EAAE,wBAAwB,CAAC;QAC5C,mBAAmB,EAAE,0BAA0B,CAAC;KACjD,EACD,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,sBAAsB;IAY3C,QAAQ,CACnB,IAAI,EAAE,UAAU,EAChB,qBAAqB,CAAC,EAAE,OAAO,EAC/B,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAsEnC,eAAe,IAAI,IAAI;IAwBvB,eAAe,IAAI,4BAA4B;IAI/C,eAAe,CAAC,IAAI,EAAE,4BAA4B,GAAG,IAAI;IA4BnD,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAsE7C,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,wBAAwB;IAsBhC,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,oBAAoB;YAiBd,MAAM;IAIpB,OAAO,CAAC,mBAAmB,CAqBzB;IAEF,OAAO,CAAC,0BAA0B;IAelC,OAAO,CAAC,gBAAgB;YAgBV,0BAA0B;YAiC1B,uBAAuB;CAkCtC"}
1
+ {"version":3,"file":"WebBleApduSender.d.ts","sourceRoot":"","sources":["../../../../src/api/transport/WebBleApduSender.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,0BAA0B,EAC/B,KAAK,YAAY,EAEjB,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EAGrB,KAAK,QAAQ,EAGb,KAAK,sBAAsB,EAE5B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,KAAK,MAAM,EAAsB,MAAM,WAAW,CAAC;AAG5D,MAAM,MAAM,4BAA4B,GAAG;IACzC,mBAAmB,EAAE,iCAAiC,CAAC;IACvD,oBAAoB,EAAE,iCAAiC,CAAC;CACzD,CAAC;AAEF,eAAO,MAAM,MAAM,IAAO,CAAC;AAE3B,qBAAa,gBACX,YAAW,gBAAgB,CAAC,4BAA4B,CAAC;IAEzD,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,mBAAmB,CAA2C;IACtE,OAAO,CAAC,kBAAkB,CAA2B;IACrD,OAAO,CAAC,oBAAoB,CAA6B;IACzD,OAAO,CAAC,kBAAkB,CAAsB;IAChD,OAAO,CAAC,OAAO,CAAyB;IAExC,OAAO,CAAC,eAAe,CAAuC;IAC9D,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,qBAAqB,CAAS;IAEtC,OAAO,CAAC,wBAAwB,CAEd;gBAGhB,mBAAmB,EAAE,4BAA4B,GAAG;QAClD,iBAAiB,EAAE,wBAAwB,CAAC;QAC5C,mBAAmB,EAAE,0BAA0B,CAAC;KACjD,EACD,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,sBAAsB;IAY3C,QAAQ,CACnB,IAAI,EAAE,UAAU,EAChB,qBAAqB,CAAC,EAAE,OAAO,EAC/B,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAuEnC,eAAe,IAAI,IAAI;IAwBvB,eAAe,IAAI,4BAA4B;IAI/C,eAAe,CAAC,IAAI,EAAE,4BAA4B,GAAG,IAAI;IA4BnD,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAsE7C,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,wBAAwB;IAsBhC,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,oBAAoB;YAiBd,MAAM;IAIpB,OAAO,CAAC,mBAAmB,CAqBzB;IAEF,OAAO,CAAC,0BAA0B;IAelC,OAAO,CAAC,gBAAgB;YAgBV,0BAA0B;YAiC1B,uBAAuB;CAkCtC"}