@ledgerhq/device-transport-kit-mockserver 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/MockserverTransport.js +1 -1
- package/lib/cjs/MockserverTransport.js.map +3 -3
- package/lib/cjs/MockserverTransport.test.js +2 -0
- package/lib/cjs/MockserverTransport.test.js.map +7 -0
- package/lib/cjs/package.json +2 -2
- package/lib/esm/MockserverTransport.js +1 -1
- package/lib/esm/MockserverTransport.js.map +3 -3
- package/lib/esm/MockserverTransport.test.js +2 -0
- package/lib/esm/MockserverTransport.test.js.map +7 -0
- package/lib/esm/package.json +2 -2
- package/lib/types/MockserverTransport.d.ts +14 -4
- package/lib/types/MockserverTransport.d.ts.map +1 -1
- package/lib/types/MockserverTransport.test.d.ts +2 -0
- package/lib/types/MockserverTransport.test.d.ts.map +1 -0
- package/lib/types/tsconfig.prod.tsbuildinfo +1 -1
- package/package.json +6 -6
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var a=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var m=Object.prototype.hasOwnProperty;var h=(s,e)=>{for(var r in e)a(s,r,{get:e[r],enumerable:!0})},y=(s,e,r,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of u(e))!m.call(s,n)&&n!==r&&a(s,n,{get:()=>e[n],enumerable:!(t=D(e,n))||t.enumerable});return s};var b=s=>y(a({},"__esModule",{value:!0}),s);var I={};h(I,{MockTransport:()=>g,mockserverIdentifier:()=>v,mockserverTransportFactory:()=>E});module.exports=b(I);var o=require("@ledgerhq/device-management-kit"),l=require("@ledgerhq/device-mockserver-client"),c=require("purify-ts"),i=require("rxjs");const v="MOCKSERVER",T=[823132160],f=new o.StaticDeviceModelDataSource,k=1e3;class g{logger;mockClient;identifier=v;constructor(e,r,t){this.logger=e("MockTransport"),this.mockClient=new l.MockClient(r,{token:t})}isSupported(){return!0}getIdentifier(){return this.identifier}listenToAvailableDevices(){return this.logger.debug("listenToAvailableDevices"),(0,i.timer)(0,k).pipe((0,i.switchMap)(()=>(0,i.from)(this.mockClient.listDevices())),(0,i.map)(e=>this.mapToDiscoveredDevices(e)),(0,i.catchError)(e=>(this.logger.error("listenToAvailableDevices failed",{data:{error:e}}),(0,i.of)([]))))}startDiscovering(){return this.logger.debug("startDiscovering"),(0,i.from)(this.mockClient.listDevices()).pipe((0,i.map)(e=>this.mapToDiscoveredDevices(e)),(0,i.mergeMap)(e=>(0,i.from)(e)))}stopDiscovering(){this.logger.debug("stopDiscovering")}async connect(e){this.logger.debug("connect");const r=e.deviceId;try{const{device:t}=await this.mockClient.connect(r),n={sendApdu:d=>this.sendApdu(r,e.deviceId,e.onDisconnect,d),deviceModel:this.buildDeviceModel(t),id:e.deviceId,type:t.connectivity_type,transport:this.identifier};return(0,c.Right)(n)}catch(t){return(0,c.Left)(new o.OpeningConnectionError(t))}}async disconnect(e){this.logger.debug("disconnect");const r=e.connectedDevice.id;try{return await this.mockClient.disconnect(r)?(0,c.Right)(void 0):(0,c.Left)(new o.DisconnectError(new Error(`Failed to disconnect ${r}`)))}catch(t){return(0,c.Left)(new o.DisconnectError(t))}}async sendApdu(e,r,t,n){this.logger.debug("send");try{const d=await this.mockClient.sendApdu(e,n);this.logger.debug((0,o.formatApduSentLog)(n));const p={statusCode:(0,o.hexaStringToBuffer)(d.response.slice(-4))??new Uint8Array,data:(0,o.hexaStringToBuffer)(d.response.slice(0,-4))??new Uint8Array};return this.logger.debug((0,o.formatApduReceivedLog)(p)),(0,c.Right)(p)}catch(d){return t(r),(0,c.Left)(new o.NoAccessibleDeviceError(d))}}mapToDiscoveredDevices(e){return e.map(r=>({id:r.id,deviceModel:this.buildDeviceModel(r),transport:this.identifier}))}buildDeviceModel(e){const r=e.device_type,t=f.getAllDeviceModels().find(n=>n.id===r);return{id:r,productName:e.name,usbProductId:16,legacyUsbProductId:1,bootloaderUsbProductId:1,getBlockSize:t?t.getBlockSize:()=>32,usbOnly:!0,memorySize:t?.memorySize??320*1024,masks:e.masks??T}}}const E=(s,e)=>({config:r,loggerServiceFactory:t})=>new g(t,s??r.mockUrl,e);0&&(module.exports={MockTransport,mockserverIdentifier,mockserverTransportFactory});
|
|
2
2
|
//# sourceMappingURL=MockserverTransport.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/MockserverTransport.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n type ApduResponse,\n type ConnectError,\n type DeviceId,\n type DeviceModelId,\n DisconnectError,\n type DisconnectHandler,\n type
|
|
5
|
-
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,mBAAAE,EAAA,yBAAAC,EAAA,+BAAAC,IAAA,eAAAC,EAAAL,GAAA,IAAAM,
|
|
6
|
-
"names": ["MockserverTransport_exports", "__export", "MockTransport", "mockserverIdentifier", "mockserverTransportFactory", "__toCommonJS", "import_device_management_kit", "import_device_mockserver_client", "import_purify_ts", "import_rxjs", "loggerServiceFactory", "
|
|
4
|
+
"sourcesContent": ["import {\n type ApduResponse,\n type ConnectError,\n type DeviceId,\n type DeviceModelId,\n DisconnectError,\n type DisconnectHandler,\n type DmkError,\n formatApduReceivedLog,\n formatApduSentLog,\n hexaStringToBuffer,\n type LoggerPublisherService,\n NoAccessibleDeviceError,\n OpeningConnectionError,\n StaticDeviceModelDataSource,\n type Transport,\n type TransportConnectedDevice,\n type TransportDiscoveredDevice,\n type TransportFactory,\n type TransportIdentifier,\n} from \"@ledgerhq/device-management-kit\";\nimport {\n type CommandResponse,\n type Device,\n MockClient,\n} from \"@ledgerhq/device-mockserver-client\";\nimport { type Either, Left, Right } from \"purify-ts\";\nimport {\n catchError,\n from,\n map,\n mergeMap,\n type Observable,\n of,\n switchMap,\n timer,\n} from \"rxjs\";\n\nexport const mockserverIdentifier: TransportIdentifier = \"MOCKSERVER\";\n\nconst DEFAULT_MASKS = [0x31100000];\n\n/**\n * Real per-model memory constants (memory size, block size, masks) so mock\n * devices report the same values as physical ones. Without this, memory-aware\n * device actions (e.g. install/update apps, which run {@link PredictOutOfMemoryTask})\n * compute against wrong constants and wrongly report out-of-memory.\n */\nconst deviceModelDataSource = new StaticDeviceModelDataSource();\n\n/** Interval (ms) at which the mock server is polled for available devices. */\nconst DISCOVERY_POLL_INTERVAL_MS = 1000;\n\nexport class MockTransport implements Transport {\n private logger: LoggerPublisherService;\n private mockClient: MockClient;\n private readonly identifier: TransportIdentifier = mockserverIdentifier;\n\n constructor(\n loggerServiceFactory: (tag: string) => LoggerPublisherService,\n mockUrl: string,\n sessionToken?: string,\n ) {\n this.logger = loggerServiceFactory(\"MockTransport\");\n this.mockClient = new MockClient(mockUrl, { token: sessionToken });\n }\n\n isSupported(): boolean {\n return true;\n }\n\n getIdentifier(): TransportIdentifier {\n return this.identifier;\n }\n\n listenToAvailableDevices(): Observable<TransportDiscoveredDevice[]> {\n this.logger.debug(\"listenToAvailableDevices\");\n return timer(0, DISCOVERY_POLL_INTERVAL_MS).pipe(\n switchMap(() => from(this.mockClient.listDevices())),\n map((devices) => this.mapToDiscoveredDevices(devices)),\n catchError((error) => {\n this.logger.error(\"listenToAvailableDevices failed\", {\n data: { error },\n });\n return of([]);\n }),\n );\n }\n\n startDiscovering(): Observable<TransportDiscoveredDevice> {\n this.logger.debug(\"startDiscovering\");\n return from(this.mockClient.listDevices()).pipe(\n map((devices) => this.mapToDiscoveredDevices(devices)),\n mergeMap((devices) => from(devices)),\n );\n }\n\n stopDiscovering(): void {\n //DO NOTHING HERE\n this.logger.debug(\"stopDiscovering\");\n }\n\n async connect(params: {\n deviceId: DeviceId;\n onDisconnect: DisconnectHandler;\n }): Promise<Either<ConnectError, TransportConnectedDevice>> {\n this.logger.debug(\"connect\");\n const deviceId: string = params.deviceId;\n try {\n const { device } = await this.mockClient.connect(deviceId);\n const connectedDevice = {\n sendApdu: (apdu) =>\n this.sendApdu(deviceId, params.deviceId, params.onDisconnect, apdu),\n deviceModel: this.buildDeviceModel(device),\n id: params.deviceId,\n type: device.connectivity_type,\n transport: this.identifier,\n } as TransportConnectedDevice;\n return Right(connectedDevice);\n } catch (error) {\n return Left(new OpeningConnectionError(error as Error));\n }\n }\n\n async disconnect(params: {\n connectedDevice: TransportConnectedDevice;\n }): Promise<Either<DmkError, void>> {\n this.logger.debug(\"disconnect\");\n const deviceId: string = params.connectedDevice.id;\n try {\n const success: boolean = await this.mockClient.disconnect(deviceId);\n if (!success) {\n return Left(\n new DisconnectError(new Error(`Failed to disconnect ${deviceId}`)),\n );\n }\n return Right(undefined);\n } catch (error) {\n return Left(new DisconnectError(error as Error));\n }\n }\n\n async sendApdu(\n deviceId: string,\n onDisconnectDeviceId: DeviceId,\n onDisconnect: DisconnectHandler,\n apdu: Uint8Array,\n ): Promise<Either<DmkError, ApduResponse>> {\n this.logger.debug(\"send\");\n try {\n const response: CommandResponse = await this.mockClient.sendApdu(\n deviceId,\n apdu,\n );\n this.logger.debug(formatApduSentLog(apdu));\n const apduResponse = {\n statusCode:\n hexaStringToBuffer(response.response.slice(-4)) ?? new Uint8Array(),\n data:\n hexaStringToBuffer(response.response.slice(0, -4)) ??\n new Uint8Array(),\n } as ApduResponse;\n this.logger.debug(formatApduReceivedLog(apduResponse));\n return Right(apduResponse);\n } catch (error) {\n onDisconnect(onDisconnectDeviceId);\n return Left(new NoAccessibleDeviceError(error as Error));\n }\n }\n\n private mapToDiscoveredDevices(\n devices: Device[],\n ): TransportDiscoveredDevice[] {\n return devices.map((device) => ({\n id: device.id,\n deviceModel: this.buildDeviceModel(device),\n transport: this.identifier,\n }));\n }\n\n private buildDeviceModel(device: Device) {\n const id = device.device_type as DeviceModelId;\n // Resolve the real model to mirror a physical device's memory constants;\n // fall back to legacy defaults for an unknown device type.\n const knownModel = deviceModelDataSource\n .getAllDeviceModels()\n .find((model) => model.id === id);\n return {\n id,\n productName: device.name,\n usbProductId: 0x10,\n legacyUsbProductId: 0x0001,\n bootloaderUsbProductId: 0x0001,\n getBlockSize: knownModel ? knownModel.getBlockSize : () => 32,\n usbOnly: true,\n memorySize: knownModel?.memorySize ?? 320 * 1024,\n masks: device.masks ?? DEFAULT_MASKS,\n };\n }\n}\n\n/**\n * Build a mock-server transport factory.\n *\n * @param mockUrl Optional mock server URL. When omitted, `config.mockUrl` from\n * the DMK configuration is used.\n * @param sessionToken Optional bearer token to share an existing session\n * When omitted, the client self-provisions a session via /auth.\n */\nexport const mockserverTransportFactory =\n (mockUrl?: string, sessionToken?: string): TransportFactory =>\n ({ config, loggerServiceFactory }) =>\n new MockTransport(\n loggerServiceFactory,\n mockUrl ?? config.mockUrl,\n sessionToken,\n );\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["MockserverTransport_exports", "__export", "MockTransport", "mockserverIdentifier", "mockserverTransportFactory", "__toCommonJS", "import_device_management_kit", "import_device_mockserver_client", "import_purify_ts", "import_rxjs", "DEFAULT_MASKS", "deviceModelDataSource", "DISCOVERY_POLL_INTERVAL_MS", "loggerServiceFactory", "mockUrl", "sessionToken", "devices", "error", "params", "deviceId", "device", "connectedDevice", "apdu", "onDisconnectDeviceId", "onDisconnect", "response", "apduResponse", "id", "knownModel", "model", "config"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var f=require("@ledgerhq/device-management-kit"),l=require("@ledgerhq/device-mockserver-client"),d=require("rxjs"),n=require("./MockserverTransport");vi.mock("@ledgerhq/device-mockserver-client",()=>({MockClient:vi.fn()}));const h=()=>({debug:vi.fn(),info:vi.fn(),warn:vi.fn(),error:vi.fn()}),c={config:{mockUrl:"http://localhost:8080"},loggerServiceFactory:h},p=(t={})=>({id:"device-1",name:"Ledger Nano X",device_type:"nanoX",connectivity_type:"USB",...t}),v=t=>{const e=vi.fn(t);return vi.mocked(l.MockClient).mockImplementation(()=>({listDevices:e})),e},i=(t={})=>{const e={listDevices:vi.fn(()=>Promise.resolve([])),connect:vi.fn(),disconnect:vi.fn(),sendApdu:vi.fn(),...t};return vi.mocked(l.MockClient).mockImplementation(()=>e),e};describe("mockserverTransportFactory",()=>{beforeEach(()=>{vi.clearAllMocks(),v(()=>Promise.resolve([]))}),it("builds a supported transport with the mockserver identifier",()=>{const t=(0,n.mockserverTransportFactory)("http://localhost:8080")(c);expect(t.getIdentifier()).toBe(n.mockserverIdentifier),expect(t.isSupported()).toBe(!0)}),it("accepts an injected session token without throwing",()=>{expect(()=>(0,n.mockserverTransportFactory)("http://localhost:8080","tok-123")(c)).not.toThrow()}),describe("listenToAvailableDevices",()=>{it("emits the mock server devices mapped as discovered devices",async()=>{v(()=>Promise.resolve([p(),p({id:"device-2",name:"Stax"})]));const t=(0,n.mockserverTransportFactory)("http://localhost:8080")(c),e=await(0,d.firstValueFrom)(t.listenToAvailableDevices());expect(e).toEqual([expect.objectContaining({id:"device-1",transport:n.mockserverIdentifier}),expect.objectContaining({id:"device-2",transport:n.mockserverIdentifier})])}),it("keeps polling so newly added devices appear",async()=>{v(()=>Promise.resolve([])).mockResolvedValueOnce([]).mockResolvedValueOnce([p()]);const e=(0,n.mockserverTransportFactory)("http://localhost:8080")(c),o=await(0,d.firstValueFrom)(e.listenToAvailableDevices().pipe((0,d.take)(2),(0,d.toArray)()));expect(o[0]).toEqual([]),expect(o[1]).toEqual([expect.objectContaining({id:"device-1"})])}),it("emits an empty list when the mock server is unreachable",async()=>{v(()=>Promise.reject(new Error("offline")));const t=(0,n.mockserverTransportFactory)("http://localhost:8080")(c),e=await(0,d.firstValueFrom)(t.listenToAvailableDevices());expect(e).toEqual([])})}),describe("startDiscovering",()=>{it("emits each device returned by the mock server",async()=>{i({listDevices:vi.fn(()=>Promise.resolve([p(),p({id:"device-2",name:"Stax"})]))});const t=(0,n.mockserverTransportFactory)("http://localhost:8080")(c),e=await(0,d.firstValueFrom)(t.startDiscovering().pipe((0,d.toArray)()));expect(e).toEqual([expect.objectContaining({id:"device-1"}),expect.objectContaining({id:"device-2"})])})}),describe("stopDiscovering",()=>{it("does nothing and does not throw",()=>{i();const t=(0,n.mockserverTransportFactory)("http://localhost:8080")(c);expect(()=>t.stopDiscovering()).not.toThrow()})}),describe("connect",()=>{it("returns a connected device on success",async()=>{i({connect:vi.fn(()=>Promise.resolve({device:p({masks:[305419896]}),connected:!0}))});const t=(0,n.mockserverTransportFactory)("http://localhost:8080")(c),e=vi.fn(),o=await t.connect({deviceId:"device-1",onDisconnect:e});expect(o.isRight()).toBe(!0);const s=o.unsafeCoerce();expect(s.id).toBe("device-1"),expect(s.transport).toBe(n.mockserverIdentifier),expect(s.deviceModel.masks).toEqual([305419896])}),it("falls back to the default masks when the device has none",async()=>{i({connect:vi.fn(()=>Promise.resolve({device:p(),connected:!0}))});const e=await(0,n.mockserverTransportFactory)("http://localhost:8080")(c).connect({deviceId:"device-1",onDisconnect:vi.fn()});expect(e.unsafeCoerce().deviceModel.masks).toEqual([823132160]),expect(e.unsafeCoerce().deviceModel.getBlockSize({firmwareVersion:"1.0.0"})).toBe(4*1024)}),it("returns an OpeningConnectionError when the client throws",async()=>{i({connect:vi.fn(()=>Promise.reject(new Error("nope")))});const e=await(0,n.mockserverTransportFactory)("http://localhost:8080")(c).connect({deviceId:"device-1",onDisconnect:vi.fn()});expect(e.isLeft()).toBe(!0),expect(e.swap().unsafeCoerce()).toBeInstanceOf(f.OpeningConnectionError)})}),describe("disconnect",()=>{const t={id:"device-1"};it("returns Right(undefined) when the client disconnects successfully",async()=>{const e=vi.fn(()=>Promise.resolve(!0));i({disconnect:e});const s=await(0,n.mockserverTransportFactory)("http://localhost:8080")(c).disconnect({connectedDevice:t});expect(e).toHaveBeenCalledWith("device-1"),expect(s.isRight()).toBe(!0)}),it("returns a DisconnectError when the client reports failure",async()=>{i({disconnect:vi.fn(()=>Promise.resolve(!1))});const o=await(0,n.mockserverTransportFactory)("http://localhost:8080")(c).disconnect({connectedDevice:t});expect(o.isLeft()).toBe(!0)}),it("returns a DisconnectError when the client throws",async()=>{i({disconnect:vi.fn(()=>Promise.reject(new Error("boom")))});const o=await(0,n.mockserverTransportFactory)("http://localhost:8080")(c).disconnect({connectedDevice:t});expect(o.isLeft()).toBe(!0)})}),describe("sendApdu",()=>{const t=e=>(i({connect:vi.fn(()=>Promise.resolve({device:p(),connected:!0})),sendApdu:e}),(0,n.mockserverTransportFactory)("http://localhost:8080")(c));it("splits the response into data and status code",async()=>{const e=vi.fn(()=>Promise.resolve({response:"aabb9000"})),o=t(e),s=vi.fn(),r=await(await o.connect({deviceId:"device-1",onDisconnect:s})).unsafeCoerce().sendApdu(Uint8Array.from([224,1,0,0]));expect(r.isRight()).toBe(!0);const u=r.unsafeCoerce();expect(Array.from(u.data)).toEqual([170,187]),expect(Array.from(u.statusCode)).toEqual([144,0]),expect(s).not.toHaveBeenCalled()}),it("calls onDisconnect and returns a NoAccessibleDeviceError on failure",async()=>{const e=vi.fn(()=>Promise.reject(new Error("device lost"))),o=t(e),s=vi.fn(),r=await(await o.connect({deviceId:"device-1",onDisconnect:s})).unsafeCoerce().sendApdu(Uint8Array.from([224,1,0,0]));expect(r.isLeft()).toBe(!0),expect(s).toHaveBeenCalledWith("device-1")}),it("returns an empty data buffer when the response is only a status word",async()=>{const e=vi.fn(()=>Promise.resolve({response:"9000"})),a=await(await t(e).connect({deviceId:"device-1",onDisconnect:vi.fn()})).unsafeCoerce().sendApdu(Uint8Array.from([224,1,0,0]));expect(a.isRight()).toBe(!0);const r=a.unsafeCoerce();expect(Array.from(r.data)).toEqual([]),expect(Array.from(r.statusCode)).toEqual([144,0])}),it("falls back to an empty status code when the status word hex is invalid",async()=>{const e=vi.fn(()=>Promise.resolve({response:"aabbXXYY"})),a=await(await t(e).connect({deviceId:"device-1",onDisconnect:vi.fn()})).unsafeCoerce().sendApdu(Uint8Array.from([224,1,0,0]));expect(a.isRight()).toBe(!0);const r=a.unsafeCoerce();expect(Array.from(r.statusCode)).toEqual([]),expect(Array.from(r.data)).toEqual([170,187])}),it("falls back to an empty data buffer when the data hex is invalid",async()=>{const e=vi.fn(()=>Promise.resolve({response:"ZZZZ9000"})),a=await(await t(e).connect({deviceId:"device-1",onDisconnect:vi.fn()})).unsafeCoerce().sendApdu(Uint8Array.from([224,1,0,0]));expect(a.isRight()).toBe(!0);const r=a.unsafeCoerce();expect(Array.from(r.data)).toEqual([]),expect(Array.from(r.statusCode)).toEqual([144,0])})}),describe("mockserverTransportFactory",()=>{it("uses the config mock url when no explicit url is provided",()=>{const t=i();expect(t).toBeDefined(),(0,n.mockserverTransportFactory)()(c),expect(l.MockClient).toHaveBeenCalledWith("http://localhost:8080",expect.anything())}),it("prefers an explicit url over the config mock url",()=>{i(),(0,n.mockserverTransportFactory)("https://explicit:9090")(c),expect(l.MockClient).toHaveBeenCalledWith("https://explicit:9090",expect.anything())})})});
|
|
2
|
+
//# sourceMappingURL=MockserverTransport.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 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": ["import_device_management_kit", "import_device_mockserver_client", "import_rxjs", "import_MockserverTransport", "loggerServiceFactory", "transportArgs", "aDevice", "overrides", "mockListDevices", "impl", "listDevices", "mockClientImpl", "client", "transport", "devices", "emissions", "onDisconnect", "result", "connected", "connectedDevice", "disconnect", "buildConnectedTransport", "sendApdu", "apduResponse"]
|
|
7
|
+
}
|
package/lib/cjs/package.json
CHANGED
|
@@ -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": "
|
|
35
|
+
"@ledgerhq/device-management-kit": "^1.7.1",
|
|
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.0
|
|
59
|
+
"version": "1.1.0"
|
|
60
60
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{DisconnectError as p,formatApduReceivedLog as g,formatApduSentLog as
|
|
1
|
+
import{DisconnectError as p,formatApduReceivedLog as g,formatApduSentLog as D,hexaStringToBuffer as l,NoAccessibleDeviceError as u,OpeningConnectionError as m,StaticDeviceModelDataSource as h}from"@ledgerhq/device-management-kit";import{MockClient as y}from"@ledgerhq/device-mockserver-client";import{Left as n,Right as s}from"purify-ts";import{catchError as b,from as c,map as v,mergeMap as T,of as f,switchMap as k,timer as E}from"rxjs";const I="MOCKSERVER",C=[823132160],A=new h,M=1e3;class S{logger;mockClient;identifier=I;constructor(e,r,t){this.logger=e("MockTransport"),this.mockClient=new y(r,{token:t})}isSupported(){return!0}getIdentifier(){return this.identifier}listenToAvailableDevices(){return this.logger.debug("listenToAvailableDevices"),E(0,M).pipe(k(()=>c(this.mockClient.listDevices())),v(e=>this.mapToDiscoveredDevices(e)),b(e=>(this.logger.error("listenToAvailableDevices failed",{data:{error:e}}),f([]))))}startDiscovering(){return this.logger.debug("startDiscovering"),c(this.mockClient.listDevices()).pipe(v(e=>this.mapToDiscoveredDevices(e)),T(e=>c(e)))}stopDiscovering(){this.logger.debug("stopDiscovering")}async connect(e){this.logger.debug("connect");const r=e.deviceId;try{const{device:t}=await this.mockClient.connect(r),i={sendApdu:o=>this.sendApdu(r,e.deviceId,e.onDisconnect,o),deviceModel:this.buildDeviceModel(t),id:e.deviceId,type:t.connectivity_type,transport:this.identifier};return s(i)}catch(t){return n(new m(t))}}async disconnect(e){this.logger.debug("disconnect");const r=e.connectedDevice.id;try{return await this.mockClient.disconnect(r)?s(void 0):n(new p(new Error(`Failed to disconnect ${r}`)))}catch(t){return n(new p(t))}}async sendApdu(e,r,t,i){this.logger.debug("send");try{const o=await this.mockClient.sendApdu(e,i);this.logger.debug(D(i));const a={statusCode:l(o.response.slice(-4))??new Uint8Array,data:l(o.response.slice(0,-4))??new Uint8Array};return this.logger.debug(g(a)),s(a)}catch(o){return t(r),n(new u(o))}}mapToDiscoveredDevices(e){return e.map(r=>({id:r.id,deviceModel:this.buildDeviceModel(r),transport:this.identifier}))}buildDeviceModel(e){const r=e.device_type,t=A.getAllDeviceModels().find(i=>i.id===r);return{id:r,productName:e.name,usbProductId:16,legacyUsbProductId:1,bootloaderUsbProductId:1,getBlockSize:t?t.getBlockSize:()=>32,usbOnly:!0,memorySize:t?.memorySize??320*1024,masks:e.masks??C}}}const x=(d,e)=>({config:r,loggerServiceFactory:t})=>new S(t,d??r.mockUrl,e);export{S as MockTransport,I as mockserverIdentifier,x as mockserverTransportFactory};
|
|
2
2
|
//# sourceMappingURL=MockserverTransport.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/MockserverTransport.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n type ApduResponse,\n type ConnectError,\n type DeviceId,\n type DeviceModelId,\n DisconnectError,\n type DisconnectHandler,\n type
|
|
5
|
-
"mappings": "AAAA,OAKE,mBAAAA,
|
|
6
|
-
"names": ["DisconnectError", "formatApduReceivedLog", "formatApduSentLog", "NoAccessibleDeviceError", "OpeningConnectionError", "MockClient", "Left", "Right", "from", "mergeMap", "mockserverIdentifier", "MockTransport", "loggerServiceFactory", "
|
|
4
|
+
"sourcesContent": ["import {\n type ApduResponse,\n type ConnectError,\n type DeviceId,\n type DeviceModelId,\n DisconnectError,\n type DisconnectHandler,\n type DmkError,\n formatApduReceivedLog,\n formatApduSentLog,\n hexaStringToBuffer,\n type LoggerPublisherService,\n NoAccessibleDeviceError,\n OpeningConnectionError,\n StaticDeviceModelDataSource,\n type Transport,\n type TransportConnectedDevice,\n type TransportDiscoveredDevice,\n type TransportFactory,\n type TransportIdentifier,\n} from \"@ledgerhq/device-management-kit\";\nimport {\n type CommandResponse,\n type Device,\n MockClient,\n} from \"@ledgerhq/device-mockserver-client\";\nimport { type Either, Left, Right } from \"purify-ts\";\nimport {\n catchError,\n from,\n map,\n mergeMap,\n type Observable,\n of,\n switchMap,\n timer,\n} from \"rxjs\";\n\nexport const mockserverIdentifier: TransportIdentifier = \"MOCKSERVER\";\n\nconst DEFAULT_MASKS = [0x31100000];\n\n/**\n * Real per-model memory constants (memory size, block size, masks) so mock\n * devices report the same values as physical ones. Without this, memory-aware\n * device actions (e.g. install/update apps, which run {@link PredictOutOfMemoryTask})\n * compute against wrong constants and wrongly report out-of-memory.\n */\nconst deviceModelDataSource = new StaticDeviceModelDataSource();\n\n/** Interval (ms) at which the mock server is polled for available devices. */\nconst DISCOVERY_POLL_INTERVAL_MS = 1000;\n\nexport class MockTransport implements Transport {\n private logger: LoggerPublisherService;\n private mockClient: MockClient;\n private readonly identifier: TransportIdentifier = mockserverIdentifier;\n\n constructor(\n loggerServiceFactory: (tag: string) => LoggerPublisherService,\n mockUrl: string,\n sessionToken?: string,\n ) {\n this.logger = loggerServiceFactory(\"MockTransport\");\n this.mockClient = new MockClient(mockUrl, { token: sessionToken });\n }\n\n isSupported(): boolean {\n return true;\n }\n\n getIdentifier(): TransportIdentifier {\n return this.identifier;\n }\n\n listenToAvailableDevices(): Observable<TransportDiscoveredDevice[]> {\n this.logger.debug(\"listenToAvailableDevices\");\n return timer(0, DISCOVERY_POLL_INTERVAL_MS).pipe(\n switchMap(() => from(this.mockClient.listDevices())),\n map((devices) => this.mapToDiscoveredDevices(devices)),\n catchError((error) => {\n this.logger.error(\"listenToAvailableDevices failed\", {\n data: { error },\n });\n return of([]);\n }),\n );\n }\n\n startDiscovering(): Observable<TransportDiscoveredDevice> {\n this.logger.debug(\"startDiscovering\");\n return from(this.mockClient.listDevices()).pipe(\n map((devices) => this.mapToDiscoveredDevices(devices)),\n mergeMap((devices) => from(devices)),\n );\n }\n\n stopDiscovering(): void {\n //DO NOTHING HERE\n this.logger.debug(\"stopDiscovering\");\n }\n\n async connect(params: {\n deviceId: DeviceId;\n onDisconnect: DisconnectHandler;\n }): Promise<Either<ConnectError, TransportConnectedDevice>> {\n this.logger.debug(\"connect\");\n const deviceId: string = params.deviceId;\n try {\n const { device } = await this.mockClient.connect(deviceId);\n const connectedDevice = {\n sendApdu: (apdu) =>\n this.sendApdu(deviceId, params.deviceId, params.onDisconnect, apdu),\n deviceModel: this.buildDeviceModel(device),\n id: params.deviceId,\n type: device.connectivity_type,\n transport: this.identifier,\n } as TransportConnectedDevice;\n return Right(connectedDevice);\n } catch (error) {\n return Left(new OpeningConnectionError(error as Error));\n }\n }\n\n async disconnect(params: {\n connectedDevice: TransportConnectedDevice;\n }): Promise<Either<DmkError, void>> {\n this.logger.debug(\"disconnect\");\n const deviceId: string = params.connectedDevice.id;\n try {\n const success: boolean = await this.mockClient.disconnect(deviceId);\n if (!success) {\n return Left(\n new DisconnectError(new Error(`Failed to disconnect ${deviceId}`)),\n );\n }\n return Right(undefined);\n } catch (error) {\n return Left(new DisconnectError(error as Error));\n }\n }\n\n async sendApdu(\n deviceId: string,\n onDisconnectDeviceId: DeviceId,\n onDisconnect: DisconnectHandler,\n apdu: Uint8Array,\n ): Promise<Either<DmkError, ApduResponse>> {\n this.logger.debug(\"send\");\n try {\n const response: CommandResponse = await this.mockClient.sendApdu(\n deviceId,\n apdu,\n );\n this.logger.debug(formatApduSentLog(apdu));\n const apduResponse = {\n statusCode:\n hexaStringToBuffer(response.response.slice(-4)) ?? new Uint8Array(),\n data:\n hexaStringToBuffer(response.response.slice(0, -4)) ??\n new Uint8Array(),\n } as ApduResponse;\n this.logger.debug(formatApduReceivedLog(apduResponse));\n return Right(apduResponse);\n } catch (error) {\n onDisconnect(onDisconnectDeviceId);\n return Left(new NoAccessibleDeviceError(error as Error));\n }\n }\n\n private mapToDiscoveredDevices(\n devices: Device[],\n ): TransportDiscoveredDevice[] {\n return devices.map((device) => ({\n id: device.id,\n deviceModel: this.buildDeviceModel(device),\n transport: this.identifier,\n }));\n }\n\n private buildDeviceModel(device: Device) {\n const id = device.device_type as DeviceModelId;\n // Resolve the real model to mirror a physical device's memory constants;\n // fall back to legacy defaults for an unknown device type.\n const knownModel = deviceModelDataSource\n .getAllDeviceModels()\n .find((model) => model.id === id);\n return {\n id,\n productName: device.name,\n usbProductId: 0x10,\n legacyUsbProductId: 0x0001,\n bootloaderUsbProductId: 0x0001,\n getBlockSize: knownModel ? knownModel.getBlockSize : () => 32,\n usbOnly: true,\n memorySize: knownModel?.memorySize ?? 320 * 1024,\n masks: device.masks ?? DEFAULT_MASKS,\n };\n }\n}\n\n/**\n * Build a mock-server transport factory.\n *\n * @param mockUrl Optional mock server URL. When omitted, `config.mockUrl` from\n * the DMK configuration is used.\n * @param sessionToken Optional bearer token to share an existing session\n * When omitted, the client self-provisions a session via /auth.\n */\nexport const mockserverTransportFactory =\n (mockUrl?: string, sessionToken?: string): TransportFactory =>\n ({ config, loggerServiceFactory }) =>\n new MockTransport(\n loggerServiceFactory,\n mockUrl ?? config.mockUrl,\n sessionToken,\n );\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["DisconnectError", "formatApduReceivedLog", "formatApduSentLog", "hexaStringToBuffer", "NoAccessibleDeviceError", "OpeningConnectionError", "StaticDeviceModelDataSource", "MockClient", "Left", "Right", "catchError", "from", "map", "mergeMap", "of", "switchMap", "timer", "mockserverIdentifier", "DEFAULT_MASKS", "deviceModelDataSource", "DISCOVERY_POLL_INTERVAL_MS", "MockTransport", "loggerServiceFactory", "mockUrl", "sessionToken", "devices", "error", "params", "deviceId", "device", "connectedDevice", "apdu", "onDisconnectDeviceId", "onDisconnect", "response", "apduResponse", "id", "knownModel", "model", "mockserverTransportFactory", "config"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{OpeningConnectionError as m}from"@ledgerhq/device-management-kit";import{MockClient as u}from"@ledgerhq/device-mockserver-client";import{firstValueFrom as p,take as x,toArray as h}from"rxjs";import{mockserverIdentifier as l,mockserverTransportFactory as o}from"./MockserverTransport";vi.mock("@ledgerhq/device-mockserver-client",()=>({MockClient:vi.fn()}));const y=()=>({debug:vi.fn(),info:vi.fn(),warn:vi.fn(),error:vi.fn()}),c={config:{mockUrl:"http://localhost:8080"},loggerServiceFactory:y},d=(t={})=>({id:"device-1",name:"Ledger Nano X",device_type:"nanoX",connectivity_type:"USB",...t}),v=t=>{const e=vi.fn(t);return vi.mocked(u).mockImplementation(()=>({listDevices:e})),e},i=(t={})=>{const e={listDevices:vi.fn(()=>Promise.resolve([])),connect:vi.fn(),disconnect:vi.fn(),sendApdu:vi.fn(),...t};return vi.mocked(u).mockImplementation(()=>e),e};describe("mockserverTransportFactory",()=>{beforeEach(()=>{vi.clearAllMocks(),v(()=>Promise.resolve([]))}),it("builds a supported transport with the mockserver identifier",()=>{const t=o("http://localhost:8080")(c);expect(t.getIdentifier()).toBe(l),expect(t.isSupported()).toBe(!0)}),it("accepts an injected session token without throwing",()=>{expect(()=>o("http://localhost:8080","tok-123")(c)).not.toThrow()}),describe("listenToAvailableDevices",()=>{it("emits the mock server devices mapped as discovered devices",async()=>{v(()=>Promise.resolve([d(),d({id:"device-2",name:"Stax"})]));const t=o("http://localhost:8080")(c),e=await p(t.listenToAvailableDevices());expect(e).toEqual([expect.objectContaining({id:"device-1",transport:l}),expect.objectContaining({id:"device-2",transport:l})])}),it("keeps polling so newly added devices appear",async()=>{v(()=>Promise.resolve([])).mockResolvedValueOnce([]).mockResolvedValueOnce([d()]);const e=o("http://localhost:8080")(c),n=await p(e.listenToAvailableDevices().pipe(x(2),h()));expect(n[0]).toEqual([]),expect(n[1]).toEqual([expect.objectContaining({id:"device-1"})])}),it("emits an empty list when the mock server is unreachable",async()=>{v(()=>Promise.reject(new Error("offline")));const t=o("http://localhost:8080")(c),e=await p(t.listenToAvailableDevices());expect(e).toEqual([])})}),describe("startDiscovering",()=>{it("emits each device returned by the mock server",async()=>{i({listDevices:vi.fn(()=>Promise.resolve([d(),d({id:"device-2",name:"Stax"})]))});const t=o("http://localhost:8080")(c),e=await p(t.startDiscovering().pipe(h()));expect(e).toEqual([expect.objectContaining({id:"device-1"}),expect.objectContaining({id:"device-2"})])})}),describe("stopDiscovering",()=>{it("does nothing and does not throw",()=>{i();const t=o("http://localhost:8080")(c);expect(()=>t.stopDiscovering()).not.toThrow()})}),describe("connect",()=>{it("returns a connected device on success",async()=>{i({connect:vi.fn(()=>Promise.resolve({device:d({masks:[305419896]}),connected:!0}))});const t=o("http://localhost:8080")(c),e=vi.fn(),n=await t.connect({deviceId:"device-1",onDisconnect:e});expect(n.isRight()).toBe(!0);const s=n.unsafeCoerce();expect(s.id).toBe("device-1"),expect(s.transport).toBe(l),expect(s.deviceModel.masks).toEqual([305419896])}),it("falls back to the default masks when the device has none",async()=>{i({connect:vi.fn(()=>Promise.resolve({device:d(),connected:!0}))});const e=await o("http://localhost:8080")(c).connect({deviceId:"device-1",onDisconnect:vi.fn()});expect(e.unsafeCoerce().deviceModel.masks).toEqual([823132160]),expect(e.unsafeCoerce().deviceModel.getBlockSize({firmwareVersion:"1.0.0"})).toBe(4*1024)}),it("returns an OpeningConnectionError when the client throws",async()=>{i({connect:vi.fn(()=>Promise.reject(new Error("nope")))});const e=await o("http://localhost:8080")(c).connect({deviceId:"device-1",onDisconnect:vi.fn()});expect(e.isLeft()).toBe(!0),expect(e.swap().unsafeCoerce()).toBeInstanceOf(m)})}),describe("disconnect",()=>{const t={id:"device-1"};it("returns Right(undefined) when the client disconnects successfully",async()=>{const e=vi.fn(()=>Promise.resolve(!0));i({disconnect:e});const s=await o("http://localhost:8080")(c).disconnect({connectedDevice:t});expect(e).toHaveBeenCalledWith("device-1"),expect(s.isRight()).toBe(!0)}),it("returns a DisconnectError when the client reports failure",async()=>{i({disconnect:vi.fn(()=>Promise.resolve(!1))});const n=await o("http://localhost:8080")(c).disconnect({connectedDevice:t});expect(n.isLeft()).toBe(!0)}),it("returns a DisconnectError when the client throws",async()=>{i({disconnect:vi.fn(()=>Promise.reject(new Error("boom")))});const n=await o("http://localhost:8080")(c).disconnect({connectedDevice:t});expect(n.isLeft()).toBe(!0)})}),describe("sendApdu",()=>{const t=e=>(i({connect:vi.fn(()=>Promise.resolve({device:d(),connected:!0})),sendApdu:e}),o("http://localhost:8080")(c));it("splits the response into data and status code",async()=>{const e=vi.fn(()=>Promise.resolve({response:"aabb9000"})),n=t(e),s=vi.fn(),r=await(await n.connect({deviceId:"device-1",onDisconnect:s})).unsafeCoerce().sendApdu(Uint8Array.from([224,1,0,0]));expect(r.isRight()).toBe(!0);const f=r.unsafeCoerce();expect(Array.from(f.data)).toEqual([170,187]),expect(Array.from(f.statusCode)).toEqual([144,0]),expect(s).not.toHaveBeenCalled()}),it("calls onDisconnect and returns a NoAccessibleDeviceError on failure",async()=>{const e=vi.fn(()=>Promise.reject(new Error("device lost"))),n=t(e),s=vi.fn(),r=await(await n.connect({deviceId:"device-1",onDisconnect:s})).unsafeCoerce().sendApdu(Uint8Array.from([224,1,0,0]));expect(r.isLeft()).toBe(!0),expect(s).toHaveBeenCalledWith("device-1")}),it("returns an empty data buffer when the response is only a status word",async()=>{const e=vi.fn(()=>Promise.resolve({response:"9000"})),a=await(await t(e).connect({deviceId:"device-1",onDisconnect:vi.fn()})).unsafeCoerce().sendApdu(Uint8Array.from([224,1,0,0]));expect(a.isRight()).toBe(!0);const r=a.unsafeCoerce();expect(Array.from(r.data)).toEqual([]),expect(Array.from(r.statusCode)).toEqual([144,0])}),it("falls back to an empty status code when the status word hex is invalid",async()=>{const e=vi.fn(()=>Promise.resolve({response:"aabbXXYY"})),a=await(await t(e).connect({deviceId:"device-1",onDisconnect:vi.fn()})).unsafeCoerce().sendApdu(Uint8Array.from([224,1,0,0]));expect(a.isRight()).toBe(!0);const r=a.unsafeCoerce();expect(Array.from(r.statusCode)).toEqual([]),expect(Array.from(r.data)).toEqual([170,187])}),it("falls back to an empty data buffer when the data hex is invalid",async()=>{const e=vi.fn(()=>Promise.resolve({response:"ZZZZ9000"})),a=await(await t(e).connect({deviceId:"device-1",onDisconnect:vi.fn()})).unsafeCoerce().sendApdu(Uint8Array.from([224,1,0,0]));expect(a.isRight()).toBe(!0);const r=a.unsafeCoerce();expect(Array.from(r.data)).toEqual([]),expect(Array.from(r.statusCode)).toEqual([144,0])})}),describe("mockserverTransportFactory",()=>{it("uses the config mock url when no explicit url is provided",()=>{const t=i();expect(t).toBeDefined(),o()(c),expect(u).toHaveBeenCalledWith("http://localhost:8080",expect.anything())}),it("prefers an explicit url over the config mock url",()=>{i(),o("https://explicit:9090")(c),expect(u).toHaveBeenCalledWith("https://explicit:9090",expect.anything())})})});
|
|
2
|
+
//# sourceMappingURL=MockserverTransport.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 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"]
|
|
7
|
+
}
|
package/lib/esm/package.json
CHANGED
|
@@ -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": "
|
|
35
|
+
"@ledgerhq/device-management-kit": "^1.7.1",
|
|
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.0
|
|
59
|
+
"version": "1.1.0"
|
|
60
60
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ApduResponse, type ConnectError, type DeviceId, type DisconnectHandler, type
|
|
1
|
+
import { type ApduResponse, type ConnectError, type DeviceId, type DisconnectHandler, type DmkError, type LoggerPublisherService, type Transport, type TransportConnectedDevice, type TransportDiscoveredDevice, type TransportFactory, type TransportIdentifier } from "@ledgerhq/device-management-kit";
|
|
2
2
|
import { type Either } from "purify-ts";
|
|
3
3
|
import { type Observable } from "rxjs";
|
|
4
4
|
export declare const mockserverIdentifier: TransportIdentifier;
|
|
@@ -6,7 +6,7 @@ export declare class MockTransport implements Transport {
|
|
|
6
6
|
private logger;
|
|
7
7
|
private mockClient;
|
|
8
8
|
private readonly identifier;
|
|
9
|
-
constructor(loggerServiceFactory: (tag: string) => LoggerPublisherService,
|
|
9
|
+
constructor(loggerServiceFactory: (tag: string) => LoggerPublisherService, mockUrl: string, sessionToken?: string);
|
|
10
10
|
isSupported(): boolean;
|
|
11
11
|
getIdentifier(): TransportIdentifier;
|
|
12
12
|
listenToAvailableDevices(): Observable<TransportDiscoveredDevice[]>;
|
|
@@ -19,7 +19,17 @@ export declare class MockTransport implements Transport {
|
|
|
19
19
|
disconnect(params: {
|
|
20
20
|
connectedDevice: TransportConnectedDevice;
|
|
21
21
|
}): Promise<Either<DmkError, void>>;
|
|
22
|
-
sendApdu(
|
|
22
|
+
sendApdu(deviceId: string, onDisconnectDeviceId: DeviceId, onDisconnect: DisconnectHandler, apdu: Uint8Array): Promise<Either<DmkError, ApduResponse>>;
|
|
23
|
+
private mapToDiscoveredDevices;
|
|
24
|
+
private buildDeviceModel;
|
|
23
25
|
}
|
|
24
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Build a mock-server transport factory.
|
|
28
|
+
*
|
|
29
|
+
* @param mockUrl Optional mock server URL. When omitted, `config.mockUrl` from
|
|
30
|
+
* the DMK configuration is used.
|
|
31
|
+
* @param sessionToken Optional bearer token to share an existing session
|
|
32
|
+
* When omitted, the client self-provisions a session via /auth.
|
|
33
|
+
*/
|
|
34
|
+
export declare const mockserverTransportFactory: (mockUrl?: string, sessionToken?: string) => TransportFactory;
|
|
25
35
|
//# sourceMappingURL=MockserverTransport.d.ts.map
|
|
@@ -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,
|
|
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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MockserverTransport.test.d.ts","sourceRoot":"","sources":["../../src/MockserverTransport.test.ts"],"names":[],"mappings":""}
|