@ledgerhq/device-transport-kit-web-hid 0.0.0-transactionInspector-resolutionObj-20250916153045 → 0.0.0-trusted-names-native-transfer-1-20260121120757

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{FramerUtils as c,OpeningConnectionError as a,SendApduTimeoutError as u}from"@ledgerhq/device-management-kit";import*as v from"@sentry/minimal";import{Left as s,Maybe as p,Nothing as m,Right as g}from"purify-ts";import{FRAME_SIZE as h}from"../data/WebHidConfig";import{WebHidSendReportError as l}from"../model/Errors";class b{dependencies;apduSender;apduReceiver;sendApduPromiseResolver;logger;constructor({dependencies:e,apduSenderFactory:d,apduReceiverFactory:n},r){const i=p.of(c.numberToByteArray(Math.floor(Math.random()*65535),2));this.logger=r("WebHidApduSender"),this.apduSender=d({frameSize:h,channel:i,padding:!0}),this.apduReceiver=n({channel:i}),this.sendApduPromiseResolver=m,this.dependencies=e,this.logger.info("\u{1F50C} Connected to device")}async sendApdu(e,d,n){this.logger.debug("[sendApdu]",{data:{apdu:e,abortTimeout:n}});let r;const i=new Promise(t=>{this.sendApduPromiseResolver=p.of((...o)=>(r&&clearTimeout(r),t(...o)))});for(const t of this.apduSender.getFrames(e))try{await this.dependencies.device.sendReport(0,new Uint8Array(t.getRawData()))}catch(o){return this.logger.info("Error sending frame",{data:{error:o}}),Promise.resolve(s(new l(o)))}return n&&(r=setTimeout(()=>{this.logger.debug("[sendApdu] Abort timeout",{data:{abortTimeout:n}}),this.sendApduPromiseResolver.map(t=>t(s(new u("Abort timeout"))))},n)),i}receiveHidInputReport(e){const d=new Uint8Array(e.data.buffer);this.apduReceiver.handleFrame(d).map(r=>{r.map(i=>{this.logger.debug("Received APDU Response",{data:{response:i}}),this.sendApduPromiseResolver.map(t=>t(g(i)))})}).mapLeft(r=>{this.sendApduPromiseResolver.map(i=>i(s(r)))})}getDependencies(){return this.dependencies}setDependencies(e){this.dependencies=e}async setupConnection(){try{this.dependencies.device.oninputreport=e=>this.receiveHidInputReport(e),await this.dependencies.device.open()}catch(e){if(e instanceof DOMException&&e.name==="InvalidStateError")this.logger.info("Device is already opened");else{const d=new a(e);throw this.logger.error("Error while opening device",{data:{error:e}}),v.captureException(d),e}}}closeConnection(){this.logger.info("\u{1F51A} Disconnect");try{this.dependencies.device.close()}catch(e){this.logger.error("Error while closing device",{data:{device:this.dependencies.device,error:e}})}}}export{b as WebHidApduSender};
1
+ import{formatApduReceivedLog as c,formatApduSentLog as a,FramerUtils as u,OpeningConnectionError as v,SendApduTimeoutError as m}from"@ledgerhq/device-management-kit";import*as g from"@sentry/minimal";import{Left as p,Maybe as s,Nothing as h,Right as l}from"purify-ts";import{FRAME_SIZE as A}from"../data/WebHidConfig";import{WebHidSendReportError as y}from"../model/Errors";class E{dependencies;apduSender;apduReceiver;sendApduPromiseResolver;logger;constructor({dependencies:e,apduSenderFactory:n,apduReceiverFactory:d},r){const i=s.of(u.numberToByteArray(Math.floor(Math.random()*65535),2));this.logger=r("WebHidApduSender"),this.apduSender=n({frameSize:A,channel:i,padding:!0}),this.apduReceiver=d({channel:i}),this.sendApduPromiseResolver=h,this.dependencies=e,this.logger.info("\u{1F50C} Connected to device")}async sendApdu(e,n,d){let r;const i=new Promise(t=>{this.sendApduPromiseResolver=s.of((...o)=>(r&&clearTimeout(r),t(...o)))});for(const t of this.apduSender.getFrames(e))try{await this.dependencies.device.sendReport(0,new Uint8Array(t.getRawData()))}catch(o){return this.logger.info("Error sending frame",{data:{error:o}}),Promise.resolve(p(new y(o)))}return this.logger.debug(a(e)),d&&(r=setTimeout(()=>{this.logger.debug("[sendApdu] Abort timeout",{data:{abortTimeout:d}}),this.sendApduPromiseResolver.map(t=>t(p(new m("Abort timeout"))))},d)),i}receiveHidInputReport(e){const n=new Uint8Array(e.data.buffer);this.apduReceiver.handleFrame(n).map(r=>{r.map(i=>{this.logger.debug(c(i)),this.sendApduPromiseResolver.map(t=>t(l(i)))})}).mapLeft(r=>{this.sendApduPromiseResolver.map(i=>i(p(r)))})}getDependencies(){return this.dependencies}setDependencies(e){this.dependencies=e}async setupConnection(){try{this.dependencies.device.oninputreport=e=>this.receiveHidInputReport(e),await this.dependencies.device.open()}catch(e){if(e instanceof DOMException&&e.name==="InvalidStateError")this.logger.info("Device is already opened");else{const n=new v(e);throw this.logger.error("Error while opening device",{data:{error:e}}),g.captureException(n),e}}}closeConnection(){this.logger.info("\u{1F51A} Disconnect");try{this.dependencies.device.close()}catch(e){this.logger.error("Error while closing device",{data:{device:this.dependencies.device,error:e}})}}}export{E as WebHidApduSender};
2
2
  //# sourceMappingURL=WebHidApduSender.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/api/transport/WebHidApduSender.ts"],
4
- "sourcesContent": ["import {\n type ApduReceiverService,\n type ApduReceiverServiceFactory,\n type ApduResponse,\n type ApduSenderService,\n type ApduSenderServiceFactory,\n type DeviceApduSender,\n type DmkError,\n FramerUtils,\n type LoggerPublisherService,\n OpeningConnectionError,\n SendApduTimeoutError,\n} from \"@ledgerhq/device-management-kit\";\nimport * as Sentry from \"@sentry/minimal\";\nimport { type Either, Left, Maybe, Nothing, Right } from \"purify-ts\";\n\nimport { FRAME_SIZE } from \"@api/data/WebHidConfig\";\nimport { WebHidSendReportError } from \"@api/model/Errors\";\n\nexport type WebHidApduSenderConstructorArgs = {\n dependencies: WebHidApduSenderDependencies;\n apduSenderFactory: ApduSenderServiceFactory;\n apduReceiverFactory: ApduReceiverServiceFactory;\n};\n\nexport type WebHidApduSenderDependencies = {\n device: HIDDevice;\n};\n\nexport class WebHidApduSender\n implements DeviceApduSender<WebHidApduSenderDependencies>\n{\n private dependencies: WebHidApduSenderDependencies;\n private readonly apduSender: ApduSenderService;\n private readonly apduReceiver: ApduReceiverService;\n private sendApduPromiseResolver: Maybe<\n (value: Either<DmkError, ApduResponse>) => void\n >;\n private readonly logger: LoggerPublisherService;\n\n constructor(\n {\n dependencies,\n apduSenderFactory,\n apduReceiverFactory,\n }: WebHidApduSenderConstructorArgs,\n loggerServiceFactory: (tag: string) => LoggerPublisherService,\n ) {\n const channel = Maybe.of(\n FramerUtils.numberToByteArray(Math.floor(Math.random() * 0xffff), 2),\n );\n this.logger = loggerServiceFactory(\"WebHidApduSender\");\n this.apduSender = apduSenderFactory({\n frameSize: FRAME_SIZE,\n channel,\n padding: true,\n });\n this.apduReceiver = apduReceiverFactory({ channel });\n this.sendApduPromiseResolver = Nothing;\n this.dependencies = dependencies;\n this.logger.info(\"\uD83D\uDD0C Connected to device\");\n }\n\n async sendApdu(\n apdu: Uint8Array,\n _triggersDisconnection?: boolean,\n abortTimeout?: number,\n ): Promise<Either<DmkError, ApduResponse>> {\n this.logger.debug(\"[sendApdu]\", {\n data: { apdu, abortTimeout },\n });\n\n let timeout: ReturnType<typeof setTimeout> | undefined;\n\n const resultPromise = new Promise<Either<DmkError, ApduResponse>>(\n (resolve) => {\n this.sendApduPromiseResolver = Maybe.of((...args) => {\n if (timeout) {\n clearTimeout(timeout);\n }\n return resolve(...args);\n });\n },\n );\n\n for (const frame of this.apduSender.getFrames(apdu)) {\n try {\n await this.dependencies.device.sendReport(\n 0,\n new Uint8Array(frame.getRawData()),\n );\n } catch (error) {\n this.logger.info(\"Error sending frame\", { data: { error } });\n return Promise.resolve(Left(new WebHidSendReportError(error)));\n }\n }\n\n if (abortTimeout) {\n timeout = setTimeout(() => {\n this.logger.debug(\"[sendApdu] Abort timeout\", {\n data: { abortTimeout },\n });\n this.sendApduPromiseResolver.map((resolve) =>\n resolve(Left(new SendApduTimeoutError(\"Abort timeout\"))),\n );\n }, abortTimeout);\n }\n\n return resultPromise;\n }\n\n private receiveHidInputReport(event: HIDInputReportEvent) {\n const data = new Uint8Array(event.data.buffer);\n const maybeApduResponse = this.apduReceiver.handleFrame(data);\n\n maybeApduResponse\n .map((response) => {\n response.map((apduResponse) => {\n this.logger.debug(\"Received APDU Response\", {\n data: { response: apduResponse },\n });\n this.sendApduPromiseResolver.map((resolve) =>\n resolve(Right(apduResponse)),\n );\n });\n })\n .mapLeft((error) => {\n this.sendApduPromiseResolver.map((resolve) => resolve(Left(error)));\n });\n }\n\n public getDependencies() {\n return this.dependencies;\n }\n\n public setDependencies(dependencies: WebHidApduSenderDependencies) {\n this.dependencies = dependencies;\n }\n\n public async setupConnection() {\n try {\n this.dependencies.device.oninputreport = (event) =>\n this.receiveHidInputReport(event);\n await this.dependencies.device.open();\n } catch (error) {\n if (error instanceof DOMException && error.name === \"InvalidStateError\") {\n this.logger.info(`Device is already opened`);\n } else {\n const connectionError = new OpeningConnectionError(error);\n this.logger.error(`Error while opening device`, {\n data: { error },\n });\n Sentry.captureException(connectionError);\n throw error;\n }\n }\n }\n\n public closeConnection() {\n this.logger.info(\"\uD83D\uDD1A Disconnect\");\n try {\n this.dependencies.device.close();\n } catch (error) {\n this.logger.error(\"Error while closing device\", {\n data: { device: this.dependencies.device, error },\n });\n }\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["FramerUtils", "OpeningConnectionError", "SendApduTimeoutError", "Sentry", "Left", "Maybe", "Nothing", "Right", "FRAME_SIZE", "WebHidSendReportError", "WebHidApduSender", "dependencies", "apduSenderFactory", "apduReceiverFactory", "loggerServiceFactory", "channel", "apdu", "_triggersDisconnection", "abortTimeout", "timeout", "resultPromise", "resolve", "args", "frame", "error", "event", "data", "response", "apduResponse", "connectionError"]
4
+ "sourcesContent": ["import {\n type ApduReceiverService,\n type ApduReceiverServiceFactory,\n type ApduResponse,\n type ApduSenderService,\n type ApduSenderServiceFactory,\n type DeviceApduSender,\n type DmkError,\n formatApduReceivedLog,\n formatApduSentLog,\n FramerUtils,\n type LoggerPublisherService,\n OpeningConnectionError,\n SendApduTimeoutError,\n} from \"@ledgerhq/device-management-kit\";\nimport * as Sentry from \"@sentry/minimal\";\nimport { type Either, Left, Maybe, Nothing, Right } from \"purify-ts\";\n\nimport { FRAME_SIZE } from \"@api/data/WebHidConfig\";\nimport { WebHidSendReportError } from \"@api/model/Errors\";\n\nexport type WebHidApduSenderConstructorArgs = {\n dependencies: WebHidApduSenderDependencies;\n apduSenderFactory: ApduSenderServiceFactory;\n apduReceiverFactory: ApduReceiverServiceFactory;\n};\n\nexport type WebHidApduSenderDependencies = {\n device: HIDDevice;\n};\n\nexport class WebHidApduSender\n implements DeviceApduSender<WebHidApduSenderDependencies>\n{\n private dependencies: WebHidApduSenderDependencies;\n private readonly apduSender: ApduSenderService;\n private readonly apduReceiver: ApduReceiverService;\n private sendApduPromiseResolver: Maybe<\n (value: Either<DmkError, ApduResponse>) => void\n >;\n private readonly logger: LoggerPublisherService;\n\n constructor(\n {\n dependencies,\n apduSenderFactory,\n apduReceiverFactory,\n }: WebHidApduSenderConstructorArgs,\n loggerServiceFactory: (tag: string) => LoggerPublisherService,\n ) {\n const channel = Maybe.of(\n FramerUtils.numberToByteArray(Math.floor(Math.random() * 0xffff), 2),\n );\n this.logger = loggerServiceFactory(\"WebHidApduSender\");\n this.apduSender = apduSenderFactory({\n frameSize: FRAME_SIZE,\n channel,\n padding: true,\n });\n this.apduReceiver = apduReceiverFactory({ channel });\n this.sendApduPromiseResolver = Nothing;\n this.dependencies = dependencies;\n this.logger.info(\"\uD83D\uDD0C Connected to device\");\n }\n\n async sendApdu(\n apdu: Uint8Array,\n _triggersDisconnection?: boolean,\n abortTimeout?: number,\n ): Promise<Either<DmkError, ApduResponse>> {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n\n const resultPromise = new Promise<Either<DmkError, ApduResponse>>(\n (resolve) => {\n this.sendApduPromiseResolver = Maybe.of((...args) => {\n if (timeout) {\n clearTimeout(timeout);\n }\n return resolve(...args);\n });\n },\n );\n\n for (const frame of this.apduSender.getFrames(apdu)) {\n try {\n await this.dependencies.device.sendReport(\n 0,\n new Uint8Array(frame.getRawData()),\n );\n } catch (error) {\n this.logger.info(\"Error sending frame\", { data: { error } });\n return Promise.resolve(Left(new WebHidSendReportError(error)));\n }\n }\n this.logger.debug(formatApduSentLog(apdu));\n\n if (abortTimeout) {\n timeout = setTimeout(() => {\n this.logger.debug(\"[sendApdu] Abort timeout\", {\n data: { abortTimeout },\n });\n this.sendApduPromiseResolver.map((resolve) =>\n resolve(Left(new SendApduTimeoutError(\"Abort timeout\"))),\n );\n }, abortTimeout);\n }\n\n return resultPromise;\n }\n\n private receiveHidInputReport(event: HIDInputReportEvent) {\n const data = new Uint8Array(event.data.buffer);\n const maybeApduResponse = this.apduReceiver.handleFrame(data);\n\n maybeApduResponse\n .map((response) => {\n response.map((apduResponse) => {\n this.logger.debug(formatApduReceivedLog(apduResponse));\n this.sendApduPromiseResolver.map((resolve) =>\n resolve(Right(apduResponse)),\n );\n });\n })\n .mapLeft((error) => {\n this.sendApduPromiseResolver.map((resolve) => resolve(Left(error)));\n });\n }\n\n public getDependencies() {\n return this.dependencies;\n }\n\n public setDependencies(dependencies: WebHidApduSenderDependencies) {\n this.dependencies = dependencies;\n }\n\n public async setupConnection() {\n try {\n this.dependencies.device.oninputreport = (event) =>\n this.receiveHidInputReport(event);\n await this.dependencies.device.open();\n } catch (error) {\n if (error instanceof DOMException && error.name === \"InvalidStateError\") {\n this.logger.info(`Device is already opened`);\n } else {\n const connectionError = new OpeningConnectionError(error);\n this.logger.error(`Error while opening device`, {\n data: { error },\n });\n Sentry.captureException(connectionError);\n throw error;\n }\n }\n }\n\n public closeConnection() {\n this.logger.info(\"\uD83D\uDD1A Disconnect\");\n try {\n this.dependencies.device.close();\n } catch (error) {\n this.logger.error(\"Error while closing device\", {\n data: { device: this.dependencies.device, error },\n });\n }\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["formatApduReceivedLog", "formatApduSentLog", "FramerUtils", "OpeningConnectionError", "SendApduTimeoutError", "Sentry", "Left", "Maybe", "Nothing", "Right", "FRAME_SIZE", "WebHidSendReportError", "WebHidApduSender", "dependencies", "apduSenderFactory", "apduReceiverFactory", "loggerServiceFactory", "channel", "apdu", "_triggersDisconnection", "abortTimeout", "timeout", "resultPromise", "resolve", "args", "frame", "error", "event", "data", "response", "apduResponse", "connectionError"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{SendApduTimeoutError as u}from"@ledgerhq/device-management-kit";import{Left as p,Maybe as l,Right as x}from"purify-ts";import{WebHidSendReportError as m}from"../model/Errors";import{WebHidApduSender as f}from"./WebHidApduSender";describe("WebHidApduSender",()=>{const c={getFrames:vi.fn()},i={handleFrame:vi.fn()},d={info:vi.fn(),debug:vi.fn(),error:vi.fn()},t={oninputreport:vi.fn(),open:vi.fn(),close:vi.fn(),sendReport:vi.fn()};let n;beforeEach(()=>{vi.clearAllMocks();const e=vi.fn().mockReturnValue(d),r=vi.fn().mockReturnValue(c),o=vi.fn().mockReturnValue(i);n=new f({dependencies:{device:t},apduSenderFactory:r,apduReceiverFactory:o},e)}),afterEach(()=>{vi.restoreAllMocks()}),it("should get dependencies",()=>{const e=n.getDependencies();expect(e).toEqual({device:t})}),it("should set dependencies",()=>{const e={oninputreport:null,open:vi.fn(),close:vi.fn(),sendReport:vi.fn()};n.setDependencies({device:e});const r=n.getDependencies();expect(r).toEqual({device:e})}),it("should setup connection",async()=>{await n.setupConnection(),expect(t.open).toHaveBeenCalled(),expect(t.oninputreport).toBeDefined()}),it("should handle setup connection error",async()=>{const e=new Error("Failed to open device");t.open=vi.fn().mockRejectedValue(e),expect(n.setupConnection()).rejects.toThrowError()}),it("should close connection",()=>{n.closeConnection(),expect(t.close).toHaveBeenCalled()}),it("should handle close connection error",()=>{const e=new Error("Failed to close device");t.close=vi.fn().mockImplementation(()=>{throw e}),n.closeConnection(),expect(d.error).toHaveBeenCalledWith("Error while closing device",{data:{device:t,error:e}})}),it("should send APDU successfully",async()=>{const e=new Uint8Array([0,1,2,3]),r=[{getRawData:()=>new Uint8Array([0,1])},{getRawData:()=>new Uint8Array([2,3])}],o={data:new Uint8Array([144,0])};c.getFrames.mockReturnValue(r),t.sendReport.mockResolvedValue({}),i.handleFrame.mockReturnValue(x(l.of(o))),await n.setupConnection();const a=n.sendApdu(e);t.oninputreport({data:{buffer:Buffer.from([])}});const s=await a;expect(t.sendReport).toHaveBeenCalled(),expect(s.isRight()).toBe(!0),expect(s.extract()).toEqual(o)}),it("should handle send APDU error",async()=>{const e=new Uint8Array([0,1,2,3]),r=[{getRawData:()=>new Uint8Array([0,1])},{getRawData:()=>new Uint8Array([2,3])}],o=new Error("Failed to send report");c.getFrames.mockReturnValue(r),t.sendReport.mockRejectedValue(o),await n.setupConnection();const a=await n.sendApdu(e);expect(a.isLeft()).toBe(!0),expect(a.extract()).toBeInstanceOf(m)}),it("should handle received response error",async()=>{const e=new Uint8Array([0,1,2,3]),r=[{getRawData:()=>new Uint8Array([0,1])},{getRawData:()=>new Uint8Array([2,3])}],o=new Error("Error while receiving APDU");c.getFrames.mockReturnValue(r),t.sendReport.mockResolvedValue({}),i.handleFrame.mockReturnValue(p(o)),await n.setupConnection();const a=n.sendApdu(e);t.oninputreport({data:{buffer:Buffer.from([])}});const s=await a;expect(t.sendReport).toHaveBeenCalled(),expect(s.isLeft()).toBe(!0),expect(s.extract()).toStrictEqual(o)}),it("should handle send APDU timeout",async()=>{const e=new Uint8Array([0,1,2,3]),r=[{getRawData:()=>new Uint8Array([0,1])},{getRawData:()=>new Uint8Array([2,3])}];c.getFrames.mockReturnValue(r),t.sendReport.mockResolvedValue({}),await n.setupConnection();const o=await n.sendApdu(e,!1,100);expect(o.isLeft()).toBe(!0),expect(o.extract()).toBeInstanceOf(u)})});
1
+ import{SendApduTimeoutError as u}from"@ledgerhq/device-management-kit";import{Left as p,Maybe as l,Right as x}from"purify-ts";import{WebHidSendReportError as m}from"../model/Errors";import{WebHidApduSender as f}from"./WebHidApduSender";describe("WebHidApduSender",()=>{const c={getFrames:vi.fn()},i={handleFrame:vi.fn()},d={info:vi.fn(),debug:vi.fn(),error:vi.fn()},t={oninputreport:vi.fn(),open:vi.fn(),close:vi.fn(),sendReport:vi.fn()};let n;beforeEach(()=>{vi.clearAllMocks();const e=vi.fn().mockReturnValue(d),r=vi.fn().mockReturnValue(c),o=vi.fn().mockReturnValue(i);n=new f({dependencies:{device:t},apduSenderFactory:r,apduReceiverFactory:o},e)}),afterEach(()=>{vi.restoreAllMocks()}),it("should get dependencies",()=>{const e=n.getDependencies();expect(e).toEqual({device:t})}),it("should set dependencies",()=>{const e={oninputreport:null,open:vi.fn(),close:vi.fn(),sendReport:vi.fn()};n.setDependencies({device:e});const r=n.getDependencies();expect(r).toEqual({device:e})}),it("should setup connection",async()=>{await n.setupConnection(),expect(t.open).toHaveBeenCalled(),expect(t.oninputreport).toBeDefined()}),it("should handle setup connection error",async()=>{const e=new Error("Failed to open device");t.open=vi.fn().mockRejectedValue(e),expect(n.setupConnection()).rejects.toThrowError()}),it("should close connection",()=>{n.closeConnection(),expect(t.close).toHaveBeenCalled()}),it("should handle close connection error",()=>{const e=new Error("Failed to close device");t.close=vi.fn().mockImplementation(()=>{throw e}),n.closeConnection(),expect(d.error).toHaveBeenCalledWith("Error while closing device",{data:{device:t,error:e}})}),it("should send APDU successfully",async()=>{const e=new Uint8Array([0,1,2,3]),r=[{getRawData:()=>new Uint8Array([0,1])},{getRawData:()=>new Uint8Array([2,3])}],o={data:new Uint8Array([1,2]),statusCode:new Uint8Array([144,0])};c.getFrames.mockReturnValue(r),t.sendReport.mockResolvedValue({}),i.handleFrame.mockReturnValue(x(l.of(o))),await n.setupConnection();const a=n.sendApdu(e);t.oninputreport({data:{buffer:Buffer.from([])}});const s=await a;expect(t.sendReport).toHaveBeenCalled(),expect(s.isRight()).toBe(!0),expect(s.extract()).toEqual(o)}),it("should handle send APDU error",async()=>{const e=new Uint8Array([0,1,2,3]),r=[{getRawData:()=>new Uint8Array([0,1])},{getRawData:()=>new Uint8Array([2,3])}],o=new Error("Failed to send report");c.getFrames.mockReturnValue(r),t.sendReport.mockRejectedValue(o),await n.setupConnection();const a=await n.sendApdu(e);expect(a.isLeft()).toBe(!0),expect(a.extract()).toBeInstanceOf(m)}),it("should handle received response error",async()=>{const e=new Uint8Array([0,1,2,3]),r=[{getRawData:()=>new Uint8Array([0,1])},{getRawData:()=>new Uint8Array([2,3])}],o=new Error("Error while receiving APDU");c.getFrames.mockReturnValue(r),t.sendReport.mockResolvedValue({}),i.handleFrame.mockReturnValue(p(o)),await n.setupConnection();const a=n.sendApdu(e);t.oninputreport({data:{buffer:Buffer.from([])}});const s=await a;expect(t.sendReport).toHaveBeenCalled(),expect(s.isLeft()).toBe(!0),expect(s.extract()).toStrictEqual(o)}),it("should handle send APDU timeout",async()=>{const e=new Uint8Array([0,1,2,3]),r=[{getRawData:()=>new Uint8Array([0,1])},{getRawData:()=>new Uint8Array([2,3])}];c.getFrames.mockReturnValue(r),t.sendReport.mockResolvedValue({}),await n.setupConnection();const o=await n.sendApdu(e,!1,100);expect(o.isLeft()).toBe(!0),expect(o.extract()).toBeInstanceOf(u)})});
2
2
  //# sourceMappingURL=WebHidApduSender.test.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/api/transport/WebHidApduSender.test.ts"],
4
- "sourcesContent": ["import {\n type ApduResponse,\n type LoggerPublisherService,\n SendApduTimeoutError,\n} from \"@ledgerhq/device-management-kit\";\nimport { Left, Maybe, Right } from \"purify-ts\";\n\nimport { WebHidSendReportError } from \"@api/model/Errors\";\n\nimport { WebHidApduSender } from \"./WebHidApduSender\";\n\ndescribe(\"WebHidApduSender\", () => {\n const mockApduSender = {\n getFrames: vi.fn(),\n };\n\n const mockApduReceiver = {\n handleFrame: vi.fn(),\n };\n\n const mockLogger = {\n info: vi.fn(),\n debug: vi.fn(),\n error: vi.fn(),\n };\n\n const mockDevice = {\n oninputreport: vi.fn(),\n open: vi.fn(),\n close: vi.fn(),\n sendReport: vi.fn(),\n };\n\n let webHidApduSender: WebHidApduSender;\n\n beforeEach(() => {\n vi.clearAllMocks();\n const mockLoggerFactory = vi\n .fn()\n .mockReturnValue(mockLogger as unknown as LoggerPublisherService);\n const mockApduSenderFactory = vi.fn().mockReturnValue(mockApduSender);\n const mockApduReceiverFactory = vi.fn().mockReturnValue(mockApduReceiver);\n webHidApduSender = new WebHidApduSender(\n {\n dependencies: { device: mockDevice as unknown as HIDDevice },\n apduSenderFactory: mockApduSenderFactory,\n apduReceiverFactory: mockApduReceiverFactory,\n },\n mockLoggerFactory,\n );\n });\n\n afterEach(() => {\n vi.restoreAllMocks();\n });\n\n it(\"should get dependencies\", () => {\n const dependencies = webHidApduSender.getDependencies();\n expect(dependencies).toEqual({\n device: mockDevice as unknown as HIDDevice,\n });\n });\n\n it(\"should set dependencies\", () => {\n const newDevice: HIDDevice = {\n oninputreport: null,\n open: vi.fn(),\n close: vi.fn(),\n sendReport: vi.fn(),\n } as unknown as HIDDevice;\n webHidApduSender.setDependencies({ device: newDevice });\n const dependencies = webHidApduSender.getDependencies();\n expect(dependencies).toEqual({ device: newDevice });\n });\n\n it(\"should setup connection\", async () => {\n await webHidApduSender.setupConnection();\n expect(mockDevice.open).toHaveBeenCalled();\n expect(mockDevice.oninputreport).toBeDefined();\n });\n\n it(\"should handle setup connection error\", async () => {\n const error = new Error(\"Failed to open device\");\n mockDevice.open = vi.fn().mockRejectedValue(error);\n expect(webHidApduSender.setupConnection()).rejects.toThrowError();\n });\n\n it(\"should close connection\", () => {\n webHidApduSender.closeConnection();\n expect(mockDevice.close).toHaveBeenCalled();\n });\n\n it(\"should handle close connection error\", () => {\n const error = new Error(\"Failed to close device\");\n mockDevice.close = vi.fn().mockImplementation(() => {\n throw error;\n });\n webHidApduSender.closeConnection();\n expect(mockLogger.error).toHaveBeenCalledWith(\n \"Error while closing device\",\n {\n data: { device: mockDevice, error },\n },\n );\n });\n\n it(\"should send APDU successfully\", async () => {\n const apdu = new Uint8Array([0x00, 0x01, 0x02, 0x03]);\n const frames = [\n { getRawData: () => new Uint8Array([0x00, 0x01]) },\n { getRawData: () => new Uint8Array([0x02, 0x03]) },\n ];\n const apduResponse = { data: new Uint8Array([0x90, 0x00]) } as ApduResponse;\n\n mockApduSender.getFrames.mockReturnValue(frames);\n mockDevice.sendReport.mockResolvedValue({});\n mockApduReceiver.handleFrame.mockReturnValue(Right(Maybe.of(apduResponse)));\n\n // Setup connection\n await webHidApduSender.setupConnection();\n\n // Send APDU\n const promise = webHidApduSender.sendApdu(apdu);\n\n // Receive response\n mockDevice.oninputreport({ data: { buffer: Buffer.from([]) } });\n\n // Await response\n const result = await promise;\n expect(mockDevice.sendReport).toHaveBeenCalled();\n expect(result.isRight()).toBe(true);\n expect(result.extract()).toEqual(apduResponse);\n });\n\n it(\"should handle send APDU error\", async () => {\n const apdu = new Uint8Array([0x00, 0x01, 0x02, 0x03]);\n const frames = [\n { getRawData: () => new Uint8Array([0x00, 0x01]) },\n { getRawData: () => new Uint8Array([0x02, 0x03]) },\n ];\n const error = new Error(\"Failed to send report\");\n\n mockApduSender.getFrames.mockReturnValue(frames);\n mockDevice.sendReport.mockRejectedValue(error);\n\n await webHidApduSender.setupConnection();\n const result = await webHidApduSender.sendApdu(apdu);\n expect(result.isLeft()).toBe(true);\n expect(result.extract()).toBeInstanceOf(WebHidSendReportError);\n });\n\n it(\"should handle received response error\", async () => {\n const apdu = new Uint8Array([0x00, 0x01, 0x02, 0x03]);\n const frames = [\n { getRawData: () => new Uint8Array([0x00, 0x01]) },\n { getRawData: () => new Uint8Array([0x02, 0x03]) },\n ];\n const apduError = new Error(\"Error while receiving APDU\");\n\n mockApduSender.getFrames.mockReturnValue(frames);\n mockDevice.sendReport.mockResolvedValue({});\n mockApduReceiver.handleFrame.mockReturnValue(Left(apduError));\n\n // Setup connection\n await webHidApduSender.setupConnection();\n\n // Send APDU\n const promise = webHidApduSender.sendApdu(apdu);\n\n // Receive response\n mockDevice.oninputreport({ data: { buffer: Buffer.from([]) } });\n\n // Await response\n const result = await promise;\n expect(mockDevice.sendReport).toHaveBeenCalled();\n expect(result.isLeft()).toBe(true);\n expect(result.extract()).toStrictEqual(apduError);\n });\n\n it(\"should handle send APDU timeout\", async () => {\n const apdu = new Uint8Array([0x00, 0x01, 0x02, 0x03]);\n const frames = [\n { getRawData: () => new Uint8Array([0x00, 0x01]) },\n { getRawData: () => new Uint8Array([0x02, 0x03]) },\n ];\n\n mockApduSender.getFrames.mockReturnValue(frames);\n mockDevice.sendReport.mockResolvedValue({});\n\n await webHidApduSender.setupConnection();\n const result = await webHidApduSender.sendApdu(apdu, false, 100);\n expect(result.isLeft()).toBe(true);\n expect(result.extract()).toBeInstanceOf(SendApduTimeoutError);\n });\n});\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n type ApduResponse,\n type LoggerPublisherService,\n SendApduTimeoutError,\n} from \"@ledgerhq/device-management-kit\";\nimport { Left, Maybe, Right } from \"purify-ts\";\n\nimport { WebHidSendReportError } from \"@api/model/Errors\";\n\nimport { WebHidApduSender } from \"./WebHidApduSender\";\n\ndescribe(\"WebHidApduSender\", () => {\n const mockApduSender = {\n getFrames: vi.fn(),\n };\n\n const mockApduReceiver = {\n handleFrame: vi.fn(),\n };\n\n const mockLogger = {\n info: vi.fn(),\n debug: vi.fn(),\n error: vi.fn(),\n };\n\n const mockDevice = {\n oninputreport: vi.fn(),\n open: vi.fn(),\n close: vi.fn(),\n sendReport: vi.fn(),\n };\n\n let webHidApduSender: WebHidApduSender;\n\n beforeEach(() => {\n vi.clearAllMocks();\n const mockLoggerFactory = vi\n .fn()\n .mockReturnValue(mockLogger as unknown as LoggerPublisherService);\n const mockApduSenderFactory = vi.fn().mockReturnValue(mockApduSender);\n const mockApduReceiverFactory = vi.fn().mockReturnValue(mockApduReceiver);\n webHidApduSender = new WebHidApduSender(\n {\n dependencies: { device: mockDevice as unknown as HIDDevice },\n apduSenderFactory: mockApduSenderFactory,\n apduReceiverFactory: mockApduReceiverFactory,\n },\n mockLoggerFactory,\n );\n });\n\n afterEach(() => {\n vi.restoreAllMocks();\n });\n\n it(\"should get dependencies\", () => {\n const dependencies = webHidApduSender.getDependencies();\n expect(dependencies).toEqual({\n device: mockDevice as unknown as HIDDevice,\n });\n });\n\n it(\"should set dependencies\", () => {\n const newDevice: HIDDevice = {\n oninputreport: null,\n open: vi.fn(),\n close: vi.fn(),\n sendReport: vi.fn(),\n } as unknown as HIDDevice;\n webHidApduSender.setDependencies({ device: newDevice });\n const dependencies = webHidApduSender.getDependencies();\n expect(dependencies).toEqual({ device: newDevice });\n });\n\n it(\"should setup connection\", async () => {\n await webHidApduSender.setupConnection();\n expect(mockDevice.open).toHaveBeenCalled();\n expect(mockDevice.oninputreport).toBeDefined();\n });\n\n it(\"should handle setup connection error\", async () => {\n const error = new Error(\"Failed to open device\");\n mockDevice.open = vi.fn().mockRejectedValue(error);\n expect(webHidApduSender.setupConnection()).rejects.toThrowError();\n });\n\n it(\"should close connection\", () => {\n webHidApduSender.closeConnection();\n expect(mockDevice.close).toHaveBeenCalled();\n });\n\n it(\"should handle close connection error\", () => {\n const error = new Error(\"Failed to close device\");\n mockDevice.close = vi.fn().mockImplementation(() => {\n throw error;\n });\n webHidApduSender.closeConnection();\n expect(mockLogger.error).toHaveBeenCalledWith(\n \"Error while closing device\",\n {\n data: { device: mockDevice, error },\n },\n );\n });\n\n it(\"should send APDU successfully\", async () => {\n const apdu = new Uint8Array([0x00, 0x01, 0x02, 0x03]);\n const frames = [\n { getRawData: () => new Uint8Array([0x00, 0x01]) },\n { getRawData: () => new Uint8Array([0x02, 0x03]) },\n ];\n const apduResponse = {\n data: new Uint8Array([0x01, 0x02]),\n statusCode: new Uint8Array([0x90, 0x00]),\n } as ApduResponse;\n\n mockApduSender.getFrames.mockReturnValue(frames);\n mockDevice.sendReport.mockResolvedValue({});\n mockApduReceiver.handleFrame.mockReturnValue(Right(Maybe.of(apduResponse)));\n\n // Setup connection\n await webHidApduSender.setupConnection();\n\n // Send APDU\n const promise = webHidApduSender.sendApdu(apdu);\n\n // Receive response\n mockDevice.oninputreport({ data: { buffer: Buffer.from([]) } });\n\n // Await response\n const result = await promise;\n expect(mockDevice.sendReport).toHaveBeenCalled();\n expect(result.isRight()).toBe(true);\n expect(result.extract()).toEqual(apduResponse);\n });\n\n it(\"should handle send APDU error\", async () => {\n const apdu = new Uint8Array([0x00, 0x01, 0x02, 0x03]);\n const frames = [\n { getRawData: () => new Uint8Array([0x00, 0x01]) },\n { getRawData: () => new Uint8Array([0x02, 0x03]) },\n ];\n const error = new Error(\"Failed to send report\");\n\n mockApduSender.getFrames.mockReturnValue(frames);\n mockDevice.sendReport.mockRejectedValue(error);\n\n await webHidApduSender.setupConnection();\n const result = await webHidApduSender.sendApdu(apdu);\n expect(result.isLeft()).toBe(true);\n expect(result.extract()).toBeInstanceOf(WebHidSendReportError);\n });\n\n it(\"should handle received response error\", async () => {\n const apdu = new Uint8Array([0x00, 0x01, 0x02, 0x03]);\n const frames = [\n { getRawData: () => new Uint8Array([0x00, 0x01]) },\n { getRawData: () => new Uint8Array([0x02, 0x03]) },\n ];\n const apduError = new Error(\"Error while receiving APDU\");\n\n mockApduSender.getFrames.mockReturnValue(frames);\n mockDevice.sendReport.mockResolvedValue({});\n mockApduReceiver.handleFrame.mockReturnValue(Left(apduError));\n\n // Setup connection\n await webHidApduSender.setupConnection();\n\n // Send APDU\n const promise = webHidApduSender.sendApdu(apdu);\n\n // Receive response\n mockDevice.oninputreport({ data: { buffer: Buffer.from([]) } });\n\n // Await response\n const result = await promise;\n expect(mockDevice.sendReport).toHaveBeenCalled();\n expect(result.isLeft()).toBe(true);\n expect(result.extract()).toStrictEqual(apduError);\n });\n\n it(\"should handle send APDU timeout\", async () => {\n const apdu = new Uint8Array([0x00, 0x01, 0x02, 0x03]);\n const frames = [\n { getRawData: () => new Uint8Array([0x00, 0x01]) },\n { getRawData: () => new Uint8Array([0x02, 0x03]) },\n ];\n\n mockApduSender.getFrames.mockReturnValue(frames);\n mockDevice.sendReport.mockResolvedValue({});\n\n await webHidApduSender.setupConnection();\n const result = await webHidApduSender.sendApdu(apdu, false, 100);\n expect(result.isLeft()).toBe(true);\n expect(result.extract()).toBeInstanceOf(SendApduTimeoutError);\n });\n});\n"],
5
+ "mappings": "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",
6
6
  "names": ["SendApduTimeoutError", "Left", "Maybe", "Right", "WebHidSendReportError", "WebHidApduSender", "mockApduSender", "mockApduReceiver", "mockLogger", "mockDevice", "webHidApduSender", "mockLoggerFactory", "mockApduSenderFactory", "mockApduReceiverFactory", "dependencies", "newDevice", "error", "apdu", "frames", "apduResponse", "promise", "result", "apduError"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{connectedDeviceStubBuilder as L,DeviceModelId as p,DeviceNotRecognizedError as X,NoAccessibleDeviceError as A,OpeningConnectionError as O,StaticDeviceModelDataSource as F,UnknownDeviceError as P}from"@ledgerhq/device-management-kit";import{Left as B,Right as V}from"purify-ts";import{lastValueFrom as b,Subject as q,toArray as j}from"rxjs";import{RECONNECT_DEVICE_TIMEOUT as x}from"../data/WebHidConfig";import{WebHidTransportNotSupportedError as W}from"../model/Errors";import{hidDeviceStubBuilder as v}from"../model/HIDDevice.stub";import{WebHidTransport as _}from"./WebHidTransport";class U{constructor(S,E){this.subscribers=S,this.tag=E}subscribers=[];tag="";error=vi.fn();warn=vi.fn();info=vi.fn();debug=vi.fn()}const R=new F,z=new U([],"web-usb-hid"),a=v(),m=async()=>{const i=await vi.importActual("timers");return new Promise(i.setImmediate)};describe("WebHidTransport",()=>{let i,S,E,h=vi.fn();const k=vi.fn(),y=vi.fn(),M={sendApdu:vi.fn().mockResolvedValue(V({data:new Uint8Array})),getDependencies:vi.fn().mockReturnValue({device:a}),setDependencies:vi.fn(),closeConnection:vi.fn(),setupConnection:vi.fn()},w={getDependencies:vi.fn().mockReturnValue({device:a}),setDependencies:vi.fn(),getDeviceId:vi.fn(),sendApdu:vi.fn().mockResolvedValue(V({data:new Uint8Array})),setupConnection:vi.fn(),eventDeviceConnected:k,eventDeviceDisconnected:y,closeConnection:vi.fn()};function T(){S=vi.fn(),E=vi.fn(),h=vi.fn(s=>({...w,getDeviceId:vi.fn().mockReturnValue(s.deviceId),getDependencies:s.deviceApduSender.getDependencies,setDependencies:s.deviceApduSender.setDependencies}));const d=vi.fn(s=>({...M,getDependencies:()=>s.dependencies,setDependencies:f=>s.dependencies=f}));i=new _(R,()=>z,E,S,h,d)}beforeEach(()=>{T(),vi.useFakeTimers()}),afterEach(()=>{vi.restoreAllMocks()});const D=(d,s)=>{i.startDiscovering().subscribe({next:d,error:s})};describe("When WebHID API is not supported",()=>{it("should not support the transport",()=>{expect(i.isSupported()).toBe(!1)}),it("should emit a startDiscovering error",()=>new Promise((d,s)=>{D(()=>{s("Should not emit any value")},f=>{expect(f).toBeInstanceOf(W),d()})}))}),describe("When WebHID API is supported",()=>{const d=vi.fn(),s=vi.fn(),f=new q,N=new q;function C(t){f.next({device:t})}function I(t){N.next({device:t})}beforeEach(()=>{global.navigator={hid:{getDevices:d,requestDevice:s,addEventListener:(t,e)=>{t==="disconnect"?N.subscribe(e):t==="connect"&&f.subscribe(e)}}},T()}),afterEach(()=>{vi.clearAllMocks(),global.navigator=void 0}),it("should support the transport",()=>{expect(i.isSupported()).toBe(!0)}),describe("startDiscovering",()=>{R.getAllDeviceModels().flatMap(e=>[{testTitle:`should emit device if user grants access through hid.requestDevice (${e.productName})`,hidDevice:v({productId:e.usbProductId<<8,productName:e.productName}),expectedDeviceModel:e},{testTitle:`should emit device if user grants access through hid.requestDevice (${e.productName}, bootloader)`,hidDevice:v({productId:e.bootloaderUsbProductId,productName:e.productName}),expectedDeviceModel:e}]).forEach(e=>{it(e.testTitle,()=>new Promise((o,n)=>{s.mockResolvedValueOnce([e.hidDevice]),D(c=>{try{expect(c).toEqual(expect.objectContaining({deviceModel:e.expectedDeviceModel})),o()}catch(r){n(r)}},c=>{n(c)})}))}),it("should emit devices if new grant accesses",()=>new Promise((e,o)=>{s.mockResolvedValueOnce([a,{...a,productId:20497,productName:"Ledger Nano S Plus"}]);let n=0;D(c=>{try{switch(n){case 0:expect(c).toEqual(expect.objectContaining({deviceModel:expect.objectContaining({id:p.NANO_X,productName:"Ledger Nano X",usbProductId:64})}));break;case 1:expect(c).toEqual(expect.objectContaining({deviceModel:expect.objectContaining({id:p.NANO_SP,productName:"Ledger Nano S Plus",usbProductId:80})})),e();break}n++}catch(r){o(r)}},c=>{o(c)})})),it("should throw DeviceNotRecognizedError if the device is not recognized",()=>new Promise((e,o)=>{s.mockResolvedValueOnce([{...a,productId:16962}]),D(()=>{o("should not return a device")},n=>{expect(n).toBeInstanceOf(X),e()})})),it("should emit an error if the request device is in error",()=>new Promise((e,o)=>{const n="request device error";s.mockImplementationOnce(()=>{throw new Error(n)}),D(()=>{o("should not return a device")},c=>{expect(c).toBeInstanceOf(A),expect(c).toStrictEqual(new A(new Error(n))),e()})})),it("should emit an error if the user did not grant us access to a device (clicking on cancel on the browser popup for ex)",()=>new Promise((e,o)=>{s.mockResolvedValueOnce([]),D(n=>{o(`Should not emit any value, but emitted ${JSON.stringify(n)}`)},n=>{try{expect(n).toBeInstanceOf(A),e()}catch(c){o(c)}})})),it("should emit the same discoveredDevice object if its discovered twice in a row",async()=>{s.mockResolvedValue([a]),d.mockResolvedValue([a]);const e=await new Promise((n,c)=>{D(()=>n(),r=>c(r))}),o=await new Promise((n,c)=>{D(()=>n(),r=>c(r))});expect(o).toBe(e)})}),describe("destroy",()=>{it("should stop monitoring connections if the discovery process is halted",()=>{const t=vi.spyOn(AbortController.prototype,"abort");i.destroy(),expect(t).toHaveBeenCalled()})}),describe("connect",()=>{it("should throw UnknownDeviceError if no internal device",async()=>{const t={deviceId:"fake",onDisconnect:vi.fn()},e=await i.connect(t);expect(e).toStrictEqual(B(new P("Unknown device fake")))}),it("should throw OpeningConnectionError if the device cannot be opened",async()=>{const t="cannot be opened";M.setupConnection.mockRejectedValue(new O(t)),s.mockResolvedValueOnce([a]),d.mockResolvedValue([a]);const e=await b(i.startDiscovering()),o=await i.connect({deviceId:e.id,onDisconnect:vi.fn()});expect(o).toStrictEqual(B(new O(t)))}),it("should return a device if available",async()=>{s.mockResolvedValueOnce([a]),d.mockResolvedValue([a]);const t=await b(i.startDiscovering()),e=await i.connect({deviceId:t.id,onDisconnect:vi.fn()});expect(e.isRight()).toStrictEqual(!0),expect(e.extract()).toEqual(expect.objectContaining({id:t.id}))}),it("should return an existing connected device",async()=>{s.mockResolvedValueOnce([a]),d.mockResolvedValue([a]);const t=await b(i.startDiscovering());await i.connect({deviceId:t.id,onDisconnect:vi.fn()});const e=await i.connect({deviceId:t.id,onDisconnect:vi.fn()});expect(e.isRight()).toStrictEqual(!0),expect(e.extract()).toEqual(expect.objectContaining({id:t.id}))})}),describe("disconnect",()=>{it("should throw an error if the device is not connected",async()=>{const t=L(),e=await i.disconnect({connectedDevice:t});expect(e).toStrictEqual(B(new P(`Unknown device ${t.id}`)))}),it("should disconnect if the device is connected",async()=>{s.mockResolvedValueOnce([a]),d.mockResolvedValue([a]);const t=await b(i.startDiscovering()),e=await i.connect({deviceId:t.id,onDisconnect:vi.fn()});expect(e.isRight()).toStrictEqual(!0);const o=await i.disconnect({connectedDevice:e.unsafeCoerce()});expect(o).toStrictEqual(V(void 0))}),it("should call disconnect handler if a connected device is unplugged",async()=>{let t=vi.fn();h.mockImplementationOnce(g=>(t=g.onTerminated,{...w,getDeviceId:vi.fn().mockReturnValue(g.deviceId)}));const e=v(),o=v();s.mockResolvedValueOnce([e,o]),d.mockResolvedValue([e,o]);const n=await b(i.startDiscovering().pipe(j()));expect(n.length).toStrictEqual(2);const c=vi.fn(),r=await i.connect({deviceId:n[0].id,onDisconnect:c}),l=vi.fn(),u=await i.connect({deviceId:n[1].id,onDisconnect:l});expect(r.isRight()).toStrictEqual(!0),expect(u.isRight()).toStrictEqual(!0),t(),expect(c).toHaveBeenCalled(),expect(l).not.toHaveBeenCalled()}),it("should call disconnect handler if a connected device is unplugged while reconnecting",async()=>{let t=vi.fn(),e=vi.fn();h.mockImplementationOnce(H=>(t=H.onTerminated,e=H.tryToReconnect,{...w,getDeviceId:vi.fn().mockReturnValue(H.deviceId)}));const o=v(),n=v();s.mockResolvedValueOnce([o,n]),d.mockResolvedValue([o,n]);const c=await b(i.startDiscovering().pipe(j()));expect(c.length).toStrictEqual(2);const r=vi.fn(),l=await i.connect({deviceId:c[0].id,onDisconnect:r}),u=vi.fn(),g=await i.connect({deviceId:c[1].id,onDisconnect:u});expect(l.isRight()).toStrictEqual(!0),expect(g.isRight()).toStrictEqual(!0),e(),t(),expect(r).toHaveBeenCalled(),expect(u).not.toHaveBeenCalled()})}),describe("reconnect",()=>{it("should stop disconnection if reconnection happen",()=>new Promise((t,e)=>{const o=vi.fn();let n=vi.fn();const c=v(),r=v();s.mockResolvedValueOnce([c]),d.mockResolvedValue([c,r]),h.mockImplementationOnce(l=>(n=l.tryToReconnect,{...w,getDeviceId:vi.fn().mockReturnValue(l.deviceId),getDependencies:l.deviceApduSender.getDependencies,setDependencies:l.deviceApduSender.setDependencies})),D(async l=>{try{await i.connect({deviceId:l.id,onDisconnect:o}),I(c),expect(c.close).toHaveBeenCalled(),await Promise.resolve(),expect(y).toHaveBeenCalled(),n(),vi.advanceTimersByTime(x/3),C(r),await Promise.resolve(),expect(k).toHaveBeenCalled(),vi.advanceTimersByTime(x),expect(o).not.toHaveBeenCalled(),t()}catch(u){e(u)}})})),it("should be able to reconnect twice in a row if the device is unplugged and replugged twice",()=>new Promise((t,e)=>{const o=vi.fn();let n=vi.fn();const c=v(),r=v(),l=v();s.mockResolvedValueOnce([c]),d.mockResolvedValue([c,r,l]),h.mockImplementationOnce(u=>(n=u.tryToReconnect,{...w,getDeviceId:vi.fn().mockReturnValue(u.deviceId),getDependencies:u.deviceApduSender.getDependencies,setDependencies:u.deviceApduSender.setDependencies})),D(async u=>{await i.connect({deviceId:u.id,onDisconnect:o});try{I(c),expect(c.close).toHaveBeenCalled(),await Promise.resolve(),expect(y).toHaveBeenCalled(),n(),vi.advanceTimersByTime(x/3),C(r),await Promise.resolve(),expect(k).toHaveBeenCalled(),vi.advanceTimersByTime(x),expect(o).not.toHaveBeenCalled(),I(r),expect(r.close).toHaveBeenCalled(),await Promise.resolve(),expect(y).toHaveBeenCalled(),n(),vi.advanceTimersByTime(x/3),C(l),await Promise.resolve(),expect(k).toHaveBeenCalled(),vi.advanceTimersByTime(x),expect(o).not.toHaveBeenCalled(),t()}catch(g){e(g)}})}))}),describe("Connection event typeguard",()=>{it("should validate type of an HIDConnectionEvent",()=>{const t={device:a},e=i.isHIDConnectionEvent(t);expect(e).toBe(!0)}),it("should not validate type of another event",()=>{const t=new Event("disconnect",{}),e=i.isHIDConnectionEvent(t);expect(e).toBe(!1)})}),describe("listenToAvailableDevices",()=>{it("should emit the devices already connected before listening",async()=>{const t=v();d.mockResolvedValue([t]);const e=vi.fn(),o=vi.fn();let n=[];i.listenToAvailableDevices().subscribe({next:c=>{n=c},complete:e,error:o}),await m(),expect(n).toEqual([expect.objectContaining({deviceModel:expect.objectContaining({id:p.NANO_X})})]),expect(e).not.toHaveBeenCalled(),expect(o).not.toHaveBeenCalled()}),it("should emit the new list of devices after connection and disconnection events",async()=>{T();const t=v({productId:R.getDeviceModel({id:p.NANO_X}).usbProductId<<8}),e=v({productId:R.getDeviceModel({id:p.STAX}).usbProductId<<8});d.mockResolvedValue([t]);const o=vi.fn(),n=vi.fn();let c=[];i.listenToAvailableDevices().subscribe({next:r=>{c=r},complete:o,error:n}),await m(),expect(c).toEqual([expect.objectContaining({deviceModel:expect.objectContaining({id:p.NANO_X})})]),d.mockResolvedValue([t,e]),C(e),await m(),expect(c).toEqual([expect.objectContaining({deviceModel:expect.objectContaining({id:p.NANO_X})}),expect.objectContaining({deviceModel:expect.objectContaining({id:p.STAX})})]),d.mockResolvedValue([e]),I(t),await m(),expect(c).toEqual([expect.objectContaining({deviceModel:expect.objectContaining({id:p.STAX})})]),expect(o).not.toHaveBeenCalled(),expect(n).not.toHaveBeenCalled()}),it("should preserve DeviceId in case the device has been disconnected and reconnected before the timeout",async()=>{const t=v();d.mockResolvedValue([t]);const e=vi.fn(),o=vi.fn();let n=[];i.listenToAvailableDevices().subscribe({next:r=>{n=r},complete:e,error:o}),await m();const c=n[0]?.id;expect(c).toBeTruthy(),expect(n[0]?.deviceModel?.id).toBe(p.NANO_X),await i.connect({deviceId:n[0].id,onDisconnect:vi.fn()}),await m(),d.mockResolvedValue([]),I(t),await m(),expect(n).toEqual([]),d.mockResolvedValue([t]),C(t),await m(),expect(n).toEqual([expect.objectContaining({deviceModel:expect.objectContaining({id:p.NANO_X})})]),expect(n[0]?.id).toBeTruthy(),expect(n[0]?.id).toBe(c)})})})});
1
+ import{connectedDeviceStubBuilder as L,DeviceModelId as p,DeviceNotRecognizedError as X,NoAccessibleDeviceError as A,OpeningConnectionError as O,StaticDeviceModelDataSource as F,UnknownDeviceError as P}from"@ledgerhq/device-management-kit";import{Left as B,Right as V}from"purify-ts";import{lastValueFrom as b,Subject as q,toArray as j}from"rxjs";import{RECONNECT_DEVICE_TIMEOUT as x}from"../data/WebHidConfig";import{WebHidTransportNotSupportedError as U}from"../model/Errors";import{hidDeviceStubBuilder as v}from"../model/HIDDevice.stub";import{WebHidTransport as W}from"./WebHidTransport";class _{constructor(S,E){this.subscribers=S,this.tag=E}subscribers=[];tag="";error=vi.fn();warn=vi.fn();info=vi.fn();debug=vi.fn()}const R=new F,z=new _([],"web-usb-hid"),a=v(),m=async()=>{const i=await vi.importActual("timers");return new Promise(i.setImmediate)};describe("WebHidTransport",()=>{let i,S,E,h=vi.fn();const k=vi.fn(),y=vi.fn(),M={sendApdu:vi.fn().mockResolvedValue(V({data:new Uint8Array,statusCode:new Uint8Array([144,0])})),getDependencies:vi.fn().mockReturnValue({device:a}),setDependencies:vi.fn(),closeConnection:vi.fn(),setupConnection:vi.fn()},w={getDependencies:vi.fn().mockReturnValue({device:a}),setDependencies:vi.fn(),getDeviceId:vi.fn(),sendApdu:vi.fn().mockResolvedValue(V({data:new Uint8Array,statusCode:new Uint8Array([144,0])})),setupConnection:vi.fn(),eventDeviceConnected:k,eventDeviceDisconnected:y,closeConnection:vi.fn()};function T(){S=vi.fn(),E=vi.fn(),h=vi.fn(s=>({...w,getDeviceId:vi.fn().mockReturnValue(s.deviceId),getDependencies:s.deviceApduSender.getDependencies,setDependencies:s.deviceApduSender.setDependencies}));const d=vi.fn(s=>({...M,getDependencies:()=>s.dependencies,setDependencies:f=>s.dependencies=f}));i=new W(R,()=>z,E,S,h,d)}beforeEach(()=>{T(),vi.useFakeTimers()}),afterEach(()=>{vi.restoreAllMocks()});const D=(d,s)=>{i.startDiscovering().subscribe({next:d,error:s})};describe("When WebHID API is not supported",()=>{it("should not support the transport",()=>{expect(i.isSupported()).toBe(!1)}),it("should emit a startDiscovering error",()=>new Promise((d,s)=>{D(()=>{s("Should not emit any value")},f=>{expect(f).toBeInstanceOf(U),d()})}))}),describe("When WebHID API is supported",()=>{const d=vi.fn(),s=vi.fn(),f=new q,N=new q;function C(t){f.next({device:t})}function I(t){N.next({device:t})}beforeEach(()=>{global.navigator={hid:{getDevices:d,requestDevice:s,addEventListener:(t,e)=>{t==="disconnect"?N.subscribe(e):t==="connect"&&f.subscribe(e)}}},T()}),afterEach(()=>{vi.clearAllMocks(),global.navigator=void 0}),it("should support the transport",()=>{expect(i.isSupported()).toBe(!0)}),describe("startDiscovering",()=>{R.getAllDeviceModels().flatMap(e=>[{testTitle:`should emit device if user grants access through hid.requestDevice (${e.productName})`,hidDevice:v({productId:e.usbProductId<<8,productName:e.productName}),expectedDeviceModel:e},{testTitle:`should emit device if user grants access through hid.requestDevice (${e.productName}, bootloader)`,hidDevice:v({productId:e.bootloaderUsbProductId,productName:e.productName}),expectedDeviceModel:e}]).forEach(e=>{it(e.testTitle,()=>new Promise((o,n)=>{s.mockResolvedValueOnce([e.hidDevice]),D(c=>{try{expect(c).toEqual(expect.objectContaining({deviceModel:e.expectedDeviceModel})),o()}catch(r){n(r)}},c=>{n(c)})}))}),it("should emit devices if new grant accesses",()=>new Promise((e,o)=>{s.mockResolvedValueOnce([a,{...a,productId:20497,productName:"Ledger Nano S Plus"}]);let n=0;D(c=>{try{switch(n){case 0:expect(c).toEqual(expect.objectContaining({deviceModel:expect.objectContaining({id:p.NANO_X,productName:"Ledger Nano X",usbProductId:64})}));break;case 1:expect(c).toEqual(expect.objectContaining({deviceModel:expect.objectContaining({id:p.NANO_SP,productName:"Ledger Nano S Plus",usbProductId:80})})),e();break}n++}catch(r){o(r)}},c=>{o(c)})})),it("should throw DeviceNotRecognizedError if the device is not recognized",()=>new Promise((e,o)=>{s.mockResolvedValueOnce([{...a,productId:16962}]),D(()=>{o("should not return a device")},n=>{expect(n).toBeInstanceOf(X),e()})})),it("should emit an error if the request device is in error",()=>new Promise((e,o)=>{const n="request device error";s.mockImplementationOnce(()=>{throw new Error(n)}),D(()=>{o("should not return a device")},c=>{expect(c).toBeInstanceOf(A),expect(c).toStrictEqual(new A(new Error(n))),e()})})),it("should emit an error if the user did not grant us access to a device (clicking on cancel on the browser popup for ex)",()=>new Promise((e,o)=>{s.mockResolvedValueOnce([]),D(n=>{o(`Should not emit any value, but emitted ${JSON.stringify(n)}`)},n=>{try{expect(n).toBeInstanceOf(A),e()}catch(c){o(c)}})})),it("should emit the same discoveredDevice object if its discovered twice in a row",async()=>{s.mockResolvedValue([a]),d.mockResolvedValue([a]);const e=await new Promise((n,c)=>{D(()=>n(),r=>c(r))}),o=await new Promise((n,c)=>{D(()=>n(),r=>c(r))});expect(o).toBe(e)})}),describe("destroy",()=>{it("should stop monitoring connections if the discovery process is halted",()=>{const t=vi.spyOn(AbortController.prototype,"abort");i.destroy(),expect(t).toHaveBeenCalled()})}),describe("connect",()=>{it("should throw UnknownDeviceError if no internal device",async()=>{const t={deviceId:"fake",onDisconnect:vi.fn()},e=await i.connect(t);expect(e).toStrictEqual(B(new P("Unknown device fake")))}),it("should throw OpeningConnectionError if the device cannot be opened",async()=>{const t="cannot be opened";M.setupConnection.mockRejectedValue(new O(t)),s.mockResolvedValueOnce([a]),d.mockResolvedValue([a]);const e=await b(i.startDiscovering()),o=await i.connect({deviceId:e.id,onDisconnect:vi.fn()});expect(o).toStrictEqual(B(new O(t)))}),it("should return a device if available",async()=>{s.mockResolvedValueOnce([a]),d.mockResolvedValue([a]);const t=await b(i.startDiscovering()),e=await i.connect({deviceId:t.id,onDisconnect:vi.fn()});expect(e.isRight()).toStrictEqual(!0),expect(e.extract()).toEqual(expect.objectContaining({id:t.id}))}),it("should return an existing connected device",async()=>{s.mockResolvedValueOnce([a]),d.mockResolvedValue([a]);const t=await b(i.startDiscovering());await i.connect({deviceId:t.id,onDisconnect:vi.fn()});const e=await i.connect({deviceId:t.id,onDisconnect:vi.fn()});expect(e.isRight()).toStrictEqual(!0),expect(e.extract()).toEqual(expect.objectContaining({id:t.id}))})}),describe("disconnect",()=>{it("should throw an error if the device is not connected",async()=>{const t=L(),e=await i.disconnect({connectedDevice:t});expect(e).toStrictEqual(B(new P(`Unknown device ${t.id}`)))}),it("should disconnect if the device is connected",async()=>{s.mockResolvedValueOnce([a]),d.mockResolvedValue([a]);const t=await b(i.startDiscovering()),e=await i.connect({deviceId:t.id,onDisconnect:vi.fn()});expect(e.isRight()).toStrictEqual(!0);const o=await i.disconnect({connectedDevice:e.unsafeCoerce()});expect(o).toStrictEqual(V(void 0))}),it("should call disconnect handler if a connected device is unplugged",async()=>{let t=vi.fn();h.mockImplementationOnce(g=>(t=g.onTerminated,{...w,getDeviceId:vi.fn().mockReturnValue(g.deviceId)}));const e=v(),o=v();s.mockResolvedValueOnce([e,o]),d.mockResolvedValue([e,o]);const n=await b(i.startDiscovering().pipe(j()));expect(n.length).toStrictEqual(2);const c=vi.fn(),r=await i.connect({deviceId:n[0].id,onDisconnect:c}),l=vi.fn(),u=await i.connect({deviceId:n[1].id,onDisconnect:l});expect(r.isRight()).toStrictEqual(!0),expect(u.isRight()).toStrictEqual(!0),t(),expect(c).toHaveBeenCalled(),expect(l).not.toHaveBeenCalled()}),it("should call disconnect handler if a connected device is unplugged while reconnecting",async()=>{let t=vi.fn(),e=vi.fn();h.mockImplementationOnce(H=>(t=H.onTerminated,e=H.tryToReconnect,{...w,getDeviceId:vi.fn().mockReturnValue(H.deviceId)}));const o=v(),n=v();s.mockResolvedValueOnce([o,n]),d.mockResolvedValue([o,n]);const c=await b(i.startDiscovering().pipe(j()));expect(c.length).toStrictEqual(2);const r=vi.fn(),l=await i.connect({deviceId:c[0].id,onDisconnect:r}),u=vi.fn(),g=await i.connect({deviceId:c[1].id,onDisconnect:u});expect(l.isRight()).toStrictEqual(!0),expect(g.isRight()).toStrictEqual(!0),e(),t(),expect(r).toHaveBeenCalled(),expect(u).not.toHaveBeenCalled()})}),describe("reconnect",()=>{it("should stop disconnection if reconnection happen",()=>new Promise((t,e)=>{const o=vi.fn();let n=vi.fn();const c=v(),r=v();s.mockResolvedValueOnce([c]),d.mockResolvedValue([c,r]),h.mockImplementationOnce(l=>(n=l.tryToReconnect,{...w,getDeviceId:vi.fn().mockReturnValue(l.deviceId),getDependencies:l.deviceApduSender.getDependencies,setDependencies:l.deviceApduSender.setDependencies})),D(async l=>{try{await i.connect({deviceId:l.id,onDisconnect:o}),I(c),expect(c.close).toHaveBeenCalled(),await Promise.resolve(),expect(y).toHaveBeenCalled(),n(),vi.advanceTimersByTime(x/3),C(r),await Promise.resolve(),expect(k).toHaveBeenCalled(),vi.advanceTimersByTime(x),expect(o).not.toHaveBeenCalled(),t()}catch(u){e(u)}})})),it("should be able to reconnect twice in a row if the device is unplugged and replugged twice",()=>new Promise((t,e)=>{const o=vi.fn();let n=vi.fn();const c=v(),r=v(),l=v();s.mockResolvedValueOnce([c]),d.mockResolvedValue([c,r,l]),h.mockImplementationOnce(u=>(n=u.tryToReconnect,{...w,getDeviceId:vi.fn().mockReturnValue(u.deviceId),getDependencies:u.deviceApduSender.getDependencies,setDependencies:u.deviceApduSender.setDependencies})),D(async u=>{await i.connect({deviceId:u.id,onDisconnect:o});try{I(c),expect(c.close).toHaveBeenCalled(),await Promise.resolve(),expect(y).toHaveBeenCalled(),n(),vi.advanceTimersByTime(x/3),C(r),await Promise.resolve(),expect(k).toHaveBeenCalled(),vi.advanceTimersByTime(x),expect(o).not.toHaveBeenCalled(),I(r),expect(r.close).toHaveBeenCalled(),await Promise.resolve(),expect(y).toHaveBeenCalled(),n(),vi.advanceTimersByTime(x/3),C(l),await Promise.resolve(),expect(k).toHaveBeenCalled(),vi.advanceTimersByTime(x),expect(o).not.toHaveBeenCalled(),t()}catch(g){e(g)}})}))}),describe("Connection event typeguard",()=>{it("should validate type of an HIDConnectionEvent",()=>{const t={device:a},e=i.isHIDConnectionEvent(t);expect(e).toBe(!0)}),it("should not validate type of another event",()=>{const t=new Event("disconnect",{}),e=i.isHIDConnectionEvent(t);expect(e).toBe(!1)})}),describe("listenToAvailableDevices",()=>{it("should emit the devices already connected before listening",async()=>{const t=v();d.mockResolvedValue([t]);const e=vi.fn(),o=vi.fn();let n=[];i.listenToAvailableDevices().subscribe({next:c=>{n=c},complete:e,error:o}),await m(),expect(n).toEqual([expect.objectContaining({deviceModel:expect.objectContaining({id:p.NANO_X})})]),expect(e).not.toHaveBeenCalled(),expect(o).not.toHaveBeenCalled()}),it("should emit the new list of devices after connection and disconnection events",async()=>{T();const t=v({productId:R.getDeviceModel({id:p.NANO_X}).usbProductId<<8}),e=v({productId:R.getDeviceModel({id:p.STAX}).usbProductId<<8});d.mockResolvedValue([t]);const o=vi.fn(),n=vi.fn();let c=[];i.listenToAvailableDevices().subscribe({next:r=>{c=r},complete:o,error:n}),await m(),expect(c).toEqual([expect.objectContaining({deviceModel:expect.objectContaining({id:p.NANO_X})})]),d.mockResolvedValue([t,e]),C(e),await m(),expect(c).toEqual([expect.objectContaining({deviceModel:expect.objectContaining({id:p.NANO_X})}),expect.objectContaining({deviceModel:expect.objectContaining({id:p.STAX})})]),d.mockResolvedValue([e]),I(t),await m(),expect(c).toEqual([expect.objectContaining({deviceModel:expect.objectContaining({id:p.STAX})})]),expect(o).not.toHaveBeenCalled(),expect(n).not.toHaveBeenCalled()}),it("should preserve DeviceId in case the device has been disconnected and reconnected before the timeout",async()=>{const t=v();d.mockResolvedValue([t]);const e=vi.fn(),o=vi.fn();let n=[];i.listenToAvailableDevices().subscribe({next:r=>{n=r},complete:e,error:o}),await m();const c=n[0]?.id;expect(c).toBeTruthy(),expect(n[0]?.deviceModel?.id).toBe(p.NANO_X),await i.connect({deviceId:n[0].id,onDisconnect:vi.fn()}),await m(),d.mockResolvedValue([]),I(t),await m(),expect(n).toEqual([]),d.mockResolvedValue([t]),C(t),await m(),expect(n).toEqual([expect.objectContaining({deviceModel:expect.objectContaining({id:p.NANO_X})})]),expect(n[0]?.id).toBeTruthy(),expect(n[0]?.id).toBe(c)})})})});
2
2
  //# sourceMappingURL=WebHidTransport.test.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/api/transport/WebHidTransport.test.ts"],
4
- "sourcesContent": ["/* eslint @typescript-eslint/consistent-type-imports: off */\nimport {\n type ApduReceiverServiceFactory,\n type ApduResponse,\n type ApduSenderServiceFactory,\n connectedDeviceStubBuilder,\n DeviceConnectionStateMachine,\n type DeviceConnectionStateMachineParams,\n type DeviceModel,\n DeviceModelId,\n DeviceNotRecognizedError,\n type LoggerPublisherService,\n type LoggerSubscriberService,\n NoAccessibleDeviceError,\n OpeningConnectionError,\n StaticDeviceModelDataSource,\n type TransportDeviceModel,\n type TransportDiscoveredDevice,\n UnknownDeviceError,\n} from \"@ledgerhq/device-management-kit\";\nimport { Left, Right } from \"purify-ts\";\nimport { lastValueFrom, Subject, toArray } from \"rxjs\";\n\nimport { RECONNECT_DEVICE_TIMEOUT } from \"@api/data/WebHidConfig\";\nimport { WebHidTransportNotSupportedError } from \"@api/model/Errors\";\nimport { hidDeviceStubBuilder } from \"@api/model/HIDDevice.stub\";\n\nimport { WebHidApduSender } from \"./WebHidApduSender\";\nimport { WebHidTransport } from \"./WebHidTransport\";\n\nclass LoggerPublisherServiceStub implements LoggerPublisherService {\n constructor(subscribers: LoggerSubscriberService[], tag: string) {\n this.subscribers = subscribers;\n this.tag = tag;\n }\n subscribers: LoggerSubscriberService[] = [];\n tag: string = \"\";\n error = vi.fn();\n warn = vi.fn();\n info = vi.fn();\n debug = vi.fn();\n}\n\n// Our StaticDeviceModelDataSource can directly be used in our unit tests\nconst usbDeviceModelDataSource = new StaticDeviceModelDataSource();\nconst logger = new LoggerPublisherServiceStub([], \"web-usb-hid\");\n\nconst stubDevice: HIDDevice = hidDeviceStubBuilder();\n\n/**\n * Flushes all pending promises\n */\nconst flushPromises = async () => {\n const timers = await vi.importActual<typeof import(\"timers\")>(\"timers\");\n return new Promise(timers.setImmediate);\n};\n\ndescribe(\"WebHidTransport\", () => {\n let transport: WebHidTransport;\n let apduReceiverServiceFactoryStub: ApduReceiverServiceFactory;\n let apduSenderServiceFactoryStub: ApduSenderServiceFactory;\n\n let mockDeviceConnectionStateMachineFactory = vi.fn();\n const mockEventDeviceConnected = vi.fn();\n const mockEventDeviceDisconnected = vi.fn();\n\n const mockDeviceApduSender = {\n sendApdu: vi\n .fn()\n .mockResolvedValue(Right({ data: new Uint8Array() } as ApduResponse)),\n getDependencies: vi.fn().mockReturnValue({ device: stubDevice }),\n setDependencies: vi.fn(),\n closeConnection: vi.fn(),\n setupConnection: vi.fn(),\n };\n\n const mockDeviceConnectionStateMachine = {\n getDependencies: vi.fn().mockReturnValue({ device: stubDevice }),\n setDependencies: vi.fn(),\n getDeviceId: vi.fn(),\n sendApdu: vi\n .fn()\n .mockResolvedValue(Right({ data: new Uint8Array() } as ApduResponse)),\n setupConnection: vi.fn(),\n eventDeviceConnected: mockEventDeviceConnected,\n eventDeviceDisconnected: mockEventDeviceDisconnected,\n closeConnection: vi.fn(),\n };\n\n function initializeTransport() {\n apduReceiverServiceFactoryStub = vi.fn();\n apduSenderServiceFactoryStub = vi.fn();\n mockDeviceConnectionStateMachineFactory = vi.fn(\n (params: DeviceConnectionStateMachineParams<{ device: HIDDevice }>) => {\n return {\n ...mockDeviceConnectionStateMachine,\n getDeviceId: vi.fn().mockReturnValue(params.deviceId),\n getDependencies: params.deviceApduSender.getDependencies,\n setDependencies: params.deviceApduSender.setDependencies,\n } as unknown as DeviceConnectionStateMachine<{ device: HIDDevice }>;\n },\n );\n const mockDeviceApduSenderFactory = vi.fn((params) => {\n return {\n ...mockDeviceApduSender,\n getDependencies: () => params.dependencies,\n setDependencies: (dependencies: { device: HIDDevice }) =>\n (params.dependencies = dependencies),\n } as unknown as WebHidApduSender;\n });\n transport = new WebHidTransport(\n usbDeviceModelDataSource,\n () => logger,\n apduSenderServiceFactoryStub,\n apduReceiverServiceFactoryStub,\n mockDeviceConnectionStateMachineFactory,\n mockDeviceApduSenderFactory,\n );\n }\n\n beforeEach(() => {\n initializeTransport();\n vi.useFakeTimers();\n });\n\n afterEach(() => {\n vi.restoreAllMocks();\n });\n\n const discoverDevice = (\n onSuccess: (discoveredDevice: TransportDiscoveredDevice) => void,\n onError?: (error: unknown) => void,\n ) => {\n transport.startDiscovering().subscribe({\n next: onSuccess,\n error: onError,\n });\n };\n\n describe(\"When WebHID API is not supported\", () => {\n it(\"should not support the transport\", () => {\n expect(transport.isSupported()).toBe(false);\n });\n\n it(\"should emit a startDiscovering error\", () =>\n new Promise<void>((resolve, reject) => {\n discoverDevice(\n () => {\n reject(\"Should not emit any value\");\n },\n (error) => {\n expect(error).toBeInstanceOf(WebHidTransportNotSupportedError);\n resolve();\n },\n );\n }));\n });\n\n describe(\"When WebHID API is supported\", () => {\n const mockedGetDevices = vi.fn();\n const mockedRequestDevice = vi.fn();\n\n const connectionEventsSubject = new Subject<HIDConnectionEvent>();\n const disconnectionEventsSubject = new Subject<HIDConnectionEvent>();\n\n function emitHIDConnectionEvent(device: HIDDevice) {\n connectionEventsSubject.next({\n device,\n } as HIDConnectionEvent);\n }\n\n function emitHIDDisconnectionEvent(device: HIDDevice) {\n disconnectionEventsSubject.next({\n device,\n } as HIDConnectionEvent);\n }\n\n beforeEach(() => {\n global.navigator = {\n hid: {\n getDevices: mockedGetDevices,\n requestDevice: mockedRequestDevice,\n addEventListener: (\n eventName: string,\n callback: (event: HIDConnectionEvent) => void,\n ) => {\n if (eventName === \"disconnect\") {\n disconnectionEventsSubject.subscribe(callback);\n } else if (eventName === \"connect\") {\n connectionEventsSubject.subscribe(callback);\n }\n },\n },\n } as unknown as Navigator;\n initializeTransport();\n });\n\n afterEach(() => {\n vi.clearAllMocks();\n global.navigator = undefined as unknown as Navigator;\n });\n\n it(\"should support the transport\", () => {\n expect(transport.isSupported()).toBe(true);\n });\n\n describe(\"startDiscovering\", () => {\n const testCases = usbDeviceModelDataSource\n .getAllDeviceModels()\n .flatMap((deviceModel) => {\n return [\n {\n testTitle: `should emit device if user grants access through hid.requestDevice (${deviceModel.productName})`,\n hidDevice: hidDeviceStubBuilder({\n productId: deviceModel.usbProductId << 8,\n productName: deviceModel.productName,\n }),\n expectedDeviceModel: deviceModel,\n },\n {\n testTitle: `should emit device if user grants access through hid.requestDevice (${deviceModel.productName}, bootloader)`,\n hidDevice: hidDeviceStubBuilder({\n productId: deviceModel.bootloaderUsbProductId,\n productName: deviceModel.productName,\n }),\n expectedDeviceModel: deviceModel,\n },\n ];\n });\n\n testCases.forEach((testCase) => {\n it(\n testCase.testTitle,\n () =>\n new Promise<void>((resolve, reject) => {\n mockedRequestDevice.mockResolvedValueOnce([testCase.hidDevice]);\n\n discoverDevice(\n (discoveredDevice) => {\n try {\n expect(discoveredDevice).toEqual(\n expect.objectContaining({\n deviceModel: testCase.expectedDeviceModel,\n }),\n );\n\n resolve();\n } catch (expectError) {\n reject(expectError as Error);\n }\n },\n (error) => {\n reject(error as Error);\n },\n );\n }),\n );\n });\n\n // It does not seem possible for a user to select several devices on the browser popup.\n // But if it was possible, we should emit them\n it(\"should emit devices if new grant accesses\", () =>\n new Promise<void>((resolve, reject) => {\n mockedRequestDevice.mockResolvedValueOnce([\n stubDevice,\n {\n ...stubDevice,\n productId: 0x5011,\n productName: \"Ledger Nano S Plus\",\n },\n ]);\n\n let count = 0;\n discoverDevice(\n (discoveredDevice) => {\n try {\n switch (count) {\n case 0:\n expect(discoveredDevice).toEqual(\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n productName: \"Ledger Nano X\",\n usbProductId: 0x40,\n }) as DeviceModel,\n }),\n );\n break;\n case 1:\n expect(discoveredDevice).toEqual(\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_SP,\n productName: \"Ledger Nano S Plus\",\n usbProductId: 0x50,\n }) as DeviceModel,\n }),\n );\n\n resolve();\n break;\n }\n\n count++;\n } catch (expectError) {\n reject(expectError as Error);\n }\n },\n (error) => {\n reject(error as Error);\n },\n );\n }));\n\n it(\"should throw DeviceNotRecognizedError if the device is not recognized\", () =>\n new Promise<void>((resolve, reject) => {\n mockedRequestDevice.mockResolvedValueOnce([\n {\n ...stubDevice,\n productId: 0x4242,\n },\n ]);\n\n discoverDevice(\n () => {\n reject(\"should not return a device\");\n },\n (error) => {\n expect(error).toBeInstanceOf(DeviceNotRecognizedError);\n resolve();\n },\n );\n }));\n\n it(\"should emit an error if the request device is in error\", () =>\n new Promise<void>((resolve, reject) => {\n const message = \"request device error\";\n mockedRequestDevice.mockImplementationOnce(() => {\n throw new Error(message);\n });\n\n discoverDevice(\n () => {\n reject(\"should not return a device\");\n },\n (error) => {\n expect(error).toBeInstanceOf(NoAccessibleDeviceError);\n expect(error).toStrictEqual(\n new NoAccessibleDeviceError(new Error(message)),\n );\n resolve();\n },\n );\n }));\n\n // [ASK] Is this the behavior we want when the user does not select any device ?\n it(\"should emit an error if the user did not grant us access to a device (clicking on cancel on the browser popup for ex)\", () =>\n new Promise<void>((resolve, reject) => {\n // When the user does not select any device, the `requestDevice` will return an empty array\n mockedRequestDevice.mockResolvedValueOnce([]);\n\n discoverDevice(\n (discoveredDevice) => {\n reject(\n `Should not emit any value, but emitted ${JSON.stringify(\n discoveredDevice,\n )}`,\n );\n },\n (error) => {\n try {\n expect(error).toBeInstanceOf(NoAccessibleDeviceError);\n resolve();\n } catch (expectError) {\n reject(expectError as Error);\n }\n },\n );\n }));\n\n it(\"should emit the same discoveredDevice object if its discovered twice in a row\", async () => {\n mockedRequestDevice.mockResolvedValue([stubDevice]);\n mockedGetDevices.mockResolvedValue([stubDevice]);\n\n const firstDiscoveredDevice = await new Promise<void>(\n (resolve, reject) => {\n discoverDevice(\n () => resolve(),\n (err) => reject(err),\n );\n },\n );\n const secondDiscoveredDevice = await new Promise<void>(\n (resolve, reject) => {\n discoverDevice(\n () => resolve(),\n (err) => reject(err),\n );\n },\n );\n expect(secondDiscoveredDevice).toBe(firstDiscoveredDevice);\n });\n });\n\n describe(\"destroy\", () => {\n it(\"should stop monitoring connections if the discovery process is halted\", () => {\n const abortSpy = vi.spyOn(AbortController.prototype, \"abort\");\n\n transport.destroy();\n\n expect(abortSpy).toHaveBeenCalled();\n });\n });\n\n describe(\"connect\", () => {\n it(\"should throw UnknownDeviceError if no internal device\", async () => {\n const connectParams = {\n deviceId: \"fake\",\n onDisconnect: vi.fn(),\n };\n\n const connect = await transport.connect(connectParams);\n\n expect(connect).toStrictEqual(\n Left(new UnknownDeviceError(\"Unknown device fake\")),\n );\n });\n\n it(\"should throw OpeningConnectionError if the device cannot be opened\", async () => {\n const message = \"cannot be opened\";\n mockDeviceApduSender.setupConnection.mockRejectedValue(\n new OpeningConnectionError(message),\n );\n mockedRequestDevice.mockResolvedValueOnce([stubDevice]);\n mockedGetDevices.mockResolvedValue([stubDevice]);\n\n const discoveredDevice = await lastValueFrom(\n transport.startDiscovering(),\n );\n const connected = await transport.connect({\n deviceId: discoveredDevice.id,\n onDisconnect: vi.fn(),\n });\n expect(connected).toStrictEqual(\n Left(new OpeningConnectionError(message)),\n );\n });\n\n it(\"should return a device if available\", async () => {\n mockedRequestDevice.mockResolvedValueOnce([stubDevice]);\n mockedGetDevices.mockResolvedValue([stubDevice]);\n\n const discoveredDevice = await lastValueFrom(\n transport.startDiscovering(),\n );\n const connected = await transport.connect({\n deviceId: discoveredDevice.id,\n onDisconnect: vi.fn(),\n });\n expect(connected.isRight()).toStrictEqual(true);\n expect(connected.extract()).toEqual(\n expect.objectContaining({ id: discoveredDevice.id }),\n );\n });\n\n it(\"should return an existing connected device\", async () => {\n mockedRequestDevice.mockResolvedValueOnce([stubDevice]);\n mockedGetDevices.mockResolvedValue([stubDevice]);\n\n const discoveredDevice = await lastValueFrom(\n transport.startDiscovering(),\n );\n await transport.connect({\n deviceId: discoveredDevice.id,\n onDisconnect: vi.fn(),\n });\n const connected = await transport.connect({\n deviceId: discoveredDevice.id,\n onDisconnect: vi.fn(),\n });\n expect(connected.isRight()).toStrictEqual(true);\n expect(connected.extract()).toEqual(\n expect.objectContaining({ id: discoveredDevice.id }),\n );\n });\n });\n\n describe(\"disconnect\", () => {\n it(\"should throw an error if the device is not connected\", async () => {\n // given\n const connectedDevice = connectedDeviceStubBuilder();\n\n // when\n const disconnect = await transport.disconnect({\n connectedDevice,\n });\n\n expect(disconnect).toStrictEqual(\n Left(new UnknownDeviceError(`Unknown device ${connectedDevice.id}`)),\n );\n });\n\n it(\"should disconnect if the device is connected\", async () => {\n mockedRequestDevice.mockResolvedValueOnce([stubDevice]);\n mockedGetDevices.mockResolvedValue([stubDevice]);\n\n const discoveredDevice = await lastValueFrom(\n transport.startDiscovering(),\n );\n const connected = await transport.connect({\n deviceId: discoveredDevice.id,\n onDisconnect: vi.fn(),\n });\n expect(connected.isRight()).toStrictEqual(true);\n const result = await transport.disconnect({\n connectedDevice: connected.unsafeCoerce(),\n });\n expect(result).toStrictEqual(Right(undefined));\n });\n\n it(\"should call disconnect handler if a connected device is unplugged\", async () => {\n // Get onTerminated for the first connection only\n let onTerminated1 = vi.fn();\n mockDeviceConnectionStateMachineFactory.mockImplementationOnce(\n (params) => {\n onTerminated1 = params.onTerminated;\n return {\n ...mockDeviceConnectionStateMachine,\n getDeviceId: vi.fn().mockReturnValue(params.deviceId),\n } as unknown as DeviceConnectionStateMachine<{ device: HIDDevice }>;\n },\n );\n\n // Add 2 discoverable devices\n const hidDevice1 = hidDeviceStubBuilder();\n const hidDevice2 = hidDeviceStubBuilder();\n mockedRequestDevice.mockResolvedValueOnce([hidDevice1, hidDevice2]);\n mockedGetDevices.mockResolvedValue([hidDevice1, hidDevice2]);\n\n // Connect the 2 devices\n const discoveredDevices = await lastValueFrom(\n transport.startDiscovering().pipe(toArray()),\n );\n expect(discoveredDevices.length).toStrictEqual(2);\n const onDisconnect1 = vi.fn();\n const connected1 = await transport.connect({\n deviceId: discoveredDevices[0]!.id,\n onDisconnect: onDisconnect1,\n });\n const onDisconnect2 = vi.fn();\n const connected2 = await transport.connect({\n deviceId: discoveredDevices[1]!.id,\n onDisconnect: onDisconnect2,\n });\n expect(connected1.isRight()).toStrictEqual(true);\n expect(connected2.isRight()).toStrictEqual(true);\n\n // unplug the first device\n onTerminated1();\n expect(onDisconnect1).toHaveBeenCalled();\n expect(onDisconnect2).not.toHaveBeenCalled();\n });\n\n it(\"should call disconnect handler if a connected device is unplugged while reconnecting\", async () => {\n // Get onTerminated for the first connection only\n let onTerminated1 = vi.fn();\n let tryToReconnect1 = vi.fn();\n mockDeviceConnectionStateMachineFactory.mockImplementationOnce(\n (params) => {\n onTerminated1 = params.onTerminated;\n tryToReconnect1 = params.tryToReconnect;\n return {\n ...mockDeviceConnectionStateMachine,\n getDeviceId: vi.fn().mockReturnValue(params.deviceId),\n } as unknown as DeviceConnectionStateMachine<{ device: HIDDevice }>;\n },\n );\n\n // Add 2 discoverable devices\n const hidDevice1 = hidDeviceStubBuilder();\n const hidDevice2 = hidDeviceStubBuilder();\n mockedRequestDevice.mockResolvedValueOnce([hidDevice1, hidDevice2]);\n mockedGetDevices.mockResolvedValue([hidDevice1, hidDevice2]);\n\n // Connect the 2 devices\n const discoveredDevices = await lastValueFrom(\n transport.startDiscovering().pipe(toArray()),\n );\n expect(discoveredDevices.length).toStrictEqual(2);\n const onDisconnect1 = vi.fn();\n const connected1 = await transport.connect({\n deviceId: discoveredDevices[0]!.id,\n onDisconnect: onDisconnect1,\n });\n const onDisconnect2 = vi.fn();\n const connected2 = await transport.connect({\n deviceId: discoveredDevices[1]!.id,\n onDisconnect: onDisconnect2,\n });\n expect(connected1.isRight()).toStrictEqual(true);\n expect(connected2.isRight()).toStrictEqual(true);\n\n // Try to reconnect the first device\n tryToReconnect1();\n\n // unplug the first device\n onTerminated1();\n expect(onDisconnect1).toHaveBeenCalled();\n expect(onDisconnect2).not.toHaveBeenCalled();\n });\n });\n\n describe(\"reconnect\", () => {\n it(\"should stop disconnection if reconnection happen\", () =>\n new Promise<void>((resolve, reject) => {\n // given\n const onDisconnect = vi.fn();\n let tryToReconnect = vi.fn();\n\n const hidDevice1 = hidDeviceStubBuilder();\n const hidDevice2 = hidDeviceStubBuilder();\n\n mockedRequestDevice.mockResolvedValueOnce([hidDevice1]);\n mockedGetDevices.mockResolvedValue([hidDevice1, hidDevice2]);\n mockDeviceConnectionStateMachineFactory.mockImplementationOnce(\n (params) => {\n tryToReconnect = params.tryToReconnect;\n return {\n ...mockDeviceConnectionStateMachine,\n getDeviceId: vi.fn().mockReturnValue(params.deviceId),\n getDependencies: params.deviceApduSender.getDependencies,\n setDependencies: params.deviceApduSender.setDependencies,\n } as unknown as DeviceConnectionStateMachine<{\n device: HIDDevice;\n }>;\n },\n );\n\n discoverDevice(async (discoveredDevice) => {\n try {\n await transport.connect({\n deviceId: discoveredDevice.id,\n onDisconnect,\n });\n\n /* Disconnection */\n emitHIDDisconnectionEvent(hidDevice1);\n expect(hidDevice1.close).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the hidDevice1.close promise is resolved\n expect(mockEventDeviceDisconnected).toHaveBeenCalled();\n\n tryToReconnect();\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT / 3);\n\n /* Reconnection */\n emitHIDConnectionEvent(hidDevice2);\n\n await Promise.resolve(); // wait for the next tick so the hidDevice2.open promise is resolved\n expect(mockEventDeviceConnected).toHaveBeenCalled();\n\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT);\n expect(onDisconnect).not.toHaveBeenCalled();\n resolve();\n } catch (error) {\n reject(error as Error);\n }\n });\n }));\n\n it(\"should be able to reconnect twice in a row if the device is unplugged and replugged twice\", () =>\n new Promise<void>((resolve, reject) => {\n // given\n const onDisconnect = vi.fn();\n let tryToReconnect = vi.fn();\n\n const hidDevice1 = hidDeviceStubBuilder();\n const hidDevice2 = hidDeviceStubBuilder();\n const hidDevice3 = hidDeviceStubBuilder();\n\n mockedRequestDevice.mockResolvedValueOnce([hidDevice1]);\n mockedGetDevices.mockResolvedValue([\n hidDevice1,\n hidDevice2,\n hidDevice3,\n ]);\n mockDeviceConnectionStateMachineFactory.mockImplementationOnce(\n (params) => {\n tryToReconnect = params.tryToReconnect;\n return {\n ...mockDeviceConnectionStateMachine,\n getDeviceId: vi.fn().mockReturnValue(params.deviceId),\n getDependencies: params.deviceApduSender.getDependencies,\n setDependencies: params.deviceApduSender.setDependencies,\n } as unknown as DeviceConnectionStateMachine<{\n device: HIDDevice;\n }>;\n },\n );\n\n // when\n discoverDevice(async (discoveredDevice) => {\n await transport.connect({\n deviceId: discoveredDevice.id,\n onDisconnect,\n });\n try {\n /* First disconnection */\n emitHIDDisconnectionEvent(hidDevice1);\n expect(hidDevice1.close).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the hidDevice1.close promise is resolved\n expect(mockEventDeviceDisconnected).toHaveBeenCalled();\n tryToReconnect();\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT / 3);\n\n /* First reconnection */\n emitHIDConnectionEvent(hidDevice2);\n\n await Promise.resolve(); // wait for the next tick so the hidDevice2.open promise is resolved\n expect(mockEventDeviceConnected).toHaveBeenCalled();\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT);\n expect(onDisconnect).not.toHaveBeenCalled();\n\n /* Second disconnection */\n emitHIDDisconnectionEvent(hidDevice2);\n expect(hidDevice2.close).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the hidDevice2.close promise is resolved\n expect(mockEventDeviceDisconnected).toHaveBeenCalled();\n tryToReconnect();\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT / 3);\n\n /* Second reconnection */\n emitHIDConnectionEvent(hidDevice3);\n\n await Promise.resolve(); // wait for the next tick so the hidDevice3.open promise is resolved\n expect(mockEventDeviceConnected).toHaveBeenCalled();\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT);\n expect(onDisconnect).not.toHaveBeenCalled();\n\n resolve();\n } catch (error) {\n reject(error as Error);\n }\n });\n }));\n });\n\n describe(\"Connection event typeguard\", () => {\n it(\"should validate type of an HIDConnectionEvent\", () => {\n // given\n const event = {\n device: stubDevice,\n } as HIDConnectionEvent;\n // when\n // @ts-expect-error trying to access private member\n const result = transport.isHIDConnectionEvent(event);\n // then\n expect(result).toBe(true);\n });\n\n it(\"should not validate type of another event\", () => {\n // given\n const event = new Event(\"disconnect\", {});\n // when\n // @ts-expect-error trying to access private member\n const result = transport.isHIDConnectionEvent(event);\n // then\n expect(result).toBe(false);\n });\n });\n\n describe(\"listenToAvailableDevices\", () => {\n it(\"should emit the devices already connected before listening\", async () => {\n // given\n const hidDevice = hidDeviceStubBuilder();\n mockedGetDevices.mockResolvedValue([hidDevice]);\n\n const onComplete = vi.fn();\n const onError = vi.fn();\n\n let observedDevices: TransportDiscoveredDevice[] = [];\n // when\n transport.listenToAvailableDevices().subscribe({\n next: (knownDevices) => {\n observedDevices = knownDevices;\n },\n complete: onComplete,\n error: onError,\n });\n\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n }) as TransportDeviceModel,\n }),\n ]);\n expect(onComplete).not.toHaveBeenCalled();\n expect(onError).not.toHaveBeenCalled();\n });\n\n it(\"should emit the new list of devices after connection and disconnection events\", async () => {\n initializeTransport();\n // given\n const hidDevice1 = hidDeviceStubBuilder({\n productId:\n usbDeviceModelDataSource.getDeviceModel({\n id: DeviceModelId.NANO_X,\n }).usbProductId << 8,\n });\n const hidDevice2 = hidDeviceStubBuilder({\n productId:\n usbDeviceModelDataSource.getDeviceModel({ id: DeviceModelId.STAX })\n .usbProductId << 8,\n });\n mockedGetDevices.mockResolvedValue([hidDevice1]);\n\n const onComplete = vi.fn();\n const onError = vi.fn();\n\n let observedDevices: TransportDiscoveredDevice[] = [];\n // when\n transport.listenToAvailableDevices().subscribe({\n next: (knownDevices) => {\n observedDevices = knownDevices;\n },\n complete: onComplete,\n error: onError,\n });\n\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n }) as TransportDeviceModel,\n }),\n ]);\n\n // When a new device is connected\n mockedGetDevices.mockResolvedValue([hidDevice1, hidDevice2]);\n emitHIDConnectionEvent(hidDevice2);\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n }) as TransportDeviceModel,\n }),\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.STAX,\n }) as TransportDeviceModel,\n }),\n ]);\n\n // When a device is disconnected\n mockedGetDevices.mockResolvedValue([hidDevice2]);\n emitHIDDisconnectionEvent(hidDevice1);\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.STAX,\n }) as TransportDeviceModel,\n }),\n ]);\n\n expect(onComplete).not.toHaveBeenCalled();\n expect(onError).not.toHaveBeenCalled();\n });\n\n it(\"should preserve DeviceId in case the device has been disconnected and reconnected before the timeout\", async () => {\n // given\n const hidDevice = hidDeviceStubBuilder();\n\n mockedGetDevices.mockResolvedValue([hidDevice]);\n\n const onComplete = vi.fn();\n const onError = vi.fn();\n let observedDevices: TransportDiscoveredDevice[] = [];\n // when\n transport.listenToAvailableDevices().subscribe({\n next: (knownDevices) => {\n observedDevices = knownDevices;\n },\n complete: onComplete,\n error: onError,\n });\n\n await flushPromises();\n\n const firstObservedDeviceId = observedDevices[0]?.id;\n expect(firstObservedDeviceId).toBeTruthy();\n expect(observedDevices[0]?.deviceModel?.id).toBe(DeviceModelId.NANO_X);\n\n // Start a connection with the device\n await transport.connect({\n deviceId: observedDevices[0]!.id,\n onDisconnect: vi.fn(),\n });\n await flushPromises();\n\n // When the device is disconnected\n mockedGetDevices.mockResolvedValue([]);\n emitHIDDisconnectionEvent(hidDevice);\n await flushPromises();\n\n expect(observedDevices).toEqual([]);\n\n // When the device is reconnected\n mockedGetDevices.mockResolvedValue([hidDevice]);\n emitHIDConnectionEvent(hidDevice);\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n }) as TransportDeviceModel,\n }),\n ]);\n\n expect(observedDevices[0]?.id).toBeTruthy();\n expect(observedDevices[0]?.id).toBe(firstObservedDeviceId);\n });\n });\n });\n});\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/* eslint @typescript-eslint/consistent-type-imports: off */\nimport {\n type ApduReceiverServiceFactory,\n type ApduResponse,\n type ApduSenderServiceFactory,\n connectedDeviceStubBuilder,\n DeviceConnectionStateMachine,\n type DeviceConnectionStateMachineParams,\n type DeviceModel,\n DeviceModelId,\n DeviceNotRecognizedError,\n type LoggerPublisherService,\n type LoggerSubscriberService,\n NoAccessibleDeviceError,\n OpeningConnectionError,\n StaticDeviceModelDataSource,\n type TransportDeviceModel,\n type TransportDiscoveredDevice,\n UnknownDeviceError,\n} from \"@ledgerhq/device-management-kit\";\nimport { Left, Right } from \"purify-ts\";\nimport { lastValueFrom, Subject, toArray } from \"rxjs\";\n\nimport { RECONNECT_DEVICE_TIMEOUT } from \"@api/data/WebHidConfig\";\nimport { WebHidTransportNotSupportedError } from \"@api/model/Errors\";\nimport { hidDeviceStubBuilder } from \"@api/model/HIDDevice.stub\";\n\nimport { WebHidApduSender } from \"./WebHidApduSender\";\nimport { WebHidTransport } from \"./WebHidTransport\";\n\nclass LoggerPublisherServiceStub implements LoggerPublisherService {\n constructor(subscribers: LoggerSubscriberService[], tag: string) {\n this.subscribers = subscribers;\n this.tag = tag;\n }\n subscribers: LoggerSubscriberService[] = [];\n tag: string = \"\";\n error = vi.fn();\n warn = vi.fn();\n info = vi.fn();\n debug = vi.fn();\n}\n\n// Our StaticDeviceModelDataSource can directly be used in our unit tests\nconst usbDeviceModelDataSource = new StaticDeviceModelDataSource();\nconst logger = new LoggerPublisherServiceStub([], \"web-usb-hid\");\n\nconst stubDevice: HIDDevice = hidDeviceStubBuilder();\n\n/**\n * Flushes all pending promises\n */\nconst flushPromises = async () => {\n const timers = await vi.importActual<typeof import(\"timers\")>(\"timers\");\n return new Promise(timers.setImmediate);\n};\n\ndescribe(\"WebHidTransport\", () => {\n let transport: WebHidTransport;\n let apduReceiverServiceFactoryStub: ApduReceiverServiceFactory;\n let apduSenderServiceFactoryStub: ApduSenderServiceFactory;\n\n let mockDeviceConnectionStateMachineFactory = vi.fn();\n const mockEventDeviceConnected = vi.fn();\n const mockEventDeviceDisconnected = vi.fn();\n\n const mockDeviceApduSender = {\n sendApdu: vi.fn().mockResolvedValue(\n Right({\n data: new Uint8Array(),\n statusCode: new Uint8Array([0x90, 0x00]),\n } as ApduResponse),\n ),\n getDependencies: vi.fn().mockReturnValue({ device: stubDevice }),\n setDependencies: vi.fn(),\n closeConnection: vi.fn(),\n setupConnection: vi.fn(),\n };\n\n const mockDeviceConnectionStateMachine = {\n getDependencies: vi.fn().mockReturnValue({ device: stubDevice }),\n setDependencies: vi.fn(),\n getDeviceId: vi.fn(),\n sendApdu: vi.fn().mockResolvedValue(\n Right({\n data: new Uint8Array(),\n statusCode: new Uint8Array([0x90, 0x00]),\n } as ApduResponse),\n ),\n setupConnection: vi.fn(),\n eventDeviceConnected: mockEventDeviceConnected,\n eventDeviceDisconnected: mockEventDeviceDisconnected,\n closeConnection: vi.fn(),\n };\n\n function initializeTransport() {\n apduReceiverServiceFactoryStub = vi.fn();\n apduSenderServiceFactoryStub = vi.fn();\n mockDeviceConnectionStateMachineFactory = vi.fn(\n (params: DeviceConnectionStateMachineParams<{ device: HIDDevice }>) => {\n return {\n ...mockDeviceConnectionStateMachine,\n getDeviceId: vi.fn().mockReturnValue(params.deviceId),\n getDependencies: params.deviceApduSender.getDependencies,\n setDependencies: params.deviceApduSender.setDependencies,\n } as unknown as DeviceConnectionStateMachine<{ device: HIDDevice }>;\n },\n );\n const mockDeviceApduSenderFactory = vi.fn((params) => {\n return {\n ...mockDeviceApduSender,\n getDependencies: () => params.dependencies,\n setDependencies: (dependencies: { device: HIDDevice }) =>\n (params.dependencies = dependencies),\n } as unknown as WebHidApduSender;\n });\n transport = new WebHidTransport(\n usbDeviceModelDataSource,\n () => logger,\n apduSenderServiceFactoryStub,\n apduReceiverServiceFactoryStub,\n mockDeviceConnectionStateMachineFactory,\n mockDeviceApduSenderFactory,\n );\n }\n\n beforeEach(() => {\n initializeTransport();\n vi.useFakeTimers();\n });\n\n afterEach(() => {\n vi.restoreAllMocks();\n });\n\n const discoverDevice = (\n onSuccess: (discoveredDevice: TransportDiscoveredDevice) => void,\n onError?: (error: unknown) => void,\n ) => {\n transport.startDiscovering().subscribe({\n next: onSuccess,\n error: onError,\n });\n };\n\n describe(\"When WebHID API is not supported\", () => {\n it(\"should not support the transport\", () => {\n expect(transport.isSupported()).toBe(false);\n });\n\n it(\"should emit a startDiscovering error\", () =>\n new Promise<void>((resolve, reject) => {\n discoverDevice(\n () => {\n reject(\"Should not emit any value\");\n },\n (error) => {\n expect(error).toBeInstanceOf(WebHidTransportNotSupportedError);\n resolve();\n },\n );\n }));\n });\n\n describe(\"When WebHID API is supported\", () => {\n const mockedGetDevices = vi.fn();\n const mockedRequestDevice = vi.fn();\n\n const connectionEventsSubject = new Subject<HIDConnectionEvent>();\n const disconnectionEventsSubject = new Subject<HIDConnectionEvent>();\n\n function emitHIDConnectionEvent(device: HIDDevice) {\n connectionEventsSubject.next({\n device,\n } as HIDConnectionEvent);\n }\n\n function emitHIDDisconnectionEvent(device: HIDDevice) {\n disconnectionEventsSubject.next({\n device,\n } as HIDConnectionEvent);\n }\n\n beforeEach(() => {\n global.navigator = {\n hid: {\n getDevices: mockedGetDevices,\n requestDevice: mockedRequestDevice,\n addEventListener: (\n eventName: string,\n callback: (event: HIDConnectionEvent) => void,\n ) => {\n if (eventName === \"disconnect\") {\n disconnectionEventsSubject.subscribe(callback);\n } else if (eventName === \"connect\") {\n connectionEventsSubject.subscribe(callback);\n }\n },\n },\n } as unknown as Navigator;\n initializeTransport();\n });\n\n afterEach(() => {\n vi.clearAllMocks();\n global.navigator = undefined as unknown as Navigator;\n });\n\n it(\"should support the transport\", () => {\n expect(transport.isSupported()).toBe(true);\n });\n\n describe(\"startDiscovering\", () => {\n const testCases = usbDeviceModelDataSource\n .getAllDeviceModels()\n .flatMap((deviceModel) => {\n return [\n {\n testTitle: `should emit device if user grants access through hid.requestDevice (${deviceModel.productName})`,\n hidDevice: hidDeviceStubBuilder({\n productId: deviceModel.usbProductId << 8,\n productName: deviceModel.productName,\n }),\n expectedDeviceModel: deviceModel,\n },\n {\n testTitle: `should emit device if user grants access through hid.requestDevice (${deviceModel.productName}, bootloader)`,\n hidDevice: hidDeviceStubBuilder({\n productId: deviceModel.bootloaderUsbProductId,\n productName: deviceModel.productName,\n }),\n expectedDeviceModel: deviceModel,\n },\n ];\n });\n\n testCases.forEach((testCase) => {\n it(\n testCase.testTitle,\n () =>\n new Promise<void>((resolve, reject) => {\n mockedRequestDevice.mockResolvedValueOnce([testCase.hidDevice]);\n\n discoverDevice(\n (discoveredDevice) => {\n try {\n expect(discoveredDevice).toEqual(\n expect.objectContaining({\n deviceModel: testCase.expectedDeviceModel,\n }),\n );\n\n resolve();\n } catch (expectError) {\n reject(expectError as Error);\n }\n },\n (error) => {\n reject(error as Error);\n },\n );\n }),\n );\n });\n\n // It does not seem possible for a user to select several devices on the browser popup.\n // But if it was possible, we should emit them\n it(\"should emit devices if new grant accesses\", () =>\n new Promise<void>((resolve, reject) => {\n mockedRequestDevice.mockResolvedValueOnce([\n stubDevice,\n {\n ...stubDevice,\n productId: 0x5011,\n productName: \"Ledger Nano S Plus\",\n },\n ]);\n\n let count = 0;\n discoverDevice(\n (discoveredDevice) => {\n try {\n switch (count) {\n case 0:\n expect(discoveredDevice).toEqual(\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n productName: \"Ledger Nano X\",\n usbProductId: 0x40,\n }) as DeviceModel,\n }),\n );\n break;\n case 1:\n expect(discoveredDevice).toEqual(\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_SP,\n productName: \"Ledger Nano S Plus\",\n usbProductId: 0x50,\n }) as DeviceModel,\n }),\n );\n\n resolve();\n break;\n }\n\n count++;\n } catch (expectError) {\n reject(expectError as Error);\n }\n },\n (error) => {\n reject(error as Error);\n },\n );\n }));\n\n it(\"should throw DeviceNotRecognizedError if the device is not recognized\", () =>\n new Promise<void>((resolve, reject) => {\n mockedRequestDevice.mockResolvedValueOnce([\n {\n ...stubDevice,\n productId: 0x4242,\n },\n ]);\n\n discoverDevice(\n () => {\n reject(\"should not return a device\");\n },\n (error) => {\n expect(error).toBeInstanceOf(DeviceNotRecognizedError);\n resolve();\n },\n );\n }));\n\n it(\"should emit an error if the request device is in error\", () =>\n new Promise<void>((resolve, reject) => {\n const message = \"request device error\";\n mockedRequestDevice.mockImplementationOnce(() => {\n throw new Error(message);\n });\n\n discoverDevice(\n () => {\n reject(\"should not return a device\");\n },\n (error) => {\n expect(error).toBeInstanceOf(NoAccessibleDeviceError);\n expect(error).toStrictEqual(\n new NoAccessibleDeviceError(new Error(message)),\n );\n resolve();\n },\n );\n }));\n\n // [ASK] Is this the behavior we want when the user does not select any device ?\n it(\"should emit an error if the user did not grant us access to a device (clicking on cancel on the browser popup for ex)\", () =>\n new Promise<void>((resolve, reject) => {\n // When the user does not select any device, the `requestDevice` will return an empty array\n mockedRequestDevice.mockResolvedValueOnce([]);\n\n discoverDevice(\n (discoveredDevice) => {\n reject(\n `Should not emit any value, but emitted ${JSON.stringify(\n discoveredDevice,\n )}`,\n );\n },\n (error) => {\n try {\n expect(error).toBeInstanceOf(NoAccessibleDeviceError);\n resolve();\n } catch (expectError) {\n reject(expectError as Error);\n }\n },\n );\n }));\n\n it(\"should emit the same discoveredDevice object if its discovered twice in a row\", async () => {\n mockedRequestDevice.mockResolvedValue([stubDevice]);\n mockedGetDevices.mockResolvedValue([stubDevice]);\n\n const firstDiscoveredDevice = await new Promise<void>(\n (resolve, reject) => {\n discoverDevice(\n () => resolve(),\n (err) => reject(err),\n );\n },\n );\n const secondDiscoveredDevice = await new Promise<void>(\n (resolve, reject) => {\n discoverDevice(\n () => resolve(),\n (err) => reject(err),\n );\n },\n );\n expect(secondDiscoveredDevice).toBe(firstDiscoveredDevice);\n });\n });\n\n describe(\"destroy\", () => {\n it(\"should stop monitoring connections if the discovery process is halted\", () => {\n const abortSpy = vi.spyOn(AbortController.prototype, \"abort\");\n\n transport.destroy();\n\n expect(abortSpy).toHaveBeenCalled();\n });\n });\n\n describe(\"connect\", () => {\n it(\"should throw UnknownDeviceError if no internal device\", async () => {\n const connectParams = {\n deviceId: \"fake\",\n onDisconnect: vi.fn(),\n };\n\n const connect = await transport.connect(connectParams);\n\n expect(connect).toStrictEqual(\n Left(new UnknownDeviceError(\"Unknown device fake\")),\n );\n });\n\n it(\"should throw OpeningConnectionError if the device cannot be opened\", async () => {\n const message = \"cannot be opened\";\n mockDeviceApduSender.setupConnection.mockRejectedValue(\n new OpeningConnectionError(message),\n );\n mockedRequestDevice.mockResolvedValueOnce([stubDevice]);\n mockedGetDevices.mockResolvedValue([stubDevice]);\n\n const discoveredDevice = await lastValueFrom(\n transport.startDiscovering(),\n );\n const connected = await transport.connect({\n deviceId: discoveredDevice.id,\n onDisconnect: vi.fn(),\n });\n expect(connected).toStrictEqual(\n Left(new OpeningConnectionError(message)),\n );\n });\n\n it(\"should return a device if available\", async () => {\n mockedRequestDevice.mockResolvedValueOnce([stubDevice]);\n mockedGetDevices.mockResolvedValue([stubDevice]);\n\n const discoveredDevice = await lastValueFrom(\n transport.startDiscovering(),\n );\n const connected = await transport.connect({\n deviceId: discoveredDevice.id,\n onDisconnect: vi.fn(),\n });\n expect(connected.isRight()).toStrictEqual(true);\n expect(connected.extract()).toEqual(\n expect.objectContaining({ id: discoveredDevice.id }),\n );\n });\n\n it(\"should return an existing connected device\", async () => {\n mockedRequestDevice.mockResolvedValueOnce([stubDevice]);\n mockedGetDevices.mockResolvedValue([stubDevice]);\n\n const discoveredDevice = await lastValueFrom(\n transport.startDiscovering(),\n );\n await transport.connect({\n deviceId: discoveredDevice.id,\n onDisconnect: vi.fn(),\n });\n const connected = await transport.connect({\n deviceId: discoveredDevice.id,\n onDisconnect: vi.fn(),\n });\n expect(connected.isRight()).toStrictEqual(true);\n expect(connected.extract()).toEqual(\n expect.objectContaining({ id: discoveredDevice.id }),\n );\n });\n });\n\n describe(\"disconnect\", () => {\n it(\"should throw an error if the device is not connected\", async () => {\n // given\n const connectedDevice = connectedDeviceStubBuilder();\n\n // when\n const disconnect = await transport.disconnect({\n connectedDevice,\n });\n\n expect(disconnect).toStrictEqual(\n Left(new UnknownDeviceError(`Unknown device ${connectedDevice.id}`)),\n );\n });\n\n it(\"should disconnect if the device is connected\", async () => {\n mockedRequestDevice.mockResolvedValueOnce([stubDevice]);\n mockedGetDevices.mockResolvedValue([stubDevice]);\n\n const discoveredDevice = await lastValueFrom(\n transport.startDiscovering(),\n );\n const connected = await transport.connect({\n deviceId: discoveredDevice.id,\n onDisconnect: vi.fn(),\n });\n expect(connected.isRight()).toStrictEqual(true);\n const result = await transport.disconnect({\n connectedDevice: connected.unsafeCoerce(),\n });\n expect(result).toStrictEqual(Right(undefined));\n });\n\n it(\"should call disconnect handler if a connected device is unplugged\", async () => {\n // Get onTerminated for the first connection only\n let onTerminated1 = vi.fn();\n mockDeviceConnectionStateMachineFactory.mockImplementationOnce(\n (params) => {\n onTerminated1 = params.onTerminated;\n return {\n ...mockDeviceConnectionStateMachine,\n getDeviceId: vi.fn().mockReturnValue(params.deviceId),\n } as unknown as DeviceConnectionStateMachine<{ device: HIDDevice }>;\n },\n );\n\n // Add 2 discoverable devices\n const hidDevice1 = hidDeviceStubBuilder();\n const hidDevice2 = hidDeviceStubBuilder();\n mockedRequestDevice.mockResolvedValueOnce([hidDevice1, hidDevice2]);\n mockedGetDevices.mockResolvedValue([hidDevice1, hidDevice2]);\n\n // Connect the 2 devices\n const discoveredDevices = await lastValueFrom(\n transport.startDiscovering().pipe(toArray()),\n );\n expect(discoveredDevices.length).toStrictEqual(2);\n const onDisconnect1 = vi.fn();\n const connected1 = await transport.connect({\n deviceId: discoveredDevices[0]!.id,\n onDisconnect: onDisconnect1,\n });\n const onDisconnect2 = vi.fn();\n const connected2 = await transport.connect({\n deviceId: discoveredDevices[1]!.id,\n onDisconnect: onDisconnect2,\n });\n expect(connected1.isRight()).toStrictEqual(true);\n expect(connected2.isRight()).toStrictEqual(true);\n\n // unplug the first device\n onTerminated1();\n expect(onDisconnect1).toHaveBeenCalled();\n expect(onDisconnect2).not.toHaveBeenCalled();\n });\n\n it(\"should call disconnect handler if a connected device is unplugged while reconnecting\", async () => {\n // Get onTerminated for the first connection only\n let onTerminated1 = vi.fn();\n let tryToReconnect1 = vi.fn();\n mockDeviceConnectionStateMachineFactory.mockImplementationOnce(\n (params) => {\n onTerminated1 = params.onTerminated;\n tryToReconnect1 = params.tryToReconnect;\n return {\n ...mockDeviceConnectionStateMachine,\n getDeviceId: vi.fn().mockReturnValue(params.deviceId),\n } as unknown as DeviceConnectionStateMachine<{ device: HIDDevice }>;\n },\n );\n\n // Add 2 discoverable devices\n const hidDevice1 = hidDeviceStubBuilder();\n const hidDevice2 = hidDeviceStubBuilder();\n mockedRequestDevice.mockResolvedValueOnce([hidDevice1, hidDevice2]);\n mockedGetDevices.mockResolvedValue([hidDevice1, hidDevice2]);\n\n // Connect the 2 devices\n const discoveredDevices = await lastValueFrom(\n transport.startDiscovering().pipe(toArray()),\n );\n expect(discoveredDevices.length).toStrictEqual(2);\n const onDisconnect1 = vi.fn();\n const connected1 = await transport.connect({\n deviceId: discoveredDevices[0]!.id,\n onDisconnect: onDisconnect1,\n });\n const onDisconnect2 = vi.fn();\n const connected2 = await transport.connect({\n deviceId: discoveredDevices[1]!.id,\n onDisconnect: onDisconnect2,\n });\n expect(connected1.isRight()).toStrictEqual(true);\n expect(connected2.isRight()).toStrictEqual(true);\n\n // Try to reconnect the first device\n tryToReconnect1();\n\n // unplug the first device\n onTerminated1();\n expect(onDisconnect1).toHaveBeenCalled();\n expect(onDisconnect2).not.toHaveBeenCalled();\n });\n });\n\n describe(\"reconnect\", () => {\n it(\"should stop disconnection if reconnection happen\", () =>\n new Promise<void>((resolve, reject) => {\n // given\n const onDisconnect = vi.fn();\n let tryToReconnect = vi.fn();\n\n const hidDevice1 = hidDeviceStubBuilder();\n const hidDevice2 = hidDeviceStubBuilder();\n\n mockedRequestDevice.mockResolvedValueOnce([hidDevice1]);\n mockedGetDevices.mockResolvedValue([hidDevice1, hidDevice2]);\n mockDeviceConnectionStateMachineFactory.mockImplementationOnce(\n (params) => {\n tryToReconnect = params.tryToReconnect;\n return {\n ...mockDeviceConnectionStateMachine,\n getDeviceId: vi.fn().mockReturnValue(params.deviceId),\n getDependencies: params.deviceApduSender.getDependencies,\n setDependencies: params.deviceApduSender.setDependencies,\n } as unknown as DeviceConnectionStateMachine<{\n device: HIDDevice;\n }>;\n },\n );\n\n discoverDevice(async (discoveredDevice) => {\n try {\n await transport.connect({\n deviceId: discoveredDevice.id,\n onDisconnect,\n });\n\n /* Disconnection */\n emitHIDDisconnectionEvent(hidDevice1);\n expect(hidDevice1.close).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the hidDevice1.close promise is resolved\n expect(mockEventDeviceDisconnected).toHaveBeenCalled();\n\n tryToReconnect();\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT / 3);\n\n /* Reconnection */\n emitHIDConnectionEvent(hidDevice2);\n\n await Promise.resolve(); // wait for the next tick so the hidDevice2.open promise is resolved\n expect(mockEventDeviceConnected).toHaveBeenCalled();\n\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT);\n expect(onDisconnect).not.toHaveBeenCalled();\n resolve();\n } catch (error) {\n reject(error as Error);\n }\n });\n }));\n\n it(\"should be able to reconnect twice in a row if the device is unplugged and replugged twice\", () =>\n new Promise<void>((resolve, reject) => {\n // given\n const onDisconnect = vi.fn();\n let tryToReconnect = vi.fn();\n\n const hidDevice1 = hidDeviceStubBuilder();\n const hidDevice2 = hidDeviceStubBuilder();\n const hidDevice3 = hidDeviceStubBuilder();\n\n mockedRequestDevice.mockResolvedValueOnce([hidDevice1]);\n mockedGetDevices.mockResolvedValue([\n hidDevice1,\n hidDevice2,\n hidDevice3,\n ]);\n mockDeviceConnectionStateMachineFactory.mockImplementationOnce(\n (params) => {\n tryToReconnect = params.tryToReconnect;\n return {\n ...mockDeviceConnectionStateMachine,\n getDeviceId: vi.fn().mockReturnValue(params.deviceId),\n getDependencies: params.deviceApduSender.getDependencies,\n setDependencies: params.deviceApduSender.setDependencies,\n } as unknown as DeviceConnectionStateMachine<{\n device: HIDDevice;\n }>;\n },\n );\n\n // when\n discoverDevice(async (discoveredDevice) => {\n await transport.connect({\n deviceId: discoveredDevice.id,\n onDisconnect,\n });\n try {\n /* First disconnection */\n emitHIDDisconnectionEvent(hidDevice1);\n expect(hidDevice1.close).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the hidDevice1.close promise is resolved\n expect(mockEventDeviceDisconnected).toHaveBeenCalled();\n tryToReconnect();\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT / 3);\n\n /* First reconnection */\n emitHIDConnectionEvent(hidDevice2);\n\n await Promise.resolve(); // wait for the next tick so the hidDevice2.open promise is resolved\n expect(mockEventDeviceConnected).toHaveBeenCalled();\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT);\n expect(onDisconnect).not.toHaveBeenCalled();\n\n /* Second disconnection */\n emitHIDDisconnectionEvent(hidDevice2);\n expect(hidDevice2.close).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the hidDevice2.close promise is resolved\n expect(mockEventDeviceDisconnected).toHaveBeenCalled();\n tryToReconnect();\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT / 3);\n\n /* Second reconnection */\n emitHIDConnectionEvent(hidDevice3);\n\n await Promise.resolve(); // wait for the next tick so the hidDevice3.open promise is resolved\n expect(mockEventDeviceConnected).toHaveBeenCalled();\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT);\n expect(onDisconnect).not.toHaveBeenCalled();\n\n resolve();\n } catch (error) {\n reject(error as Error);\n }\n });\n }));\n });\n\n describe(\"Connection event typeguard\", () => {\n it(\"should validate type of an HIDConnectionEvent\", () => {\n // given\n const event = {\n device: stubDevice,\n } as HIDConnectionEvent;\n // when\n // @ts-expect-error trying to access private member\n const result = transport.isHIDConnectionEvent(event);\n // then\n expect(result).toBe(true);\n });\n\n it(\"should not validate type of another event\", () => {\n // given\n const event = new Event(\"disconnect\", {});\n // when\n // @ts-expect-error trying to access private member\n const result = transport.isHIDConnectionEvent(event);\n // then\n expect(result).toBe(false);\n });\n });\n\n describe(\"listenToAvailableDevices\", () => {\n it(\"should emit the devices already connected before listening\", async () => {\n // given\n const hidDevice = hidDeviceStubBuilder();\n mockedGetDevices.mockResolvedValue([hidDevice]);\n\n const onComplete = vi.fn();\n const onError = vi.fn();\n\n let observedDevices: TransportDiscoveredDevice[] = [];\n // when\n transport.listenToAvailableDevices().subscribe({\n next: (knownDevices) => {\n observedDevices = knownDevices;\n },\n complete: onComplete,\n error: onError,\n });\n\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n }) as TransportDeviceModel,\n }),\n ]);\n expect(onComplete).not.toHaveBeenCalled();\n expect(onError).not.toHaveBeenCalled();\n });\n\n it(\"should emit the new list of devices after connection and disconnection events\", async () => {\n initializeTransport();\n // given\n const hidDevice1 = hidDeviceStubBuilder({\n productId:\n usbDeviceModelDataSource.getDeviceModel({\n id: DeviceModelId.NANO_X,\n }).usbProductId << 8,\n });\n const hidDevice2 = hidDeviceStubBuilder({\n productId:\n usbDeviceModelDataSource.getDeviceModel({ id: DeviceModelId.STAX })\n .usbProductId << 8,\n });\n mockedGetDevices.mockResolvedValue([hidDevice1]);\n\n const onComplete = vi.fn();\n const onError = vi.fn();\n\n let observedDevices: TransportDiscoveredDevice[] = [];\n // when\n transport.listenToAvailableDevices().subscribe({\n next: (knownDevices) => {\n observedDevices = knownDevices;\n },\n complete: onComplete,\n error: onError,\n });\n\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n }) as TransportDeviceModel,\n }),\n ]);\n\n // When a new device is connected\n mockedGetDevices.mockResolvedValue([hidDevice1, hidDevice2]);\n emitHIDConnectionEvent(hidDevice2);\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n }) as TransportDeviceModel,\n }),\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.STAX,\n }) as TransportDeviceModel,\n }),\n ]);\n\n // When a device is disconnected\n mockedGetDevices.mockResolvedValue([hidDevice2]);\n emitHIDDisconnectionEvent(hidDevice1);\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.STAX,\n }) as TransportDeviceModel,\n }),\n ]);\n\n expect(onComplete).not.toHaveBeenCalled();\n expect(onError).not.toHaveBeenCalled();\n });\n\n it(\"should preserve DeviceId in case the device has been disconnected and reconnected before the timeout\", async () => {\n // given\n const hidDevice = hidDeviceStubBuilder();\n\n mockedGetDevices.mockResolvedValue([hidDevice]);\n\n const onComplete = vi.fn();\n const onError = vi.fn();\n let observedDevices: TransportDiscoveredDevice[] = [];\n // when\n transport.listenToAvailableDevices().subscribe({\n next: (knownDevices) => {\n observedDevices = knownDevices;\n },\n complete: onComplete,\n error: onError,\n });\n\n await flushPromises();\n\n const firstObservedDeviceId = observedDevices[0]?.id;\n expect(firstObservedDeviceId).toBeTruthy();\n expect(observedDevices[0]?.deviceModel?.id).toBe(DeviceModelId.NANO_X);\n\n // Start a connection with the device\n await transport.connect({\n deviceId: observedDevices[0]!.id,\n onDisconnect: vi.fn(),\n });\n await flushPromises();\n\n // When the device is disconnected\n mockedGetDevices.mockResolvedValue([]);\n emitHIDDisconnectionEvent(hidDevice);\n await flushPromises();\n\n expect(observedDevices).toEqual([]);\n\n // When the device is reconnected\n mockedGetDevices.mockResolvedValue([hidDevice]);\n emitHIDConnectionEvent(hidDevice);\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n }) as TransportDeviceModel,\n }),\n ]);\n\n expect(observedDevices[0]?.id).toBeTruthy();\n expect(observedDevices[0]?.id).toBe(firstObservedDeviceId);\n });\n });\n });\n});\n"],
5
+ "mappings": "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",
6
6
  "names": ["connectedDeviceStubBuilder", "DeviceModelId", "DeviceNotRecognizedError", "NoAccessibleDeviceError", "OpeningConnectionError", "StaticDeviceModelDataSource", "UnknownDeviceError", "Left", "Right", "lastValueFrom", "Subject", "toArray", "RECONNECT_DEVICE_TIMEOUT", "WebHidTransportNotSupportedError", "hidDeviceStubBuilder", "WebHidTransport", "LoggerPublisherServiceStub", "subscribers", "tag", "usbDeviceModelDataSource", "logger", "stubDevice", "flushPromises", "timers", "transport", "apduReceiverServiceFactoryStub", "apduSenderServiceFactoryStub", "mockDeviceConnectionStateMachineFactory", "mockEventDeviceConnected", "mockEventDeviceDisconnected", "mockDeviceApduSender", "mockDeviceConnectionStateMachine", "initializeTransport", "params", "mockDeviceApduSenderFactory", "dependencies", "discoverDevice", "onSuccess", "onError", "resolve", "reject", "error", "mockedGetDevices", "mockedRequestDevice", "connectionEventsSubject", "disconnectionEventsSubject", "emitHIDConnectionEvent", "device", "emitHIDDisconnectionEvent", "eventName", "callback", "deviceModel", "testCase", "discoveredDevice", "expectError", "count", "message", "firstDiscoveredDevice", "err", "secondDiscoveredDevice", "abortSpy", "connectParams", "connect", "connected", "connectedDevice", "disconnect", "result", "onTerminated1", "hidDevice1", "hidDevice2", "discoveredDevices", "onDisconnect1", "connected1", "onDisconnect2", "connected2", "tryToReconnect1", "onDisconnect", "tryToReconnect", "hidDevice3", "event", "hidDevice", "onComplete", "observedDevices", "knownDevices", "firstObservedDeviceId"]
7
7
  }
@@ -1,34 +1,4 @@
1
1
  {
2
- "name": "@ledgerhq/device-transport-kit-web-hid",
3
- "version": "1.2.0",
4
- "license": "Apache-2.0",
5
- "private": false,
6
- "exports": {
7
- ".": {
8
- "types": "./lib/types/index.d.ts",
9
- "import": "./lib/esm/index.js"
10
- }
11
- },
12
- "files": [
13
- "./lib",
14
- "package.json"
15
- ],
16
- "scripts": {
17
- "prebuild": "rimraf lib",
18
- "build": "pnpm ldmk-tool build --entryPoints src/index.ts,src/**/*.ts --tsconfig tsconfig.prod.json --platform web",
19
- "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
- "lint": "eslint",
23
- "lint:fix": "pnpm lint --fix",
24
- "postpack": "find . -name '*.tgz' -exec cp {} ../../../dist/ \\; ",
25
- "prettier": "prettier . --check",
26
- "prettier:fix": "prettier . --write",
27
- "typecheck": "tsc --noEmit",
28
- "test": "vitest run",
29
- "test:watch": "vitest",
30
- "test:coverage": "vitest run --coverage"
31
- },
32
2
  "dependencies": {
33
3
  "@sentry/minimal": "catalog:",
34
4
  "purify-ts": "catalog:",
@@ -36,8 +6,8 @@
36
6
  },
37
7
  "devDependencies": {
38
8
  "@ledgerhq/device-management-kit": "workspace:*",
39
- "@ledgerhq/ldmk-tool": "workspace:*",
40
9
  "@ledgerhq/eslint-config-dsdk": "workspace:*",
10
+ "@ledgerhq/ldmk-tool": "workspace:*",
41
11
  "@ledgerhq/prettier-config-dsdk": "workspace:*",
42
12
  "@ledgerhq/tsconfig-dsdk": "workspace:*",
43
13
  "@ledgerhq/vitest-config-dmk": "workspace:*",
@@ -46,8 +16,42 @@
46
16
  "rxjs": "catalog:",
47
17
  "ts-node": "catalog:"
48
18
  },
19
+ "exports": {
20
+ ".": {
21
+ "import": "./lib/esm/index.js",
22
+ "types": "./lib/types/index.d.ts"
23
+ }
24
+ },
25
+ "files": [
26
+ "./lib",
27
+ "package.json"
28
+ ],
29
+ "license": "Apache-2.0",
30
+ "name": "@ledgerhq/device-transport-kit-web-hid",
49
31
  "peerDependencies": {
50
32
  "@ledgerhq/device-management-kit": "workspace:*",
51
33
  "rxjs": "catalog:"
52
- }
34
+ },
35
+ "private": false,
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/LedgerHQ/device-sdk-ts.git"
39
+ },
40
+ "scripts": {
41
+ "build": "pnpm ldmk-tool build --entryPoints src/index.ts,src/**/*.ts --tsconfig tsconfig.prod.json --platform web",
42
+ "dev": "concurrently \"pnpm watch:builds\" \"pnpm watch:types\"",
43
+ "lint": "eslint",
44
+ "lint:fix": "pnpm lint --fix",
45
+ "postpack": "find . -name '*.tgz' -exec cp {} ../../../dist/ \\; ",
46
+ "prebuild": "rimraf lib",
47
+ "prettier": "prettier . --check",
48
+ "prettier:fix": "prettier . --write",
49
+ "test": "vitest run",
50
+ "test:coverage": "vitest run --coverage",
51
+ "test:watch": "vitest",
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\""
55
+ },
56
+ "version": "0.0.0-trusted-names-native-transfer-1-20260121120757"
53
57
  }
@@ -1 +1 @@
1
- {"version":3,"file":"WebHidApduSender.d.ts","sourceRoot":"","sources":["../../../../src/api/transport/WebHidApduSender.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,0BAA0B,EAC/B,KAAK,YAAY,EAEjB,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EACrB,KAAK,QAAQ,EAEb,KAAK,sBAAsB,EAG5B,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,KAAK,MAAM,EAA+B,MAAM,WAAW,CAAC;AAKrE,MAAM,MAAM,+BAA+B,GAAG;IAC5C,YAAY,EAAE,4BAA4B,CAAC;IAC3C,iBAAiB,EAAE,wBAAwB,CAAC;IAC5C,mBAAmB,EAAE,0BAA0B,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IACzC,MAAM,EAAE,SAAS,CAAC;CACnB,CAAC;AAEF,qBAAa,gBACX,YAAW,gBAAgB,CAAC,4BAA4B,CAAC;IAEzD,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAC/C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsB;IACnD,OAAO,CAAC,uBAAuB,CAE7B;IACF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyB;gBAG9C,EACE,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,GACpB,EAAE,+BAA+B,EAClC,oBAAoB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,sBAAsB;IAiBzD,QAAQ,CACZ,IAAI,EAAE,UAAU,EAChB,sBAAsB,CAAC,EAAE,OAAO,EAChC,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IA4C1C,OAAO,CAAC,qBAAqB;IAoBtB,eAAe;IAIf,eAAe,CAAC,YAAY,EAAE,4BAA4B;IAIpD,eAAe;IAmBrB,eAAe;CAUvB"}
1
+ {"version":3,"file":"WebHidApduSender.d.ts","sourceRoot":"","sources":["../../../../src/api/transport/WebHidApduSender.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,0BAA0B,EAC/B,KAAK,YAAY,EAEjB,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EACrB,KAAK,QAAQ,EAIb,KAAK,sBAAsB,EAG5B,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,KAAK,MAAM,EAA+B,MAAM,WAAW,CAAC;AAKrE,MAAM,MAAM,+BAA+B,GAAG;IAC5C,YAAY,EAAE,4BAA4B,CAAC;IAC3C,iBAAiB,EAAE,wBAAwB,CAAC;IAC5C,mBAAmB,EAAE,0BAA0B,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IACzC,MAAM,EAAE,SAAS,CAAC;CACnB,CAAC;AAEF,qBAAa,gBACX,YAAW,gBAAgB,CAAC,4BAA4B,CAAC;IAEzD,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAC/C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsB;IACnD,OAAO,CAAC,uBAAuB,CAE7B;IACF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyB;gBAG9C,EACE,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,GACpB,EAAE,+BAA+B,EAClC,oBAAoB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,sBAAsB;IAiBzD,QAAQ,CACZ,IAAI,EAAE,UAAU,EAChB,sBAAsB,CAAC,EAAE,OAAO,EAChC,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAyC1C,OAAO,CAAC,qBAAqB;IAkBtB,eAAe;IAIf,eAAe,CAAC,YAAY,EAAE,4BAA4B;IAIpD,eAAe;IAmBrB,eAAe;CAUvB"}