Skip to content

Commit

Permalink
♻️ (webhid): Extract transport web-hid in it's own module
Browse files Browse the repository at this point in the history
  • Loading branch information
valpinkman committed Oct 31, 2024
1 parent ae3b59c commit 32d6481
Show file tree
Hide file tree
Showing 80 changed files with 541 additions and 345 deletions.
22 changes: 12 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,18 @@ This project uses [turbo monorepo](https://turbo.build/repo/docs) to build and r

A brief description of this project packages:

| Name | Path | Description |
| --------------------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| @ledgerhq/device-sdk-sample | apps/sample | React Next web app used to test & demonstrate the Web Device Management Kit |
| @ledgerhq/eslint-config-dsdk | packages/config/eslint | internal package which contains eslint shared config. Used by `extends: ["@ledgerhq/dsdk"]` in `.eslintrc`. |
| @ledgerhq/jest-config-dsdk | packages/config/jest | internal package which contains jest shared config. Used by `preset: "@ledgerhq/jest-config-dsdk"` in `jest.config.ts` |
| @ledgerhq/tsconfig-dsdk | packages/config/typescript | internal package which contains typescript shared config. Used by `"extends": "@ledgerhq/tsconfig-dsdk/tsconfig.sdk"` in `tsconfig.json` |
| @ledgerhq/device-management-kit | packages/core | external package that contains the core of the Web SDK |
| @ledgerhq/device-sdk-signer | packages/signer | external package that contains device coin application dedicated handlers |
| @ledgerhq/device-sdk-trusted-apps | packages/trusted-apps | external package that contains device trusted application dedicated handlers |
| @ledgerhq/device-sdk-ui | packages/ui | external package |
| Name | Path | Description |
| -------------------------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| @ledgerhq/device-sdk-sample | apps/sample | React Next web app used to test & demonstrate the Web Device Management Kit |
| @ledgerhq/eslint-config-dsdk | packages/config/eslint | internal package which contains eslint shared config. Used by `extends: ["@ledgerhq/dsdk"]` in `.eslintrc`. |
| @ledgerhq/jest-config-dsdk | packages/config/jest | internal package which contains jest shared config. Used by `preset: "@ledgerhq/jest-config-dsdk"` in `jest.config.ts` |
| @ledgerhq/tsconfig-dsdk | packages/config/typescript | internal package which contains typescript shared config. Used by `"extends": "@ledgerhq/tsconfig-dsdk/tsconfig.sdk"` in `tsconfig.json` |
| @ledgerhq/device-management-kit | packages/core | external package that contains the core of the Web SDK |
| @ledgerhq/device-sdk-signer | packages/signer | external package that contains device coin application dedicated handlers |
| @ledgerhq/device-sdk-trusted-apps | packages/trusted-apps | external package that contains device trusted application dedicated handlers |
| @ledgerhq/device-sdk-ui | packages/ui | external package |
| @ledgerhq/device-transport-kit-web-hid | packages/transport/web-hid | external package that contains the Web Hid transport implementation |
| @ledgerhq/device-transport-kit-web-ble | packages/transport/web-ble | external package that contains the Web Ble transport implementation |

# Getting started

Expand Down
1 change: 1 addition & 0 deletions apps/sample/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@ledgerhq/device-signer-kit-ethereum": "workspace:*",
"@ledgerhq/device-signer-kit-solana": "workspace:*",
"@ledgerhq/device-sdk-transport-mock": "workspace:*",
"@ledgerhq/device-transport-kit-web-hid": "workspace:*",
"@ledgerhq/react-ui": "^0.16.2",
"@sentry/nextjs": "^8.32.0",
"@playwright/test": "^1.47.0",
Expand Down
9 changes: 5 additions & 4 deletions apps/sample/src/components/MainView/ConnectDeviceActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
BuiltinTransports,
type SdkError,
} from "@ledgerhq/device-management-kit";
import { webHidIdentifier } from "@ledgerhq/device-transport-kit-web-hid";
import { Button, Flex } from "@ledgerhq/react-ui";
import styled from "styled-components";

Expand All @@ -26,7 +27,7 @@ export const ConnectDeviceActions = ({
const sdk = useSdk();

const onSelectDeviceClicked = useCallback(
(selectedTransport: BuiltinTransports) => {
(selectedTransport: string) => {
onError(null);
sdk.startDiscovering({ transport: selectedTransport }).subscribe({
next: (device) => {
Expand Down Expand Up @@ -78,21 +79,21 @@ export const ConnectDeviceActions = ({
) : (
<Flex>
<ConnectButton
onClick={() => onSelectDeviceClicked(BuiltinTransports.USB)}
onClick={() => onSelectDeviceClicked(webHidIdentifier)}
variant="main"
backgroundColor="main"
size="large"
>
Select a USB device
</ConnectButton>
<ConnectButton
{/* <ConnectButton
onClick={() => onSelectDeviceClicked(BuiltinTransports.BLE)}
variant="main"
backgroundColor="main"
size="large"
>
Select a BLE device
</ConnectButton>
</ConnectButton> */}
</Flex>
);
};
49 changes: 32 additions & 17 deletions apps/sample/src/providers/DeviceSdkProvider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
WebLogsExporterLogger,
} from "@ledgerhq/device-management-kit";
import { FlipperSdkLogger } from "@ledgerhq/device-management-kit-flipper-plugin-client";
import { WebHidTransport } from "@ledgerhq/device-transport-kit-web-hid";

import { useHasChanged } from "@/hooks/useHasChanged";
import { useSdkConfigContext } from "@/providers/SdkConfig";
Expand All @@ -17,23 +18,35 @@ const LogsExporterContext = createContext<WebLogsExporterLogger | null>(null);

function buildDefaultSdk(logsExporter: WebLogsExporterLogger) {
return new DeviceSdkBuilder()
.addTransport(BuiltinTransports.USB)
.addTransport(BuiltinTransports.BLE)
.addLogger(new ConsoleLogger())
.addTransport(
({
deviceModelDataSource,
loggerServiceFactory,
apduSenderServiceFactory,
apduReceiverServiceFactory,
}) =>
new WebHidTransport(
deviceModelDataSource,
loggerServiceFactory,
apduSenderServiceFactory,
apduReceiverServiceFactory,
),
)
.addLogger(logsExporter)
.addLogger(new FlipperSdkLogger())
.build();
}

function buildMockSdk(url: string, logsExporter: WebLogsExporterLogger) {
return new DeviceSdkBuilder()
.addTransport(BuiltinTransports.MOCK_SERVER)
.addLogger(new ConsoleLogger())
.addLogger(logsExporter)
.addLogger(new FlipperSdkLogger())
.addConfig({ mockUrl: url })
.build();
}
// function buildMockSdk(url: string, logsExporter: WebLogsExporterLogger) {
// return new DeviceSdkBuilder()
// .addTransport(BuiltinTransports.MOCK_SERVER)
// .addLogger(new ConsoleLogger())
// .addLogger(logsExporter)
// .addLogger(new FlipperSdkLogger())
// .addConfig({ mockUrl: url })
// .build();
// }

export const SdkProvider: React.FC<PropsWithChildren> = ({ children }) => {
const {
Expand All @@ -43,9 +56,10 @@ export const SdkProvider: React.FC<PropsWithChildren> = ({ children }) => {
const mockServerEnabled = transport === BuiltinTransports.MOCK_SERVER;
const [state, setState] = useState(() => {
const logsExporter = new WebLogsExporterLogger();
const sdk = mockServerEnabled
? buildMockSdk(mockServerUrl, logsExporter)
: buildDefaultSdk(logsExporter);
// const sdk = mockServerEnabled
// ? buildMockSdk(mockServerUrl, logsExporter)
// : buildDefaultSdk(logsExporter);
const sdk = buildDefaultSdk(logsExporter);
return { sdk, logsExporter };
});

Expand All @@ -55,9 +69,10 @@ export const SdkProvider: React.FC<PropsWithChildren> = ({ children }) => {
if (mockServerEnabledChanged || mockServerUrlChanged) {
setState(({ logsExporter }) => {
return {
sdk: mockServerEnabled
? buildMockSdk(mockServerUrl, logsExporter)
: buildDefaultSdk(logsExporter),
// sdk: mockServerEnabled
// ? buildMockSdk(mockServerUrl, logsExporter)
// : buildDefaultSdk(logsExporter),
sdk: buildDefaultSdk(logsExporter),
logsExporter,
};
});
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"scripts": {
"build": "turbo run build",
"build:libs": "turbo run build --filter=./packages/**",
"dev": "turbo run dev",
"dev": "turbo run dev --concurrency 20",
"lint": "turbo run lint",
"lint:fix": "turbo run lint:fix",
"prettier": "turbo run prettier",
Expand All @@ -23,6 +23,9 @@
"transport-mock": "pnpm --filter @ledgerhq/device-sdk-transport-mock",
"trusted-apps": "pnpm --filter @ledgerhq/device-sdk-trusted-apps",
"ui": "pnpm --filter @ledgerhq/device-sdk-ui",
"transports": "pnpm --filter @ledgerhq/device-transport-*",
"transport-web-hid": "pnpm --filter @ledgerhq/device-transport-kit-web-hid",
"transport-web-ble": "pnpm --filter @ledgerhq/device-transport-kit-web-ble",
"flipper": "pnpm --filter @ledgerhq/device-management-kit-flipper-plugin-client",
"sample": "pnpm --filter @ledgerhq/device-sdk-sample",
"bump": "changeset version",
Expand Down
6 changes: 4 additions & 2 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,13 @@
"inversify-logger-middleware": "^3.1.0",
"purify-ts": "^2.1.0",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",
"semver": "^7.6.3",
"uuid": "^10.0.0",
"xstate": "^5.18.2"
},
"peerDependencies": {
"rxjs": "^7.8.1"
},
"devDependencies": {
"@ledgerhq/esbuild-tools": "workspace:*",
"@ledgerhq/eslint-config-dsdk": "workspace:*",
Expand All @@ -57,8 +59,8 @@
"@ledgerhq/tsconfig-dsdk": "workspace:*",
"@types/semver": "^7.5.8",
"@types/uuid": "^10.0.0",
"@types/w3c-web-hid": "^1.0.6",
"@types/web-bluetooth": "^0.0.20",
"rxjs": "^7.8.1",
"ts-node": "^10.9.2"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { Left } from "purify-ts";

import { type Command } from "@api/command/Command";
import { CommandResultStatus } from "@api/command/model/CommandResult";
import { type LoggerPublisherService } from "@api/logger-publisher/service/LoggerPublisherService";
import { deviceSessionStubBuilder } from "@internal/device-session/model/DeviceSession.stub";
import { DefaultDeviceSessionService } from "@internal/device-session/service/DefaultDeviceSessionService";
import { type DeviceSessionService } from "@internal/device-session/service/DeviceSessionService";
import { DefaultLoggerPublisherService } from "@internal/logger-publisher/service/DefaultLoggerPublisherService";
import { type LoggerPublisherService } from "@internal/logger-publisher/service/LoggerPublisherService";
import { AxiosManagerApiDataSource } from "@internal/manager-api/data/AxiosManagerApiDataSource";
import { type ManagerApiDataSource } from "@internal/manager-api/data/ManagerApiDataSource";
import { DefaultManagerApiService } from "@internal/manager-api/service/DefaultManagerApiService";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { inject, injectable } from "inversify";

import { Command } from "@api/command/Command";
import { CommandResult } from "@api/command/model/CommandResult";
import { LoggerPublisherService } from "@api/logger-publisher/service/LoggerPublisherService";
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";

export type SendCommandUseCaseArgs<Response, ErrorStatusCodes, Args = void> = {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import {
ExecuteDeviceActionReturnType,
} from "@api/device-action/DeviceAction";
import { SdkError } from "@api/Error";
import { LoggerPublisherService } from "@api/logger-publisher/service/LoggerPublisherService";
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";

export type ExecuteDeviceActionUseCaseArgs<
Output,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ export interface ApduReceiverService {
handleFrame(apdu: Uint8Array): Either<SdkError, Maybe<ApduResponse>>;
}

export type ApduReceiverConstructorArgs = Partial<{
channel: Maybe<Uint8Array>;
}>;
export type ApduReceiverConstructorArgs = {
channel?: Maybe<Uint8Array>;
};

export type ApduReceiverServiceFactory = (
args?: ApduReceiverConstructorArgs,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Maybe } from "purify-ts";

import { type LoggerPublisherService } from "@internal/logger-publisher/service/LoggerPublisherService";
import { type LoggerPublisherService } from "@api/logger-publisher/service/LoggerPublisherService";

import { type ApduReceiverService } from "./ApduReceiverService";
import { type ApduReceiverConstructorArgs } from "./ApduReceiverService";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import {
HEAD_TAG_LENGTH,
INDEX_LENGTH,
} from "@api/device-session/model/FramerConst";
import { FramerUtils } from "@api/device-session/utils/FramerUtils";
import { LoggerPublisherService } from "@api/logger-publisher/service/LoggerPublisherService";
import { APDU_RESPONSE_STATUS_CODE_LENGTH } from "@internal/device-session/data/ApduResponseConst";
import { ReceiverApduError } from "@internal/device-session/model/Errors";
import { Frame } from "@internal/device-session/model/Frame";
import { FrameHeader } from "@internal/device-session/model/FrameHeader";
import { FramerUtils } from "@internal/device-session/utils/FramerUtils";
import { loggerTypes } from "@internal/logger-publisher/di/loggerTypes";
import { LoggerPublisherService } from "@internal/logger-publisher/service/LoggerPublisherService";

import {
type ApduReceiverConstructorArgs,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Maybe } from "purify-ts";

import { type LoggerPublisherService } from "@internal/logger-publisher/service/LoggerPublisherService";
import { type LoggerPublisherService } from "@api/logger-publisher/service/LoggerPublisherService";

import { type ApduSenderService } from "./ApduSenderService";
import { type ApduSenderServiceConstructorArgs } from "./ApduSenderService";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import {
HEAD_TAG_LENGTH,
INDEX_LENGTH,
} from "@api/device-session/model/FramerConst";
import { FramerUtils } from "@api/device-session/utils/FramerUtils";
import { LoggerPublisherService } from "@api/logger-publisher/service/LoggerPublisherService";
import {
FramerApduError,
FramerOverflowError,
} from "@internal/device-session/model/Errors";
import { Frame } from "@internal/device-session/model/Frame";
import { FrameHeader } from "@internal/device-session/model/FrameHeader";
import { FramerUtils } from "@internal/device-session/utils/FramerUtils";
import { loggerTypes } from "@internal/logger-publisher/di/loggerTypes";
import { LoggerPublisherService } from "@internal/logger-publisher/service/LoggerPublisherService";
import { SdkError } from "@root/src/api/Error";

import type {
Expand Down
21 changes: 21 additions & 0 deletions packages/core/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export { BuiltinTransports } from "./transport/model/TransportIdentifier";
export * from "./types";
export * from "@api/apdu/utils/AppBuilderError";
export { InvalidStatusWordError } from "@api/command/Errors";
export { LEDGER_VENDOR_ID } from "@api/device/DeviceModel";
export {
type DeviceAction,
type DeviceActionIntermediateValue,
Expand Down Expand Up @@ -117,11 +118,31 @@ export {
type DeviceActionStateMachine,
XStateDeviceAction,
} from "@api/device-action/xstate-utils/XStateDeviceAction";
export { type DeviceModelDataSource } from "@api/device-model/data/DeviceModelDataSource";
export { StaticDeviceModelDataSource } from "@api/device-model/data/StaticDeviceModelDataSource";
export { TransportDeviceModel } from "@api/device-model/model/DeviceModel";
export {
type DeviceSessionState,
DeviceSessionStateType,
} from "@api/device-session/DeviceSessionState";
export * from "@api/device-session/model/FramerConst";
export { type ApduReceiverService } from "@api/device-session/service/ApduReceiverService";
export { type ApduReceiverServiceFactory } from "@api/device-session/service/ApduReceiverService";
export { type ApduSenderServiceFactory } from "@api/device-session/service/ApduSenderService";
export { type ApduSenderService } from "@api/device-session/service/ApduSenderService";
export { defaultApduReceiverServiceStubBuilder } from "@api/device-session/service/DefaultApduReceiverService.stub";
export { defaultApduSenderServiceStubBuilder } from "@api/device-session/service/DefaultApduSenderService.stub";
export { FramerUtils } from "@api/device-session/utils/FramerUtils";
export { type SdkError } from "@api/Error";
export { type LoggerPublisherService } from "@api/logger-publisher/service/LoggerPublisherService";
export {
type DeviceConnection,
type DisconnectHandler,
} from "@api/transport/model/DeviceConnection";
export * from "@api/transport/model/Errors";
export { TransportConnectedDevice } from "@api/transport/model/TransportConnectedDevice";
export { connectedDeviceStubBuilder } from "@api/transport/model/TransportConnectedDevice.stub";
export { type TransportDiscoveredDevice } from "@api/transport/model/TransportDiscoveredDevice";
export { base64StringToBuffer, isBase64String } from "@api/utils/Base64String";
export {
bufferToHexaString,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type LoggerSubscriberService } from "@api/logger-subscriber/service/LoggerSubscriberService";
import { type LogPublisherOptions } from "@internal/logger-publisher/model/LogPublisherOptions";
import type { LoggerSubscriberService } from "@api/logger-subscriber/service/LoggerSubscriberService";
import type { LogPublisherOptions } from "@internal/logger-publisher/model/LogPublisherOptions";

export interface LoggerPublisherService {
subscribers: LoggerSubscriberService[];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export class DeviceConnectionFactoryStub {
constructor() {}

create = jest.fn().mockImplementation(() => ({
sendApdu: jest.fn(),
}));
}
12 changes: 12 additions & 0 deletions packages/core/src/api/transport/model/Transport.stub.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Transport } from "./Transport";

export class TransportStub implements Transport {
constructor() {}
getIdentifier = jest.fn();
isSupported = jest.fn();
startDiscovering = jest.fn();
stopDiscovering = jest.fn();
listenToKnownDevices = jest.fn();
connect = jest.fn();
disconnect = jest.fn();
}
Loading

0 comments on commit 32d6481

Please sign in to comment.