npm package: @medassistant/recorder
Description: React hooks for MedAssistant audio recording, upload, and transcription polling.
Latest version: 1.0.3

# @medassistant/recorder

React hooks for recording, uploading, transcribing, and optionally generating notes with MedAssistant.

Full guide: https://platform.medassistant.ca/docs/react-packages/audio-recorder

## Installation

```bash
npm install @medassistant/recorder
```

## When to use this package

Use `@medassistant/recorder` when you want to build your own React UI around the recorder lifecycle.

- `useMedAssistantRecorder` handles recording, uploads, transcription, and note polling
- `useNoteTemplates` loads note categories and templates for your own form controls
- `issueShortLivedToken` helps you issue browser-safe tokens from your backend

## Issue short-lived tokens from your backend

Keep your MedAssistant API key on the server and issue a user-scoped short-lived token from your own backend route:

```ts
import { issueShortLivedToken } from "@medassistant/recorder";

async function getAuth() {
  return { userId: "replace-with-your-session-user-id" };
}

export async function POST() {
  const { userId } = await getAuth();

  if (!userId) {
    return new Response("Unauthorized", { status: 401 });
  }

  const token = await issueShortLivedToken({
    apiKey: process.env.MEDASSISTANT_API_KEY!,
    externalUserId: userId,
  });

  return Response.json(token, { status: 201 });
}
```

## Quick start

```tsx
"use client";

import {
  useMedAssistantRecorder,
  type ShortLivedTokenResponse,
} from "@medassistant/recorder";

async function fetchShortLivedToken(): Promise<ShortLivedTokenResponse> {
  const response = await fetch("/api/medassistant-token", {
    method: "POST",
  });

  if (!response.ok) {
    throw new Error("Failed to issue short-lived token");
  }

  return response.json();
}

const shortLivedToken = { getToken: fetchShortLivedToken };

export function Recorder() {
  const [state, controls] = useMedAssistantRecorder({
    shortLivedToken,
    onTranscriptReady: (transcript) => {
      console.log("Transcript ready:", transcript);
    },
    onNoteReady: (note) => {
      console.log("Note ready:", note.id);
    },
    onNoteFailed: (note) => {
      console.error("Note failed:", note.id);
    },
    onError: (error) => {
      console.error("Recorder error:", error);
    },
  });

  return (
    <div>
      <p>Phase: {state.phase}</p>

      {state.phase === "idle" ? (
        <button onClick={() => void controls.start()}>Start</button>
      ) : null}

      {state.phase === "recording" ? (
        <>
          <button onClick={controls.pause}>Pause</button>
          <button onClick={() => void controls.stop()}>Stop</button>
          <button onClick={controls.discard}>Discard</button>
        </>
      ) : null}

      {state.phase === "paused" ? (
        <>
          <button onClick={controls.resume}>Resume</button>
          <button onClick={() => void controls.stop()}>Stop</button>
          <button onClick={controls.discard}>Discard</button>
        </>
      ) : null}
    </div>
  );
}
```

Use `controls.discard()` when you want to delete the current recording entirely. Use `controls.reset()` when you just want to return the UI to its initial state after a completed attempt.

If you want to let users choose note categories and templates in your own UI, pair the recorder hook with `useNoteTemplates`. The full guide above includes a complete example using both hooks together.

## Browser support notes

- Requires `MediaDevices.getUserMedia`, `MediaRecorder`, and `AudioContext`
- Use HTTPS in production so microphone access is available