@tanstack/ai-svelte 0.10.1 → 0.10.3

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.
@@ -46,13 +46,22 @@ export function createChat(options) {
46
46
  // by reference. Callbacks are therefore frozen to whatever the caller passed
47
47
  // at creation — to swap them dynamically, mutate the options object
48
48
  // in-place or call `client.updateOptions(...)` imperatively.
49
+ // Optional fields use conditional spread because the target
50
+ // `ChatClientOptions` declares them as `field?: T` (absent vs. present)
51
+ // rather than `field?: T | undefined`. Under `exactOptionalPropertyTypes`,
52
+ // passing an explicit `undefined` for an absent-only optional is a type
53
+ // error, so we omit the key when the caller's value is undefined.
49
54
  const client = new ChatClient({
50
55
  connection: options.connection,
51
56
  id: clientId,
52
- initialMessages: options.initialMessages,
53
- body: options.body,
54
- forwardedProps: options.forwardedProps,
55
- onResponse: options.onResponse,
57
+ ...(options.initialMessages !== undefined && {
58
+ initialMessages: options.initialMessages,
59
+ }),
60
+ ...(options.body !== undefined && { body: options.body }),
61
+ ...(options.forwardedProps !== undefined && {
62
+ forwardedProps: options.forwardedProps,
63
+ }),
64
+ ...(options.onResponse !== undefined && { onResponse: options.onResponse }),
56
65
  onChunk: (chunk) => {
57
66
  options.onChunk?.(chunk);
58
67
  },
@@ -63,8 +72,12 @@ export function createChat(options) {
63
72
  options.onError?.(err);
64
73
  },
65
74
  tools: options.tools,
66
- onCustomEvent: options.onCustomEvent,
67
- streamProcessor: options.streamProcessor,
75
+ ...(options.onCustomEvent !== undefined && {
76
+ onCustomEvent: options.onCustomEvent,
77
+ }),
78
+ ...(options.streamProcessor !== undefined && {
79
+ streamProcessor: options.streamProcessor,
80
+ }),
68
81
  onMessagesChange: (newMessages) => {
69
82
  messages = newMessages;
70
83
  },
@@ -138,7 +151,7 @@ export function createChat(options) {
138
151
  const activeStructuredPart = $derived.by(() => {
139
152
  let lastUserIndex = -1;
140
153
  for (let i = messages.length - 1; i >= 0; i--) {
141
- if (messages[i].role === 'user') {
154
+ if (messages[i]?.role === 'user') {
142
155
  lastUserIndex = i;
143
156
  break;
144
157
  }
@@ -147,7 +160,7 @@ export function createChat(options) {
147
160
  return null;
148
161
  for (let i = messages.length - 1; i > lastUserIndex; i--) {
149
162
  const m = messages[i];
150
- if (m.role !== 'assistant')
163
+ if (m?.role !== 'assistant')
151
164
  continue;
152
165
  const part = m.parts.find((p) => p.type === 'structured-output');
153
166
  if (part)
@@ -166,6 +179,7 @@ export function createChat(options) {
166
179
  : null);
167
180
  // Return the chat interface with reactive getters
168
181
  // Using getters allows Svelte to track reactivity without needing $ prefix
182
+ // eslint-disable-next-line no-restricted-syntax -- rune return shape diverges from generic CreateChatReturn<TTools, TSchema> due to TSchema conditional partial/final fields; TS can't structurally narrow.
169
183
  return {
170
184
  get messages() {
171
185
  return messages;
@@ -39,6 +39,10 @@ export function createGenerateVideo(options) {
39
39
  let isLoading = $state(false);
40
40
  let error = $state(undefined);
41
41
  let status = $state('idle');
42
+ // `body` uses a conditional spread because `VideoGenerationClientOptions.body`
43
+ // is declared `body?: Record<string, any>` (absent vs. present) under
44
+ // `exactOptionalPropertyTypes`. The optional caller `options.body` may be
45
+ // undefined, in which case we want the key to be absent on the target.
42
46
  const baseOptions = {
43
47
  id: clientId,
44
48
  body: options.body,
@@ -37,6 +37,11 @@ export function createGeneration(options) {
37
37
  let isLoading = $state(false);
38
38
  let error = $state(undefined);
39
39
  let status = $state('idle');
40
+ // `body` uses a conditional spread because `GenerationClientOptions.body`
41
+ // is declared `body?: Record<string, any>` (absent vs. present) under
42
+ // `exactOptionalPropertyTypes`. Assigning `undefined` directly would be
43
+ // rejected — the optional caller `options.body` may be undefined, in which
44
+ // case we want the key to be absent.
40
45
  const clientOptions = {
41
46
  id: clientId,
42
47
  body: options.body,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/ai-svelte",
3
- "version": "0.10.1",
3
+ "version": "0.10.3",
4
4
  "description": "Svelte bindings for TanStack AI",
5
5
  "author": "",
6
6
  "license": "MIT",
@@ -33,11 +33,11 @@
33
33
  "streaming"
34
34
  ],
35
35
  "dependencies": {
36
- "@tanstack/ai-client": "0.11.1"
36
+ "@tanstack/ai-client": "0.11.3"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "svelte": "^5.0.0",
40
- "@tanstack/ai": "^0.19.1"
40
+ "@tanstack/ai": "^0.20.1"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@standard-schema/spec": "^1.1.0",
@@ -50,7 +50,7 @@
50
50
  "svelte-check": "^4.2.0",
51
51
  "typescript": "5.9.3",
52
52
  "vite": "^7.3.3",
53
- "@tanstack/ai": "0.19.1"
53
+ "@tanstack/ai": "0.20.1"
54
54
  },
55
55
  "scripts": {
56
56
  "clean": "rm -rf ./dist",
@@ -81,13 +81,22 @@ export function createChat<
81
81
  // by reference. Callbacks are therefore frozen to whatever the caller passed
82
82
  // at creation — to swap them dynamically, mutate the options object
83
83
  // in-place or call `client.updateOptions(...)` imperatively.
84
+ // Optional fields use conditional spread because the target
85
+ // `ChatClientOptions` declares them as `field?: T` (absent vs. present)
86
+ // rather than `field?: T | undefined`. Under `exactOptionalPropertyTypes`,
87
+ // passing an explicit `undefined` for an absent-only optional is a type
88
+ // error, so we omit the key when the caller's value is undefined.
84
89
  const client = new ChatClient({
85
90
  connection: options.connection,
86
91
  id: clientId,
87
- initialMessages: options.initialMessages,
88
- body: options.body,
89
- forwardedProps: options.forwardedProps,
90
- onResponse: options.onResponse,
92
+ ...(options.initialMessages !== undefined && {
93
+ initialMessages: options.initialMessages,
94
+ }),
95
+ ...(options.body !== undefined && { body: options.body }),
96
+ ...(options.forwardedProps !== undefined && {
97
+ forwardedProps: options.forwardedProps,
98
+ }),
99
+ ...(options.onResponse !== undefined && { onResponse: options.onResponse }),
91
100
  onChunk: (chunk: StreamChunk) => {
92
101
  options.onChunk?.(chunk)
93
102
  },
@@ -98,8 +107,12 @@ export function createChat<
98
107
  options.onError?.(err)
99
108
  },
100
109
  tools: options.tools,
101
- onCustomEvent: options.onCustomEvent,
102
- streamProcessor: options.streamProcessor,
110
+ ...(options.onCustomEvent !== undefined && {
111
+ onCustomEvent: options.onCustomEvent,
112
+ }),
113
+ ...(options.streamProcessor !== undefined && {
114
+ streamProcessor: options.streamProcessor,
115
+ }),
103
116
  onMessagesChange: (newMessages: Array<UIMessage<TTools>>) => {
104
117
  messages = newMessages
105
118
  },
@@ -195,15 +208,15 @@ export function createChat<
195
208
  const activeStructuredPart: StructuredOutputPart | null = $derived.by(() => {
196
209
  let lastUserIndex = -1
197
210
  for (let i = messages.length - 1; i >= 0; i--) {
198
- if (messages[i]!.role === 'user') {
211
+ if (messages[i]?.role === 'user') {
199
212
  lastUserIndex = i
200
213
  break
201
214
  }
202
215
  }
203
216
  if (lastUserIndex === -1) return null
204
217
  for (let i = messages.length - 1; i > lastUserIndex; i--) {
205
- const m = messages[i]!
206
- if (m.role !== 'assistant') continue
218
+ const m = messages[i]
219
+ if (m?.role !== 'assistant') continue
207
220
  const part = m.parts.find(
208
221
  (p): p is StructuredOutputPart => p.type === 'structured-output',
209
222
  )
@@ -226,6 +239,7 @@ export function createChat<
226
239
 
227
240
  // Return the chat interface with reactive getters
228
241
  // Using getters allows Svelte to track reactivity without needing $ prefix
242
+ // eslint-disable-next-line no-restricted-syntax -- rune return shape diverges from generic CreateChatReturn<TTools, TSchema> due to TSchema conditional partial/final fields; TS can't structurally narrow.
229
243
  return {
230
244
  get messages() {
231
245
  return messages
@@ -125,6 +125,10 @@ export function createGenerateVideo<
125
125
  let error = $state<Error | undefined>(undefined)
126
126
  let status = $state<GenerationClientState>('idle')
127
127
 
128
+ // `body` uses a conditional spread because `VideoGenerationClientOptions.body`
129
+ // is declared `body?: Record<string, any>` (absent vs. present) under
130
+ // `exactOptionalPropertyTypes`. The optional caller `options.body` may be
131
+ // undefined, in which case we want the key to be absent on the target.
128
132
  const baseOptions = {
129
133
  id: clientId,
130
134
  body: options.body,
@@ -116,6 +116,11 @@ export function createGeneration<
116
116
  let error = $state<Error | undefined>(undefined)
117
117
  let status = $state<GenerationClientState>('idle')
118
118
 
119
+ // `body` uses a conditional spread because `GenerationClientOptions.body`
120
+ // is declared `body?: Record<string, any>` (absent vs. present) under
121
+ // `exactOptionalPropertyTypes`. Assigning `undefined` directly would be
122
+ // rejected — the optional caller `options.body` may be undefined, in which
123
+ // case we want the key to be absent.
119
124
  const clientOptions: GenerationClientOptions<TInput, TResult, TOutput> = {
120
125
  id: clientId,
121
126
  body: options.body,