@vidtreo/recorder-vue 1.8.0 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,7 +19,7 @@ npm install @vidtreo/recorder-vue @vidtreo/recorder
19
19
  ```
20
20
 
21
21
  **Peer dependencies**:
22
- - `@vidtreo/recorder >=1.8.0`
22
+ - `@vidtreo/recorder >=1.9.0`
23
23
  - `vue >=3.0.0`
24
24
 
25
25
  Don't forget the stylesheet — either import it once in your entry, or rely on the built-in CSS injection (added to `<head>` automatically when the package loads).
@@ -89,6 +89,7 @@ The component accepts a single `recorder-props` object so the discriminated unio
89
89
  | `tabVisibilityOverlayText` | `string` | No | localized default | Custom message for the tab-visibility overlay. |
90
90
  | `mobileMode` | `"embed" \| "overlay" \| "native"` | No | `"overlay"` | Mobile experience. `"embed"` = same as desktop, `"overlay"` = fullscreen modal, `"native"` = device's native camera (file input). |
91
91
  | `nativeCamera` | `boolean` | No | – | **Deprecated** — use `mobileMode: "native"` instead. |
92
+ | `audioOnly` | `boolean` | No | `false` | Record audio only with the microphone (no camera). Requires audio recording enabled for the environment in the backend. See [Audio-only recording](#audio-only-recording). |
92
93
  | `maxFileSize` | `number` | No | – | Maximum file size in MB (native camera mode). |
93
94
  | `lang` | `string` | No | `"en"` | Language code (`"en"` or `"es"`). |
94
95
  | `texts` | `PartialTranslations` | No | – | Per-key text overrides. |
@@ -214,9 +215,13 @@ type RecordingUploadResult = {
214
215
  transferredAt: string | null;
215
216
  r2DeleteAfter: string | null;
216
217
  r2DeletedAt: string | null;
218
+ mediaType?: "audio"; // set for audio-only recordings
219
+ audioId?: string; // same value as id, set for audio-only recordings
217
220
  };
218
221
  ```
219
222
 
223
+ For audio-only recordings (`audioOnly: true`) the payload also has `mediaType: "audio"` and `audioId`.
224
+
220
225
  ### Upload errors
221
226
 
222
227
  When an upload fails with a known cause, the component shows a dialog (`role="alertdialog"`) after recording and processing finish, and `upload-error` receives an error with a code:
@@ -246,7 +251,7 @@ function onUploadError(error: Error) {
246
251
 
247
252
  | Code | Meaning |
248
253
  |------|---------|
249
- | `upload.insufficient-credits` | The account has no credits left (HTTP 402). The upload is not retried. |
254
+ | `upload.insufficient-credits` | The account has no credits left (HTTP 402). The upload stays queued and is retried every 5 minutes; `onUploadError` fires on each rejected attempt. The first rejection of each queued upload per page session also sets the built-in dialog and `uploadErrorCode`; repeated rejections only call `onUploadError` (no `onError`, no state change). |
250
255
 
251
256
  `getUploadErrorCode` returns `null` for other errors. Network errors are retried automatically before they are reported; while a retry is in progress the progress bar shows the `retryingUpload` label.
252
257
 
@@ -335,15 +340,15 @@ const { state, actions, audioLevel, controller } = useVidtreoRecorder({
335
340
 
336
341
  | Action | Signature | What it does |
337
342
  |--------|-----------|--------------|
338
- | `startRecording` | `(sourceType?: "camera" \| "screen") => Promise<void>` | Begin recording (after countdown if configured). |
339
- | `stopRecording` | `() => Promise<RecordingStopResult>` | Stop and trigger upload. |
343
+ | `startRecording` | `(sourceType?: "camera" \| "screen" \| "audio") => Promise<void>` | Begin recording (after countdown if configured). Defaults to `"audio"` when `audioOnly` is set, otherwise `"camera"`. |
344
+ | `stopRecording` | `() => Promise<RecordingStopResult>` | Stop and trigger upload. The result has `blob` and `mediaType` (`"audio"` or `"video"`). |
340
345
  | `pauseRecording` | `() => void` | Pause an active recording. |
341
346
  | `resumeRecording` | `() => void` | Resume from pause. |
342
347
  | `toggleMute` | `() => void` | Toggle the audio mute state. |
343
348
  | `switchSource` | `(sourceType: "camera" \| "screen") => Promise<void>` | Swap between camera and screen during preview/recording. |
344
349
  | `changeCamera` | `(deviceId: string) => Promise<void>` | Switch to a different camera. |
345
350
  | `changeMic` | `(deviceId: string) => Promise<void>` | Switch to a different microphone. |
346
- | `startPreview` | `(sourceType?: "camera" \| "screen") => Promise<void>` | Open the stream without recording. |
351
+ | `startPreview` | `(sourceType?: "camera" \| "screen" \| "audio") => Promise<void>` | Open the stream without recording. `"audio"` opens a microphone-only stream. |
347
352
  | `stopPreview` | `() => void` | Tear the preview stream down. |
348
353
  | `downloadVideo` | `() => void` | Download the last `recordedBlob` (demo mode). |
349
354
  | `clearUploadError` | `() => void` | Clear `uploadErrorCode` after the user dismisses the upload error. |
@@ -578,6 +583,23 @@ Every key is identical (name and default copy) across `@vidtreo/recorder-react`,
578
583
  | `permissionFlowRecoveryTitle` | Allow access to continue | Permite el acceso para continuar |
579
584
  | `permissionFlowRecoveryInstructions` | Open your browser settings and allow camera and microphone access, then try again. | Abre la configuración de tu navegador y permite el acceso a la cámara y micrófono, luego intenta de nuevo. |
580
585
  | `permissionFlowConnecting` | Setting up... | Preparando... |
586
+ | `initializingMicrophone` | Initializing microphone... | Iniciando micrófono... |
587
+ | `grantMicrophonePermission` | Grant microphone permission when prompted | Concede el permiso de micrófono cuando se te solicite |
588
+ | `retryMicrophone` | Retry Microphone | Reintentar micrófono |
589
+ | `audioOnlyReady` | Ready to record | Listo para grabar |
590
+ | `audioOnlyRecording` | Recording | Grabando |
591
+ | `audioOnlyPaused` | Paused | En pausa |
592
+ | `audioOnlyUploading` | Uploading {progress}% | Subiendo {progress}% |
593
+ | `audioOnlyUploaded` | Upload complete | Subida completada |
594
+ | `audioOnlyElapsedTime` | Elapsed time | Tiempo transcurrido |
595
+ | `audioOnlyNoMicrophones` | No microphones available | No hay micrófonos disponibles |
596
+ | `audioRecordingDisabledTitle` | Audio recording unavailable | Grabación de audio no disponible |
597
+ | `audioRecordingDisabled` | Audio recording is not enabled for this environment | La grabación de audio no está habilitada para este entorno |
598
+ | `permissionFlowMicrophoneOnlyTitle` | Microphone | Micrófono |
599
+ | `permissionFlowMicrophoneOnlyLabel` | We need access to your microphone to start recording | Necesitamos acceso a tu micrófono para comenzar a grabar |
600
+ | `permissionFlowMicrophoneOnlyRecoveryInstructions` | Open your browser settings and allow microphone access, then try again. | Abre la configuración de tu navegador y permite el acceso al micrófono, luego intenta de nuevo. |
601
+ | `mobileOpenMicrophoneTitle` | Microphone | Micrófono |
602
+ | `mobileOpenMicrophoneDescription` | We need access to your microphone to start recording | Necesitamos acceso a tu micrófono para comenzar a grabar |
581
603
 
582
604
  `TranslationKeys` lists every available key. The full key list lives in [`src/i18n/translations.ts`](./src/i18n/translations.ts) — there's a key for every visible string, including the permission flow recovery guide.
583
605
 
@@ -593,6 +615,24 @@ Every key is identical (name and default copy) across `@vidtreo/recorder-react`,
593
615
 
594
616
  The `<VidtreoRecorder>` component probes browser capabilities on mobile and falls back gracefully when `WebCodecs` isn't available.
595
617
 
618
+ ## Audio-only recording
619
+
620
+ Set `audioOnly: true` to record audio with the microphone only:
621
+
622
+ ```vue
623
+ <template>
624
+ <VidtreoRecorder :recorder-props="{ apiKey: 'your-api-key', audioOnly: true }" />
625
+ </template>
626
+ ```
627
+
628
+ - Audio recording must be enabled for the environment in the backend. The environment's audio settings (format, bitrate, max duration) apply, and the max duration is shown next to the timer (for example `00:12 / 10:00`).
629
+ - Only microphone permission is requested. The recorder renders as a compact voice-note pill (about 56px high, at most 20rem wide, light and dark aware): a red record/stop button, a live 18-bar waveform, the timer with the max duration (for example `00:12 / 10:00`) and a microphone button that opens a menu. The menu lists microphones when idle and holds pause/resume and mute/unmute while recording. Status text, permission prompts, errors and the upload-complete message appear on a caption line below the pill, and upload progress runs along the pill; there is no video area. The camera selector, source switching and the tab visibility overlay are not used.
630
+ - On mobile, `mobileMode: "native"` (and `nativeCamera`) is not used; the recorder falls back to `"overlay"`.
631
+ - `upload-complete` receives `mediaType: "audio"` and `audioId`.
632
+ - Demo mode has no environment audio config, so audio-only recording is unavailable there.
633
+
634
+ If audio recording is disabled for the environment, starting the recorder fails with the error code `recording.audio-disabled` (`ERROR_AUDIO_RECORDING_DISABLED` in `@vidtreo/recorder`). The bar shows the `audioRecordingDisabled` message without a retry button, and `error` is emitted with the original error.
635
+
596
636
  ## SSR (Nuxt, Astro-Vue, etc.)
597
637
 
598
638
  Every browser API is gated to `onMounted`/`if (typeof window !== "undefined")`. If you're on Nuxt 3, the cleanest path is the [`@vidtreo/recorder-nuxt`](../recorder-nuxt) module — it registers the component as `client`-only and injects the CSS for you.
@@ -0,0 +1,40 @@
1
+ import { type PermissionFlowStep } from "@vidtreo/recorder";
2
+ import type { TranslationKeys } from "../../i18n/translations";
3
+ import type { VidtreoRecorderState } from "../../types";
4
+ type __VLS_Props = {
5
+ state: VidtreoRecorderState;
6
+ audioLevel: number;
7
+ translations: TranslationKeys;
8
+ isStopLocked: boolean;
9
+ isRetrying: boolean;
10
+ permissionStep: PermissionFlowStep | null;
11
+ canRetryPermission: boolean;
12
+ enablePause?: boolean;
13
+ enableMute?: boolean;
14
+ enableDeviceChange?: boolean;
15
+ };
16
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
17
+ record: () => any;
18
+ stop: () => any;
19
+ pause: () => any;
20
+ resume: () => any;
21
+ retry: () => any;
22
+ toggleMute: () => any;
23
+ micChange: (deviceId: string) => any;
24
+ closeUploadError: () => any;
25
+ requestPermission: () => any;
26
+ retryPermission: () => any;
27
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
28
+ onRecord?: (() => any) | undefined;
29
+ onStop?: (() => any) | undefined;
30
+ onPause?: (() => any) | undefined;
31
+ onResume?: (() => any) | undefined;
32
+ onRetry?: (() => any) | undefined;
33
+ onToggleMute?: (() => any) | undefined;
34
+ onMicChange?: ((deviceId: string) => any) | undefined;
35
+ onCloseUploadError?: (() => any) | undefined;
36
+ onRequestPermission?: (() => any) | undefined;
37
+ onRetryPermission?: (() => any) | undefined;
38
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
39
+ declare const _default: typeof __VLS_export;
40
+ export default _default;
@@ -8,11 +8,11 @@ type DeviceProps = {
8
8
  enabled: boolean;
9
9
  };
10
10
  declare const __VLS_export: import("vue").DefineComponent<DeviceProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
11
- cameraChange: (deviceId: string) => any;
12
11
  micChange: (deviceId: string) => any;
12
+ cameraChange: (deviceId: string) => any;
13
13
  }, string, import("vue").PublicProps, Readonly<DeviceProps> & Readonly<{
14
- onCameraChange?: ((deviceId: string) => any) | undefined;
15
14
  onMicChange?: ((deviceId: string) => any) | undefined;
15
+ onCameraChange?: ((deviceId: string) => any) | undefined;
16
16
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
17
17
  declare const _default: typeof __VLS_export;
18
18
  export default _default;
@@ -27,6 +27,7 @@ type __VLS_Props = {
27
27
  recoveryData: PermissionFlowState["recoveryData"] | undefined;
28
28
  canRetry: boolean;
29
29
  translations: PermissionFlowStepsTranslations;
30
+ audioOnly?: boolean;
30
31
  };
31
32
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
32
33
  requestPermission: () => any;
@@ -1,5 +1,5 @@
1
1
  type __VLS_Props = {
2
- cameraLabel: string;
2
+ cameraLabel?: string;
3
3
  microphoneLabel: string;
4
4
  };
5
5
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -55,20 +55,20 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
55
55
  resume: () => any;
56
56
  switchSource: () => any;
57
57
  download: () => any;
58
+ toggleMute: () => any;
58
59
  toggleSettings: () => any;
59
60
  startRecording: () => any;
60
61
  stopRecording: () => any;
61
- toggleMute: () => any;
62
62
  loadedChange: (loaded: boolean) => any;
63
63
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
64
64
  onPause?: (() => any) | undefined;
65
65
  onResume?: (() => any) | undefined;
66
66
  onSwitchSource?: (() => any) | undefined;
67
67
  onDownload?: (() => any) | undefined;
68
+ onToggleMute?: (() => any) | undefined;
68
69
  onToggleSettings?: (() => any) | undefined;
69
70
  onStartRecording?: (() => any) | undefined;
70
71
  onStopRecording?: (() => any) | undefined;
71
- onToggleMute?: (() => any) | undefined;
72
72
  onLoadedChange?: ((loaded: boolean) => any) | undefined;
73
73
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
74
74
  declare const _default: typeof __VLS_export;
@@ -39,10 +39,10 @@ declare const __VLS_export: import("vue").DefineComponent<{
39
39
  resume: () => any;
40
40
  switchSource: () => any;
41
41
  download: () => any;
42
+ toggleMute: () => any;
42
43
  toggleSettings: () => any;
43
44
  startRecording: () => any;
44
45
  stopRecording: () => any;
45
- toggleMute: () => any;
46
46
  }, string, import("vue").PublicProps, Readonly<{
47
47
  buttonVisibility: {
48
48
  showSettingsButton: boolean;
@@ -66,10 +66,10 @@ declare const __VLS_export: import("vue").DefineComponent<{
66
66
  onResume?: (() => any) | undefined;
67
67
  onSwitchSource?: (() => any) | undefined;
68
68
  onDownload?: (() => any) | undefined;
69
+ onToggleMute?: (() => any) | undefined;
69
70
  onToggleSettings?: (() => any) | undefined;
70
71
  onStartRecording?: (() => any) | undefined;
71
72
  onStopRecording?: (() => any) | undefined;
72
- onToggleMute?: (() => any) | undefined;
73
73
  }>, {
74
74
  translations: RecordingControlsButtonsTranslations;
75
75
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -15,9 +15,10 @@ declare const __VLS_export: import("vue").DefineComponent<{
15
15
  selectedMic: string | null;
16
16
  };
17
17
  translations?: SettingsPanelTranslations;
18
+ audioOnly?: boolean;
18
19
  }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
19
- cameraChange: (value: string) => any;
20
20
  micChange: (value: string) => any;
21
+ cameraChange: (value: string) => any;
21
22
  }, string, import("vue").PublicProps, Readonly<{
22
23
  devices: {
23
24
  cameras: MediaDeviceInfo[];
@@ -26,9 +27,11 @@ declare const __VLS_export: import("vue").DefineComponent<{
26
27
  selectedMic: string | null;
27
28
  };
28
29
  translations?: SettingsPanelTranslations;
30
+ audioOnly?: boolean;
29
31
  }> & Readonly<{
30
- onCameraChange?: ((value: string) => any) | undefined;
31
32
  onMicChange?: ((value: string) => any) | undefined;
33
+ onCameraChange?: ((value: string) => any) | undefined;
32
34
  }>, {
33
35
  translations: SettingsPanelTranslations;
36
+ audioOnly: boolean;
34
37
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -1,4 +1,4 @@
1
- import type { PermissionFlowChangeReason, PermissionFlowLanguage, PermissionFlowState, PermissionFlowStep } from "@vidtreo/recorder";
1
+ import type { PermissionFlowChangeReason, PermissionFlowLanguage, PermissionFlowMediaType, PermissionFlowState, PermissionFlowStep } from "@vidtreo/recorder";
2
2
  import { type ComputedRef, type MaybeRefOrGetter } from "vue";
3
3
  export type PermissionStepStatus = PermissionFlowState["permissions"]["camera"];
4
4
  export type PermissionFlowStepInfo = {
@@ -7,6 +7,7 @@ export type PermissionFlowStepInfo = {
7
7
  };
8
8
  export type UsePermissionFlowOptions = {
9
9
  language?: MaybeRefOrGetter<PermissionFlowLanguage | undefined>;
10
+ mediaType?: PermissionFlowMediaType;
10
11
  onComplete?: (state: PermissionFlowState) => void;
11
12
  onChange?: (state: PermissionFlowState, reason: PermissionFlowChangeReason) => void;
12
13
  };
@@ -122,6 +122,23 @@ export type TranslationKeys = {
122
122
  permissionFlowRecoveryTitle: string;
123
123
  permissionFlowRecoveryInstructions: string;
124
124
  permissionFlowConnecting: string;
125
+ initializingMicrophone: string;
126
+ grantMicrophonePermission: string;
127
+ retryMicrophone: string;
128
+ audioOnlyReady: string;
129
+ audioOnlyRecording: string;
130
+ audioOnlyPaused: string;
131
+ audioOnlyUploading: string;
132
+ audioOnlyUploaded: string;
133
+ audioOnlyElapsedTime: string;
134
+ audioOnlyNoMicrophones: string;
135
+ audioRecordingDisabledTitle: string;
136
+ audioRecordingDisabled: string;
137
+ permissionFlowMicrophoneOnlyTitle: string;
138
+ permissionFlowMicrophoneOnlyLabel: string;
139
+ permissionFlowMicrophoneOnlyRecoveryInstructions: string;
140
+ mobileOpenMicrophoneTitle: string;
141
+ mobileOpenMicrophoneDescription: string;
125
142
  };
126
143
  export declare const defaultTranslations: Record<string, TranslationKeys>;
127
144
  export type PartialTranslations = Partial<TranslationKeys>;
package/dist/index.d.ts CHANGED
@@ -14,4 +14,4 @@ export type { ButtonTranslations, PreviewTranslations, RecorderTranslations, Set
14
14
  export { useRecorderTranslations } from "./composables/use-recorder-translations";
15
15
  export { useVidtreoRecorder } from "./composables/use-vidtreo-recorder";
16
16
  export { defaultTranslations, getTranslations, type PartialTranslations, type TranslationKeys, } from "./i18n/translations";
17
- export type { AccessTokenProvider, AudioWarning, MobileMode, RecordingPrompt, RecordingPromptCountdown, RecordingPromptCountdownPlacement, RecordingState, RecordingStopResult, RecordingUploadResult, SourceType, UploadErrorCode, UploadProgressPhase, UseVidtreoRecorderConfig, UseVidtreoRecorderReturn, VidtreoRecorderActions, VidtreoRecorderEmits, VidtreoRecorderProps, VidtreoRecorderState, } from "./types";
17
+ export type { AccessTokenProvider, AudioWarning, MediaType, MobileMode, RecordingPrompt, RecordingPromptCountdown, RecordingPromptCountdownPlacement, RecordingState, RecordingStopResult, RecordingUploadResult, SourceType, UploadErrorCode, UploadProgressPhase, UseVidtreoRecorderConfig, UseVidtreoRecorderReturn, VidtreoRecorderActions, VidtreoRecorderEmits, VidtreoRecorderProps, VidtreoRecorderState, } from "./types";