@multiplayer-app/session-recorder-node
Version:
Multiplayer Fullstack Session Recorder for Node.js
231 lines (206 loc) • 5.46 kB
text/typescript
import { MULTIPLAYER_BASE_API_URL } from '../config'
import { ISession } from '../types'
export interface ApiServiceConfig {
apiKey?: string
apiBaseUrl?: string
continuousRecording?: boolean
}
export interface StartSessionRequest {
name?: string
resourceAttributes?: Record<string, any>
sessionAttributes?: Record<string, any>
tags?: {
key?: string
value: string
}[]
}
export interface StopSessionRequest {
sessionAttributes?: {
email?: string
comment?: string
},
}
export class ApiService {
private config: ApiServiceConfig
constructor() {
this.config = {
apiBaseUrl: MULTIPLAYER_BASE_API_URL,
}
}
/**
* Initialize the API service
* @param config - API service configuration
* @param config.apiKey - API key for authentication
* @param config.apiBaseUrl - Base URL for API endpoints (preferred)
* @param config.continuousRecording - Whether continuous recording is enabled
*/
public init(config: ApiServiceConfig) {
const { apiBaseUrl: _apiBaseUrl, ...restConfig } = config
const apiBaseUrl = _apiBaseUrl || MULTIPLAYER_BASE_API_URL
this.config = {
...this.config,
...restConfig,
apiBaseUrl,
}
}
/**
* Update the API service configuration
* @param config - Partial configuration to update
*/
public updateConfigs(config: Partial<ApiServiceConfig>) {
const { apiBaseUrl: _apiBaseUrl, ...restConfig } = config
const apiBaseUrl = _apiBaseUrl || MULTIPLAYER_BASE_API_URL
this.config = {
...this.config,
...restConfig,
apiBaseUrl,
}
}
/**
* Get the current API base URL
* @returns The current API base URL
*/
public getApiBaseUrl(): string {
return this.config.apiBaseUrl || MULTIPLAYER_BASE_API_URL
}
/**
* Start a new debug session
* @param requestBody - Session start request data
* @param signal - Optional AbortSignal for request cancellation
*/
async startSession(
requestBody: StartSessionRequest,
signal?: AbortSignal,
): Promise<ISession> {
return this.makeRequest(
'/debug-sessions/start',
'POST',
requestBody,
signal,
)
}
/**
* Stop an active debug session
* @param sessionId - ID of the session to stop
* @param requestBody - Session stop request data
*/
async stopSession(
sessionId: string,
requestBody: StopSessionRequest,
): Promise<any> {
return this.makeRequest(
`/debug-sessions/${sessionId}/stop`,
'PATCH',
requestBody,
)
}
/**
* Cancel an active session
* @param sessionId - ID of the session to cancel
*/
async cancelSession(sessionId: string): Promise<any> {
return this.makeRequest(
`/debug-sessions/${sessionId}/cancel`,
'DELETE',
)
}
/**
* Start a new session
* @param requestBody - Session start request data
* @param signal - Optional AbortSignal for request cancellation
*/
async startContinuousSession(
requestBody: StartSessionRequest,
signal?: AbortSignal,
): Promise<any> {
return this.makeRequest(
'/continuous-debug-sessions/start',
'POST',
requestBody,
signal,
)
}
/**
* Save a continuous session
* @param sessionId - ID of the session to save
* @param requestBody - Session save request data
* @param signal - Optional AbortSignal for request cancellation
*/
async saveContinuousSession(
sessionId: string,
requestBody: StartSessionRequest,
signal?: AbortSignal,
): Promise<any> {
return this.makeRequest(
`/continuous-debug-sessions/${sessionId}/save`,
'POST',
requestBody,
signal,
)
}
/**
* Cancel an active debug session
* @param sessionId - ID of the session to cancel
*/
async stopContinuousSession(sessionId: string): Promise<any> {
return this.makeRequest(
`/continuous-debug-sessions/${sessionId}/cancel`,
'DELETE',
)
}
/**
* Check debug session should be started remotely
*/
async checkRemoteSession(
requestBody: StartSessionRequest,
signal?: AbortSignal,
): Promise<{ state: 'START' | 'STOP' }> {
return this.makeRequest(
'/remote-debug-session/check',
'POST',
requestBody,
signal,
)
}
/**
* Make a request to the session API
* @param path - API endpoint path (relative to the base URL)
* @param method - HTTP method (GET, POST, PATCH, etc.)
* @param body - request payload
* @param signal - AbortSignal to set request's signal
*/
private async makeRequest(
path: string,
method: string,
body?: any,
signal?: AbortSignal,
): Promise<any> {
const url = `${this.config.apiBaseUrl}/v0/radar${path}`
const params = {
method,
body: body ? JSON.stringify(body) : null,
headers: {
'Content-Type': 'application/json',
...(this.config.apiKey && { 'X-Api-Key': this.config.apiKey }),
},
}
try {
const response = await fetch(url, {
...params,
credentials: 'include',
signal,
})
if (!response.ok) {
throw new Error('Network response was not ok: ' + response.statusText)
}
if (response.status === 204) {
return null
}
return await response.json()
} catch (error: any) {
if (error?.name === 'AbortError') {
throw new Error('Request aborted')
}
}
}
}