@ledgerhq/device-transport-kit-mockserver 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/MockserverTransport.test.ts"],
4
- "sourcesContent": ["import {\n type LoggerPublisherService,\n OpeningConnectionError,\n type TransportConnectedDevice,\n} from \"@ledgerhq/device-management-kit\";\nimport { type Device, MockClient } from \"@ledgerhq/device-mockserver-client\";\nimport { firstValueFrom, take, toArray } from \"rxjs\";\n\nimport {\n mockserverIdentifier,\n mockserverTransportFactory,\n} from \"./MockserverTransport\";\n\nvi.mock(\"@ledgerhq/device-mockserver-client\", () => ({\n MockClient: vi.fn(),\n}));\n\ntype TransportArgs = Parameters<\n ReturnType<typeof mockserverTransportFactory>\n>[0];\n\nconst loggerServiceFactory = (): LoggerPublisherService =>\n ({\n debug: vi.fn(),\n info: vi.fn(),\n warn: vi.fn(),\n error: vi.fn(),\n }) as unknown as LoggerPublisherService;\n\nconst transportArgs = {\n config: { mockUrl: \"http://localhost:8080\" },\n loggerServiceFactory,\n} as unknown as TransportArgs;\n\nconst aDevice = (overrides: Partial<Device> = {}): Device => ({\n id: \"device-1\",\n name: \"Ledger Nano X\",\n device_type: \"nanoX\",\n connectivity_type: \"USB\",\n ...overrides,\n});\n\nconst mockListDevices = (\n impl: () => Promise<Device[]>,\n): ReturnType<typeof vi.fn> => {\n const listDevices = vi.fn(impl);\n vi.mocked(MockClient).mockImplementation(\n () => ({ listDevices }) as unknown as MockClient,\n );\n return listDevices;\n};\n\nconst mockClientImpl = (overrides: Partial<Record<string, unknown>> = {}) => {\n const client = {\n listDevices: vi.fn(() => Promise.resolve([])),\n connect: vi.fn(),\n disconnect: vi.fn(),\n sendApdu: vi.fn(),\n ...overrides,\n };\n vi.mocked(MockClient).mockImplementation(\n () => client as unknown as MockClient,\n );\n return client;\n};\n\ndescribe(\"mockserverTransportFactory\", () => {\n beforeEach(() => {\n vi.clearAllMocks();\n mockListDevices(() => Promise.resolve([]));\n });\n\n it(\"builds a supported transport with the mockserver identifier\", () => {\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n expect(transport.getIdentifier()).toBe(mockserverIdentifier);\n expect(transport.isSupported()).toBe(true);\n });\n\n it(\"accepts an injected session token without throwing\", () => {\n expect(() =>\n mockserverTransportFactory(\n \"http://localhost:8080\",\n \"tok-123\",\n )(transportArgs),\n ).not.toThrow();\n });\n\n describe(\"listenToAvailableDevices\", () => {\n it(\"emits the mock server devices mapped as discovered devices\", async () => {\n mockListDevices(() =>\n Promise.resolve([aDevice(), aDevice({ id: \"device-2\", name: \"Stax\" })]),\n );\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n const devices = await firstValueFrom(\n transport.listenToAvailableDevices(),\n );\n\n expect(devices).toEqual([\n expect.objectContaining({\n id: \"device-1\",\n transport: mockserverIdentifier,\n }),\n expect.objectContaining({\n id: \"device-2\",\n transport: mockserverIdentifier,\n }),\n ]);\n });\n\n it(\"keeps polling so newly added devices appear\", async () => {\n const listDevices = mockListDevices(() => Promise.resolve([]));\n listDevices.mockResolvedValueOnce([]).mockResolvedValueOnce([aDevice()]);\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n const emissions = await firstValueFrom(\n transport.listenToAvailableDevices().pipe(take(2), toArray()),\n );\n\n expect(emissions[0]).toEqual([]);\n expect(emissions[1]).toEqual([\n expect.objectContaining({ id: \"device-1\" }),\n ]);\n });\n\n it(\"emits an empty list when the mock server is unreachable\", async () => {\n mockListDevices(() => Promise.reject(new Error(\"offline\")));\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n const devices = await firstValueFrom(\n transport.listenToAvailableDevices(),\n );\n\n expect(devices).toEqual([]);\n });\n });\n\n describe(\"startDiscovering\", () => {\n it(\"emits each device returned by the mock server\", async () => {\n mockClientImpl({\n listDevices: vi.fn(() =>\n Promise.resolve([\n aDevice(),\n aDevice({ id: \"device-2\", name: \"Stax\" }),\n ]),\n ),\n });\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n const devices = await firstValueFrom(\n transport.startDiscovering().pipe(toArray()),\n );\n\n expect(devices).toEqual([\n expect.objectContaining({ id: \"device-1\" }),\n expect.objectContaining({ id: \"device-2\" }),\n ]);\n });\n });\n\n describe(\"stopDiscovering\", () => {\n it(\"does nothing and does not throw\", () => {\n mockClientImpl();\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n expect(() => transport.stopDiscovering()).not.toThrow();\n });\n });\n\n describe(\"connect\", () => {\n it(\"returns a connected device on success\", async () => {\n mockClientImpl({\n connect: vi.fn(() =>\n Promise.resolve({\n device: aDevice({ masks: [0x12345678] }),\n connected: true,\n }),\n ),\n });\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n const onDisconnect = vi.fn();\n\n const result = await transport.connect({\n deviceId: \"device-1\",\n onDisconnect,\n });\n\n expect(result.isRight()).toBe(true);\n const connected = result.unsafeCoerce();\n expect(connected.id).toBe(\"device-1\");\n expect(connected.transport).toBe(mockserverIdentifier);\n expect(connected.deviceModel.masks).toEqual([0x12345678]);\n });\n\n it(\"falls back to the default masks when the device has none\", async () => {\n mockClientImpl({\n connect: vi.fn(() =>\n Promise.resolve({ device: aDevice(), connected: true }),\n ),\n });\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n const result = await transport.connect({\n deviceId: \"device-1\",\n onDisconnect: vi.fn(),\n });\n\n expect(result.unsafeCoerce().deviceModel.masks).toEqual([0x31100000]);\n // A known model (nanoX) reports its real block size, not the legacy default.\n expect(\n result.unsafeCoerce().deviceModel.getBlockSize({\n firmwareVersion: \"1.0.0\",\n }),\n ).toBe(4 * 1024);\n });\n\n it(\"returns an OpeningConnectionError when the client throws\", async () => {\n mockClientImpl({\n connect: vi.fn(() => Promise.reject(new Error(\"nope\"))),\n });\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n const result = await transport.connect({\n deviceId: \"device-1\",\n onDisconnect: vi.fn(),\n });\n\n expect(result.isLeft()).toBe(true);\n expect(result.swap().unsafeCoerce()).toBeInstanceOf(\n OpeningConnectionError,\n );\n });\n });\n\n describe(\"disconnect\", () => {\n const connectedDevice = {\n id: \"device-1\",\n } as TransportConnectedDevice;\n\n it(\"returns Right(undefined) when the client disconnects successfully\", async () => {\n const disconnect = vi.fn(() => Promise.resolve(true));\n mockClientImpl({ disconnect });\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n const result = await transport.disconnect({ connectedDevice });\n\n expect(disconnect).toHaveBeenCalledWith(\"device-1\");\n expect(result.isRight()).toBe(true);\n });\n\n it(\"returns a DisconnectError when the client reports failure\", async () => {\n mockClientImpl({ disconnect: vi.fn(() => Promise.resolve(false)) });\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n const result = await transport.disconnect({ connectedDevice });\n\n expect(result.isLeft()).toBe(true);\n });\n\n it(\"returns a DisconnectError when the client throws\", async () => {\n mockClientImpl({\n disconnect: vi.fn(() => Promise.reject(new Error(\"boom\"))),\n });\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n const result = await transport.disconnect({ connectedDevice });\n\n expect(result.isLeft()).toBe(true);\n });\n });\n\n describe(\"sendApdu\", () => {\n const buildConnectedTransport = (sendApdu: ReturnType<typeof vi.fn>) => {\n mockClientImpl({\n connect: vi.fn(() =>\n Promise.resolve({ device: aDevice(), connected: true }),\n ),\n sendApdu,\n });\n return mockserverTransportFactory(\"http://localhost:8080\")(transportArgs);\n };\n\n it(\"splits the response into data and status code\", async () => {\n const sendApdu = vi.fn(() => Promise.resolve({ response: \"aabb9000\" }));\n const transport = buildConnectedTransport(sendApdu);\n const onDisconnect = vi.fn();\n const connected = (\n await transport.connect({ deviceId: \"device-1\", onDisconnect })\n ).unsafeCoerce();\n\n const result = await connected.sendApdu(\n Uint8Array.from([0xe0, 0x01, 0x00, 0x00]),\n );\n\n expect(result.isRight()).toBe(true);\n const apduResponse = result.unsafeCoerce();\n expect(Array.from(apduResponse.data)).toEqual([0xaa, 0xbb]);\n expect(Array.from(apduResponse.statusCode)).toEqual([0x90, 0x00]);\n expect(onDisconnect).not.toHaveBeenCalled();\n });\n\n it(\"calls onDisconnect and returns a NoAccessibleDeviceError on failure\", async () => {\n const sendApdu = vi.fn(() => Promise.reject(new Error(\"device lost\")));\n const transport = buildConnectedTransport(sendApdu);\n const onDisconnect = vi.fn();\n const connected = (\n await transport.connect({ deviceId: \"device-1\", onDisconnect })\n ).unsafeCoerce();\n\n const result = await connected.sendApdu(\n Uint8Array.from([0xe0, 0x01, 0x00, 0x00]),\n );\n\n expect(result.isLeft()).toBe(true);\n expect(onDisconnect).toHaveBeenCalledWith(\"device-1\");\n });\n\n it(\"returns an empty data buffer when the response is only a status word\", async () => {\n const sendApdu = vi.fn(() => Promise.resolve({ response: \"9000\" }));\n const transport = buildConnectedTransport(sendApdu);\n const connected = (\n await transport.connect({ deviceId: \"device-1\", onDisconnect: vi.fn() })\n ).unsafeCoerce();\n\n const result = await connected.sendApdu(\n Uint8Array.from([0xe0, 0x01, 0x00, 0x00]),\n );\n\n expect(result.isRight()).toBe(true);\n const apduResponse = result.unsafeCoerce();\n expect(Array.from(apduResponse.data)).toEqual([]);\n expect(Array.from(apduResponse.statusCode)).toEqual([0x90, 0x00]);\n });\n\n it(\"falls back to an empty status code when the status word hex is invalid\", async () => {\n // slice(-4) = \"XXYY\" is not valid hex -> hexaStringToBuffer returns null.\n const sendApdu = vi.fn(() => Promise.resolve({ response: \"aabbXXYY\" }));\n const transport = buildConnectedTransport(sendApdu);\n const connected = (\n await transport.connect({ deviceId: \"device-1\", onDisconnect: vi.fn() })\n ).unsafeCoerce();\n\n const result = await connected.sendApdu(\n Uint8Array.from([0xe0, 0x01, 0x00, 0x00]),\n );\n\n expect(result.isRight()).toBe(true);\n const apduResponse = result.unsafeCoerce();\n expect(Array.from(apduResponse.statusCode)).toEqual([]);\n expect(Array.from(apduResponse.data)).toEqual([0xaa, 0xbb]);\n });\n\n it(\"falls back to an empty data buffer when the data hex is invalid\", async () => {\n // slice(0, -4) = \"ZZZZ\" is not valid hex -> hexaStringToBuffer returns null.\n const sendApdu = vi.fn(() => Promise.resolve({ response: \"ZZZZ9000\" }));\n const transport = buildConnectedTransport(sendApdu);\n const connected = (\n await transport.connect({ deviceId: \"device-1\", onDisconnect: vi.fn() })\n ).unsafeCoerce();\n\n const result = await connected.sendApdu(\n Uint8Array.from([0xe0, 0x01, 0x00, 0x00]),\n );\n\n expect(result.isRight()).toBe(true);\n const apduResponse = result.unsafeCoerce();\n expect(Array.from(apduResponse.data)).toEqual([]);\n expect(Array.from(apduResponse.statusCode)).toEqual([0x90, 0x00]);\n });\n });\n\n describe(\"mockserverTransportFactory\", () => {\n it(\"uses the config mock url when no explicit url is provided\", () => {\n const client = mockClientImpl();\n expect(client).toBeDefined();\n\n mockserverTransportFactory()(transportArgs);\n\n expect(MockClient).toHaveBeenCalledWith(\n \"http://localhost:8080\",\n expect.anything(),\n );\n });\n\n it(\"prefers an explicit url over the config mock url\", () => {\n mockClientImpl();\n\n mockserverTransportFactory(\"https://explicit:9090\")(transportArgs);\n\n expect(MockClient).toHaveBeenCalledWith(\n \"https://explicit:9090\",\n expect.anything(),\n );\n });\n });\n});\n"],
5
- "mappings": "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",
6
- "names": ["OpeningConnectionError", "MockClient", "firstValueFrom", "take", "toArray", "mockserverIdentifier", "mockserverTransportFactory", "loggerServiceFactory", "transportArgs", "aDevice", "overrides", "mockListDevices", "impl", "listDevices", "mockClientImpl", "client", "transport", "devices", "emissions", "onDisconnect", "result", "connected", "connectedDevice", "disconnect", "buildConnectedTransport", "sendApdu", "apduResponse"]
4
+ "sourcesContent": ["import {\n type LoggerPublisherService,\n OpeningConnectionError,\n type TransportConnectedDevice,\n} from \"@ledgerhq/device-management-kit\";\nimport { type Device, MockClient } from \"@ledgerhq/device-mockserver-client\";\nimport { firstValueFrom, take, toArray } from \"rxjs\";\n\nimport {\n mockserverIdentifier,\n mockserverTransportFactory,\n} from \"./MockserverTransport\";\n\nvi.mock(\"@ledgerhq/device-mockserver-client\", () => ({\n MockClient: vi.fn(),\n}));\n\ntype TransportArgs = Parameters<\n ReturnType<typeof mockserverTransportFactory>\n>[0];\n\nconst loggerServiceFactory = (): LoggerPublisherService =>\n ({\n debug: vi.fn(),\n info: vi.fn(),\n warn: vi.fn(),\n error: vi.fn(),\n }) as unknown as LoggerPublisherService;\n\nconst transportArgs = {\n config: { mockUrl: \"http://localhost:8080\" },\n loggerServiceFactory,\n} as unknown as TransportArgs;\n\n/** Mirrors the transport's own discovery interval. */\nconst POLL_INTERVAL_MS = 1000;\n\nconst aDevice = (overrides: Partial<Device> = {}): Device => ({\n id: \"device-1\",\n name: \"Ledger Nano X\",\n device_type: \"nanoX\",\n connectivity_type: \"USB\",\n ...overrides,\n});\n\nconst mockListDevices = (\n impl: () => Promise<Device[]>,\n): ReturnType<typeof vi.fn> => {\n const listDevices = vi.fn(impl);\n vi.mocked(MockClient).mockImplementation(\n () => ({ listDevices }) as unknown as MockClient,\n );\n return listDevices;\n};\n\nconst mockClientImpl = (overrides: Partial<Record<string, unknown>> = {}) => {\n const client = {\n listDevices: vi.fn(() => Promise.resolve([])),\n connect: vi.fn(),\n disconnect: vi.fn(),\n sendApdu: vi.fn(),\n ...overrides,\n };\n vi.mocked(MockClient).mockImplementation(\n () => client as unknown as MockClient,\n );\n return client;\n};\n\ndescribe(\"mockserverTransportFactory\", () => {\n beforeEach(() => {\n vi.clearAllMocks();\n mockListDevices(() => Promise.resolve([]));\n });\n\n afterEach(() => {\n vi.useRealTimers();\n });\n\n it(\"builds a supported transport with the mockserver identifier\", () => {\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n expect(transport.getIdentifier()).toBe(mockserverIdentifier);\n expect(transport.isSupported()).toBe(true);\n });\n\n it(\"accepts an injected session token without throwing\", () => {\n expect(() =>\n mockserverTransportFactory(\n \"http://localhost:8080\",\n \"tok-123\",\n )(transportArgs),\n ).not.toThrow();\n });\n\n describe(\"listenToAvailableDevices\", () => {\n it(\"emits the mock server devices mapped as discovered devices\", async () => {\n mockListDevices(() =>\n Promise.resolve([aDevice(), aDevice({ id: \"device-2\", name: \"Stax\" })]),\n );\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n const devices = await firstValueFrom(\n transport.listenToAvailableDevices(),\n );\n\n expect(devices).toEqual([\n expect.objectContaining({\n id: \"device-1\",\n transport: mockserverIdentifier,\n }),\n expect.objectContaining({\n id: \"device-2\",\n transport: mockserverIdentifier,\n }),\n ]);\n });\n\n it(\"keeps polling so newly added devices appear\", async () => {\n vi.useFakeTimers();\n const listDevices = mockListDevices(() => Promise.resolve([]));\n listDevices.mockResolvedValueOnce([]).mockResolvedValueOnce([aDevice()]);\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n const polled = firstValueFrom(\n transport.listenToAvailableDevices().pipe(take(2), toArray()),\n );\n await vi.advanceTimersByTimeAsync(POLL_INTERVAL_MS);\n const emissions = await polled;\n\n expect(emissions[0]).toEqual([]);\n expect(emissions[1]).toEqual([\n expect.objectContaining({ id: \"device-1\" }),\n ]);\n });\n\n it(\"emits an empty list when the mock server is unreachable\", async () => {\n mockListDevices(() => Promise.reject(new Error(\"offline\")));\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n const devices = await firstValueFrom(\n transport.listenToAvailableDevices(),\n );\n\n expect(devices).toEqual([]);\n });\n\n it(\"keeps polling after a failed request\", async () => {\n vi.useFakeTimers();\n const listDevices = mockListDevices(() => Promise.resolve([]));\n listDevices\n .mockRejectedValueOnce(new Error(\"offline\"))\n .mockResolvedValueOnce([aDevice()]);\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n const polled = firstValueFrom(\n transport.listenToAvailableDevices().pipe(take(2), toArray()),\n );\n await vi.advanceTimersByTimeAsync(POLL_INTERVAL_MS);\n const emissions = await polled;\n\n expect(emissions[0]).toEqual([]);\n expect(emissions[1]).toEqual([\n expect.objectContaining({ id: \"device-1\" }),\n ]);\n });\n });\n\n describe(\"startDiscovering\", () => {\n it(\"emits each device returned by the mock server\", async () => {\n mockClientImpl({\n listDevices: vi.fn(() =>\n Promise.resolve([\n aDevice(),\n aDevice({ id: \"device-2\", name: \"Stax\" }),\n ]),\n ),\n });\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n const devices = await firstValueFrom(\n transport.startDiscovering().pipe(toArray()),\n );\n\n expect(devices).toEqual([\n expect.objectContaining({ id: \"device-1\" }),\n expect.objectContaining({ id: \"device-2\" }),\n ]);\n });\n });\n\n describe(\"stopDiscovering\", () => {\n it(\"does nothing and does not throw\", () => {\n mockClientImpl();\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n expect(() => transport.stopDiscovering()).not.toThrow();\n });\n });\n\n describe(\"connect\", () => {\n it(\"returns a connected device on success\", async () => {\n mockClientImpl({\n connect: vi.fn(() =>\n Promise.resolve({\n device: aDevice({ masks: [0x12345678] }),\n connected: true,\n }),\n ),\n });\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n const onDisconnect = vi.fn();\n\n const result = await transport.connect({\n deviceId: \"device-1\",\n onDisconnect,\n });\n\n expect(result.isRight()).toBe(true);\n const connected = result.unsafeCoerce();\n expect(connected.id).toBe(\"device-1\");\n expect(connected.transport).toBe(mockserverIdentifier);\n expect(connected.deviceModel.masks).toEqual([0x12345678]);\n });\n\n it(\"falls back to the default masks when the device has none\", async () => {\n mockClientImpl({\n connect: vi.fn(() =>\n Promise.resolve({ device: aDevice(), connected: true }),\n ),\n });\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n const result = await transport.connect({\n deviceId: \"device-1\",\n onDisconnect: vi.fn(),\n });\n\n expect(result.unsafeCoerce().deviceModel.masks).toEqual([0x31100000]);\n // A known model (nanoX) reports its real block size, not the legacy default.\n expect(\n result.unsafeCoerce().deviceModel.getBlockSize({\n firmwareVersion: \"1.0.0\",\n }),\n ).toBe(4 * 1024);\n });\n\n it(\"returns an OpeningConnectionError when the client throws\", async () => {\n mockClientImpl({\n connect: vi.fn(() => Promise.reject(new Error(\"nope\"))),\n });\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n const result = await transport.connect({\n deviceId: \"device-1\",\n onDisconnect: vi.fn(),\n });\n\n expect(result.isLeft()).toBe(true);\n expect(result.swap().unsafeCoerce()).toBeInstanceOf(\n OpeningConnectionError,\n );\n });\n });\n\n describe(\"disconnect\", () => {\n const connectedDevice = {\n id: \"device-1\",\n } as TransportConnectedDevice;\n\n it(\"returns Right(undefined) when the client disconnects successfully\", async () => {\n const disconnect = vi.fn(() => Promise.resolve(true));\n mockClientImpl({ disconnect });\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n const result = await transport.disconnect({ connectedDevice });\n\n expect(disconnect).toHaveBeenCalledWith(\"device-1\");\n expect(result.isRight()).toBe(true);\n });\n\n it(\"returns a DisconnectError when the client reports failure\", async () => {\n mockClientImpl({ disconnect: vi.fn(() => Promise.resolve(false)) });\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n const result = await transport.disconnect({ connectedDevice });\n\n expect(result.isLeft()).toBe(true);\n });\n\n it(\"returns a DisconnectError when the client throws\", async () => {\n mockClientImpl({\n disconnect: vi.fn(() => Promise.reject(new Error(\"boom\"))),\n });\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n\n const result = await transport.disconnect({ connectedDevice });\n\n expect(result.isLeft()).toBe(true);\n });\n });\n\n describe(\"sendApdu\", () => {\n const buildConnectedTransport = (sendApdu: ReturnType<typeof vi.fn>) => {\n mockClientImpl({\n connect: vi.fn(() =>\n Promise.resolve({ device: aDevice(), connected: true }),\n ),\n sendApdu,\n });\n return mockserverTransportFactory(\"http://localhost:8080\")(transportArgs);\n };\n\n it(\"splits the response into data and status code\", async () => {\n const sendApdu = vi.fn(() => Promise.resolve({ response: \"aabb9000\" }));\n const transport = buildConnectedTransport(sendApdu);\n const onDisconnect = vi.fn();\n const connected = (\n await transport.connect({ deviceId: \"device-1\", onDisconnect })\n ).unsafeCoerce();\n\n const result = await connected.sendApdu(\n Uint8Array.from([0xe0, 0x01, 0x00, 0x00]),\n );\n\n expect(result.isRight()).toBe(true);\n const apduResponse = result.unsafeCoerce();\n expect(Array.from(apduResponse.data)).toEqual([0xaa, 0xbb]);\n expect(Array.from(apduResponse.statusCode)).toEqual([0x90, 0x00]);\n expect(onDisconnect).not.toHaveBeenCalled();\n });\n\n it(\"calls onDisconnect and returns a NoAccessibleDeviceError on failure\", async () => {\n const sendApdu = vi.fn(() => Promise.reject(new Error(\"device lost\")));\n const transport = buildConnectedTransport(sendApdu);\n const onDisconnect = vi.fn();\n const connected = (\n await transport.connect({ deviceId: \"device-1\", onDisconnect })\n ).unsafeCoerce();\n\n const result = await connected.sendApdu(\n Uint8Array.from([0xe0, 0x01, 0x00, 0x00]),\n );\n\n expect(result.isLeft()).toBe(true);\n expect(onDisconnect).toHaveBeenCalledWith(\"device-1\");\n });\n\n it(\"returns an empty data buffer when the response is only a status word\", async () => {\n const sendApdu = vi.fn(() => Promise.resolve({ response: \"9000\" }));\n const transport = buildConnectedTransport(sendApdu);\n const connected = (\n await transport.connect({ deviceId: \"device-1\", onDisconnect: vi.fn() })\n ).unsafeCoerce();\n\n const result = await connected.sendApdu(\n Uint8Array.from([0xe0, 0x01, 0x00, 0x00]),\n );\n\n expect(result.isRight()).toBe(true);\n const apduResponse = result.unsafeCoerce();\n expect(Array.from(apduResponse.data)).toEqual([]);\n expect(Array.from(apduResponse.statusCode)).toEqual([0x90, 0x00]);\n });\n\n it(\"falls back to an empty status code when the status word hex is invalid\", async () => {\n // slice(-4) = \"XXYY\" is not valid hex -> hexaStringToBuffer returns null.\n const sendApdu = vi.fn(() => Promise.resolve({ response: \"aabbXXYY\" }));\n const transport = buildConnectedTransport(sendApdu);\n const connected = (\n await transport.connect({ deviceId: \"device-1\", onDisconnect: vi.fn() })\n ).unsafeCoerce();\n\n const result = await connected.sendApdu(\n Uint8Array.from([0xe0, 0x01, 0x00, 0x00]),\n );\n\n expect(result.isRight()).toBe(true);\n const apduResponse = result.unsafeCoerce();\n expect(Array.from(apduResponse.statusCode)).toEqual([]);\n expect(Array.from(apduResponse.data)).toEqual([0xaa, 0xbb]);\n });\n\n it(\"falls back to an empty data buffer when the data hex is invalid\", async () => {\n // slice(0, -4) = \"ZZZZ\" is not valid hex -> hexaStringToBuffer returns null.\n const sendApdu = vi.fn(() => Promise.resolve({ response: \"ZZZZ9000\" }));\n const transport = buildConnectedTransport(sendApdu);\n const connected = (\n await transport.connect({ deviceId: \"device-1\", onDisconnect: vi.fn() })\n ).unsafeCoerce();\n\n const result = await connected.sendApdu(\n Uint8Array.from([0xe0, 0x01, 0x00, 0x00]),\n );\n\n expect(result.isRight()).toBe(true);\n const apduResponse = result.unsafeCoerce();\n expect(Array.from(apduResponse.data)).toEqual([]);\n expect(Array.from(apduResponse.statusCode)).toEqual([0x90, 0x00]);\n });\n });\n\n describe(\"disconnect polling\", () => {\n beforeEach(() => {\n vi.useFakeTimers();\n });\n\n afterEach(() => {\n vi.useRealTimers();\n });\n\n const connectTo = async (listDevices: ReturnType<typeof vi.fn>) => {\n mockClientImpl({\n connect: vi.fn(() =>\n Promise.resolve({ device: aDevice(), connected: true }),\n ),\n disconnect: vi.fn(() => Promise.resolve(true)),\n listDevices,\n });\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n const onDisconnect = vi.fn();\n const connected = (\n await transport.connect({ deviceId: \"device-1\", onDisconnect })\n ).unsafeCoerce();\n return { transport, connected, onDisconnect };\n };\n\n it(\"calls onDisconnect once the device is gone from the mock server\", async () => {\n const listDevices = vi.fn(() => Promise.resolve([aDevice()]));\n const { onDisconnect } = await connectTo(listDevices);\n\n await vi.advanceTimersByTimeAsync(1000);\n expect(onDisconnect).not.toHaveBeenCalled();\n\n listDevices.mockResolvedValue([]);\n await vi.advanceTimersByTimeAsync(1000);\n\n expect(onDisconnect).toHaveBeenCalledWith(\"device-1\");\n });\n\n it(\"reports a replaced device as unplugged before listing its replacement\", async () => {\n let serverDevices = [aDevice()];\n const { transport, onDisconnect } = await connectTo(\n vi.fn(() => Promise.resolve(serverDevices)),\n );\n const events: unknown[] = [];\n onDisconnect.mockImplementation((id) => events.push(`disconnect ${id}`));\n transport\n .listenToAvailableDevices()\n .subscribe((devices) => events.push(devices.map(({ id }) => id)));\n await vi.advanceTimersByTimeAsync(0);\n\n serverDevices = [aDevice({ id: \"device-2\" })];\n await vi.advanceTimersByTimeAsync(POLL_INTERVAL_MS);\n\n expect(events).toEqual([\n [\"device-1\"],\n \"disconnect device-1\",\n [],\n [\"device-2\"],\n ]);\n });\n\n it(\"reports the disconnect from discovery before the next liveness tick\", async () => {\n let serverDevices = [aDevice()];\n mockClientImpl({\n connect: vi.fn(() =>\n Promise.resolve({ device: aDevice(), connected: true }),\n ),\n listDevices: vi.fn(() => Promise.resolve(serverDevices)),\n });\n const transport = mockserverTransportFactory(\"http://localhost:8080\")(\n transportArgs,\n );\n const onDisconnect = vi.fn();\n transport.listenToAvailableDevices().subscribe();\n await vi.advanceTimersByTimeAsync(POLL_INTERVAL_MS / 2);\n await transport.connect({ deviceId: \"device-1\", onDisconnect });\n\n serverDevices = [];\n await vi.advanceTimersByTimeAsync(POLL_INTERVAL_MS / 2);\n\n expect(onDisconnect).toHaveBeenCalledOnce();\n });\n\n it(\"calls onDisconnect when the server reports the device as disconnected\", async () => {\n const listDevices = vi.fn(() =>\n Promise.resolve([aDevice({ connected: false })]),\n );\n const { onDisconnect } = await connectTo(listDevices);\n\n await vi.advanceTimersByTimeAsync(1000);\n\n expect(onDisconnect).toHaveBeenCalledWith(\"device-1\");\n });\n\n it(\"keeps the device connected while the mock server is unreachable\", async () => {\n const listDevices = vi.fn(() => Promise.reject(new Error(\"offline\")));\n const { onDisconnect } = await connectTo(listDevices);\n\n await vi.advanceTimersByTimeAsync(3000);\n\n expect(onDisconnect).not.toHaveBeenCalled();\n });\n\n it(\"reports the disconnect only once\", async () => {\n const listDevices = vi.fn(() => Promise.resolve([]));\n const { onDisconnect } = await connectTo(listDevices);\n\n await vi.advanceTimersByTimeAsync(3000);\n\n expect(onDisconnect).toHaveBeenCalledTimes(1);\n });\n\n it(\"stops polling after an explicit disconnect\", async () => {\n const listDevices = vi.fn(() => Promise.resolve([aDevice()]));\n const { transport, connected, onDisconnect } =\n await connectTo(listDevices);\n\n await transport.disconnect({ connectedDevice: connected });\n listDevices.mockResolvedValue([]);\n await vi.advanceTimersByTimeAsync(3000);\n\n expect(onDisconnect).not.toHaveBeenCalled();\n });\n\n it(\"stays silent when a request in flight answers after a disconnect\", async () => {\n // Clearing the interval cannot cancel a request already sent.\n let answer = (_: Device[]) => {};\n const listDevices = vi.fn(\n () =>\n new Promise<Device[]>((resolve) => {\n answer = resolve;\n }),\n );\n const { transport, connected, onDisconnect } =\n await connectTo(listDevices);\n\n await vi.advanceTimersByTimeAsync(1000);\n await transport.disconnect({ connectedDevice: connected });\n answer([]);\n await vi.advanceTimersByTimeAsync(0);\n\n expect(onDisconnect).not.toHaveBeenCalled();\n });\n\n it(\"reports once when two polls overlap\", async () => {\n // A request slower than the interval leaves two in flight at once.\n const answers: ((devices: Device[]) => void)[] = [];\n const listDevices = vi.fn(\n () =>\n new Promise<Device[]>((resolve) => {\n answers.push(resolve);\n }),\n );\n const { onDisconnect } = await connectTo(listDevices);\n\n await vi.advanceTimersByTimeAsync(2000);\n expect(answers).toHaveLength(2);\n answers.forEach((answer) => answer([]));\n await vi.advanceTimersByTimeAsync(0);\n\n expect(onDisconnect).toHaveBeenCalledTimes(1);\n });\n });\n\n describe(\"mockserverTransportFactory\", () => {\n it(\"uses the config mock url when no explicit url is provided\", () => {\n const client = mockClientImpl();\n expect(client).toBeDefined();\n\n mockserverTransportFactory()(transportArgs);\n\n expect(MockClient).toHaveBeenCalledWith(\n \"http://localhost:8080\",\n expect.anything(),\n );\n });\n\n it(\"prefers an explicit url over the config mock url\", () => {\n mockClientImpl();\n\n mockserverTransportFactory(\"https://explicit:9090\")(transportArgs);\n\n expect(MockClient).toHaveBeenCalledWith(\n \"https://explicit:9090\",\n expect.anything(),\n );\n });\n });\n});\n"],
5
+ "mappings": "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",
6
+ "names": ["OpeningConnectionError", "MockClient", "firstValueFrom", "take", "toArray", "mockserverIdentifier", "mockserverTransportFactory", "loggerServiceFactory", "transportArgs", "POLL_INTERVAL_MS", "aDevice", "overrides", "mockListDevices", "impl", "listDevices", "mockClientImpl", "client", "transport", "devices", "polled", "emissions", "onDisconnect", "result", "connected", "connectedDevice", "disconnect", "buildConnectedTransport", "sendApdu", "apduResponse", "connectTo", "serverDevices", "events", "id", "answer", "_", "resolve", "answers"]
7
7
  }
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "dependencies": {
3
+ "@ledgerhq/device-mockserver-client": "^1.3.0",
3
4
  "@sentry/minimal": "catalog:",
4
5
  "purify-ts": "catalog:"
5
6
  },
6
7
  "devDependencies": {
7
8
  "@ledgerhq/device-management-kit": "workspace:^",
8
- "@ledgerhq/device-mockserver-client": "workspace:^",
9
9
  "@ledgerhq/eslint-config-dsdk": "workspace:^",
10
10
  "@ledgerhq/ldmk-tool": "workspace:^",
11
11
  "@ledgerhq/prettier-config-dsdk": "workspace:^",
@@ -32,7 +32,7 @@
32
32
  "license": "Apache-2.0",
33
33
  "name": "@ledgerhq/device-transport-kit-mockserver",
34
34
  "peerDependencies": {
35
- "@ledgerhq/device-management-kit": "^1.7.1",
35
+ "@ledgerhq/device-management-kit": "workspace:^",
36
36
  "rxjs": "catalog:"
37
37
  },
38
38
  "private": false,
@@ -56,5 +56,5 @@
56
56
  "watch:builds": "pnpm ldmk-tool watch --entryPoints src/index.ts,src/**/*.ts --tsconfig tsconfig.prod.json",
57
57
  "watch:types": "concurrently \"tsc --watch -p tsconfig.prod.json\" \"tsc-alias --watch -p tsconfig.prod.json\""
58
58
  },
59
- "version": "1.1.0"
59
+ "version": "1.1.2"
60
60
  }
@@ -6,6 +6,7 @@ export declare class MockTransport implements Transport {
6
6
  private logger;
7
7
  private mockClient;
8
8
  private readonly identifier;
9
+ private readonly disconnectPolls;
9
10
  constructor(loggerServiceFactory: (tag: string) => LoggerPublisherService, mockUrl: string, sessionToken?: string);
10
11
  isSupported(): boolean;
11
12
  getIdentifier(): TransportIdentifier;
@@ -20,6 +21,14 @@ export declare class MockTransport implements Transport {
20
21
  connectedDevice: TransportConnectedDevice;
21
22
  }): Promise<Either<DmkError, void>>;
22
23
  sendApdu(deviceId: string, onDisconnectDeviceId: DeviceId, onDisconnect: DisconnectHandler, apdu: Uint8Array): Promise<Either<DmkError, ApduResponse>>;
24
+ /**
25
+ * A device can be deleted or disconnected through the API by any client, and
26
+ * nothing announces it the way a physical unplug does. Without the signal,
27
+ * DMK keeps a session that claims to be connected.
28
+ */
29
+ private listenForDisconnect;
30
+ private reportDisconnect;
31
+ private clearDisconnectPoll;
23
32
  private mapToDiscoveredDevices;
24
33
  private buildDeviceModel;
25
34
  }
@@ -1 +1 @@
1
- {"version":3,"file":"MockserverTransport.d.ts","sourceRoot":"","sources":["../../src/MockserverTransport.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,QAAQ,EAGb,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EAIb,KAAK,sBAAsB,EAI3B,KAAK,SAAS,EACd,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACzB,MAAM,iCAAiC,CAAC;AAMzC,OAAO,EAAE,KAAK,MAAM,EAAe,MAAM,WAAW,CAAC;AACrD,OAAO,EAKL,KAAK,UAAU,EAIhB,MAAM,MAAM,CAAC;AAEd,eAAO,MAAM,oBAAoB,EAAE,mBAAkC,CAAC;AAetE,qBAAa,aAAc,YAAW,SAAS;IAC7C,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6C;gBAGtE,oBAAoB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,sBAAsB,EAC7D,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM;IAMvB,WAAW,IAAI,OAAO;IAItB,aAAa,IAAI,mBAAmB;IAIpC,wBAAwB,IAAI,UAAU,CAAC,yBAAyB,EAAE,CAAC;IAcnE,gBAAgB,IAAI,UAAU,CAAC,yBAAyB,CAAC;IAQzD,eAAe,IAAI,IAAI;IAKjB,OAAO,CAAC,MAAM,EAAE;QACpB,QAAQ,EAAE,QAAQ,CAAC;QACnB,YAAY,EAAE,iBAAiB,CAAC;KACjC,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,wBAAwB,CAAC,CAAC;IAmBrD,UAAU,CAAC,MAAM,EAAE;QACvB,eAAe,EAAE,wBAAwB,CAAC;KAC3C,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAgB7B,QAAQ,CACZ,QAAQ,EAAE,MAAM,EAChB,oBAAoB,EAAE,QAAQ,EAC9B,YAAY,EAAE,iBAAiB,EAC/B,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAuB1C,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,gBAAgB;CAmBzB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,GACpC,UAAU,MAAM,EAAE,eAAe,MAAM,KAAG,gBAMxC,CAAC"}
1
+ {"version":3,"file":"MockserverTransport.d.ts","sourceRoot":"","sources":["../../src/MockserverTransport.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,QAAQ,EAGb,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EAIb,KAAK,sBAAsB,EAI3B,KAAK,SAAS,EACd,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACzB,MAAM,iCAAiC,CAAC;AAMzC,OAAO,EAAE,KAAK,MAAM,EAAe,MAAM,WAAW,CAAC;AACrD,OAAO,EAML,KAAK,UAAU,EAIhB,MAAM,MAAM,CAAC;AAEd,eAAO,MAAM,oBAAoB,EAAE,mBAAkC,CAAC;AAkBtE,qBAAa,aAAc,YAAW,SAAS;IAC7C,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6C;IACxE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAG5B;gBAGF,oBAAoB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,sBAAsB,EAC7D,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM;IAMvB,WAAW,IAAI,OAAO;IAItB,aAAa,IAAI,mBAAmB;IAIpC,wBAAwB,IAAI,UAAU,CAAC,yBAAyB,EAAE,CAAC;IAqCnE,gBAAgB,IAAI,UAAU,CAAC,yBAAyB,CAAC;IAQzD,eAAe,IAAI,IAAI;IAKjB,OAAO,CAAC,MAAM,EAAE;QACpB,QAAQ,EAAE,QAAQ,CAAC;QACnB,YAAY,EAAE,iBAAiB,CAAC;KACjC,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,wBAAwB,CAAC,CAAC;IAoBrD,UAAU,CAAC,MAAM,EAAE;QACvB,eAAe,EAAE,wBAAwB,CAAC;KAC3C,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAiB7B,QAAQ,CACZ,QAAQ,EAAE,MAAM,EAChB,oBAAoB,EAAE,QAAQ,EAC9B,YAAY,EAAE,iBAAiB,EAC/B,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAwB1C;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IA8B3B,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,mBAAmB;IAS3B,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,gBAAgB;CAmBzB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,GACpC,UAAU,MAAM,EAAE,eAAe,MAAM,KAAG,gBAMxC,CAAC"}