(
options: Omit<UseGenerateVideoOptions, 'onResult'> & {
onResult?: (result: VideoGenerateResult) => TTransformed
},
)
| 108 | // parameter is typed as `VideoGenerateResult` and `result` narrows to the |
| 109 | // transform's return. See issue #848. |
| 110 | export function useGenerateVideo<TTransformed = void>( |
| 111 | options: Omit<UseGenerateVideoOptions, 'onResult'> & { |
| 112 | onResult?: (result: VideoGenerateResult) => TTransformed |
| 113 | }, |
| 114 | ): UseGenerateVideoReturn< |
| 115 | InferGenerationOutputFromReturn<VideoGenerateResult, TTransformed> |
| 116 | > { |
| 117 | type TOutput = InferGenerationOutputFromReturn< |
| 118 | VideoGenerateResult, |
| 119 | TTransformed |
| 120 | > |
| 121 | const hookId = useId() |
| 122 | const clientId = options.id || hookId |
| 123 | |
| 124 | const [result, setResult] = useState<TOutput | null>(null) |
| 125 | const [jobId, setJobId] = useState<string | null>(null) |
| 126 | const [videoStatus, setVideoStatus] = useState<VideoStatusInfo | null>(null) |
| 127 | const [isLoading, setIsLoading] = useState(false) |
| 128 | const [error, setError] = useState<Error | undefined>(undefined) |
| 129 | const [status, setStatus] = useState<GenerationClientState>('idle') |
| 130 | |
| 131 | const optionsRef = useRef(options) |
| 132 | optionsRef.current = options |
| 133 | |
| 134 | const client = useMemo(() => { |
| 135 | const opts = optionsRef.current |
| 136 | |
| 137 | // Conditional spread for `body` (strict-optional in target). |
| 138 | // Optional callbacks are wrapped in non-returning bodies so |
| 139 | // `?.()`'s implicit `undefined` doesn't widen the function |
| 140 | // return type (which `exactOptionalPropertyTypes` rejects |
| 141 | // against the strict-optional target). |
| 142 | const baseOptions = { |
| 143 | id: clientId, |
| 144 | body: opts.body, |
| 145 | devtoolsBridgeFactory: createVideoDevtoolsBridge, |
| 146 | devtools: { |
| 147 | ...opts.devtools, |
| 148 | framework: 'react', |
| 149 | hookName: 'useGenerateVideo', |
| 150 | outputKind: 'video' as const, |
| 151 | }, |
| 152 | // The transform's raw return type (`TTransformed`) and the stored output |
| 153 | // (`TOutput`, with null/void/undefined stripped) are identical at runtime; |
| 154 | // the cast bridges the relationship that the conditional type hides. |
| 155 | onResult: ((r: VideoGenerateResult) => |
| 156 | optionsRef.current.onResult?.(r)) as ( |
| 157 | result: VideoGenerateResult, |
| 158 | ) => TOutput | null | void, |
| 159 | onError: (e: Error) => { |
| 160 | optionsRef.current.onError?.(e) |
| 161 | }, |
| 162 | onProgress: (p: number, m?: string) => { |
| 163 | optionsRef.current.onProgress?.(p, m) |
| 164 | }, |
| 165 | onChunk: (c: StreamChunk) => { |
| 166 | optionsRef.current.onChunk?.(c) |
| 167 | }, |
no test coverage detected