react-record-webcam
Advanced tools
Comparing version 1.0.0 to 1.0.1
@@ -1,1 +0,79 @@ | ||
export * from './useRecordWebcam'; | ||
declare enum STATUS { | ||
INITIAL = "INITIAL", | ||
CLOSED = "CLOSED", | ||
OPEN = "OPEN", | ||
RECORDING = "RECORDING", | ||
STOPPED = "STOPPED", | ||
ERROR = "ERROR", | ||
PAUSED = "PAUSED" | ||
} | ||
type Status = keyof typeof STATUS; | ||
type Recording = { | ||
id: string; | ||
audioId: string; | ||
audioLabel?: string; | ||
fileName: string; | ||
fileType: string; | ||
isMuted: boolean; | ||
mimeType: string; | ||
objectURL: string | null; | ||
onDataAvailableResolve: Function | null; | ||
onDataAvailablePromise: Promise<void>; | ||
previewRef: React.RefObject<HTMLVideoElement>; | ||
recorder: MediaRecorder | null; | ||
status: Status; | ||
videoId: string; | ||
videoLabel?: string; | ||
webcamRef: React.RefObject<HTMLVideoElement>; | ||
}; | ||
type RecordingError = { | ||
recordingId?: string; | ||
error: unknown; | ||
}; | ||
type Options = { | ||
fileName: string; | ||
fileType: string; | ||
mimeType: string; | ||
}; | ||
type UseRecordWebcam = { | ||
constraints: Partial<MediaTrackConstraints>; | ||
recorderOptions: Partial<MediaRecorderOptions>; | ||
options: Partial<Options>; | ||
}; | ||
declare function useRecordWebcam(args?: Partial<UseRecordWebcam>): { | ||
activeRecordings: Recording[]; | ||
applyConstraints: (recordingId: string, constraints: MediaTrackConstraints) => Promise<Recording | void>; | ||
applyRecordingOptions: (recordingId: string, options: Options) => Promise<Recording | void>; | ||
cancelRecording: (recordingId: string) => Promise<undefined>; | ||
clearAllRecordings: () => Promise<void>; | ||
clearPreview: (recordingId: string) => Promise<Recording | void>; | ||
closeCamera: (recordingId: string) => Promise<Recording | void>; | ||
createRecording: (videoId?: string, audioId?: string) => Promise<Recording | void>; | ||
devicesById: { | ||
[x: string]: { | ||
label: string; | ||
type: "videoinput" | "audioinput"; | ||
}; | ||
}; | ||
devicesByType: { | ||
video: { | ||
label: string; | ||
deviceId: string; | ||
}[]; | ||
audio: { | ||
label: string; | ||
deviceId: string; | ||
}[]; | ||
}; | ||
download: (recordingId: string) => Promise<void>; | ||
errorMessage: RecordingError | null; | ||
muteRecording: (recordingId: string) => Promise<Recording | void>; | ||
openCamera: (recordingId: string) => Promise<Recording | void>; | ||
pauseRecording: (recordingId: string) => Promise<Recording | void>; | ||
resumeRecording: (recordingId: string) => Promise<Recording | void>; | ||
startRecording: (recordingId: string) => Promise<Recording | void>; | ||
stopRecording: (recordingId: string) => Promise<Recording | void>; | ||
}; | ||
export { useRecordWebcam }; |
@@ -1,2 +0,548 @@ | ||
export * from './useRecordWebcam'; | ||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxtQkFBbUIsQ0FBQyJ9 | ||
import { useMemo, useEffect, useState, useCallback, createRef } from 'react'; | ||
var __defProp = Object.defineProperty; | ||
var __getOwnPropSymbols = Object.getOwnPropertySymbols; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __propIsEnum = Object.prototype.propertyIsEnumerable; | ||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
var __spreadValues = (a, b) => { | ||
for (var prop in b || (b = {})) | ||
if (__hasOwnProp.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
if (__getOwnPropSymbols) | ||
for (var prop of __getOwnPropSymbols(b)) { | ||
if (__propIsEnum.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
} | ||
return a; | ||
}; | ||
var __async = (__this, __arguments, generator) => { | ||
return new Promise((resolve, reject) => { | ||
var fulfilled = (value) => { | ||
try { | ||
step(generator.next(value)); | ||
} catch (e) { | ||
reject(e); | ||
} | ||
}; | ||
var rejected = (value) => { | ||
try { | ||
step(generator.throw(value)); | ||
} catch (e) { | ||
reject(e); | ||
} | ||
}; | ||
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); | ||
step((generator = generator.apply(__this, __arguments)).next()); | ||
}); | ||
}; | ||
// src/constants.ts | ||
var DEFAULT_RECORDER_OPTIONS = { | ||
audioBitsPerSecond: 128e3, | ||
videoBitsPerSecond: 25e5, | ||
mimeType: "video/webm;codecs=vp9" | ||
}; | ||
var ERROR_MESSAGES = { | ||
BY_ID_NOT_FOUND: "No recording by id found", | ||
SESSION_EXISTS: "Recording session already exists" | ||
}; | ||
var DEFAULT_CONSTRAINTS = { | ||
aspectRatio: 1.7, | ||
echoCancellation: true, | ||
height: 720, | ||
width: 1280 | ||
}; | ||
// src/useRecording.ts | ||
function createRecording({ | ||
videoId, | ||
audioId, | ||
videoLabel, | ||
audioLabel | ||
}) { | ||
const recordingId = `${videoId}-${audioId}`; | ||
let onDataAvailableResolve = null; | ||
const onDataAvailablePromise = new Promise((resolve) => { | ||
onDataAvailableResolve = resolve; | ||
}); | ||
const recording = { | ||
id: recordingId, | ||
audioId, | ||
audioLabel, | ||
fileName: String((/* @__PURE__ */ new Date()).getTime()), | ||
fileType: "webm", | ||
isMuted: false, | ||
mimeType: "video/webm;codecs=vp9", | ||
objectURL: null, | ||
onDataAvailableResolve, | ||
onDataAvailablePromise, | ||
previewRef: createRef(), | ||
recorder: null, | ||
status: "INITIAL" /* INITIAL */, | ||
videoId, | ||
videoLabel, | ||
webcamRef: createRef() | ||
}; | ||
return recording; | ||
} | ||
var recordingMap = /* @__PURE__ */ new Map(); | ||
function useRecording(isDevMode) { | ||
const [activeRecordings, setActiveRecordings] = useState([]); | ||
const [errorMessage, setErrorMessage] = useState(null); | ||
const updateActiveRecordings = () => __async(this, null, function* () { | ||
const recordings = Array.from(recordingMap.values()); | ||
setActiveRecordings(recordings); | ||
}); | ||
const isRecordingCreated = useCallback( | ||
(recordingId) => { | ||
const isCreated = recordingMap.get(recordingId); | ||
return Boolean(isCreated); | ||
}, | ||
[recordingMap] | ||
); | ||
const getRecording = useCallback( | ||
(recordingId) => { | ||
const recording = recordingMap.get(recordingId); | ||
if (!recording) { | ||
throw new Error(ERROR_MESSAGES.BY_ID_NOT_FOUND); | ||
} | ||
return recording; | ||
}, | ||
[recordingMap] | ||
); | ||
const setRecording = useCallback( | ||
(params) => __async(this, null, function* () { | ||
const recording = createRecording(params); | ||
recordingMap.set(recording.id, recording); | ||
yield updateActiveRecordings(); | ||
return recording; | ||
}), | ||
[recordingMap] | ||
); | ||
const updateRecording = useCallback( | ||
(recordingId, updatedValues) => __async(this, null, function* () { | ||
const recording = recordingMap.get(recordingId); | ||
recordingMap.set(recordingId, __spreadValues(__spreadValues({}, recording), updatedValues)); | ||
yield updateActiveRecordings(); | ||
return getRecording(recordingId); | ||
}), | ||
[recordingMap, setRecording, getRecording] | ||
); | ||
const deleteRecording = useCallback( | ||
(recordingId) => __async(this, null, function* () { | ||
recordingMap.delete(recordingId); | ||
yield updateActiveRecordings(); | ||
}), | ||
[recordingMap] | ||
); | ||
const clearAllRecordings = () => __async(this, null, function* () { | ||
Array.from(recordingMap.values()).forEach((recording) => { | ||
var _a; | ||
const stream = (_a = recording.webcamRef.current) == null ? void 0 : _a.srcObject; | ||
if (stream) { | ||
stream.getTracks().forEach((track) => track.stop()); | ||
} | ||
}); | ||
recordingMap.clear(); | ||
setActiveRecordings([]); | ||
}); | ||
const handleError = (functionName, error, recordingId) => __async(this, null, function* () { | ||
if (isDevMode) { | ||
console.error(`@${functionName}: `, error); | ||
} | ||
if (recordingId) { | ||
const recording = getRecording(recordingId); | ||
setErrorMessage({ recordingId, error }); | ||
if (recording) | ||
recording.status = "ERROR" /* ERROR */; | ||
} | ||
throw error; | ||
}); | ||
return { | ||
activeRecordings, | ||
clearAllRecordings, | ||
deleteRecording, | ||
errorMessage, | ||
getRecording, | ||
handleError, | ||
isRecordingCreated, | ||
setRecording, | ||
updateRecording | ||
}; | ||
} | ||
function byId(devices) { | ||
return __async(this, null, function* () { | ||
return devices.reduce( | ||
(result, { deviceId, kind, label }) => { | ||
if (kind === "videoinput" || kind === "audioinput") { | ||
result[deviceId] = { | ||
label, | ||
type: kind | ||
}; | ||
} | ||
return result; | ||
}, | ||
{} | ||
); | ||
}); | ||
} | ||
function byType(devices) { | ||
return __async(this, null, function* () { | ||
return devices.reduce( | ||
(result, { deviceId, kind, label }) => { | ||
if (kind === "videoinput") { | ||
result.video.push({ label, deviceId }); | ||
} | ||
if (kind === "audioinput") { | ||
result.audio.push({ label, deviceId }); | ||
} | ||
return result; | ||
}, | ||
{ | ||
video: [], | ||
audio: [] | ||
} | ||
); | ||
}); | ||
} | ||
function getUserPermission() { | ||
return __async(this, null, function* () { | ||
try { | ||
const stream = yield navigator.mediaDevices.getUserMedia({ | ||
audio: true, | ||
video: true | ||
}); | ||
const mediaDevices = yield navigator.mediaDevices.enumerateDevices(); | ||
stream.getTracks().forEach((track) => { | ||
track.stop(); | ||
}); | ||
return mediaDevices; | ||
} catch (error) { | ||
throw new Error("getUserPermission"); | ||
} | ||
}); | ||
} | ||
function useDeviceInitialization() { | ||
const { handleError } = useRecording(); | ||
const [devicesByType, setDevicesByType] = useState({ | ||
video: [], | ||
audio: [] | ||
}); | ||
const [devicesById, setDevicesById] = useState({}); | ||
const [initialDevices, setInitialDevices] = useState({ | ||
video: null, | ||
audio: null | ||
}); | ||
useEffect(() => { | ||
const initializeDevices = () => __async(this, null, function* () { | ||
try { | ||
const mediaDevices = yield getUserPermission(); | ||
const [allById, allByType] = yield Promise.all([ | ||
byId(mediaDevices), | ||
byType(mediaDevices) | ||
]); | ||
setDevicesById(allById); | ||
setDevicesByType(allByType); | ||
setInitialDevices({ | ||
video: { | ||
deviceId: allByType.video[0].deviceId, | ||
label: allByType.video[0].label | ||
}, | ||
audio: { | ||
deviceId: allByType.audio[0].deviceId, | ||
label: allByType.audio[0].deviceId | ||
} | ||
}); | ||
} catch (error) { | ||
handleError("initializeDevices", error); | ||
} | ||
}); | ||
initializeDevices(); | ||
}, []); | ||
return { devicesByType, devicesById, initialDevices }; | ||
} | ||
// src/stream.ts | ||
function startStream(videoId, audioId, constraints) { | ||
return __async(this, null, function* () { | ||
const newStream = yield navigator.mediaDevices.getUserMedia({ | ||
video: { deviceId: { exact: videoId } }, | ||
audio: { | ||
deviceId: { exact: audioId } | ||
} | ||
}); | ||
const tracks = newStream.getTracks(); | ||
tracks.forEach((track) => track.applyConstraints(constraints)); | ||
return newStream; | ||
}); | ||
} | ||
// src/useRecordWebcam.ts | ||
function useRecordWebcam(args) { | ||
const { devicesByType, devicesById, initialDevices } = useDeviceInitialization(); | ||
const { | ||
activeRecordings, | ||
clearAllRecordings, | ||
deleteRecording, | ||
errorMessage, | ||
getRecording, | ||
handleError, | ||
isRecordingCreated, | ||
setRecording, | ||
updateRecording | ||
} = useRecording(); | ||
const constraints = useMemo( | ||
() => __spreadValues(__spreadValues({}, DEFAULT_CONSTRAINTS), args == null ? void 0 : args.constraints), | ||
[args] | ||
); | ||
const recorderOptions = useMemo( | ||
() => __spreadValues(__spreadValues({}, DEFAULT_RECORDER_OPTIONS), args == null ? void 0 : args.recorderOptions), | ||
[args] | ||
); | ||
const createRecording2 = (videoId, audioId) => __async(this, null, function* () { | ||
var _a, _b, _c, _d; | ||
try { | ||
const recordingId = `${videoId}-${audioId}`; | ||
const isCreated = isRecordingCreated(recordingId); | ||
if (isCreated) | ||
throw new Error(ERROR_MESSAGES.SESSION_EXISTS); | ||
const videoLabel = videoId ? devicesById == null ? void 0 : devicesById[videoId].label : (_a = initialDevices.video) == null ? void 0 : _a.label; | ||
const audioLabel = audioId ? devicesById == null ? void 0 : devicesById[audioId].label : (_b = initialDevices.audio) == null ? void 0 : _b.label; | ||
const recording = yield setRecording({ | ||
videoId: videoId || ((_c = initialDevices.video) == null ? void 0 : _c.deviceId), | ||
audioId: audioId || ((_d = initialDevices.audio) == null ? void 0 : _d.deviceId), | ||
videoLabel, | ||
audioLabel | ||
}); | ||
return recording; | ||
} catch (error) { | ||
handleError("createRecording", error, `${videoId}-${audioId}`); | ||
} | ||
}); | ||
const openCamera = (recordingId) => __async(this, null, function* () { | ||
try { | ||
const recording = getRecording(recordingId); | ||
const stream = yield startStream( | ||
recording.videoId, | ||
recording.audioId, | ||
constraints | ||
); | ||
if (recording.webcamRef.current) { | ||
recording.webcamRef.current.srcObject = stream; | ||
yield recording.webcamRef.current.play(); | ||
} | ||
recording.status = "OPEN" /* OPEN */; | ||
const updatedRecording = yield updateRecording(recording.id, recording); | ||
return updatedRecording; | ||
} catch (error) { | ||
handleError("openCamera", error); | ||
} | ||
}); | ||
const closeCamera = (recordingId) => __async(this, null, function* () { | ||
var _a; | ||
try { | ||
const recording = getRecording(recordingId); | ||
if (recording.webcamRef.current) { | ||
const stream = recording.webcamRef.current.srcObject; | ||
stream == null ? void 0 : stream.getTracks().forEach((track) => track.stop()); | ||
((_a = recording.recorder) == null ? void 0 : _a.ondataavailable) && (recording.recorder.ondataavailable = null); | ||
recording.webcamRef.current.srcObject = null; | ||
recording.webcamRef.current.load(); | ||
} | ||
recording.status = "CLOSED" /* CLOSED */; | ||
const updatedRecording = yield updateRecording(recording.id, recording); | ||
return updatedRecording; | ||
} catch (error) { | ||
handleError("closeCamera", error, recordingId); | ||
} | ||
}); | ||
const startRecording = (recordingId) => __async(this, null, function* () { | ||
var _a; | ||
try { | ||
const recording = getRecording(recordingId); | ||
const stream = (_a = recording.webcamRef.current) == null ? void 0 : _a.srcObject; | ||
recording.recorder = new MediaRecorder(stream, recorderOptions); | ||
recording.recorder.ondataavailable = (event) => __async(this, null, function* () { | ||
var _a2, _b; | ||
if (event.data.size) { | ||
const blob = new Blob([event.data], { | ||
type: `video/${((_a2 = args == null ? void 0 : args.options) == null ? void 0 : _a2.mimeType) || recording.mimeType}` | ||
}); | ||
const url = URL.createObjectURL(blob); | ||
recording.objectURL = url; | ||
if (recording.previewRef.current) | ||
recording.previewRef.current.src = url; | ||
recording.status = "STOPPED" /* STOPPED */; | ||
yield updateRecording(recording.id, recording); | ||
(_b = recording.onDataAvailableResolve) == null ? void 0 : _b.call(recording); | ||
} | ||
}); | ||
recording.recorder.start(); | ||
recording.status = "RECORDING" /* RECORDING */; | ||
const updatedRecording = yield updateRecording(recording.id, recording); | ||
return updatedRecording; | ||
} catch (error) { | ||
handleError("startRecording", error, recordingId); | ||
} | ||
}); | ||
const pauseRecording = (recordingId) => __async(this, null, function* () { | ||
var _a; | ||
try { | ||
const recording = getRecording(recordingId); | ||
(_a = recording.recorder) == null ? void 0 : _a.pause(); | ||
recording.status = "PAUSED" /* PAUSED */; | ||
const updatedRecording = yield updateRecording(recording.id, recording); | ||
return updatedRecording; | ||
} catch (error) { | ||
handleError("pauseRecording", error, recordingId); | ||
} | ||
}); | ||
const resumeRecording = (recordingId) => __async(this, null, function* () { | ||
var _a; | ||
try { | ||
const recording = getRecording(recordingId); | ||
(_a = recording.recorder) == null ? void 0 : _a.resume(); | ||
recording.status = "RECORDING" /* RECORDING */; | ||
const updatedRecording = yield updateRecording(recording.id, recording); | ||
return updatedRecording; | ||
} catch (error) { | ||
handleError("resumeRecording", error, recordingId); | ||
} | ||
}); | ||
const stopRecording = (recordingId) => __async(this, null, function* () { | ||
var _a; | ||
try { | ||
let recording = getRecording(recordingId); | ||
(_a = recording.recorder) == null ? void 0 : _a.stop(); | ||
yield recording.onDataAvailablePromise; | ||
recording = getRecording(recordingId); | ||
recording.status = "STOPPED" /* STOPPED */; | ||
const updatedRecording = yield updateRecording(recording.id, recording); | ||
return updatedRecording; | ||
} catch (error) { | ||
handleError("stopRecording", error, recordingId); | ||
} | ||
}); | ||
const cancelRecording = (recordingId) => __async(this, null, function* () { | ||
var _a, _b, _c; | ||
try { | ||
const recording = getRecording(recordingId); | ||
const tracks = (_a = recording == null ? void 0 : recording.recorder) == null ? void 0 : _a.stream.getTracks(); | ||
(_b = recording == null ? void 0 : recording.recorder) == null ? void 0 : _b.stop(); | ||
tracks == null ? void 0 : tracks.forEach((track) => track.stop()); | ||
((_c = recording.recorder) == null ? void 0 : _c.ondataavailable) && (recording.recorder.ondataavailable = null); | ||
if (recording.webcamRef.current) { | ||
const stream = recording.webcamRef.current.srcObject; | ||
stream == null ? void 0 : stream.getTracks().forEach((track) => track.stop()); | ||
recording.webcamRef.current.srcObject = null; | ||
recording.webcamRef.current.load(); | ||
} | ||
URL.revokeObjectURL(recording.objectURL); | ||
recording.status = "INITIAL" /* INITIAL */; | ||
const updatedRecording = yield updateRecording(recording.id, recording); | ||
yield deleteRecording(updatedRecording.id); | ||
} catch (error) { | ||
handleError("cancelRecording", error, recordingId); | ||
} | ||
}); | ||
const clearPreview = (recordingId) => __async(this, null, function* () { | ||
try { | ||
const recording = getRecording(recordingId); | ||
if (recording.previewRef.current) | ||
recording.previewRef.current.src = ""; | ||
recording.status = "INITIAL" /* INITIAL */; | ||
URL.revokeObjectURL(recording.objectURL); | ||
const updatedRecording = yield updateRecording(recording.id, recording); | ||
return updatedRecording; | ||
} catch (error) { | ||
handleError("clearPreview", error, recordingId); | ||
} | ||
}); | ||
const muteRecording = (recordingId) => __async(this, null, function* () { | ||
var _a; | ||
try { | ||
const recording = getRecording(recordingId); | ||
(_a = recording.recorder) == null ? void 0 : _a.stream.getAudioTracks().forEach((track) => { | ||
track.enabled = !track.enabled; | ||
}); | ||
recording.isMuted = !recording.isMuted; | ||
const updatedRecording = yield updateRecording(recording.id, recording); | ||
return updatedRecording; | ||
} catch (error) { | ||
handleError("muteRecording", error, recordingId); | ||
} | ||
}); | ||
const download = (recordingId) => __async(this, null, function* () { | ||
var _a, _b; | ||
try { | ||
const recording = getRecording(recordingId); | ||
const downloadElement = document.createElement("a"); | ||
if (recording == null ? void 0 : recording.objectURL) { | ||
downloadElement.href = recording.objectURL; | ||
} | ||
downloadElement.download = `${((_a = args == null ? void 0 : args.options) == null ? void 0 : _a.fileName) || recording.fileName}.${((_b = args == null ? void 0 : args.options) == null ? void 0 : _b.fileType) || recording.fileType}`; | ||
downloadElement.click(); | ||
} catch (error) { | ||
handleError("download", error, recordingId); | ||
} | ||
}); | ||
const applyConstraints = (recordingId, constraints2) => __async(this, null, function* () { | ||
var _a, _b; | ||
try { | ||
const recording = getRecording(recordingId); | ||
if ((_a = recording.webcamRef.current) == null ? void 0 : _a.srcObject) { | ||
const stream = (_b = recording.webcamRef.current) == null ? void 0 : _b.srcObject; | ||
const tracks = stream.getTracks() || []; | ||
tracks == null ? void 0 : tracks.forEach((track) => { | ||
track.applyConstraints(__spreadValues({}, constraints2)); | ||
}); | ||
} | ||
return recording; | ||
} catch (error) { | ||
handleError("applyConstraints", error, recordingId); | ||
} | ||
}); | ||
const applyRecordingOptions = (recordingId, options) => __async(this, null, function* () { | ||
try { | ||
const recording = getRecording(recordingId); | ||
if (options.fileName) { | ||
recording.fileName = options.fileName; | ||
} | ||
if (options.fileType) { | ||
recording.fileType = options.fileType; | ||
} | ||
const updatedRecording = yield updateRecording(recording.id, recording); | ||
return updatedRecording; | ||
} catch (error) { | ||
handleError("applyRecordingOptions", error, recordingId); | ||
} | ||
}); | ||
useEffect(() => { | ||
return () => { | ||
clearAllRecordings(); | ||
}; | ||
}, []); | ||
return { | ||
activeRecordings, | ||
applyConstraints, | ||
applyRecordingOptions, | ||
cancelRecording, | ||
clearAllRecordings, | ||
clearPreview, | ||
closeCamera, | ||
createRecording: createRecording2, | ||
devicesById, | ||
devicesByType, | ||
download, | ||
errorMessage, | ||
muteRecording, | ||
openCamera, | ||
pauseRecording, | ||
resumeRecording, | ||
startRecording, | ||
stopRecording | ||
}; | ||
} | ||
export { useRecordWebcam }; |
{ | ||
"name": "react-record-webcam", | ||
"description": "Webcam recording tool for React", | ||
"version": "1.0.0", | ||
"version": "1.0.1", | ||
"main": "dist/index.js", | ||
"files": [ | ||
"dist" | ||
"dist", | ||
"README.md", | ||
"LICENSE" | ||
], | ||
@@ -14,20 +16,25 @@ "types": "dist/index.d.ts", | ||
"peerDependencies": { | ||
"react": "*" | ||
"react": "^16.3 || ^17.0 || ^18.0" | ||
}, | ||
"scripts": { | ||
"start": "rm -rf ./dist && tsc --watch", | ||
"build": "rm -rf ./dist && tsc" | ||
"build": "tsup" | ||
}, | ||
"keywords": [ | ||
"react", | ||
"record", | ||
"webcam", | ||
"multi", | ||
"recording", | ||
"concurrent", | ||
"simultaneous", | ||
"record", | ||
"recording", | ||
"hook", | ||
"video", | ||
"audio" | ||
] | ||
], | ||
"sideEffects": false, | ||
"type": "module", | ||
"exports": { | ||
".": "./dist/index.js" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Yes
30992
5
619
1