@independo/capacitor-voice-recorder 8.1.8 → 8.1.9-dev.2

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/dist/plugin.js CHANGED
@@ -74,13 +74,51 @@ var capacitorVoiceRecorder = (function (exports, core, filesystem, write_blob) {
74
74
  /** Error for browsers that do not support permission queries. */
75
75
  const couldNotQueryPermissionStatusError = () => new Error('COULD_NOT_QUERY_PERMISSION_STATUS');
76
76
 
77
- /** Preferred MIME types to probe in order of fallback. */
77
+ /**
78
+ * Ordered MIME types to probe for audio recording via `MediaRecorder.isTypeSupported()`.
79
+ *
80
+ * ⚠️ The order is intentional and MUST remain stable unless you also update the
81
+ * selection policy in code and test on Safari/iOS + WebViews.
82
+ *
83
+ * ✅ What this list is used for
84
+ * - Selecting a `mimeType` for `new MediaRecorder(stream, { mimeType })`.
85
+ *
86
+ * ❌ What this list does NOT guarantee
87
+ * - It does NOT guarantee that the recorded output will be playable via the
88
+ * HTML `<audio>` element in the same browser.
89
+ *
90
+ * Real-world caveat (important):
91
+ * - We have observed cases where `MediaRecorder.isTypeSupported('audio/webm;codecs=opus')`
92
+ * returned `true`, the recorder produced a Blob, but `<audio>` could not play it.
93
+ * This can happen due to container/codec playback support differences, platform
94
+ * quirks (especially Safari/iOS / WKWebView), or incomplete WebM playback support.
95
+ *
96
+ * Current selection behavior in this implementation:
97
+ * - By default, MIME selection treats recorder support and playback support as separate
98
+ * capabilities and probes both:
99
+ * - Recorder capability: `MediaRecorder.isTypeSupported(type)`
100
+ * - Playback capability: `audio.canPlayType(type)`
101
+ * - This default can be disabled via `RecordingOptions.requirePlaybackSupport = false`
102
+ * to fall back to recorder-only probing.
103
+ *
104
+ * Keeping legacy keys:
105
+ * - Some entries are kept even if they overlap (e.g. `audio/mp4` and explicit codec),
106
+ * to maximize compatibility across differing browser implementations.
107
+ */
78
108
  const POSSIBLE_MIME_TYPES = {
79
- 'audio/aac': '.aac',
80
- 'audio/webm;codecs=opus': '.ogg',
81
- 'audio/mp4': '.mp3',
82
- 'audio/webm': '.ogg',
83
- 'audio/ogg;codecs=opus': '.ogg',
109
+ // ✅ Most universal
110
+ 'audio/mp4;codecs="mp4a.40.2"': '.m4a', // AAC in MP4 (explicit codec helps detection)
111
+ 'audio/mp4': '.m4a', // (legacy key kept; broad support)
112
+ 'audio/aac': '.aac', // (legacy key kept; less common in the wild)
113
+ 'audio/mpeg': '.mp3', // MP3 (universal)
114
+ 'audio/wav': '.wav', // WAV (universal, big files)
115
+ // ✅ Modern high-quality (very widely supported, but slightly less “universal” than MP3/AAC)
116
+ 'audio/webm;codecs="opus"': '.webm', // Opus in WebM (explicit codec helps detection)
117
+ 'audio/webm;codecs=opus': '.webm', // (legacy key kept)
118
+ 'audio/webm': '.webm', // (legacy key kept; container-only, codec-dependent)
119
+ // ⚠️ Least universal (Safari/iOS historically the limiting factor)
120
+ 'audio/ogg;codecs=opus': '.ogg', // (legacy key kept)
121
+ 'audio/ogg;codecs=vorbis': '.ogg', // Ogg Vorbis (weakest mainstream support)
84
122
  };
85
123
  /** Creates a promise that never resolves. */
86
124
  const neverResolvingPromise = () => new Promise(() => undefined);
@@ -94,22 +132,40 @@ var capacitorVoiceRecorder = (function (exports, core, filesystem, write_blob) {
94
132
  /** Promise resolved when the recorder stops and payload is ready. */
95
133
  this.pendingResult = neverResolvingPromise();
96
134
  }
97
- /** Returns whether the browser can start a recording session. */
98
- static async canDeviceVoiceRecord() {
135
+ /**
136
+ * Returns whether the browser can start a recording session.
137
+ *
138
+ * On web this checks:
139
+ * - `navigator.mediaDevices.getUserMedia`
140
+ * - at least one supported recording MIME type using {@link getSupportedMimeType}
141
+ *
142
+ * The optional `requirePlaybackSupport` flag is forwarded to MIME selection and defaults
143
+ * to `true` when omitted.
144
+ */
145
+ static async canDeviceVoiceRecord(options) {
99
146
  var _a;
100
- if (((_a = navigator === null || navigator === void 0 ? void 0 : navigator.mediaDevices) === null || _a === void 0 ? void 0 : _a.getUserMedia) == null || VoiceRecorderImpl.getSupportedMimeType() == null) {
147
+ if (((_a = navigator === null || navigator === void 0 ? void 0 : navigator.mediaDevices) === null || _a === void 0 ? void 0 : _a.getUserMedia) == null ||
148
+ VoiceRecorderImpl.getSupportedMimeType({
149
+ requirePlaybackSupport: options === null || options === void 0 ? void 0 : options.requirePlaybackSupport,
150
+ }) == null) {
101
151
  return failureResponse();
102
152
  }
103
153
  else {
104
154
  return successResponse();
105
155
  }
106
156
  }
107
- /** Starts a recording session using MediaRecorder. */
157
+ /**
158
+ * Starts a recording session using `MediaRecorder`.
159
+ *
160
+ * The selected MIME type is resolved once at start time (using the optional
161
+ * `requirePlaybackSupport` flag from `RecordingOptions`) and reused for the final Blob
162
+ * and file extension to keep the recording payload internally consistent.
163
+ */
108
164
  async startRecording(options) {
109
165
  if (this.mediaRecorder != null) {
110
166
  throw alreadyRecordingError();
111
167
  }
112
- const deviceCanRecord = await VoiceRecorderImpl.canDeviceVoiceRecord();
168
+ const deviceCanRecord = await VoiceRecorderImpl.canDeviceVoiceRecord(options);
113
169
  if (!deviceCanRecord.value) {
114
170
  throw deviceCannotVoiceRecordError();
115
171
  }
@@ -211,30 +267,91 @@ var capacitorVoiceRecorder = (function (exports, core, filesystem, write_blob) {
211
267
  return Promise.resolve({ status: 'NONE' });
212
268
  }
213
269
  }
214
- /** Returns the first supported MIME type, if any. */
215
- static getSupportedMimeType() {
270
+ /**
271
+ * Returns the first MIME type (key of {@link POSSIBLE_MIME_TYPES}) that the current
272
+ * environment reports as supported for recording via `MediaRecorder.isTypeSupported()`,
273
+ * optionally requiring native HTML `<audio>` playback support too.
274
+ *
275
+ * The search order is the iteration order of {@link POSSIBLE_MIME_TYPES}.
276
+ *
277
+ * @typeParam T - A MIME type string that exists as a key in {@link POSSIBLE_MIME_TYPES}.
278
+ *
279
+ * @returns The first supported MIME type for `MediaRecorder`, or `null` if:
280
+ * - `MediaRecorder` is unavailable, or
281
+ * - no configured MIME types are supported.
282
+ *
283
+ * ⚠️ Important: `MediaRecorder` support ≠ `<audio>` playback support
284
+ *
285
+ * Some browsers/platforms can claim support for recording a format (notably WebM/Opus)
286
+ * but still fail to play the resulting Blob through the native HTML audio pipeline.
287
+ * This mismatch is especially likely on Safari/iOS / WKWebView variants, so the default
288
+ * behavior also probes `HTMLAudioElement.canPlayType(type)` when available.
289
+ *
290
+ * Selection policy when playback probing is enabled:
291
+ * - keep the global priority order from {@link POSSIBLE_MIME_TYPES}
292
+ * - among recordable types, prefer the first `"probably"` playable candidate
293
+ * - otherwise return the first `"maybe"` playable candidate
294
+ * - treat `""` as not playable
295
+ *
296
+ * Note: The <audio> element is never attached to the DOM, so it won't appear to users or assistive tech.
297
+ *
298
+ * Fallback behavior:
299
+ * - If `document` / `audio.canPlayType` is unavailable (e.g. SSR-like environments),
300
+ * this falls back to record-only probing.
301
+ */
302
+ static getSupportedMimeType(options) {
303
+ var _a, _b, _c, _d, _e;
216
304
  if ((MediaRecorder === null || MediaRecorder === void 0 ? void 0 : MediaRecorder.isTypeSupported) == null)
217
305
  return null;
218
- const foundSupportedType = Object.keys(POSSIBLE_MIME_TYPES).find((type) => MediaRecorder.isTypeSupported(type));
219
- return foundSupportedType !== null && foundSupportedType !== void 0 ? foundSupportedType : null;
306
+ const orderedTypes = Object.keys(POSSIBLE_MIME_TYPES);
307
+ const recordSupportedTypes = orderedTypes.filter((type) => MediaRecorder.isTypeSupported(type));
308
+ if (recordSupportedTypes.length === 0)
309
+ return null;
310
+ const requirePlaybackSupport = (_a = options === null || options === void 0 ? void 0 : options.requirePlaybackSupport) !== null && _a !== void 0 ? _a : VoiceRecorderImpl.DEFAULT_REQUIRE_PLAYBACK_SUPPORT;
311
+ if (!requirePlaybackSupport) {
312
+ return (_b = recordSupportedTypes[0]) !== null && _b !== void 0 ? _b : null;
313
+ }
314
+ if (typeof document === 'undefined' || typeof document.createElement !== 'function') {
315
+ return (_c = recordSupportedTypes[0]) !== null && _c !== void 0 ? _c : null;
316
+ }
317
+ const audioElement = document.createElement('audio');
318
+ if (typeof audioElement.canPlayType !== 'function') {
319
+ return (_d = recordSupportedTypes[0]) !== null && _d !== void 0 ? _d : null;
320
+ }
321
+ let firstProbably = null;
322
+ let firstMaybe = null;
323
+ for (const type of recordSupportedTypes) {
324
+ const playbackSupport = audioElement.canPlayType(type);
325
+ if (playbackSupport === 'probably') {
326
+ firstProbably = type;
327
+ break;
328
+ }
329
+ if (playbackSupport === 'maybe' && firstMaybe == null) {
330
+ firstMaybe = type;
331
+ }
332
+ }
333
+ return (_e = firstProbably !== null && firstProbably !== void 0 ? firstProbably : firstMaybe) !== null && _e !== void 0 ? _e : null;
220
334
  }
221
335
  /** Initializes MediaRecorder and wires up handlers. */
222
336
  onSuccessfullyStartedRecording(stream, options) {
223
337
  this.pendingResult = new Promise((resolve, reject) => {
224
- this.mediaRecorder = new MediaRecorder(stream);
338
+ const mimeType = VoiceRecorderImpl.getSupportedMimeType({
339
+ requirePlaybackSupport: options === null || options === void 0 ? void 0 : options.requirePlaybackSupport,
340
+ });
341
+ if (mimeType == null) {
342
+ this.prepareInstanceForNextOperation();
343
+ reject(failedToRecordError());
344
+ return;
345
+ }
346
+ this.mediaRecorder = new MediaRecorder(stream, { mimeType });
225
347
  this.mediaRecorder.onerror = () => {
226
348
  this.prepareInstanceForNextOperation();
227
349
  reject(failedToRecordError());
228
350
  };
229
351
  this.mediaRecorder.onstop = async () => {
230
- var _a, _b, _c;
231
- const mimeType = VoiceRecorderImpl.getSupportedMimeType();
232
- if (mimeType == null) {
233
- this.prepareInstanceForNextOperation();
234
- reject(failedToFetchRecordingError());
235
- return;
236
- }
237
- const blobVoiceRecording = new Blob(this.chunks, { type: mimeType });
352
+ var _a, _b, _c, _d, _e;
353
+ const mt = (_b = (_a = this.mediaRecorder) === null || _a === void 0 ? void 0 : _a.mimeType) !== null && _b !== void 0 ? _b : mimeType;
354
+ const blobVoiceRecording = new Blob(this.chunks, { type: mt });
238
355
  if (blobVoiceRecording.size <= 0) {
239
356
  this.prepareInstanceForNextOperation();
240
357
  reject(emptyRecordingError());
@@ -243,8 +360,8 @@ var capacitorVoiceRecorder = (function (exports, core, filesystem, write_blob) {
243
360
  let uri = undefined;
244
361
  let recordDataBase64 = '';
245
362
  if (options === null || options === void 0 ? void 0 : options.directory) {
246
- const subDirectory = (_c = (_b = (_a = options.subDirectory) === null || _a === void 0 ? void 0 : _a.match(/^\/?(.+[^/])\/?$/)) === null || _b === void 0 ? void 0 : _b[1]) !== null && _c !== void 0 ? _c : '';
247
- const path = `${subDirectory}/recording-${new Date().getTime()}${POSSIBLE_MIME_TYPES[mimeType]}`;
363
+ const subDirectory = (_e = (_d = (_c = options.subDirectory) === null || _c === void 0 ? void 0 : _c.match(/^\/?(.+[^/])\/?$/)) === null || _d === void 0 ? void 0 : _d[1]) !== null && _e !== void 0 ? _e : '';
364
+ const path = `${subDirectory}/recording-${new Date().getTime()}${POSSIBLE_MIME_TYPES[mt]}`;
248
365
  await write_blob({
249
366
  blob: blobVoiceRecording,
250
367
  directory: options.directory,
@@ -259,7 +376,14 @@ var capacitorVoiceRecorder = (function (exports, core, filesystem, write_blob) {
259
376
  }
260
377
  const recordingDuration = await getBlobDuration(blobVoiceRecording);
261
378
  this.prepareInstanceForNextOperation();
262
- resolve({ value: { recordDataBase64, mimeType, msDuration: recordingDuration * 1000, uri } });
379
+ resolve({
380
+ value: {
381
+ recordDataBase64,
382
+ mimeType: mt,
383
+ msDuration: recordingDuration * 1000,
384
+ uri
385
+ }
386
+ });
263
387
  };
264
388
  this.mediaRecorder.ondataavailable = (event) => this.chunks.push(event.data);
265
389
  this.mediaRecorder.start();
@@ -299,6 +423,8 @@ var capacitorVoiceRecorder = (function (exports, core, filesystem, write_blob) {
299
423
  this.chunks = [];
300
424
  }
301
425
  }
426
+ /** Default behavior for web MIME selection: require recorder + playback support. */
427
+ VoiceRecorderImpl.DEFAULT_REQUIRE_PLAYBACK_SUPPORT = true;
302
428
 
303
429
  /** Web adapter that delegates to the browser-specific implementation. */
304
430
  class VoiceRecorderWebAdapter {
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/platform/web/get-blob-duration.js","esm/platform/web/predefined-web-responses.js","esm/platform/web/VoiceRecorderImpl.js","esm/adapters/VoiceRecorderWebAdapter.js","esm/core/response-format.js","esm/core/error-codes.js","esm/core/recording-contract.js","esm/service/VoiceRecorderService.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst VoiceRecorder = registerPlugin('VoiceRecorder', {\n web: () => import('./web').then((m) => new m.VoiceRecorderWeb()),\n});\nexport * from './definitions';\nexport { VoiceRecorder };\n//# sourceMappingURL=index.js.map","/**\n * @param {Blob | string} blob\n * @returns {Promise<number>} Blob duration in seconds.\n */\nexport default async function getBlobDuration(blob) {\n // Check for AudioContext or webkitAudioContext (Safari)\n const AudioCtx = window.AudioContext || window.webkitAudioContext;\n if (!AudioCtx) {\n throw new Error('AudioContext is not supported in this environment.');\n }\n let audioContext = null;\n try {\n audioContext = new AudioCtx();\n let arrayBuffer;\n if (typeof blob === 'string') {\n arrayBuffer = base64ToArrayBuffer(blob);\n }\n else {\n arrayBuffer = await blob.arrayBuffer();\n }\n const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);\n return audioBuffer.duration;\n }\n catch (err) {\n throw new Error('Failed to get audio duration (AudioContext may require user interaction or is not supported): ' + (err instanceof Error ? err.message : String(err)));\n }\n finally {\n if (audioContext) {\n await audioContext.close();\n }\n }\n}\n/**\n * Convert base64 string to ArrayBuffer.\n * @param base64 The base64 string to convert.\n * @returns The converted ArrayBuffer.\n * @remarks This function is exported for test coverage purposes.\n */\nexport function base64ToArrayBuffer(base64) {\n const cleanBase64 = base64.replace(/^data:[^;]+;base64,/, '');\n const binaryString = atob(cleanBase64);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes.buffer;\n}\n//# sourceMappingURL=get-blob-duration.js.map","/** Success wrapper for boolean plugin responses. */\nexport const successResponse = () => ({ value: true });\n/** Failure wrapper for boolean plugin responses. */\nexport const failureResponse = () => ({ value: false });\n/** Error for missing microphone permission. */\nexport const missingPermissionError = () => new Error('MISSING_PERMISSION');\n/** Error for attempting to start while already recording. */\nexport const alreadyRecordingError = () => new Error('ALREADY_RECORDING');\n/** Error for microphone in use by another app or recorder. */\nexport const microphoneBeingUsedError = () => new Error('MICROPHONE_BEING_USED');\n/** Error for devices that cannot record audio. */\nexport const deviceCannotVoiceRecordError = () => new Error('DEVICE_CANNOT_VOICE_RECORD');\n/** Error for recorder start failures. */\nexport const failedToRecordError = () => new Error('FAILED_TO_RECORD');\n/** Error for empty or zero-length recordings. */\nexport const emptyRecordingError = () => new Error('EMPTY_RECORDING');\n/** Error for stopping without an active recording. */\nexport const recordingHasNotStartedError = () => new Error('RECORDING_HAS_NOT_STARTED');\n/** Error for failures when fetching recording data. */\nexport const failedToFetchRecordingError = () => new Error('FAILED_TO_FETCH_RECORDING');\n/** Error for browsers that do not support permission queries. */\nexport const couldNotQueryPermissionStatusError = () => new Error('COULD_NOT_QUERY_PERMISSION_STATUS');\n//# sourceMappingURL=predefined-web-responses.js.map","import { Filesystem } from '@capacitor/filesystem';\nimport write_blob from 'capacitor-blob-writer';\nimport getBlobDuration from './get-blob-duration';\nimport { alreadyRecordingError, couldNotQueryPermissionStatusError, deviceCannotVoiceRecordError, emptyRecordingError, failedToFetchRecordingError, failedToRecordError, failureResponse, missingPermissionError, recordingHasNotStartedError, successResponse, } from './predefined-web-responses';\n/** Preferred MIME types to probe in order of fallback. */\nconst POSSIBLE_MIME_TYPES = {\n 'audio/aac': '.aac',\n 'audio/webm;codecs=opus': '.ogg',\n 'audio/mp4': '.mp3',\n 'audio/webm': '.ogg',\n 'audio/ogg;codecs=opus': '.ogg',\n};\n/** Creates a promise that never resolves. */\nconst neverResolvingPromise = () => new Promise(() => undefined);\n/** Browser implementation backed by MediaRecorder and Capacitor Filesystem. */\nexport class VoiceRecorderImpl {\n constructor() {\n /** Active MediaRecorder instance, if recording. */\n this.mediaRecorder = null;\n /** Collected data chunks from MediaRecorder. */\n this.chunks = [];\n /** Promise resolved when the recorder stops and payload is ready. */\n this.pendingResult = neverResolvingPromise();\n }\n /** Returns whether the browser can start a recording session. */\n static async canDeviceVoiceRecord() {\n var _a;\n if (((_a = navigator === null || navigator === void 0 ? void 0 : navigator.mediaDevices) === null || _a === void 0 ? void 0 : _a.getUserMedia) == null || VoiceRecorderImpl.getSupportedMimeType() == null) {\n return failureResponse();\n }\n else {\n return successResponse();\n }\n }\n /** Starts a recording session using MediaRecorder. */\n async startRecording(options) {\n if (this.mediaRecorder != null) {\n throw alreadyRecordingError();\n }\n const deviceCanRecord = await VoiceRecorderImpl.canDeviceVoiceRecord();\n if (!deviceCanRecord.value) {\n throw deviceCannotVoiceRecordError();\n }\n const havingPermission = await VoiceRecorderImpl.hasAudioRecordingPermission().catch(() => successResponse());\n if (!havingPermission.value) {\n throw missingPermissionError();\n }\n return navigator.mediaDevices\n .getUserMedia({ audio: true })\n .then((stream) => this.onSuccessfullyStartedRecording(stream, options))\n .catch(this.onFailedToStartRecording.bind(this));\n }\n /** Stops the current recording and resolves the pending payload. */\n async stopRecording() {\n if (this.mediaRecorder == null) {\n throw recordingHasNotStartedError();\n }\n try {\n this.mediaRecorder.stop();\n this.mediaRecorder.stream.getTracks().forEach((track) => track.stop());\n return this.pendingResult;\n }\n catch (ignore) {\n throw failedToFetchRecordingError();\n }\n finally {\n this.prepareInstanceForNextOperation();\n }\n }\n /** Returns whether the browser has microphone permission. */\n static async hasAudioRecordingPermission() {\n // Safari does not support navigator.permissions.query\n if (!navigator.permissions.query) {\n if (navigator.mediaDevices !== undefined) {\n return navigator.mediaDevices\n .getUserMedia({ audio: true })\n .then(() => successResponse())\n .catch(() => {\n throw couldNotQueryPermissionStatusError();\n });\n }\n }\n return navigator.permissions\n .query({ name: 'microphone' })\n .then((result) => ({ value: result.state === 'granted' }))\n .catch(() => {\n throw couldNotQueryPermissionStatusError();\n });\n }\n /** Requests microphone permission from the browser. */\n static async requestAudioRecordingPermission() {\n const havingPermission = await VoiceRecorderImpl.hasAudioRecordingPermission().catch(() => failureResponse());\n if (havingPermission.value) {\n return successResponse();\n }\n return navigator.mediaDevices\n .getUserMedia({ audio: true })\n .then(() => successResponse())\n .catch(() => failureResponse());\n }\n /** Pauses the recording session when supported. */\n pauseRecording() {\n if (this.mediaRecorder == null) {\n throw recordingHasNotStartedError();\n }\n else if (this.mediaRecorder.state === 'recording') {\n this.mediaRecorder.pause();\n return Promise.resolve(successResponse());\n }\n else {\n return Promise.resolve(failureResponse());\n }\n }\n /** Resumes a paused recording session when supported. */\n resumeRecording() {\n if (this.mediaRecorder == null) {\n throw recordingHasNotStartedError();\n }\n else if (this.mediaRecorder.state === 'paused') {\n this.mediaRecorder.resume();\n return Promise.resolve(successResponse());\n }\n else {\n return Promise.resolve(failureResponse());\n }\n }\n /** Returns the current recording status from MediaRecorder. */\n getCurrentStatus() {\n if (this.mediaRecorder == null) {\n return Promise.resolve({ status: 'NONE' });\n }\n else if (this.mediaRecorder.state === 'recording') {\n return Promise.resolve({ status: 'RECORDING' });\n }\n else if (this.mediaRecorder.state === 'paused') {\n return Promise.resolve({ status: 'PAUSED' });\n }\n else {\n return Promise.resolve({ status: 'NONE' });\n }\n }\n /** Returns the first supported MIME type, if any. */\n static getSupportedMimeType() {\n if ((MediaRecorder === null || MediaRecorder === void 0 ? void 0 : MediaRecorder.isTypeSupported) == null)\n return null;\n const foundSupportedType = Object.keys(POSSIBLE_MIME_TYPES).find((type) => MediaRecorder.isTypeSupported(type));\n return foundSupportedType !== null && foundSupportedType !== void 0 ? foundSupportedType : null;\n }\n /** Initializes MediaRecorder and wires up handlers. */\n onSuccessfullyStartedRecording(stream, options) {\n this.pendingResult = new Promise((resolve, reject) => {\n this.mediaRecorder = new MediaRecorder(stream);\n this.mediaRecorder.onerror = () => {\n this.prepareInstanceForNextOperation();\n reject(failedToRecordError());\n };\n this.mediaRecorder.onstop = async () => {\n var _a, _b, _c;\n const mimeType = VoiceRecorderImpl.getSupportedMimeType();\n if (mimeType == null) {\n this.prepareInstanceForNextOperation();\n reject(failedToFetchRecordingError());\n return;\n }\n const blobVoiceRecording = new Blob(this.chunks, { type: mimeType });\n if (blobVoiceRecording.size <= 0) {\n this.prepareInstanceForNextOperation();\n reject(emptyRecordingError());\n return;\n }\n let uri = undefined;\n let recordDataBase64 = '';\n if (options === null || options === void 0 ? void 0 : options.directory) {\n const subDirectory = (_c = (_b = (_a = options.subDirectory) === null || _a === void 0 ? void 0 : _a.match(/^\\/?(.+[^/])\\/?$/)) === null || _b === void 0 ? void 0 : _b[1]) !== null && _c !== void 0 ? _c : '';\n const path = `${subDirectory}/recording-${new Date().getTime()}${POSSIBLE_MIME_TYPES[mimeType]}`;\n await write_blob({\n blob: blobVoiceRecording,\n directory: options.directory,\n fast_mode: true,\n path,\n recursive: true,\n });\n ({ uri } = await Filesystem.getUri({ directory: options.directory, path }));\n }\n else {\n recordDataBase64 = await VoiceRecorderImpl.blobToBase64(blobVoiceRecording);\n }\n const recordingDuration = await getBlobDuration(blobVoiceRecording);\n this.prepareInstanceForNextOperation();\n resolve({ value: { recordDataBase64, mimeType, msDuration: recordingDuration * 1000, uri } });\n };\n this.mediaRecorder.ondataavailable = (event) => this.chunks.push(event.data);\n this.mediaRecorder.start();\n });\n return successResponse();\n }\n /** Handles failures from getUserMedia. */\n onFailedToStartRecording() {\n this.prepareInstanceForNextOperation();\n throw failedToRecordError();\n }\n /** Converts a Blob payload into a base64 string. */\n static blobToBase64(blob) {\n return new Promise((resolve) => {\n const reader = new FileReader();\n reader.onloadend = () => {\n const recordingResult = String(reader.result);\n const splitResult = recordingResult.split('base64,');\n const toResolve = splitResult.length > 1 ? splitResult[1] : recordingResult;\n resolve(toResolve.trim());\n };\n reader.readAsDataURL(blob);\n });\n }\n /** Resets state for the next recording attempt. */\n prepareInstanceForNextOperation() {\n if (this.mediaRecorder != null && this.mediaRecorder.state === 'recording') {\n try {\n this.mediaRecorder.stop();\n }\n catch (ignore) {\n console.warn('Failed to stop recording during cleanup');\n }\n }\n this.pendingResult = neverResolvingPromise();\n this.mediaRecorder = null;\n this.chunks = [];\n }\n}\n//# sourceMappingURL=VoiceRecorderImpl.js.map","import { VoiceRecorderImpl } from '../platform/web/VoiceRecorderImpl';\n/** Web adapter that delegates to the browser-specific implementation. */\nexport class VoiceRecorderWebAdapter {\n constructor() {\n /** Browser implementation that talks to MediaRecorder APIs. */\n this.voiceRecorderImpl = new VoiceRecorderImpl();\n }\n /** Checks whether the browser can record audio. */\n canDeviceVoiceRecord() {\n return VoiceRecorderImpl.canDeviceVoiceRecord();\n }\n /** Returns whether the browser has microphone permission. */\n hasAudioRecordingPermission() {\n return VoiceRecorderImpl.hasAudioRecordingPermission();\n }\n /** Requests microphone permission through the browser. */\n requestAudioRecordingPermission() {\n return VoiceRecorderImpl.requestAudioRecordingPermission();\n }\n /** Starts a recording session using MediaRecorder. */\n startRecording(options) {\n return this.voiceRecorderImpl.startRecording(options);\n }\n /** Stops the recording session and returns the payload. */\n stopRecording() {\n return this.voiceRecorderImpl.stopRecording();\n }\n /** Pauses the recording session when supported. */\n pauseRecording() {\n return this.voiceRecorderImpl.pauseRecording();\n }\n /** Resumes a paused recording session when supported. */\n resumeRecording() {\n return this.voiceRecorderImpl.resumeRecording();\n }\n /** Returns the current recording state. */\n getCurrentStatus() {\n return this.voiceRecorderImpl.getCurrentStatus();\n }\n}\n//# sourceMappingURL=VoiceRecorderWebAdapter.js.map","/** Default response shape when no config is provided. */\nexport const DEFAULT_RESPONSE_FORMAT = 'legacy';\n/** Parses a user-provided response format into a supported value. */\nexport const resolveResponseFormat = (value) => {\n if (typeof value === 'string' && value.toLowerCase() === 'normalized') {\n return 'normalized';\n }\n return DEFAULT_RESPONSE_FORMAT;\n};\n/** Reads the response format from a Capacitor plugin config object. */\nexport const getResponseFormatFromConfig = (config) => {\n if (config && typeof config === 'object' && 'responseFormat' in config) {\n return resolveResponseFormat(config.responseFormat);\n }\n return DEFAULT_RESPONSE_FORMAT;\n};\n//# sourceMappingURL=response-format.js.map","/** Maps legacy error messages to canonical error codes. */\nconst legacyToCanonical = {\n CANNOT_RECORD_ON_THIS_PHONE: 'DEVICE_CANNOT_VOICE_RECORD',\n};\n/** Normalizes legacy error messages into canonical error codes. */\nexport const toCanonicalErrorCode = (legacyMessage) => {\n var _a;\n return (_a = legacyToCanonical[legacyMessage]) !== null && _a !== void 0 ? _a : legacyMessage;\n};\n/** Adds a canonical `code` field to Error-like objects when possible. */\nexport const attachCanonicalErrorCode = (error) => {\n if (!error || typeof error !== 'object') {\n return;\n }\n const messageValue = error.message;\n if (typeof messageValue !== 'string') {\n return;\n }\n error.code = toCanonicalErrorCode(messageValue);\n};\n//# sourceMappingURL=error-codes.js.map","/** Normalizes recording payloads into a stable contract shape. */\nexport const normalizeRecordingData = (data) => {\n const { recordDataBase64, uri, msDuration, mimeType } = data.value;\n const normalizedValue = { msDuration, mimeType };\n const trimmedUri = typeof uri === 'string' && uri.length > 0 ? uri : undefined;\n const trimmedBase64 = typeof recordDataBase64 === 'string' && recordDataBase64.length > 0 ? recordDataBase64 : undefined;\n if (trimmedUri) {\n normalizedValue.uri = trimmedUri;\n }\n else if (trimmedBase64) {\n normalizedValue.recordDataBase64 = trimmedBase64;\n }\n return { value: normalizedValue };\n};\n//# sourceMappingURL=recording-contract.js.map","import { attachCanonicalErrorCode } from '../core/error-codes';\nimport { normalizeRecordingData } from '../core/recording-contract';\n/** Orchestrates platform calls and normalizes responses when requested. */\nexport class VoiceRecorderService {\n constructor(platform, responseFormat) {\n this.platform = platform;\n this.responseFormat = responseFormat;\n }\n /** Checks whether the device can record audio. */\n canDeviceVoiceRecord() {\n return this.execute(() => this.platform.canDeviceVoiceRecord());\n }\n /** Returns whether microphone permission is currently granted. */\n hasAudioRecordingPermission() {\n return this.execute(() => this.platform.hasAudioRecordingPermission());\n }\n /** Requests microphone permission from the user. */\n requestAudioRecordingPermission() {\n return this.execute(() => this.platform.requestAudioRecordingPermission());\n }\n /** Starts a recording session. */\n startRecording(options) {\n return this.execute(() => this.platform.startRecording(options));\n }\n /** Stops the recording session and formats the payload if needed. */\n async stopRecording() {\n return this.execute(async () => {\n const data = await this.platform.stopRecording();\n if (this.responseFormat === 'normalized') {\n return normalizeRecordingData(data);\n }\n return data;\n });\n }\n /** Pauses the recording session when supported. */\n pauseRecording() {\n return this.execute(() => this.platform.pauseRecording());\n }\n /** Resumes a paused recording session when supported. */\n resumeRecording() {\n return this.execute(() => this.platform.resumeRecording());\n }\n /** Returns the current recording state. */\n getCurrentStatus() {\n return this.execute(() => this.platform.getCurrentStatus());\n }\n /** Wraps calls to apply canonical error codes when requested. */\n async execute(fn) {\n try {\n return await fn();\n }\n catch (error) {\n if (this.responseFormat === 'normalized') {\n attachCanonicalErrorCode(error);\n }\n throw error;\n }\n }\n}\n//# sourceMappingURL=VoiceRecorderService.js.map","import { Capacitor, WebPlugin } from '@capacitor/core';\nimport { VoiceRecorderWebAdapter } from './adapters/VoiceRecorderWebAdapter';\nimport { getResponseFormatFromConfig } from './core/response-format';\nimport { VoiceRecorderService } from './service/VoiceRecorderService';\n/** Web implementation of the VoiceRecorder Capacitor plugin. */\nexport class VoiceRecorderWeb extends WebPlugin {\n constructor() {\n var _a, _b;\n super();\n const pluginConfig = (_b = (_a = Capacitor === null || Capacitor === void 0 ? void 0 : Capacitor.config) === null || _a === void 0 ? void 0 : _a.plugins) === null || _b === void 0 ? void 0 : _b.VoiceRecorder;\n const responseFormat = getResponseFormatFromConfig(pluginConfig);\n this.service = new VoiceRecorderService(new VoiceRecorderWebAdapter(), responseFormat);\n }\n /** Checks whether the browser can record audio. */\n canDeviceVoiceRecord() {\n return this.service.canDeviceVoiceRecord();\n }\n /** Returns whether microphone permission is currently granted. */\n hasAudioRecordingPermission() {\n return this.service.hasAudioRecordingPermission();\n }\n /** Requests microphone permission from the user. */\n requestAudioRecordingPermission() {\n return this.service.requestAudioRecordingPermission();\n }\n /** Starts a recording session. */\n startRecording(options) {\n return this.service.startRecording(options);\n }\n /** Stops the current recording session and returns the payload. */\n stopRecording() {\n return this.service.stopRecording();\n }\n /** Pauses the recording session when supported. */\n pauseRecording() {\n return this.service.pauseRecording();\n }\n /** Resumes a paused recording session when supported. */\n resumeRecording() {\n return this.service.resumeRecording();\n }\n /** Returns the current recording state. */\n getCurrentStatus() {\n return this.service.getCurrentStatus();\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","Filesystem","WebPlugin","Capacitor"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/platform/web/get-blob-duration.js","esm/platform/web/predefined-web-responses.js","esm/platform/web/VoiceRecorderImpl.js","esm/adapters/VoiceRecorderWebAdapter.js","esm/core/response-format.js","esm/core/error-codes.js","esm/core/recording-contract.js","esm/service/VoiceRecorderService.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst VoiceRecorder = registerPlugin('VoiceRecorder', {\n web: () => import('./web').then((m) => new m.VoiceRecorderWeb()),\n});\nexport * from './definitions';\nexport { VoiceRecorder };\n//# sourceMappingURL=index.js.map","/**\n * @param {Blob | string} blob\n * @returns {Promise<number>} Blob duration in seconds.\n */\nexport default async function getBlobDuration(blob) {\n // Check for AudioContext or webkitAudioContext (Safari)\n const AudioCtx = window.AudioContext || window.webkitAudioContext;\n if (!AudioCtx) {\n throw new Error('AudioContext is not supported in this environment.');\n }\n let audioContext = null;\n try {\n audioContext = new AudioCtx();\n let arrayBuffer;\n if (typeof blob === 'string') {\n arrayBuffer = base64ToArrayBuffer(blob);\n }\n else {\n arrayBuffer = await blob.arrayBuffer();\n }\n const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);\n return audioBuffer.duration;\n }\n catch (err) {\n throw new Error('Failed to get audio duration (AudioContext may require user interaction or is not supported): ' + (err instanceof Error ? err.message : String(err)));\n }\n finally {\n if (audioContext) {\n await audioContext.close();\n }\n }\n}\n/**\n * Convert base64 string to ArrayBuffer.\n * @param base64 The base64 string to convert.\n * @returns The converted ArrayBuffer.\n * @remarks This function is exported for test coverage purposes.\n */\nexport function base64ToArrayBuffer(base64) {\n const cleanBase64 = base64.replace(/^data:[^;]+;base64,/, '');\n const binaryString = atob(cleanBase64);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes.buffer;\n}\n//# sourceMappingURL=get-blob-duration.js.map","/** Success wrapper for boolean plugin responses. */\nexport const successResponse = () => ({ value: true });\n/** Failure wrapper for boolean plugin responses. */\nexport const failureResponse = () => ({ value: false });\n/** Error for missing microphone permission. */\nexport const missingPermissionError = () => new Error('MISSING_PERMISSION');\n/** Error for attempting to start while already recording. */\nexport const alreadyRecordingError = () => new Error('ALREADY_RECORDING');\n/** Error for microphone in use by another app or recorder. */\nexport const microphoneBeingUsedError = () => new Error('MICROPHONE_BEING_USED');\n/** Error for devices that cannot record audio. */\nexport const deviceCannotVoiceRecordError = () => new Error('DEVICE_CANNOT_VOICE_RECORD');\n/** Error for recorder start failures. */\nexport const failedToRecordError = () => new Error('FAILED_TO_RECORD');\n/** Error for empty or zero-length recordings. */\nexport const emptyRecordingError = () => new Error('EMPTY_RECORDING');\n/** Error for stopping without an active recording. */\nexport const recordingHasNotStartedError = () => new Error('RECORDING_HAS_NOT_STARTED');\n/** Error for failures when fetching recording data. */\nexport const failedToFetchRecordingError = () => new Error('FAILED_TO_FETCH_RECORDING');\n/** Error for browsers that do not support permission queries. */\nexport const couldNotQueryPermissionStatusError = () => new Error('COULD_NOT_QUERY_PERMISSION_STATUS');\n//# sourceMappingURL=predefined-web-responses.js.map","import { Filesystem } from '@capacitor/filesystem';\nimport write_blob from 'capacitor-blob-writer';\nimport getBlobDuration from './get-blob-duration';\nimport { alreadyRecordingError, couldNotQueryPermissionStatusError, deviceCannotVoiceRecordError, emptyRecordingError, failedToFetchRecordingError, failedToRecordError, failureResponse, missingPermissionError, recordingHasNotStartedError, successResponse, } from './predefined-web-responses';\n/**\n * Ordered MIME types to probe for audio recording via `MediaRecorder.isTypeSupported()`.\n *\n * ⚠️ The order is intentional and MUST remain stable unless you also update the\n * selection policy in code and test on Safari/iOS + WebViews.\n *\n * ✅ What this list is used for\n * - Selecting a `mimeType` for `new MediaRecorder(stream, { mimeType })`.\n *\n * ❌ What this list does NOT guarantee\n * - It does NOT guarantee that the recorded output will be playable via the\n * HTML `<audio>` element in the same browser.\n *\n * Real-world caveat (important):\n * - We have observed cases where `MediaRecorder.isTypeSupported('audio/webm;codecs=opus')`\n * returned `true`, the recorder produced a Blob, but `<audio>` could not play it.\n * This can happen due to container/codec playback support differences, platform\n * quirks (especially Safari/iOS / WKWebView), or incomplete WebM playback support.\n *\n * Current selection behavior in this implementation:\n * - By default, MIME selection treats recorder support and playback support as separate\n * capabilities and probes both:\n * - Recorder capability: `MediaRecorder.isTypeSupported(type)`\n * - Playback capability: `audio.canPlayType(type)`\n * - This default can be disabled via `RecordingOptions.requirePlaybackSupport = false`\n * to fall back to recorder-only probing.\n *\n * Keeping legacy keys:\n * - Some entries are kept even if they overlap (e.g. `audio/mp4` and explicit codec),\n * to maximize compatibility across differing browser implementations.\n */\nconst POSSIBLE_MIME_TYPES = {\n // ✅ Most universal\n 'audio/mp4;codecs=\"mp4a.40.2\"': '.m4a', // AAC in MP4 (explicit codec helps detection)\n 'audio/mp4': '.m4a', // (legacy key kept; broad support)\n 'audio/aac': '.aac', // (legacy key kept; less common in the wild)\n 'audio/mpeg': '.mp3', // MP3 (universal)\n 'audio/wav': '.wav', // WAV (universal, big files)\n // ✅ Modern high-quality (very widely supported, but slightly less “universal” than MP3/AAC)\n 'audio/webm;codecs=\"opus\"': '.webm', // Opus in WebM (explicit codec helps detection)\n 'audio/webm;codecs=opus': '.webm', // (legacy key kept)\n 'audio/webm': '.webm', // (legacy key kept; container-only, codec-dependent)\n // ⚠️ Least universal (Safari/iOS historically the limiting factor)\n 'audio/ogg;codecs=opus': '.ogg', // (legacy key kept)\n 'audio/ogg;codecs=vorbis': '.ogg', // Ogg Vorbis (weakest mainstream support)\n};\n/** Creates a promise that never resolves. */\nconst neverResolvingPromise = () => new Promise(() => undefined);\n/** Browser implementation backed by MediaRecorder and Capacitor Filesystem. */\nexport class VoiceRecorderImpl {\n constructor() {\n /** Active MediaRecorder instance, if recording. */\n this.mediaRecorder = null;\n /** Collected data chunks from MediaRecorder. */\n this.chunks = [];\n /** Promise resolved when the recorder stops and payload is ready. */\n this.pendingResult = neverResolvingPromise();\n }\n /**\n * Returns whether the browser can start a recording session.\n *\n * On web this checks:\n * - `navigator.mediaDevices.getUserMedia`\n * - at least one supported recording MIME type using {@link getSupportedMimeType}\n *\n * The optional `requirePlaybackSupport` flag is forwarded to MIME selection and defaults\n * to `true` when omitted.\n */\n static async canDeviceVoiceRecord(options) {\n var _a;\n if (((_a = navigator === null || navigator === void 0 ? void 0 : navigator.mediaDevices) === null || _a === void 0 ? void 0 : _a.getUserMedia) == null ||\n VoiceRecorderImpl.getSupportedMimeType({\n requirePlaybackSupport: options === null || options === void 0 ? void 0 : options.requirePlaybackSupport,\n }) == null) {\n return failureResponse();\n }\n else {\n return successResponse();\n }\n }\n /**\n * Starts a recording session using `MediaRecorder`.\n *\n * The selected MIME type is resolved once at start time (using the optional\n * `requirePlaybackSupport` flag from `RecordingOptions`) and reused for the final Blob\n * and file extension to keep the recording payload internally consistent.\n */\n async startRecording(options) {\n if (this.mediaRecorder != null) {\n throw alreadyRecordingError();\n }\n const deviceCanRecord = await VoiceRecorderImpl.canDeviceVoiceRecord(options);\n if (!deviceCanRecord.value) {\n throw deviceCannotVoiceRecordError();\n }\n const havingPermission = await VoiceRecorderImpl.hasAudioRecordingPermission().catch(() => successResponse());\n if (!havingPermission.value) {\n throw missingPermissionError();\n }\n return navigator.mediaDevices\n .getUserMedia({ audio: true })\n .then((stream) => this.onSuccessfullyStartedRecording(stream, options))\n .catch(this.onFailedToStartRecording.bind(this));\n }\n /** Stops the current recording and resolves the pending payload. */\n async stopRecording() {\n if (this.mediaRecorder == null) {\n throw recordingHasNotStartedError();\n }\n try {\n this.mediaRecorder.stop();\n this.mediaRecorder.stream.getTracks().forEach((track) => track.stop());\n return this.pendingResult;\n }\n catch (ignore) {\n throw failedToFetchRecordingError();\n }\n finally {\n this.prepareInstanceForNextOperation();\n }\n }\n /** Returns whether the browser has microphone permission. */\n static async hasAudioRecordingPermission() {\n // Safari does not support navigator.permissions.query\n if (!navigator.permissions.query) {\n if (navigator.mediaDevices !== undefined) {\n return navigator.mediaDevices\n .getUserMedia({ audio: true })\n .then(() => successResponse())\n .catch(() => {\n throw couldNotQueryPermissionStatusError();\n });\n }\n }\n return navigator.permissions\n .query({ name: 'microphone' })\n .then((result) => ({ value: result.state === 'granted' }))\n .catch(() => {\n throw couldNotQueryPermissionStatusError();\n });\n }\n /** Requests microphone permission from the browser. */\n static async requestAudioRecordingPermission() {\n const havingPermission = await VoiceRecorderImpl.hasAudioRecordingPermission().catch(() => failureResponse());\n if (havingPermission.value) {\n return successResponse();\n }\n return navigator.mediaDevices\n .getUserMedia({ audio: true })\n .then(() => successResponse())\n .catch(() => failureResponse());\n }\n /** Pauses the recording session when supported. */\n pauseRecording() {\n if (this.mediaRecorder == null) {\n throw recordingHasNotStartedError();\n }\n else if (this.mediaRecorder.state === 'recording') {\n this.mediaRecorder.pause();\n return Promise.resolve(successResponse());\n }\n else {\n return Promise.resolve(failureResponse());\n }\n }\n /** Resumes a paused recording session when supported. */\n resumeRecording() {\n if (this.mediaRecorder == null) {\n throw recordingHasNotStartedError();\n }\n else if (this.mediaRecorder.state === 'paused') {\n this.mediaRecorder.resume();\n return Promise.resolve(successResponse());\n }\n else {\n return Promise.resolve(failureResponse());\n }\n }\n /** Returns the current recording status from MediaRecorder. */\n getCurrentStatus() {\n if (this.mediaRecorder == null) {\n return Promise.resolve({ status: 'NONE' });\n }\n else if (this.mediaRecorder.state === 'recording') {\n return Promise.resolve({ status: 'RECORDING' });\n }\n else if (this.mediaRecorder.state === 'paused') {\n return Promise.resolve({ status: 'PAUSED' });\n }\n else {\n return Promise.resolve({ status: 'NONE' });\n }\n }\n /**\n * Returns the first MIME type (key of {@link POSSIBLE_MIME_TYPES}) that the current\n * environment reports as supported for recording via `MediaRecorder.isTypeSupported()`,\n * optionally requiring native HTML `<audio>` playback support too.\n *\n * The search order is the iteration order of {@link POSSIBLE_MIME_TYPES}.\n *\n * @typeParam T - A MIME type string that exists as a key in {@link POSSIBLE_MIME_TYPES}.\n *\n * @returns The first supported MIME type for `MediaRecorder`, or `null` if:\n * - `MediaRecorder` is unavailable, or\n * - no configured MIME types are supported.\n *\n * ⚠️ Important: `MediaRecorder` support ≠ `<audio>` playback support\n *\n * Some browsers/platforms can claim support for recording a format (notably WebM/Opus)\n * but still fail to play the resulting Blob through the native HTML audio pipeline.\n * This mismatch is especially likely on Safari/iOS / WKWebView variants, so the default\n * behavior also probes `HTMLAudioElement.canPlayType(type)` when available.\n *\n * Selection policy when playback probing is enabled:\n * - keep the global priority order from {@link POSSIBLE_MIME_TYPES}\n * - among recordable types, prefer the first `\"probably\"` playable candidate\n * - otherwise return the first `\"maybe\"` playable candidate\n * - treat `\"\"` as not playable\n *\n * Note: The <audio> element is never attached to the DOM, so it won't appear to users or assistive tech.\n *\n * Fallback behavior:\n * - If `document` / `audio.canPlayType` is unavailable (e.g. SSR-like environments),\n * this falls back to record-only probing.\n */\n static getSupportedMimeType(options) {\n var _a, _b, _c, _d, _e;\n if ((MediaRecorder === null || MediaRecorder === void 0 ? void 0 : MediaRecorder.isTypeSupported) == null)\n return null;\n const orderedTypes = Object.keys(POSSIBLE_MIME_TYPES);\n const recordSupportedTypes = orderedTypes.filter((type) => MediaRecorder.isTypeSupported(type));\n if (recordSupportedTypes.length === 0)\n return null;\n const requirePlaybackSupport = (_a = options === null || options === void 0 ? void 0 : options.requirePlaybackSupport) !== null && _a !== void 0 ? _a : VoiceRecorderImpl.DEFAULT_REQUIRE_PLAYBACK_SUPPORT;\n if (!requirePlaybackSupport) {\n return (_b = recordSupportedTypes[0]) !== null && _b !== void 0 ? _b : null;\n }\n if (typeof document === 'undefined' || typeof document.createElement !== 'function') {\n return (_c = recordSupportedTypes[0]) !== null && _c !== void 0 ? _c : null;\n }\n const audioElement = document.createElement('audio');\n if (typeof audioElement.canPlayType !== 'function') {\n return (_d = recordSupportedTypes[0]) !== null && _d !== void 0 ? _d : null;\n }\n let firstProbably = null;\n let firstMaybe = null;\n for (const type of recordSupportedTypes) {\n const playbackSupport = audioElement.canPlayType(type);\n if (playbackSupport === 'probably') {\n firstProbably = type;\n break;\n }\n if (playbackSupport === 'maybe' && firstMaybe == null) {\n firstMaybe = type;\n }\n }\n return (_e = firstProbably !== null && firstProbably !== void 0 ? firstProbably : firstMaybe) !== null && _e !== void 0 ? _e : null;\n }\n /** Initializes MediaRecorder and wires up handlers. */\n onSuccessfullyStartedRecording(stream, options) {\n this.pendingResult = new Promise((resolve, reject) => {\n const mimeType = VoiceRecorderImpl.getSupportedMimeType({\n requirePlaybackSupport: options === null || options === void 0 ? void 0 : options.requirePlaybackSupport,\n });\n if (mimeType == null) {\n this.prepareInstanceForNextOperation();\n reject(failedToRecordError());\n return;\n }\n this.mediaRecorder = new MediaRecorder(stream, { mimeType });\n this.mediaRecorder.onerror = () => {\n this.prepareInstanceForNextOperation();\n reject(failedToRecordError());\n };\n this.mediaRecorder.onstop = async () => {\n var _a, _b, _c, _d, _e;\n const mt = (_b = (_a = this.mediaRecorder) === null || _a === void 0 ? void 0 : _a.mimeType) !== null && _b !== void 0 ? _b : mimeType;\n const blobVoiceRecording = new Blob(this.chunks, { type: mt });\n if (blobVoiceRecording.size <= 0) {\n this.prepareInstanceForNextOperation();\n reject(emptyRecordingError());\n return;\n }\n let uri = undefined;\n let recordDataBase64 = '';\n if (options === null || options === void 0 ? void 0 : options.directory) {\n const subDirectory = (_e = (_d = (_c = options.subDirectory) === null || _c === void 0 ? void 0 : _c.match(/^\\/?(.+[^/])\\/?$/)) === null || _d === void 0 ? void 0 : _d[1]) !== null && _e !== void 0 ? _e : '';\n const path = `${subDirectory}/recording-${new Date().getTime()}${POSSIBLE_MIME_TYPES[mt]}`;\n await write_blob({\n blob: blobVoiceRecording,\n directory: options.directory,\n fast_mode: true,\n path,\n recursive: true,\n });\n ({ uri } = await Filesystem.getUri({ directory: options.directory, path }));\n }\n else {\n recordDataBase64 = await VoiceRecorderImpl.blobToBase64(blobVoiceRecording);\n }\n const recordingDuration = await getBlobDuration(blobVoiceRecording);\n this.prepareInstanceForNextOperation();\n resolve({\n value: {\n recordDataBase64,\n mimeType: mt,\n msDuration: recordingDuration * 1000,\n uri\n }\n });\n };\n this.mediaRecorder.ondataavailable = (event) => this.chunks.push(event.data);\n this.mediaRecorder.start();\n });\n return successResponse();\n }\n /** Handles failures from getUserMedia. */\n onFailedToStartRecording() {\n this.prepareInstanceForNextOperation();\n throw failedToRecordError();\n }\n /** Converts a Blob payload into a base64 string. */\n static blobToBase64(blob) {\n return new Promise((resolve) => {\n const reader = new FileReader();\n reader.onloadend = () => {\n const recordingResult = String(reader.result);\n const splitResult = recordingResult.split('base64,');\n const toResolve = splitResult.length > 1 ? splitResult[1] : recordingResult;\n resolve(toResolve.trim());\n };\n reader.readAsDataURL(blob);\n });\n }\n /** Resets state for the next recording attempt. */\n prepareInstanceForNextOperation() {\n if (this.mediaRecorder != null && this.mediaRecorder.state === 'recording') {\n try {\n this.mediaRecorder.stop();\n }\n catch (ignore) {\n console.warn('Failed to stop recording during cleanup');\n }\n }\n this.pendingResult = neverResolvingPromise();\n this.mediaRecorder = null;\n this.chunks = [];\n }\n}\n/** Default behavior for web MIME selection: require recorder + playback support. */\nVoiceRecorderImpl.DEFAULT_REQUIRE_PLAYBACK_SUPPORT = true;\n//# sourceMappingURL=VoiceRecorderImpl.js.map","import { VoiceRecorderImpl } from '../platform/web/VoiceRecorderImpl';\n/** Web adapter that delegates to the browser-specific implementation. */\nexport class VoiceRecorderWebAdapter {\n constructor() {\n /** Browser implementation that talks to MediaRecorder APIs. */\n this.voiceRecorderImpl = new VoiceRecorderImpl();\n }\n /** Checks whether the browser can record audio. */\n canDeviceVoiceRecord() {\n return VoiceRecorderImpl.canDeviceVoiceRecord();\n }\n /** Returns whether the browser has microphone permission. */\n hasAudioRecordingPermission() {\n return VoiceRecorderImpl.hasAudioRecordingPermission();\n }\n /** Requests microphone permission through the browser. */\n requestAudioRecordingPermission() {\n return VoiceRecorderImpl.requestAudioRecordingPermission();\n }\n /** Starts a recording session using MediaRecorder. */\n startRecording(options) {\n return this.voiceRecorderImpl.startRecording(options);\n }\n /** Stops the recording session and returns the payload. */\n stopRecording() {\n return this.voiceRecorderImpl.stopRecording();\n }\n /** Pauses the recording session when supported. */\n pauseRecording() {\n return this.voiceRecorderImpl.pauseRecording();\n }\n /** Resumes a paused recording session when supported. */\n resumeRecording() {\n return this.voiceRecorderImpl.resumeRecording();\n }\n /** Returns the current recording state. */\n getCurrentStatus() {\n return this.voiceRecorderImpl.getCurrentStatus();\n }\n}\n//# sourceMappingURL=VoiceRecorderWebAdapter.js.map","/** Default response shape when no config is provided. */\nexport const DEFAULT_RESPONSE_FORMAT = 'legacy';\n/** Parses a user-provided response format into a supported value. */\nexport const resolveResponseFormat = (value) => {\n if (typeof value === 'string' && value.toLowerCase() === 'normalized') {\n return 'normalized';\n }\n return DEFAULT_RESPONSE_FORMAT;\n};\n/** Reads the response format from a Capacitor plugin config object. */\nexport const getResponseFormatFromConfig = (config) => {\n if (config && typeof config === 'object' && 'responseFormat' in config) {\n return resolveResponseFormat(config.responseFormat);\n }\n return DEFAULT_RESPONSE_FORMAT;\n};\n//# sourceMappingURL=response-format.js.map","/** Maps legacy error messages to canonical error codes. */\nconst legacyToCanonical = {\n CANNOT_RECORD_ON_THIS_PHONE: 'DEVICE_CANNOT_VOICE_RECORD',\n};\n/** Normalizes legacy error messages into canonical error codes. */\nexport const toCanonicalErrorCode = (legacyMessage) => {\n var _a;\n return (_a = legacyToCanonical[legacyMessage]) !== null && _a !== void 0 ? _a : legacyMessage;\n};\n/** Adds a canonical `code` field to Error-like objects when possible. */\nexport const attachCanonicalErrorCode = (error) => {\n if (!error || typeof error !== 'object') {\n return;\n }\n const messageValue = error.message;\n if (typeof messageValue !== 'string') {\n return;\n }\n error.code = toCanonicalErrorCode(messageValue);\n};\n//# sourceMappingURL=error-codes.js.map","/** Normalizes recording payloads into a stable contract shape. */\nexport const normalizeRecordingData = (data) => {\n const { recordDataBase64, uri, msDuration, mimeType } = data.value;\n const normalizedValue = { msDuration, mimeType };\n const trimmedUri = typeof uri === 'string' && uri.length > 0 ? uri : undefined;\n const trimmedBase64 = typeof recordDataBase64 === 'string' && recordDataBase64.length > 0 ? recordDataBase64 : undefined;\n if (trimmedUri) {\n normalizedValue.uri = trimmedUri;\n }\n else if (trimmedBase64) {\n normalizedValue.recordDataBase64 = trimmedBase64;\n }\n return { value: normalizedValue };\n};\n//# sourceMappingURL=recording-contract.js.map","import { attachCanonicalErrorCode } from '../core/error-codes';\nimport { normalizeRecordingData } from '../core/recording-contract';\n/** Orchestrates platform calls and normalizes responses when requested. */\nexport class VoiceRecorderService {\n constructor(platform, responseFormat) {\n this.platform = platform;\n this.responseFormat = responseFormat;\n }\n /** Checks whether the device can record audio. */\n canDeviceVoiceRecord() {\n return this.execute(() => this.platform.canDeviceVoiceRecord());\n }\n /** Returns whether microphone permission is currently granted. */\n hasAudioRecordingPermission() {\n return this.execute(() => this.platform.hasAudioRecordingPermission());\n }\n /** Requests microphone permission from the user. */\n requestAudioRecordingPermission() {\n return this.execute(() => this.platform.requestAudioRecordingPermission());\n }\n /** Starts a recording session. */\n startRecording(options) {\n return this.execute(() => this.platform.startRecording(options));\n }\n /** Stops the recording session and formats the payload if needed. */\n async stopRecording() {\n return this.execute(async () => {\n const data = await this.platform.stopRecording();\n if (this.responseFormat === 'normalized') {\n return normalizeRecordingData(data);\n }\n return data;\n });\n }\n /** Pauses the recording session when supported. */\n pauseRecording() {\n return this.execute(() => this.platform.pauseRecording());\n }\n /** Resumes a paused recording session when supported. */\n resumeRecording() {\n return this.execute(() => this.platform.resumeRecording());\n }\n /** Returns the current recording state. */\n getCurrentStatus() {\n return this.execute(() => this.platform.getCurrentStatus());\n }\n /** Wraps calls to apply canonical error codes when requested. */\n async execute(fn) {\n try {\n return await fn();\n }\n catch (error) {\n if (this.responseFormat === 'normalized') {\n attachCanonicalErrorCode(error);\n }\n throw error;\n }\n }\n}\n//# sourceMappingURL=VoiceRecorderService.js.map","import { Capacitor, WebPlugin } from '@capacitor/core';\nimport { VoiceRecorderWebAdapter } from './adapters/VoiceRecorderWebAdapter';\nimport { getResponseFormatFromConfig } from './core/response-format';\nimport { VoiceRecorderService } from './service/VoiceRecorderService';\n/** Web implementation of the VoiceRecorder Capacitor plugin. */\nexport class VoiceRecorderWeb extends WebPlugin {\n constructor() {\n var _a, _b;\n super();\n const pluginConfig = (_b = (_a = Capacitor === null || Capacitor === void 0 ? void 0 : Capacitor.config) === null || _a === void 0 ? void 0 : _a.plugins) === null || _b === void 0 ? void 0 : _b.VoiceRecorder;\n const responseFormat = getResponseFormatFromConfig(pluginConfig);\n this.service = new VoiceRecorderService(new VoiceRecorderWebAdapter(), responseFormat);\n }\n /** Checks whether the browser can record audio. */\n canDeviceVoiceRecord() {\n return this.service.canDeviceVoiceRecord();\n }\n /** Returns whether microphone permission is currently granted. */\n hasAudioRecordingPermission() {\n return this.service.hasAudioRecordingPermission();\n }\n /** Requests microphone permission from the user. */\n requestAudioRecordingPermission() {\n return this.service.requestAudioRecordingPermission();\n }\n /** Starts a recording session. */\n startRecording(options) {\n return this.service.startRecording(options);\n }\n /** Stops the current recording session and returns the payload. */\n stopRecording() {\n return this.service.stopRecording();\n }\n /** Pauses the recording session when supported. */\n pauseRecording() {\n return this.service.pauseRecording();\n }\n /** Resumes a paused recording session when supported. */\n resumeRecording() {\n return this.service.resumeRecording();\n }\n /** Returns the current recording state. */\n getCurrentStatus() {\n return this.service.getCurrentStatus();\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","Filesystem","WebPlugin","Capacitor"],"mappings":"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"}
@@ -1,6 +1,8 @@
1
1
  import Foundation
2
2
  import AVFoundation
3
3
 
4
+ private let m4aFileExtension = "m4a"
5
+
4
6
  protocol AudioSessionProtocol: AnyObject {
5
7
  var category: AVAudioSession.Category { get }
6
8
  func setCategory(_ category: AVAudioSession.Category) throws
@@ -95,7 +97,9 @@ class CustomMediaRecorder: RecorderAdapter {
95
97
  originalRecordingSessionCategory = recordingSession.category
96
98
  try recordingSession.setCategory(AVAudioSession.Category.playAndRecord)
97
99
  try recordingSession.setActive(true, options: [])
98
- baseAudioFilePath = getDirectoryToSaveAudioFile().appendingPathComponent("recording-\(Int(Date().timeIntervalSince1970 * 1000)).aac")
100
+ baseAudioFilePath = getDirectoryToSaveAudioFile().appendingPathComponent(
101
+ "recording-\(Int(Date().timeIntervalSince1970 * 1000)).\(m4aFileExtension)"
102
+ )
99
103
  audioFileSegments = [baseAudioFilePath]
100
104
  audioRecorder = try audioRecorderFactory(baseAudioFilePath, settings)
101
105
  setupInterruptionHandling()
@@ -187,7 +191,9 @@ class CustomMediaRecorder: RecorderAdapter {
187
191
  let directory = getDirectoryToSaveAudioFile()
188
192
  let timestamp = Int(Date().timeIntervalSince1970 * 1000)
189
193
  let segmentNumber = audioFileSegments.count
190
- let segmentPath = directory.appendingPathComponent("recording-\(timestamp)-segment-\(segmentNumber).aac")
194
+ let segmentPath = directory.appendingPathComponent(
195
+ "recording-\(timestamp)-segment-\(segmentNumber).\(m4aFileExtension)"
196
+ )
191
197
  audioRecorder = try audioRecorderFactory(segmentPath, settings)
192
198
  audioFileSegments.append(segmentPath)
193
199
  }
@@ -263,7 +269,7 @@ class CustomMediaRecorder: RecorderAdapter {
263
269
  }
264
270
 
265
271
  let basePathWithoutExtension = baseAudioFilePath.deletingPathExtension()
266
- let mergedFilePath = basePathWithoutExtension.appendingPathExtension("m4a")
272
+ let mergedFilePath = basePathWithoutExtension.appendingPathExtension(m4aFileExtension)
267
273
  let segmentURLs = audioFileSegments
268
274
  let keys = ["tracks", "duration"]
269
275
  let dispatchGroup = DispatchGroup()
@@ -348,7 +354,9 @@ class CustomMediaRecorder: RecorderAdapter {
348
354
  }
349
355
 
350
356
  let tempDirectory = self.getDirectoryToSaveAudioFile()
351
- let tempPath = tempDirectory.appendingPathComponent("temp-merged-\(Int(Date().timeIntervalSince1970 * 1000)).m4a")
357
+ let tempPath = tempDirectory.appendingPathComponent(
358
+ "temp-merged-\(Int(Date().timeIntervalSince1970 * 1000)).\(m4aFileExtension)"
359
+ )
352
360
 
353
361
  exportSession.outputURL = tempPath
354
362
  exportSession.outputFileType = .m4a
@@ -1,5 +1,9 @@
1
1
  import Foundation
2
2
 
3
+ private let m4aFileExtension = "m4a"
4
+ private let mp4AudioMimeType = "audio/mp4"
5
+ private let aacAudioMimeType = "audio/aac"
6
+
3
7
  /// Service layer that orchestrates recording operations.
4
8
  final class VoiceRecorderService {
5
9
  /// Platform adapter for device and file operations.
@@ -82,7 +86,7 @@ final class VoiceRecorderService {
82
86
 
83
87
  let audioFileUrl = recorder.getOutputFile()
84
88
  let fileExtension = audioFileUrl.pathExtension.lowercased()
85
- let mimeType = fileExtension == "m4a" ? "audio/mp4" : "audio/aac"
89
+ let mimeType = fileExtension == m4aFileExtension ? mp4AudioMimeType : aacAudioMimeType
86
90
  let sendDataAsBase64 = recorder.options?.directory == nil
87
91
  let recordDataBase64 = sendDataAsBase64 ? self.platform.readFileAsBase64(audioFileUrl) : nil
88
92
  let uri = sendDataAsBase64 ? nil : audioFileUrl.path
package/package.json CHANGED
@@ -13,31 +13,32 @@
13
13
  "url": "https://github.com/independo-gmbh/capacitor-voice-recorder.git"
14
14
  },
15
15
  "description": "Capacitor plugin for voice recording",
16
- "version": "8.1.8",
16
+ "version": "8.1.9-dev.2",
17
+ "packageManager": "pnpm@10.30.2",
17
18
  "devDependencies": {
18
- "@capacitor/android": "^8.0.2",
19
- "@capacitor/core": "^8.0.2",
20
- "@capacitor/ios": "^8.0.2",
21
- "conventional-changelog-conventionalcommits": "^9.1.0",
22
- "jest-environment-jsdom": "^30.2.0",
23
- "jest": "^30.2.0",
24
- "rollup": "^4.56.0",
25
- "eslint": "^8.57.0",
26
- "@semantic-release/git": "^10.0.1",
19
+ "@capacitor/android": "catalog:",
20
+ "@capacitor/core": "catalog:",
21
+ "@capacitor/docgen": "catalog:",
22
+ "@capacitor/ios": "catalog:",
23
+ "@ionic/eslint-config": "^0.4.0",
24
+ "@ionic/prettier-config": "^4.0.0",
27
25
  "@ionic/swiftlint-config": "^2.0.0",
28
- "swiftlint": "^2.0.0",
29
- "@typescript-eslint/parser": "^5.62.0",
30
- "typescript": "^5.9.3",
31
- "@semantic-release/changelog": "^6.0.3",
32
- "@types/node": "^25.0.10",
33
26
  "@saithodev/semantic-release-backmerge": "^4.0.1",
34
- "@capacitor/docgen": "^0.3.1",
35
- "semantic-release": "^25.0.2",
36
- "@typescript-eslint/eslint-plugin": "^5.62.0",
27
+ "@semantic-release/changelog": "^6.0.3",
28
+ "@semantic-release/git": "^10.0.1",
37
29
  "@types/jest": "^30.0.0",
38
- "@ionic/prettier-config": "^4.0.0",
39
- "@ionic/eslint-config": "^0.4.0",
40
- "ts-jest": "^29.4.6"
30
+ "@types/node": "^25.3.0",
31
+ "@typescript-eslint/eslint-plugin": "^5.62.0",
32
+ "@typescript-eslint/parser": "^5.62.0",
33
+ "conventional-changelog-conventionalcommits": "^9.1.0",
34
+ "eslint": "^8.57.1",
35
+ "jest": "^30.2.0",
36
+ "jest-environment-jsdom": "^30.2.0",
37
+ "rollup": "^4.59.0",
38
+ "semantic-release": "^25.0.3",
39
+ "swiftlint": "^2.0.0",
40
+ "ts-jest": "^29.4.6",
41
+ "typescript": "^5.9.3"
41
42
  },
42
43
  "main": "dist/plugin.cjs.js",
43
44
  "files": [
@@ -54,16 +55,16 @@
54
55
  "url": "https://github.com/independo-gmbh/capacitor-voice-recorder/issues"
55
56
  },
56
57
  "scripts": {
57
- "upgrade": "npx npm-check-updates -u",
58
- "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
59
- "lint": "npm run eslint",
60
- "prepublishOnly": "npm run build",
61
- "verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
58
+ "upgrade": "pnpm dlx npm-check-updates -u",
59
+ "build": "pnpm run clean && pnpm run docgen && tsc && rollup -c rollup.config.mjs",
60
+ "lint": "pnpm run eslint",
61
+ "prepublishOnly": "pnpm run build",
62
+ "verify": "pnpm run verify:ios && pnpm run verify:android && pnpm run verify:web",
62
63
  "verify:android": "node scripts/verify-android.js",
63
64
  "verify:ios": "xcodebuild -scheme IndependoCapacitorVoiceRecorder -destination generic/platform=iOS",
64
- "verify:web": "npm run build",
65
+ "verify:web": "pnpm run build",
65
66
  "watch": "tsc --watch",
66
- "test": "npm run test:web && npm run test:android && npm run test:ios",
67
+ "test": "pnpm run test:web && pnpm run test:android && pnpm run test:ios",
67
68
  "test:web": "jest",
68
69
  "test:web:coverage": "jest --coverage --coverageReporters=lcov --coverageReporters=text-summary",
69
70
  "test:android": "node scripts/verify-android.js testDebugUnitTest",
@@ -74,7 +75,7 @@
74
75
  "clean": "rm -rf dist",
75
76
  "swiftlint": "node-swiftlint",
76
77
  "docgen": "docgen --api VoiceRecorderPlugin --output-readme README.md --output-json dist/docs.json",
77
- "fmt": "npm run eslint -- --fix"
78
+ "fmt": "pnpm run eslint --fix"
78
79
  },
79
80
  "eslintConfig": {
80
81
  "extends": "@ionic/eslint-config/recommended"
@@ -112,8 +113,8 @@
112
113
  }
113
114
  ],
114
115
  "peerDependencies": {
115
- "@capacitor/filesystem": ">=8.0.0",
116
- "@capacitor/core": ">=8.0.0"
116
+ "@capacitor/core": ">=8.0.0",
117
+ "@capacitor/filesystem": ">=8.0.0"
117
118
  },
118
119
  "module": "dist/esm/index.js"
119
120
  }