npm package: @fvc/session-recorder
Description: A comprehensive React component for recording user sessions with video capture and detailed logging capabilities.
Latest version: 2.1.9

# SessionRecorder

A comprehensive React component for recording user sessions with video capture and detailed logging capabilities.

## Features

- **Screen Recording**: Capture video of user interactions using MediaRecorder API
- **Comprehensive Logging**: Track network requests, console logs, errors, performance metrics, user interactions, and annotations
- **Keyboard Shortcuts**: Use `Ctrl+Shift+K` to toggle recording interface
- **Export Capabilities**: Save recordings in multiple formats (WebM video, JSON logs, HAR files, CSV)
- **Annotation System**: Add contextual annotations during recording
- **Data Access**: Access all recorded data programmatically via callback

## Installation

```bash
npm install @fvc/sessionRecorder
# or
bun add @fvc/sessionRecorder
```

## Configuration

The SessionRecorder uses environment variables for configuration:

| Environment Variable                    | Description                                 | Default                                |
| --------------------------------------- | ------------------------------------------- | -------------------------------------- |
| `NEXT_PUBLIC_SESSION_RECORDER_BASE_URL` | Base URL for Next.js apps (client-side)     | `https://dev-tools.e-taxes.gov.az/api` |
| `SESSION_RECORDER_BASE_URL`             | Base URL for Node.js/server-side (fallback) | `https://dev-tools.e-taxes.gov.az/api` |
| `REACT_APP_SESSION_RECORDER_BASE_URL`   | Base URL for Create React App               | `https://dev-tools.e-taxes.gov.az/api` |
| `VITE_SESSION_RECORDER_BASE_URL`        | Base URL for Vite apps                      | `https://dev-tools.e-taxes.gov.az/api` |

The component automatically constructs the API endpoint by appending `/v1/logs/create` to the base URL.

### Environment Setup Examples

**.env.local** (Next.js):

```env
NEXT_PUBLIC_SESSION_RECORDER_BASE_URL=https://your-api.com
```

**.env** (Vite):

```env
VITE_SESSION_RECORDER_BASE_URL=https://your-api.com
```

**.env** (Create React App):

```env
REACT_APP_SESSION_RECORDER_BASE_URL=https://your-api.com
```

**.env** (Other frameworks / Server-side):

```env
SESSION_RECORDER_BASE_URL=https://your-api.com
```

### Framework Support

The component checks environment variables in the following order (first match wins):

1. **Next.js**: `process.env.NEXT_PUBLIC_SESSION_RECORDER_BASE_URL`
2. **Server-side**: `process.env.SESSION_RECORDER_BASE_URL`
3. **Create React App**: `process.env.REACT_APP_SESSION_RECORDER_BASE_URL`
4. **Vite**: `import.meta.env.VITE_SESSION_RECORDER_BASE_URL`
5. **Vite (alt)**: `import.meta.env.NEXT_PUBLIC_SESSION_RECORDER_BASE_URL`

This will result in:

- API URL: `https://your-api.com/v1/logs/create`
- User search URL: `https://your-api.com`

## Basic Usage

```tsx
import { SessionRecorder } from '@fvc/sessionRecorder';

function App() {
  return (
    <SessionRecorder>
      <div>Your app content here</div>
    </SessionRecorder>
  );
}
```

### Using the `baseUrl` Prop (Recommended)

The most reliable way to configure the API URL is using the `baseUrl` prop directly:

```tsx
import { SessionRecorder } from '@fvc/sessionRecorder';

function App() {
  return (
    <SessionRecorder baseUrl="http://localhost:5002">
      <div>Your app content here</div>
    </SessionRecorder>
  );
}
```

This is especially useful when environment variables are not being picked up correctly by your bundler.

## Advanced Usage with API-Ready Data

Use the `onSave` prop to receive data in a format ready for API upload:

````tsx
import { SessionRecorder, ApiUploadData } from '@fvc/sessionRecorder';

function App() {
  const handleSave = async (apiData: ApiUploadData) => {
    console.log('Video file:', apiData.video_file); // Blob or null
    console.log('Log file:', apiData.log_file);     // Compressed gzip Blob

    // Create FormData for API upload
    const formData = new FormData();

    if (apiData.video_file) {
      formData.append('video_file', apiData.video_file, 'recording.webm');
    }

    formData.append('log_file', apiData.log_file, 'logs.gz');

    // Send to your API
    await fetch('/api/screenlogs', {
      method: 'POST',
      body: formData
    });
  };

  return (
    <SessionRecorder onSave={handleSave}>
      <div>Your app content here</div>
    </SessionRecorder>
  );
}
```## Props

| Prop       | Type                                                   | Default | Description                                                           |
| ---------- | ------------------------------------------------------ | ------- | --------------------------------------------------------------------- |
| `children` | `React.ReactNode`                                      | -       | The app content to wrap                                               |
| `testId`   | `string`                                               | -       | Test ID for the component                                             |
| `onSave`   | `(data: ApiUploadData) => void \| Promise<void>` | -       | Callback function called when user clicks save with API-ready data |

## ApiUploadData Structure

The `onSave` callback receives an `ApiUploadData` object ready for API upload:

```typescript
type ApiUploadData = {
  video_file: Blob | null;  // Video recording (WebM format, video/webm)
  log_file: Blob;          // Compressed logs (gzip format, application/gzip)
};
````

### API Compatibility

The data structure matches your API requirements:

- **video_file**: WebM video blob (MIME type: `video/webm`) - max 10 MB
- **log_file**: Gzipped JSON logs (MIME type: `application/gzip`) - max 10 MB

Example API upload:

```typescript
const handleSave = async (apiData: ApiUploadData) => {
  const formData = new FormData();

  if (apiData.video_file) {
    formData.append('video_file', apiData.video_file, 'recording.webm');
  }

  formData.append('log_file', apiData.log_file, 'logs.gz');

  const response = await fetch('/api/screenlogs', {
    method: 'POST',
    body: formData,
    headers: {
      Authorization: 'Bearer your-token-here',
    },
  });
};
```

### Log File Contents

The `log_file` contains all session data except the video, compressed as gzip:

```typescript
{
  session: {
    timestamp: number;      // Recording start time
    duration: number;       // Recording duration in ms
  };
  logs: {
    network: NetworkLog[];     // HTTP requests/responses
    console: ConsoleLog[];     // Console messages
    error: ErrorLog[];         // JavaScript errors
    performance: PerformanceLog[]; // Performance metrics
    interaction: InteractionLog[]; // User interactions
    annotation: AnnotationLog[];   // User annotations
  };
  metadata: {
    userAgent: string;      // Browser user agent
    url: string;           // Current page URL
    exported: string;      // Export timestamp
  };
};
```

## Keyboard Shortcuts

- `Ctrl+Shift+K` (Windows/Linux) or `Cmd+Shift+K` (Mac): Toggle recording interface

## Recording Workflow

1. Press `Ctrl+Shift+K` to show recording controls
2. Click "Record" to start recording
3. Interact with your application (all actions are logged)
4. Add annotations using the floating action button
5. Click "Stop" to end recording
6. Click "Save" to download files or trigger the `onSave` callback
7. Use panel controls to view different types of logs

## Log Types

- **Network**: HTTP requests, responses, timing
- **Console**: Console.log, warn, error messages
- **Error**: JavaScript errors and stack traces
- **Performance**: Page load times, resource timing
- **Interaction**: Clicks, form submissions, navigation
- **Annotation**: User-added contextual notes

## Browser Compatibility

- Chrome/Edge: Full support
- Firefox: Full support
- Safari: Partial support (some MediaRecorder limitations)

## License

MIT