@tanstack/ai-react 0.21.1 → 0.21.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.
|
@@ -39,5 +39,7 @@ export interface UseAudioRecorderReturn<TOutput> {
|
|
|
39
39
|
* sendMessage({ content: [rec.part] })
|
|
40
40
|
* ```
|
|
41
41
|
*/
|
|
42
|
-
export declare function useAudioRecorder<TOnComplete extends (recording: AudioRecording) => unknown>(options: UseAudioRecorderOptions<TOnComplete>
|
|
42
|
+
export declare function useAudioRecorder<TOnComplete extends (recording: AudioRecording) => unknown>(options: UseAudioRecorderOptions<TOnComplete> & {
|
|
43
|
+
onComplete: TOnComplete;
|
|
44
|
+
}): UseAudioRecorderReturn<InferAudioRecordingOutput<TOnComplete>>;
|
|
43
45
|
export declare function useAudioRecorder(options?: UseAudioRecorderOptions<undefined>): UseAudioRecorderReturn<AudioRecording>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-audio-recorder.js","names":[],"sources":["../../src/use-audio-recorder.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { AudioRecorder } from '@tanstack/ai-client'\nimport type {\n AudioRecorderOptions,\n AudioRecording,\n InferAudioRecordingOutput,\n} from '@tanstack/ai-client'\n\nexport type UseAudioRecorderOptions<TOnComplete> = AudioRecorderOptions & {\n /**\n * Optional transform applied to the recording when `stop()` resolves. Its\n * (awaited) return value becomes `recording` and the resolved value of\n * `stop()`. Return nothing to keep the raw `AudioRecording`.\n */\n onComplete?: TOnComplete\n}\n\nexport interface UseAudioRecorderReturn<TOutput> {\n /** Latest recording (transformed if `onComplete` provided), or null. */\n recording: TOutput | null\n /** True while actively capturing audio. */\n isRecording: boolean\n /** Whether the browser supports recording (getUserMedia + MediaRecorder). */\n isSupported: boolean\n /** Acquire the mic and begin recording. */\n start: () => Promise<void>\n /** Stop and resolve with the completed recording (transformed if `onComplete` provided). */\n stop: () => Promise<TOutput>\n /** Discard the in-progress recording and release the mic. */\n cancel: () => void\n}\n\n/**\n * React hook for recording an audio message. The resolved\n * {@link AudioRecording} carries `.part` (an audio content part for\n * `useChat.sendMessage`) and `.base64` (for the generation hooks).\n *\n * Errors are delivered via `onError`. `start()` and `stop()` also reject on\n * failure (and `stop()` rejects with `Recording cancelled` if the component\n * unmounts while a stop is in flight) — handle one channel, not both.\n *\n * @example\n * ```tsx\n * const { isRecording, start, stop, recording } = useAudioRecorder()\n * const { sendMessage } = useChat({ connection })\n * // ...\n * const rec = await stop()\n * sendMessage({ content: [rec.part] })\n * ```\n */\nexport function useAudioRecorder<\n TOnComplete extends (recording: AudioRecording) => unknown,\n>(\n options: UseAudioRecorderOptions<TOnComplete
|
|
1
|
+
{"version":3,"file":"use-audio-recorder.js","names":[],"sources":["../../src/use-audio-recorder.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { AudioRecorder } from '@tanstack/ai-client'\nimport type {\n AudioRecorderOptions,\n AudioRecording,\n InferAudioRecordingOutput,\n} from '@tanstack/ai-client'\n\nexport type UseAudioRecorderOptions<TOnComplete> = AudioRecorderOptions & {\n /**\n * Optional transform applied to the recording when `stop()` resolves. Its\n * (awaited) return value becomes `recording` and the resolved value of\n * `stop()`. Return nothing to keep the raw `AudioRecording`.\n */\n onComplete?: TOnComplete\n}\n\nexport interface UseAudioRecorderReturn<TOutput> {\n /** Latest recording (transformed if `onComplete` provided), or null. */\n recording: TOutput | null\n /** True while actively capturing audio. */\n isRecording: boolean\n /** Whether the browser supports recording (getUserMedia + MediaRecorder). */\n isSupported: boolean\n /** Acquire the mic and begin recording. */\n start: () => Promise<void>\n /** Stop and resolve with the completed recording (transformed if `onComplete` provided). */\n stop: () => Promise<TOutput>\n /** Discard the in-progress recording and release the mic. */\n cancel: () => void\n}\n\n/**\n * React hook for recording an audio message. The resolved\n * {@link AudioRecording} carries `.part` (an audio content part for\n * `useChat.sendMessage`) and `.base64` (for the generation hooks).\n *\n * Errors are delivered via `onError`. `start()` and `stop()` also reject on\n * failure (and `stop()` rejects with `Recording cancelled` if the component\n * unmounts while a stop is in flight) — handle one channel, not both.\n *\n * @example\n * ```tsx\n * const { isRecording, start, stop, recording } = useAudioRecorder()\n * const { sendMessage } = useChat({ connection })\n * // ...\n * const rec = await stop()\n * sendMessage({ content: [rec.part] })\n * ```\n */\n// The transforming overload requires `onComplete`. Without that constraint an\n// options object carrying only unrelated keys (`useAudioRecorder({ onError })`)\n// still matches it, `TOnComplete` infers as `unknown`, and `recording`/`stop()`\n// collapse to `unknown` — so passing any option would silently cost you the\n// `AudioRecording` type. Requiring it here sends those calls to the second\n// overload instead (issue #1001).\nexport function useAudioRecorder<\n TOnComplete extends (recording: AudioRecording) => unknown,\n>(\n options: UseAudioRecorderOptions<TOnComplete> & { onComplete: TOnComplete },\n): UseAudioRecorderReturn<InferAudioRecordingOutput<TOnComplete>>\nexport function useAudioRecorder(\n options?: UseAudioRecorderOptions<undefined>,\n): UseAudioRecorderReturn<AudioRecording>\nexport function useAudioRecorder(\n options: UseAudioRecorderOptions<(recording: AudioRecording) => unknown> = {},\n): UseAudioRecorderReturn<unknown> {\n const [isRecording, setIsRecording] = useState(false)\n const [recording, setRecording] = useState<unknown>(null)\n // Read the freshest callbacks at fire time without recreating the recorder.\n const optionsRef = useRef(options)\n optionsRef.current = options\n\n const recorder = useMemo(\n () =>\n new AudioRecorder({\n ...(options.audio !== undefined && { audio: options.audio }),\n ...(options.mimeType !== undefined && { mimeType: options.mimeType }),\n onError: (err) => optionsRef.current.onError?.(err),\n }),\n // Recorder config (audio/mimeType) is captured once at mount, matching the\n // other hooks' create-once pattern.\n [],\n )\n\n useEffect(() => {\n const unsubscribe = recorder.subscribe((state) => {\n setIsRecording(state === 'recording')\n })\n return () => {\n unsubscribe()\n recorder.cancel()\n }\n }, [recorder])\n\n const start = useCallback(() => recorder.start(), [recorder])\n const stop = useCallback(async () => {\n const recording = await recorder.stop()\n const transformed = await optionsRef.current.onComplete?.(recording)\n // Only `undefined` (returning nothing) falls back to the raw recording, so\n // a transform that returns null is preserved — matching the inferred type,\n // which excludes only undefined/void/null from the transform's return.\n const output = transformed === undefined ? recording : transformed\n setRecording(() => output)\n return output\n }, [recorder])\n const cancel = useCallback(() => recorder.cancel(), [recorder])\n\n return {\n recording,\n isRecording,\n // recording is client-only; if SSR'd, gate UI on a mounted flag.\n isSupported: AudioRecorder.isSupported(),\n start,\n stop,\n cancel,\n }\n}\n"],"mappings":";;;AAgEA,SAAgB,iBACd,UAA2E,CAAC,GAC3C;CACjC,MAAM,CAAC,aAAa,kBAAkB,SAAS,KAAK;CACpD,MAAM,CAAC,WAAW,gBAAgB,SAAkB,IAAI;CAExD,MAAM,aAAa,OAAO,OAAO;CACjC,WAAW,UAAU;CAErB,MAAM,WAAW,cAEb,IAAI,cAAc;EAChB,GAAI,QAAQ,UAAU,KAAA,KAAa,EAAE,OAAO,QAAQ,MAAM;EAC1D,GAAI,QAAQ,aAAa,KAAA,KAAa,EAAE,UAAU,QAAQ,SAAS;EACnE,UAAU,QAAQ,WAAW,QAAQ,UAAU,GAAG;CACpD,CAAC,GAGH,CAAC,CACH;CAEA,gBAAgB;EACd,MAAM,cAAc,SAAS,WAAW,UAAU;GAChD,eAAe,UAAU,WAAW;EACtC,CAAC;EACD,aAAa;GACX,YAAY;GACZ,SAAS,OAAO;EAClB;CACF,GAAG,CAAC,QAAQ,CAAC;CAEb,MAAM,QAAQ,kBAAkB,SAAS,MAAM,GAAG,CAAC,QAAQ,CAAC;CAC5D,MAAM,OAAO,YAAY,YAAY;EACnC,MAAM,YAAY,MAAM,SAAS,KAAK;EACtC,MAAM,cAAc,MAAM,WAAW,QAAQ,aAAa,SAAS;EAInE,MAAM,SAAS,gBAAgB,KAAA,IAAY,YAAY;EACvD,mBAAmB,MAAM;EACzB,OAAO;CACT,GAAG,CAAC,QAAQ,CAAC;CACb,MAAM,SAAS,kBAAkB,SAAS,OAAO,GAAG,CAAC,QAAQ,CAAC;CAE9D,OAAO;EACL;EACA;EAEA,aAAa,cAAc,YAAY;EACvC;EACA;EACA;CACF;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/ai-react",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.2",
|
|
4
4
|
"description": "React hooks for TanStack AI streaming chat, realtime voice, structured outputs, and media generation.",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,13 +49,13 @@
|
|
|
49
49
|
"media-generation"
|
|
50
50
|
],
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@tanstack/ai-client": "^0.25.
|
|
52
|
+
"@tanstack/ai-client": "^0.25.2"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"@mcp-ui/client": "^7",
|
|
56
56
|
"@types/react": ">=18.0.0",
|
|
57
57
|
"react": ">=18.0.0",
|
|
58
|
-
"@tanstack/ai": "^0.47.
|
|
58
|
+
"@tanstack/ai": "^0.47.3"
|
|
59
59
|
},
|
|
60
60
|
"peerDependenciesMeta": {
|
|
61
61
|
"@mcp-ui/client": {
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"jsdom": "^27.4.0",
|
|
72
72
|
"react": "^19.2.3",
|
|
73
73
|
"vite": "^8.2.1",
|
|
74
|
-
"@tanstack/ai": "0.47.
|
|
74
|
+
"@tanstack/ai": "0.47.3"
|
|
75
75
|
},
|
|
76
76
|
"scripts": {
|
|
77
77
|
"clean": "premove ./build ./dist",
|
|
@@ -48,10 +48,16 @@ export interface UseAudioRecorderReturn<TOutput> {
|
|
|
48
48
|
* sendMessage({ content: [rec.part] })
|
|
49
49
|
* ```
|
|
50
50
|
*/
|
|
51
|
+
// The transforming overload requires `onComplete`. Without that constraint an
|
|
52
|
+
// options object carrying only unrelated keys (`useAudioRecorder({ onError })`)
|
|
53
|
+
// still matches it, `TOnComplete` infers as `unknown`, and `recording`/`stop()`
|
|
54
|
+
// collapse to `unknown` — so passing any option would silently cost you the
|
|
55
|
+
// `AudioRecording` type. Requiring it here sends those calls to the second
|
|
56
|
+
// overload instead (issue #1001).
|
|
51
57
|
export function useAudioRecorder<
|
|
52
58
|
TOnComplete extends (recording: AudioRecording) => unknown,
|
|
53
59
|
>(
|
|
54
|
-
options: UseAudioRecorderOptions<TOnComplete
|
|
60
|
+
options: UseAudioRecorderOptions<TOnComplete> & { onComplete: TOnComplete },
|
|
55
61
|
): UseAudioRecorderReturn<InferAudioRecordingOutput<TOnComplete>>
|
|
56
62
|
export function useAudioRecorder(
|
|
57
63
|
options?: UseAudioRecorderOptions<undefined>,
|