import type { DeviceId, Fingerprint } from '../../../../domain/device.js' import type { Infrastructure } from '../../../../infrastructure/mod.js' import { isError, makeError, makeSuccess, unwrapResult, type Result, } from '../../../../framework/types/result.js' import { DeviceExpiredError, DeviceRegistrationError, DeviceDeregisteredError, EnsureDeviceClientError, EnsureDevicePlatformError, } from './errors.js' import { encodeJson } from '../../../../framework/json/mod.js' import type { EncryptedDeviceRegistration } from '../../../../domain/device-registration-manifest.js' interface Options { infrastructure: Infrastructure } export interface Dto { readonly device: Readonly<{ id: DeviceId fingerprint: Fingerprint }> readonly license: { jwt: string } } export interface ErrorResponse { readonly type: string readonly message: string } type EnsureDeviceError = | DeviceExpiredError | DeviceRegistrationError | DeviceDeregisteredError | EnsureDeviceClientError | EnsureDevicePlatformError export function buildEnsureDevice(options: Options) { return async function ensureDevice( dto: Dto, ): Promise> { const { httpAdapter } = options.infrastructure const dtoResult = encodeJson(dto) if (isError(dtoResult)) { return makeError( new EnsureDeviceClientError( `failed to encode the DTO: ${dtoResult.error}`, ), ) } const requestResult = await httpAdapter.request( `/licensing/devices/${dto.device.id}/verifications`, { method: 'PUT', body: unwrapResult(dtoResult), }, ) if (isError(requestResult)) { return makeError(new EnsureDeviceClientError(requestResult.error)) } const response = unwrapResult(requestResult) const responseResult = await httpAdapter.parseResponseBody< ErrorResponse | { registration: EncryptedDeviceRegistration } >(response) if (isError(responseResult)) { return makeError(new EnsureDeviceClientError(responseResult.error)) } const { body, status } = unwrapResult(responseResult) if (status !== 201) { const error = body as ErrorResponse const message = error.message switch (status) { case 400: { return makeError(new DeviceRegistrationError(message)) } case 403: { return makeError(new DeviceExpiredError(message)) } case 410: { return makeError(new DeviceDeregisteredError(message)) } default: { return makeError(new EnsureDevicePlatformError(message)) } } } const { registration } = body as { registration: EncryptedDeviceRegistration } return makeSuccess(registration) } }