diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index cdc16cedc..c4b0316b4 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -19,7 +19,7 @@ jobs: danger: name: Run Danger check - if: ${{ !contains(github.ref_name, 'dependencies') }} + if: ${{ github.actor != 'dependabot[bot]' }} runs-on: [ubuntu-latest] steps: - uses: actions/checkout@v4 diff --git a/packages/core/src/api/DeviceSdk.ts b/packages/core/src/api/DeviceSdk.ts index d2d585df7..589072948 100644 --- a/packages/core/src/api/DeviceSdk.ts +++ b/packages/core/src/api/DeviceSdk.ts @@ -9,29 +9,25 @@ import { import { ApduResponse } from "@api/device-session/ApduResponse"; import { DeviceSessionState } from "@api/device-session/DeviceSessionState"; import { DeviceSessionId } from "@api/device-session/types"; +import { + ConnectUseCaseArgs, + DisconnectUseCaseArgs, + DiscoveredDevice, + SendApduUseCaseArgs, +} from "@api/types"; import { ConnectedDevice } from "@api/usb/model/ConnectedDevice"; import { configTypes } from "@internal/config/di/configTypes"; import { GetSdkVersionUseCase } from "@internal/config/use-case/GetSdkVersionUseCase"; import { deviceSessionTypes } from "@internal/device-session/di/deviceSessionTypes"; import { GetDeviceSessionStateUseCase } from "@internal/device-session/use-case/GetDeviceSessionStateUseCase"; import { discoveryTypes } from "@internal/discovery/di/discoveryTypes"; -import { - ConnectUseCase, - ConnectUseCaseArgs, -} from "@internal/discovery/use-case/ConnectUseCase"; -import { - DisconnectUseCase, - DisconnectUseCaseArgs, -} from "@internal/discovery/use-case/DisconnectUseCase"; +import { ConnectUseCase } from "@internal/discovery/use-case/ConnectUseCase"; +import { DisconnectUseCase } from "@internal/discovery/use-case/DisconnectUseCase"; import type { StartDiscoveringUseCase } from "@internal/discovery/use-case/StartDiscoveringUseCase"; import type { StopDiscoveringUseCase } from "@internal/discovery/use-case/StopDiscoveringUseCase"; import { sendTypes } from "@internal/send/di/sendTypes"; -import { - SendApduUseCase, - SendApduUseCaseArgs, -} from "@internal/send/use-case/SendApduUseCase"; +import { SendApduUseCase } from "@internal/send/use-case/SendApduUseCase"; import { usbDiTypes } from "@internal/usb/di/usbDiTypes"; -import { DiscoveredDevice } from "@internal/usb/model/DiscoveredDevice"; import { GetConnectedDeviceUseCase, GetConnectedDeviceUseCaseArgs, @@ -127,10 +123,12 @@ export class DeviceSdk { /** * Sends a command to a device through a device session. * - * @param {SendCommandUseCaseArgs} - The device session ID, command and command parameters to send. + * @param {SendCommandUseCaseArgs} args - The device session ID, command and command parameters to send. * @returns A promise resolving with the response from the command. */ - sendCommand(args: SendCommandUseCaseArgs): Promise { + sendCommand( + args: SendCommandUseCaseArgs, + ): Promise { return this.container .get(commandTypes.SendCommandUseCase) .execute(args); diff --git a/packages/core/src/api/apdu/model/Apdu.ts b/packages/core/src/api/apdu/model/Apdu.ts index 4482cb23c..1e12988ac 100644 --- a/packages/core/src/api/apdu/model/Apdu.ts +++ b/packages/core/src/api/apdu/model/Apdu.ts @@ -1,5 +1,5 @@ /** - * Represents an APDU command that can be sent to a device. + * An APDU command that can be sent to a device. * DO NOT USE THIS CLASS DIRECTLY, use ApduBuilder instead. */ export class Apdu { diff --git a/packages/core/src/api/command/Command.ts b/packages/core/src/api/command/Command.ts index 16970fee3..84c281607 100644 --- a/packages/core/src/api/command/Command.ts +++ b/packages/core/src/api/command/Command.ts @@ -5,17 +5,17 @@ import { ApduResponse } from "@api/device-session/ApduResponse"; /** * A command that can be sent to a device. * - * @template T - The type of the response returned by the device. - * @template U - The type of the arguments passed to the command (optional). + * @template Response - The type of the response returned by the device. + * @template Args - The type of the arguments passed to the command (optional). */ -export interface Command { +export interface Command { /** * Gets the APDU (Application Protocol Data Unit) for the command. * * @param args - The arguments passed to the command (optional). * @returns The APDU for the command. */ - getApdu(args?: U): Apdu; + getApdu(args?: Args): Apdu; /** * Parses the response received from the device. @@ -27,5 +27,5 @@ export interface Command { parseResponse( apduResponse: ApduResponse, deviceModelId: DeviceModelId | void, - ): T; + ): Response; } diff --git a/packages/core/src/api/command/use-case/SendCommandUseCase.test.ts b/packages/core/src/api/command/use-case/SendCommandUseCase.test.ts index 713932625..9c0b04f60 100644 --- a/packages/core/src/api/command/use-case/SendCommandUseCase.test.ts +++ b/packages/core/src/api/command/use-case/SendCommandUseCase.test.ts @@ -34,7 +34,7 @@ describe("SendCommandUseCase", () => { const useCase = new SendCommandUseCase(sessionService, () => logger); jest - .spyOn(deviceSession, "getCommand") + .spyOn(deviceSession, "sendCommand") .mockReturnValue(async () => Promise.resolve({ status: "success" })); const response = await useCase.execute<{ status: string }>({ diff --git a/packages/core/src/api/command/use-case/SendCommandUseCase.ts b/packages/core/src/api/command/use-case/SendCommandUseCase.ts index 19ce38102..7a16f32e6 100644 --- a/packages/core/src/api/command/use-case/SendCommandUseCase.ts +++ b/packages/core/src/api/command/use-case/SendCommandUseCase.ts @@ -6,7 +6,7 @@ import type { DeviceSessionService } from "@internal/device-session/service/Devi import { loggerTypes } from "@internal/logger-publisher/di/loggerTypes"; import { LoggerPublisherService } from "@internal/logger-publisher/service/LoggerPublisherService"; -export type SendCommandUseCaseArgs = { +export type SendCommandUseCaseArgs = { /** * The device session id. */ @@ -14,11 +14,11 @@ export type SendCommandUseCaseArgs = { /** * The command to send. */ - command: Command; + command: Command; /** * The parameters of the command. */ - params: U; + params: Args; }; /** @@ -46,11 +46,11 @@ export class SendCommandUseCase { * @param params - The parameters of the command. * @returns The response from the command. */ - async execute({ + async execute({ sessionId, command, params, - }: SendCommandUseCaseArgs): Promise { + }: SendCommandUseCaseArgs): Promise { const deviceSessionOrError = this._sessionService.getDeviceSessionById(sessionId); @@ -58,7 +58,7 @@ export class SendCommandUseCase { // Case device session found Right: async (deviceSession) => { const deviceModelId = deviceSession.connectedDevice.deviceModel.id; - const action = deviceSession.getCommand(command); + const action = deviceSession.sendCommand(command); return await action(deviceModelId, params); }, // Case device session not found diff --git a/packages/core/src/api/device/DeviceModel.ts b/packages/core/src/api/device/DeviceModel.ts index b4f60e01c..50432be29 100644 --- a/packages/core/src/api/device/DeviceModel.ts +++ b/packages/core/src/api/device/DeviceModel.ts @@ -15,10 +15,20 @@ export enum DeviceModelId { */ export type DeviceId = string; +export type DeviceModelArgs = { + id: DeviceId; + model: DeviceModelId; + name: string; +}; + export class DeviceModel { - constructor( - public id: DeviceId, - public model: DeviceModelId, - public name: string, - ) {} + public id: DeviceId; + public model: DeviceModelId; + public name: string; + + constructor({ id, model, name }: DeviceModelArgs) { + this.id = id; + this.model = model; + this.name = name; + } } diff --git a/packages/core/src/api/types.ts b/packages/core/src/api/types.ts index c8180c92e..554fd97f1 100644 --- a/packages/core/src/api/types.ts +++ b/packages/core/src/api/types.ts @@ -1,4 +1,9 @@ export type { DeviceId } from "./device/DeviceModel"; export type { ConnectionType } from "./discovery/ConnectionType"; export type { LogSubscriberOptions } from "./logger-subscriber/model/LogSubscriberOptions"; +export type { DiscoveredDevice } from "./usb/model/DiscoveredDevice"; +export type { DeviceModelId } from "@api/device/DeviceModel"; export type { DeviceSessionId } from "@api/device-session/types"; +export type { ConnectUseCaseArgs } from "@internal/discovery/use-case/ConnectUseCase"; +export type { DisconnectUseCaseArgs } from "@internal/discovery/use-case/DisconnectUseCase"; +export type { SendApduUseCaseArgs } from "@internal/send/use-case/SendApduUseCase"; diff --git a/packages/core/src/api/usb/model/DiscoveredDevice.ts b/packages/core/src/api/usb/model/DiscoveredDevice.ts new file mode 100644 index 000000000..c78b2ae58 --- /dev/null +++ b/packages/core/src/api/usb/model/DiscoveredDevice.ts @@ -0,0 +1,9 @@ +import { DeviceId, DeviceModel } from "@api/device/DeviceModel"; + +/** + * A discovered device. + */ +export type DiscoveredDevice = { + id: DeviceId; + deviceModel: DeviceModel; +}; diff --git a/packages/core/src/internal/device-session/model/DeviceSession.ts b/packages/core/src/internal/device-session/model/DeviceSession.ts index 8b9cb41b9..1806e8d10 100644 --- a/packages/core/src/internal/device-session/model/DeviceSession.ts +++ b/packages/core/src/internal/device-session/model/DeviceSession.ts @@ -97,8 +97,11 @@ export class DeviceSession { }); } - getCommand(command: Command) { - return async (deviceModelId: DeviceModelId, getApduArgs: U): Promise => { + sendCommand(command: Command) { + return async ( + deviceModelId: DeviceModelId, + getApduArgs: Args, + ): Promise => { const apdu = command.getApdu(getApduArgs); const response = await this.sendApdu(apdu.getRawApdu()); diff --git a/packages/core/src/internal/discovery/use-case/ConnectUseCase.ts b/packages/core/src/internal/discovery/use-case/ConnectUseCase.ts index 6f7a0d175..e0f4c24d6 100644 --- a/packages/core/src/internal/discovery/use-case/ConnectUseCase.ts +++ b/packages/core/src/internal/discovery/use-case/ConnectUseCase.ts @@ -1,7 +1,7 @@ import { inject, injectable } from "inversify"; -import { DeviceId } from "@api/device/DeviceModel"; import { DeviceSessionId } from "@api/device-session/types"; +import { DeviceId } from "@api/types"; import { deviceSessionTypes } from "@internal/device-session/di/deviceSessionTypes"; import { DeviceSession } from "@internal/device-session/model/DeviceSession"; import type { DeviceSessionService } from "@internal/device-session/service/DeviceSessionService"; @@ -11,9 +11,12 @@ import { usbDiTypes } from "@internal/usb/di/usbDiTypes"; import type { UsbHidTransport } from "@internal/usb/transport/UsbHidTransport"; import type { DisconnectHandler } from "@internal/usb/transport/WebUsbHidTransport"; +/** + * The arguments for the ConnectUseCase. + */ export type ConnectUseCaseArgs = { /** - * UUID of the device obtained through device discovery `StartDiscoveringUseCase` + * UUID of the device got from device discovery `StartDiscoveringUseCase` */ deviceId: DeviceId; }; diff --git a/packages/core/src/internal/discovery/use-case/DisconnectUseCase.ts b/packages/core/src/internal/discovery/use-case/DisconnectUseCase.ts index 05cb9ab93..143df7036 100644 --- a/packages/core/src/internal/discovery/use-case/DisconnectUseCase.ts +++ b/packages/core/src/internal/discovery/use-case/DisconnectUseCase.ts @@ -1,6 +1,6 @@ import { inject, injectable } from "inversify"; -import { DeviceSessionId } from "@api/device-session/types"; +import type { DeviceSessionId } from "@api/types"; import { deviceSessionTypes } from "@internal/device-session/di/deviceSessionTypes"; import type { DeviceSessionService } from "@internal/device-session/service/DeviceSessionService"; import { loggerTypes } from "@internal/logger-publisher/di/loggerTypes"; @@ -8,7 +8,13 @@ import { LoggerPublisherService } from "@internal/logger-publisher/service/Logge import { usbDiTypes } from "@internal/usb/di/usbDiTypes"; import type { UsbHidTransport } from "@internal/usb/transport/UsbHidTransport"; +/** + * The arguments for the DisconnectUseCase. + */ export type DisconnectUseCaseArgs = { + /** + * Device session identifier from `DeviceSdk.connect`. + */ sessionId: DeviceSessionId; }; diff --git a/packages/core/src/internal/discovery/use-case/StartDiscoveringUseCase.test.ts b/packages/core/src/internal/discovery/use-case/StartDiscoveringUseCase.test.ts index 1e14232fb..6d1521cfb 100644 --- a/packages/core/src/internal/discovery/use-case/StartDiscoveringUseCase.test.ts +++ b/packages/core/src/internal/discovery/use-case/StartDiscoveringUseCase.test.ts @@ -1,10 +1,12 @@ import { of } from "rxjs"; +import { DeviceModel } from "@api/index"; +import { DeviceModelId, DiscoveredDevice } from "@api/types"; import { DeviceModelDataSource } from "@internal/device-model/data/DeviceModelDataSource"; import { InternalDeviceModel } from "@internal/device-model/model/DeviceModel"; import { DefaultLoggerPublisherService } from "@internal/logger-publisher/service/DefaultLoggerPublisherService"; import { LoggerPublisherService } from "@internal/logger-publisher/service/LoggerPublisherService"; -import { DiscoveredDevice } from "@internal/usb/model/DiscoveredDevice"; +import { InternalDiscoveredDevice } from "@internal/usb/model/InternalDiscoveredDevice"; import { usbHidDeviceConnectionFactoryStubBuilder } from "@internal/usb/service/UsbHidDeviceConnectionFactory.stub"; import { WebUsbHidTransport } from "@internal/usb/transport/WebUsbHidTransport"; @@ -14,9 +16,12 @@ let transport: WebUsbHidTransport; let logger: LoggerPublisherService; describe("StartDiscoveringUseCase", () => { - const stubDiscoveredDevice: DiscoveredDevice = { - id: "", - deviceModel: {} as InternalDeviceModel, + const stubDiscoveredDevice: InternalDiscoveredDevice = { + id: "internal-discovered-device-id", + deviceModel: { + id: "nanoSP" as DeviceModelId, + productName: "productName", + } as InternalDeviceModel, }; const tag = "logger-tag"; @@ -47,7 +52,14 @@ describe("StartDiscoveringUseCase", () => { expect(mockedStartDiscovering).toHaveBeenCalled(); discover.subscribe({ next: (discoveredDevice) => { - expect(discoveredDevice).toBe(stubDiscoveredDevice); + expect(discoveredDevice).toStrictEqual({ + id: "internal-discovered-device-id", + deviceModel: new DeviceModel({ + id: "internal-discovered-device-id", + model: "nanoSP" as DeviceModelId, + name: "productName", + }), + } as DiscoveredDevice); done(); }, error: (error) => { diff --git a/packages/core/src/internal/discovery/use-case/StartDiscoveringUseCase.ts b/packages/core/src/internal/discovery/use-case/StartDiscoveringUseCase.ts index b0a133642..f3d935b87 100644 --- a/packages/core/src/internal/discovery/use-case/StartDiscoveringUseCase.ts +++ b/packages/core/src/internal/discovery/use-case/StartDiscoveringUseCase.ts @@ -1,8 +1,10 @@ import { inject, injectable } from "inversify"; -import { Observable } from "rxjs"; +import { map, Observable } from "rxjs"; +import { DeviceModel } from "@api/index"; +import { DiscoveredDevice } from "@api/types"; import { usbDiTypes } from "@internal/usb/di/usbDiTypes"; -import { DiscoveredDevice } from "@internal/usb/model/DiscoveredDevice"; +import { InternalDiscoveredDevice } from "@internal/usb/model/InternalDiscoveredDevice"; import type { UsbHidTransport } from "@internal/usb/transport/UsbHidTransport"; /** @@ -19,6 +21,18 @@ export class StartDiscoveringUseCase { ) {} execute(): Observable { - return this.usbHidTransport.startDiscovering(); + return this.usbHidTransport.startDiscovering().pipe( + map((data: InternalDiscoveredDevice) => { + const deviceModel = new DeviceModel({ + id: data.id, + model: data.deviceModel.id, + name: data.deviceModel.productName, + }); + return { + id: data.id, + deviceModel, + }; + }), + ); } } diff --git a/packages/core/src/internal/send/use-case/SendApduUseCase.ts b/packages/core/src/internal/send/use-case/SendApduUseCase.ts index ce0905387..84ff963d0 100644 --- a/packages/core/src/internal/send/use-case/SendApduUseCase.ts +++ b/packages/core/src/internal/send/use-case/SendApduUseCase.ts @@ -1,19 +1,22 @@ import { inject, injectable } from "inversify"; import { ApduResponse } from "@api/device-session/ApduResponse"; -import { DeviceSessionId } from "@api/device-session/types"; +import { DeviceSessionId } from "@api/types"; import { deviceSessionTypes } from "@internal/device-session/di/deviceSessionTypes"; import type { DeviceSessionService } from "@internal/device-session/service/DeviceSessionService"; import { loggerTypes } from "@internal/logger-publisher/di/loggerTypes"; import { LoggerPublisherService } from "@internal/logger-publisher/service/LoggerPublisherService"; +/** + * The arguments for the SendApduUseCase. + */ export type SendApduUseCaseArgs = { /** - * Device session identifier obtained through `DeviceSdk.connect` + * Device session identifier from `DeviceSdk.connect`. */ sessionId: DeviceSessionId; /** - * APDU to send to the device + * Raw APDU to send to the device. */ apdu: Uint8Array; }; diff --git a/packages/core/src/internal/usb/model/InternalConnectedDevice.ts b/packages/core/src/internal/usb/model/InternalConnectedDevice.ts index c457d4e80..a333e6544 100644 --- a/packages/core/src/internal/usb/model/InternalConnectedDevice.ts +++ b/packages/core/src/internal/usb/model/InternalConnectedDevice.ts @@ -4,7 +4,7 @@ import { InternalDeviceModel } from "@internal/device-model/model/DeviceModel"; import { SendApduFnType } from "@internal/usb/transport/DeviceConnection"; /** - * Represents an internal connected device. + * The internal connected device. */ export type ConnectedDeviceConstructorArgs = { id: DeviceId; diff --git a/packages/core/src/internal/usb/model/DiscoveredDevice.ts b/packages/core/src/internal/usb/model/InternalDiscoveredDevice.ts similarity index 86% rename from packages/core/src/internal/usb/model/DiscoveredDevice.ts rename to packages/core/src/internal/usb/model/InternalDiscoveredDevice.ts index 5dc6a39a1..560bfb469 100644 --- a/packages/core/src/internal/usb/model/DiscoveredDevice.ts +++ b/packages/core/src/internal/usb/model/InternalDiscoveredDevice.ts @@ -2,9 +2,9 @@ import { DeviceId } from "@api/device/DeviceModel"; import { InternalDeviceModel } from "@internal/device-model/model/DeviceModel"; /** - * Represents a discovered/scanned (not yet connected to) device. + * A discovered / scanned (not yet connected to) device. */ -export type DiscoveredDevice = { +export type InternalDiscoveredDevice = { // type: "web-hid", // "node-hid" in the future -> no need as we will only have 1 USB transport implementation running /** diff --git a/packages/core/src/internal/usb/transport/UsbHidTransport.ts b/packages/core/src/internal/usb/transport/UsbHidTransport.ts index 5e62aceae..9808443bd 100644 --- a/packages/core/src/internal/usb/transport/UsbHidTransport.ts +++ b/packages/core/src/internal/usb/transport/UsbHidTransport.ts @@ -3,9 +3,9 @@ import { Observable } from "rxjs"; import { DeviceId } from "@api/device/DeviceModel"; import { SdkError } from "@api/Error"; -import { DiscoveredDevice } from "@internal/usb/model/DiscoveredDevice"; import { ConnectError } from "@internal/usb/model/Errors"; import { InternalConnectedDevice } from "@internal/usb/model/InternalConnectedDevice"; +import { InternalDiscoveredDevice } from "@internal/usb/model/InternalDiscoveredDevice"; import type { DisconnectHandler } from "@internal/usb/transport/WebUsbHidTransport"; /** @@ -14,7 +14,7 @@ import type { DisconnectHandler } from "@internal/usb/transport/WebUsbHidTranspo export interface UsbHidTransport { isSupported(): boolean; - startDiscovering(): Observable; + startDiscovering(): Observable; stopDiscovering(): void; diff --git a/packages/core/src/internal/usb/transport/WebUsbHidTransport.ts b/packages/core/src/internal/usb/transport/WebUsbHidTransport.ts index 3304e0da5..42a5683d4 100644 --- a/packages/core/src/internal/usb/transport/WebUsbHidTransport.ts +++ b/packages/core/src/internal/usb/transport/WebUsbHidTransport.ts @@ -12,7 +12,6 @@ import { loggerTypes } from "@internal/logger-publisher/di/loggerTypes"; import type { LoggerPublisherService } from "@internal/logger-publisher/service/LoggerPublisherService"; import { LEDGER_VENDOR_ID } from "@internal/usb/data/UsbHidConfig"; import { usbDiTypes } from "@internal/usb/di/usbDiTypes"; -import { DiscoveredDevice } from "@internal/usb/model/DiscoveredDevice"; import { ConnectError, DeviceNotRecognizedError, @@ -24,6 +23,7 @@ import { UsbHidTransportNotSupportedError, } from "@internal/usb/model/Errors"; import { InternalConnectedDevice } from "@internal/usb/model/InternalConnectedDevice"; +import { InternalDiscoveredDevice } from "@internal/usb/model/InternalDiscoveredDevice"; import { UsbHidDeviceConnectionFactory } from "@internal/usb/service/UsbHidDeviceConnectionFactory"; import { UsbHidTransport } from "./UsbHidTransport"; @@ -32,7 +32,7 @@ import { UsbHidTransport } from "./UsbHidTransport"; type WebHidInternalDevice = { id: DeviceId; hidDevice: HIDDevice; - discoveredDevice: DiscoveredDevice; + discoveredDevice: InternalDiscoveredDevice; }; export type DisconnectHandler = (deviceId: DeviceId) => void; @@ -163,7 +163,7 @@ export class WebUsbHidTransport implements UsbHidTransport { * [ASK] For the 2nd option: the DiscoveredDevice could have a `isSelected` property ? * So the consumer can directly select this device. */ - startDiscovering(): Observable { + startDiscovering(): Observable { this._logger.debug("startDiscovering"); // Logs the connection and disconnection events