- Add hardware fingerprinting with cross-platform support - Implement secure device registration flow with X.509 certificates - Add WebSocket real-time communication for device status - Create comprehensive device management dashboard - Establish zero-trust security architecture with multi-layer protection - Add database migrations for device registration entities - Implement Rust edge client with hardware identification - Add certificate management and automated provisioning system 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
189 lines
5.4 KiB
TypeScript
189 lines
5.4 KiB
TypeScript
import {
|
|
DevicesResponse,
|
|
DeviceDto,
|
|
InitiateRegistrationRequest,
|
|
InitiateRegistrationResponse,
|
|
ClaimDeviceRequest,
|
|
ClaimDeviceResponse,
|
|
DeviceRegistrationSession,
|
|
DeviceConfiguration,
|
|
DeviceHeartbeat,
|
|
DeviceStatus
|
|
} from '../types/device'
|
|
|
|
const BASE_URL = "http://localhost:3001/api/v1"
|
|
|
|
// Helper function to get auth headers
|
|
const getAuthHeaders = (): HeadersInit => {
|
|
const token = localStorage.getItem("accessToken")
|
|
if (!token) {
|
|
throw new Error("No access token found")
|
|
}
|
|
|
|
return {
|
|
"Authorization": `Bearer ${token}`,
|
|
"Content-Type": "application/json",
|
|
}
|
|
}
|
|
|
|
// Helper function to handle API responses
|
|
const handleResponse = async <T>(response: Response): Promise<T> => {
|
|
if (!response.ok) {
|
|
if (response.status === 401) {
|
|
throw new Error("Unauthorized - please login again")
|
|
}
|
|
|
|
let errorMessage = `Request failed: ${response.statusText}`
|
|
try {
|
|
const errorData = await response.json()
|
|
errorMessage = errorData.message || errorMessage
|
|
} catch {
|
|
// Ignore JSON parse error, use default message
|
|
}
|
|
|
|
throw new Error(errorMessage)
|
|
}
|
|
|
|
return response.json()
|
|
}
|
|
|
|
export const devicesApi = {
|
|
// Device Management
|
|
async getDevices(): Promise<DevicesResponse> {
|
|
const response = await fetch(`${BASE_URL}/devices`, {
|
|
method: "GET",
|
|
headers: getAuthHeaders(),
|
|
})
|
|
|
|
return handleResponse<DevicesResponse>(response)
|
|
},
|
|
|
|
async getDevice(deviceId: string): Promise<DeviceDto> {
|
|
const response = await fetch(`${BASE_URL}/devices/${deviceId}`, {
|
|
method: "GET",
|
|
headers: getAuthHeaders(),
|
|
})
|
|
|
|
return handleResponse<DeviceDto>(response)
|
|
},
|
|
|
|
async updateDevice(deviceId: string, updates: Partial<DeviceDto>): Promise<DeviceDto> {
|
|
const response = await fetch(`${BASE_URL}/devices/${deviceId}`, {
|
|
method: "PATCH",
|
|
headers: getAuthHeaders(),
|
|
body: JSON.stringify(updates),
|
|
})
|
|
|
|
return handleResponse<DeviceDto>(response)
|
|
},
|
|
|
|
async deleteDevice(deviceId: string): Promise<void> {
|
|
const response = await fetch(`${BASE_URL}/devices/${deviceId}`, {
|
|
method: "DELETE",
|
|
headers: getAuthHeaders(),
|
|
})
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to delete device: ${response.statusText}`)
|
|
}
|
|
},
|
|
|
|
async updateDeviceStatus(deviceId: string, status: DeviceStatus): Promise<DeviceDto> {
|
|
const response = await fetch(`${BASE_URL}/devices/${deviceId}/status`, {
|
|
method: "PATCH",
|
|
headers: getAuthHeaders(),
|
|
body: JSON.stringify({ status }),
|
|
})
|
|
|
|
return handleResponse<DeviceDto>(response)
|
|
},
|
|
|
|
// Device Registration
|
|
async initiateRegistration(request: InitiateRegistrationRequest): Promise<InitiateRegistrationResponse> {
|
|
const response = await fetch(`${BASE_URL}/device-registration/test-initiate`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify(request),
|
|
})
|
|
|
|
return handleResponse<InitiateRegistrationResponse>(response)
|
|
},
|
|
|
|
async getRegistrationSession(sessionId: string): Promise<DeviceRegistrationSession> {
|
|
const response = await fetch(`${BASE_URL}/device-registration/session/${sessionId}`, {
|
|
method: "GET",
|
|
headers: getAuthHeaders(),
|
|
})
|
|
|
|
return handleResponse<DeviceRegistrationSession>(response)
|
|
},
|
|
|
|
async claimDevice(request: ClaimDeviceRequest): Promise<ClaimDeviceResponse> {
|
|
const response = await fetch(`${BASE_URL}/device-registration/claim`, {
|
|
method: "POST",
|
|
headers: getAuthHeaders(),
|
|
body: JSON.stringify(request),
|
|
})
|
|
|
|
return handleResponse<ClaimDeviceResponse>(response)
|
|
},
|
|
|
|
async cancelRegistration(sessionId: string): Promise<void> {
|
|
const response = await fetch(`${BASE_URL}/device-registration/${sessionId}`, {
|
|
method: "DELETE",
|
|
headers: getAuthHeaders(),
|
|
})
|
|
|
|
if (!response.ok && response.status !== 204) {
|
|
throw new Error(`Failed to cancel registration: ${response.statusText}`)
|
|
}
|
|
},
|
|
|
|
// Device Configuration
|
|
async getDeviceConfiguration(deviceId: string): Promise<DeviceConfiguration[]> {
|
|
const response = await fetch(`${BASE_URL}/devices/${deviceId}/configuration`, {
|
|
method: "GET",
|
|
headers: getAuthHeaders(),
|
|
})
|
|
|
|
return handleResponse<DeviceConfiguration[]>(response)
|
|
},
|
|
|
|
async updateDeviceConfiguration(
|
|
deviceId: string,
|
|
configType: string,
|
|
configData: Record<string, any>
|
|
): Promise<DeviceConfiguration> {
|
|
const response = await fetch(`${BASE_URL}/devices/${deviceId}/configuration`, {
|
|
method: "POST",
|
|
headers: getAuthHeaders(),
|
|
body: JSON.stringify({ configType, configData }),
|
|
})
|
|
|
|
return handleResponse<DeviceConfiguration>(response)
|
|
},
|
|
|
|
// Device Heartbeat
|
|
async sendHeartbeat(heartbeat: DeviceHeartbeat): Promise<void> {
|
|
const response = await fetch(`${BASE_URL}/devices/heartbeat`, {
|
|
method: "POST",
|
|
headers: getAuthHeaders(),
|
|
body: JSON.stringify(heartbeat),
|
|
})
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to send heartbeat: ${response.statusText}`)
|
|
}
|
|
},
|
|
|
|
async getDeviceHeartbeats(deviceId: string, limit: number = 50): Promise<DeviceHeartbeat[]> {
|
|
const response = await fetch(`${BASE_URL}/devices/${deviceId}/heartbeats?limit=${limit}`, {
|
|
method: "GET",
|
|
headers: getAuthHeaders(),
|
|
})
|
|
|
|
return handleResponse<DeviceHeartbeat[]>(response)
|
|
},
|
|
} |