(
options: Omit<CreateGenerationOptions<TInput, TResult>, 'onResult'> & {
onResult?: (result: TResult) => TTransformed
},
)
| 110 | // default, leaving the parameter `any` — a hard error under `strict`. See |
| 111 | // issue #848. |
| 112 | export function createGeneration< |
| 113 | TInput extends Record<string, any>, |
| 114 | TResult, |
| 115 | TTransformed = void, |
| 116 | >( |
| 117 | options: Omit<CreateGenerationOptions<TInput, TResult>, 'onResult'> & { |
| 118 | onResult?: (result: TResult) => TTransformed |
| 119 | }, |
| 120 | ): CreateGenerationReturn< |
| 121 | InferGenerationOutputFromReturn<TResult, TTransformed> |
| 122 | > { |
| 123 | type TOutput = InferGenerationOutputFromReturn<TResult, TTransformed> |
| 124 | const clientId = |
| 125 | options.id || `gen-${Date.now()}-${Math.random().toString(36).substring(7)}` |
| 126 | |
| 127 | // Create reactive state using Svelte 5 runes |
| 128 | let result = $state<TOutput | null>(null) |
| 129 | let isLoading = $state(false) |
| 130 | let error = $state<Error | undefined>(undefined) |
| 131 | let status = $state<GenerationClientState>('idle') |
| 132 | |
| 133 | // `body` uses a conditional spread because `GenerationClientOptions.body` |
| 134 | // is declared `body?: Record<string, any>` (absent vs. present) under |
| 135 | // `exactOptionalPropertyTypes`. Assigning `undefined` directly would be |
| 136 | // rejected — the optional caller `options.body` may be undefined, in which |
| 137 | // case we want the key to be absent. |
| 138 | const clientOptions: GenerationClientOptions<TInput, TResult, TOutput> = { |
| 139 | id: clientId, |
| 140 | body: options.body, |
| 141 | devtoolsBridgeFactory: createGenerationDevtoolsBridge, |
| 142 | devtools: { |
| 143 | ...options.devtools, |
| 144 | framework: 'svelte', |
| 145 | hookName: 'createGeneration', |
| 146 | }, |
| 147 | // The transform's raw return type (`TTransformed`) and the stored output |
| 148 | // (`TOutput`, with null/void/undefined stripped) are identical at runtime; |
| 149 | // the cast bridges the relationship that the conditional type hides. |
| 150 | onResult: ((r: TResult) => options.onResult?.(r)) as ( |
| 151 | result: TResult, |
| 152 | ) => TOutput | null | void, |
| 153 | onError: (e: Error) => options.onError?.(e), |
| 154 | onProgress: (p: number, m?: string) => options.onProgress?.(p, m), |
| 155 | onChunk: (c: StreamChunk) => options.onChunk?.(c), |
| 156 | onResultChange: (r: TOutput | null) => { |
| 157 | result = r |
| 158 | }, |
| 159 | onLoadingChange: (l: boolean) => { |
| 160 | isLoading = l |
| 161 | }, |
| 162 | onErrorChange: (e: Error | undefined) => { |
| 163 | error = e |
| 164 | }, |
| 165 | onStatusChange: (s: GenerationClientState) => { |
| 166 | status = s |
| 167 | }, |
| 168 | } |
| 169 |
no test coverage detected