@assistant-ui/mcp-docs-server 0.1.15 → 0.1.17
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.
- package/.docs/organized/code-examples/store-example.md +249 -147
- package/.docs/organized/code-examples/with-ag-ui.md +250 -186
- package/.docs/organized/code-examples/with-ai-sdk-v5.md +250 -199
- package/.docs/organized/code-examples/with-assistant-transport.md +195 -243
- package/.docs/organized/code-examples/with-cloud.md +277 -226
- package/.docs/organized/code-examples/with-custom-thread-list.md +1855 -0
- package/.docs/organized/code-examples/with-external-store.md +246 -180
- package/.docs/organized/code-examples/with-ffmpeg.md +255 -189
- package/.docs/organized/code-examples/with-langgraph.md +293 -242
- package/.docs/organized/code-examples/with-parent-id-grouping.md +243 -263
- package/.docs/organized/code-examples/with-react-hook-form.md +262 -196
- package/.docs/organized/code-examples/with-tanstack.md +1578 -0
- package/.docs/raw/blog/2024-07-29-hello/index.mdx +2 -2
- package/.docs/raw/docs/api-reference/overview.mdx +6 -6
- package/.docs/raw/docs/api-reference/primitives/ActionBar.mdx +85 -4
- package/.docs/raw/docs/api-reference/primitives/AssistantIf.mdx +200 -0
- package/.docs/raw/docs/api-reference/primitives/Composer.mdx +0 -20
- package/.docs/raw/docs/api-reference/primitives/Message.mdx +0 -45
- package/.docs/raw/docs/api-reference/primitives/Thread.mdx +0 -50
- package/.docs/raw/docs/cloud/persistence/ai-sdk.mdx +2 -3
- package/.docs/raw/docs/cloud/persistence/langgraph.mdx +2 -3
- package/.docs/raw/docs/devtools.mdx +2 -3
- package/.docs/raw/docs/getting-started.mdx +36 -1102
- package/.docs/raw/docs/guides/Attachments.mdx +3 -25
- package/.docs/raw/docs/guides/Branching.mdx +1 -1
- package/.docs/raw/docs/guides/Speech.mdx +1 -1
- package/.docs/raw/docs/guides/ToolUI.mdx +1 -1
- package/.docs/raw/docs/legacy/styled/AssistantModal.mdx +2 -3
- package/.docs/raw/docs/legacy/styled/Decomposition.mdx +6 -5
- package/.docs/raw/docs/legacy/styled/Markdown.mdx +2 -3
- package/.docs/raw/docs/legacy/styled/Thread.mdx +2 -3
- package/.docs/raw/docs/react-compatibility.mdx +2 -5
- package/.docs/raw/docs/runtimes/ai-sdk/use-chat.mdx +3 -4
- package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +3 -6
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +2 -3
- package/.docs/raw/docs/runtimes/custom/local.mdx +11 -41
- package/.docs/raw/docs/runtimes/data-stream.mdx +15 -11
- package/.docs/raw/docs/runtimes/langgraph/index.mdx +3 -3
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +1 -1
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +2 -3
- package/.docs/raw/docs/runtimes/langserve.mdx +2 -3
- package/.docs/raw/docs/runtimes/mastra/full-stack-integration.mdx +2 -3
- package/.docs/raw/docs/runtimes/mastra/separate-server-integration.mdx +2 -3
- package/.docs/raw/docs/ui/AssistantModal.mdx +3 -25
- package/.docs/raw/docs/ui/AssistantSidebar.mdx +2 -24
- package/.docs/raw/docs/ui/Attachment.mdx +3 -25
- package/.docs/raw/docs/ui/Markdown.mdx +2 -24
- package/.docs/raw/docs/ui/Mermaid.mdx +2 -24
- package/.docs/raw/docs/ui/Reasoning.mdx +2 -24
- package/.docs/raw/docs/ui/Scrollbar.mdx +4 -6
- package/.docs/raw/docs/ui/SyntaxHighlighting.mdx +3 -47
- package/.docs/raw/docs/ui/Thread.mdx +38 -53
- package/.docs/raw/docs/ui/ThreadList.mdx +4 -47
- package/.docs/raw/docs/ui/ToolFallback.mdx +2 -24
- package/package.json +6 -7
|
@@ -82,10 +82,10 @@ export default function Home() {
|
|
|
82
82
|
<div className="min-h-screen bg-gradient-to-br from-gray-50 to-gray-100 p-8 dark:from-gray-900 dark:to-gray-800">
|
|
83
83
|
<div className="mx-auto max-w-4xl">
|
|
84
84
|
<div className="mb-8">
|
|
85
|
-
<h1 className="mb-2
|
|
85
|
+
<h1 className="mb-2 font-bold text-4xl text-gray-900 dark:text-white">
|
|
86
86
|
@assistant-ui/store Example
|
|
87
87
|
</h1>
|
|
88
|
-
<p className="text-
|
|
88
|
+
<p className="text-gray-600 text-lg dark:text-gray-400">
|
|
89
89
|
Demonstrating tap-based state management with scopes, lists, and
|
|
90
90
|
providers
|
|
91
91
|
</p>
|
|
@@ -104,57 +104,59 @@ export default function Home() {
|
|
|
104
104
|
```tsx
|
|
105
105
|
"use client";
|
|
106
106
|
|
|
107
|
+
import { useState } from "react";
|
|
107
108
|
import {
|
|
108
109
|
useAssistantClient,
|
|
109
110
|
AssistantProvider,
|
|
110
111
|
useAssistantState,
|
|
112
|
+
useAssistantEvent,
|
|
111
113
|
} from "@assistant-ui/store";
|
|
112
114
|
import { FooList, FooListResource } from "./store/foo-store";
|
|
113
115
|
|
|
114
|
-
import "./store/foo-scope"; // Register the fooList scope (demonstrates scope registry)
|
|
115
|
-
|
|
116
116
|
/**
|
|
117
117
|
* Single Foo component - displays and allows editing a single foo
|
|
118
118
|
*/
|
|
119
119
|
const Foo = () => {
|
|
120
120
|
const aui = useAssistantClient();
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
121
|
+
const fooId = useAssistantState(({ foo }) => foo.id);
|
|
122
|
+
const fooBar = useAssistantState(({ foo }) => foo.bar);
|
|
123
|
+
|
|
124
|
+
// Each foo logs its own events - only receives events from THIS foo instance
|
|
125
|
+
useAssistantEvent("foo.updated", (payload) => {
|
|
126
|
+
console.log(`[${fooId}] Updated to: ${payload.newValue}`);
|
|
124
127
|
});
|
|
125
128
|
|
|
126
129
|
const handleUpdate = () => {
|
|
127
130
|
aui.foo().updateBar(`Updated at ${new Date().toLocaleTimeString()}`);
|
|
128
|
-
console.log("Foo state", aui.foo().getState(), fooState);
|
|
129
131
|
};
|
|
130
132
|
|
|
131
133
|
return (
|
|
132
134
|
<div className="rounded-lg border border-gray-200 bg-white p-6 shadow-md transition-shadow hover:shadow-lg dark:border-gray-700 dark:bg-gray-800">
|
|
133
135
|
<div className="space-y-3">
|
|
134
136
|
<div className="flex items-center gap-2">
|
|
135
|
-
<span className="
|
|
137
|
+
<span className="font-semibold text-gray-500 text-sm dark:text-gray-400">
|
|
136
138
|
ID:
|
|
137
139
|
</span>
|
|
138
|
-
<span className="font-mono text-
|
|
139
|
-
{
|
|
140
|
+
<span className="font-mono text-gray-900 text-sm dark:text-white">
|
|
141
|
+
{fooId}
|
|
140
142
|
</span>
|
|
141
143
|
</div>
|
|
142
144
|
<div className="flex items-center gap-2">
|
|
143
|
-
<span className="
|
|
145
|
+
<span className="font-semibold text-gray-500 text-sm dark:text-gray-400">
|
|
144
146
|
Value:
|
|
145
147
|
</span>
|
|
146
|
-
<span className="text-gray-900 dark:text-white">{
|
|
148
|
+
<span className="text-gray-900 dark:text-white">{fooBar}</span>
|
|
147
149
|
</div>
|
|
148
150
|
<div className="mt-2 flex gap-2">
|
|
149
151
|
<button
|
|
150
152
|
onClick={handleUpdate}
|
|
151
|
-
className="flex-1 rounded-md bg-blue-600 px-4 py-2 font-medium text-white transition-colors hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2
|
|
153
|
+
className="flex-1 rounded-md bg-blue-600 px-4 py-2 font-medium text-white transition-colors hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800"
|
|
152
154
|
>
|
|
153
155
|
Update
|
|
154
156
|
</button>
|
|
155
157
|
<button
|
|
156
158
|
onClick={() => aui.foo().remove()}
|
|
157
|
-
className="rounded-md bg-red-600 px-4 py-2 font-medium text-white transition-colors hover:bg-red-700 focus:ring-2 focus:ring-red-500 focus:ring-offset-2
|
|
159
|
+
className="rounded-md bg-red-600 px-4 py-2 font-medium text-white transition-colors hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800"
|
|
158
160
|
>
|
|
159
161
|
Delete
|
|
160
162
|
</button>
|
|
@@ -178,13 +180,73 @@ const AddFooButton = () => {
|
|
|
178
180
|
return (
|
|
179
181
|
<button
|
|
180
182
|
onClick={() => aui.fooList().addFoo()}
|
|
181
|
-
className="rounded-md bg-green-600 px-4 py-2 font-medium text-white transition-colors hover:bg-green-700 focus:ring-2 focus:ring-green-500 focus:ring-offset-2
|
|
183
|
+
className="rounded-md bg-green-600 px-4 py-2 font-medium text-white transition-colors hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800"
|
|
182
184
|
>
|
|
183
185
|
Add New
|
|
184
186
|
</button>
|
|
185
187
|
);
|
|
186
188
|
};
|
|
187
189
|
|
|
190
|
+
type EventLogEntry = {
|
|
191
|
+
id: number;
|
|
192
|
+
event: string;
|
|
193
|
+
payload: unknown;
|
|
194
|
+
timestamp: Date;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
let idCounter = 0;
|
|
198
|
+
/**
|
|
199
|
+
* EventLog component - demonstrates event subscription
|
|
200
|
+
*/
|
|
201
|
+
const EventLog = () => {
|
|
202
|
+
const [logs, setLogs] = useState<EventLogEntry[]>([]);
|
|
203
|
+
|
|
204
|
+
// Subscribe to all events using the wildcard selector
|
|
205
|
+
useAssistantEvent("*", (data) => {
|
|
206
|
+
setLogs((prev) => [
|
|
207
|
+
{
|
|
208
|
+
id: ++idCounter,
|
|
209
|
+
event: data.event,
|
|
210
|
+
payload: data.payload,
|
|
211
|
+
timestamp: new Date(),
|
|
212
|
+
},
|
|
213
|
+
...prev.slice(0, 9), // Keep last 10 entries
|
|
214
|
+
]);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
return (
|
|
218
|
+
<div className="rounded-lg border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-700 dark:bg-gray-800">
|
|
219
|
+
<h3 className="mb-3 font-semibold text-gray-900 dark:text-white">
|
|
220
|
+
Event Log
|
|
221
|
+
</h3>
|
|
222
|
+
<div className="max-h-48 space-y-2 overflow-y-auto">
|
|
223
|
+
{logs.length === 0 ? (
|
|
224
|
+
<p className="text-gray-500 text-sm dark:text-gray-400">
|
|
225
|
+
No events yet. Try updating or deleting a foo.
|
|
226
|
+
</p>
|
|
227
|
+
) : (
|
|
228
|
+
logs.map((log) => (
|
|
229
|
+
<div
|
|
230
|
+
key={log.id}
|
|
231
|
+
className="rounded border border-gray-100 bg-gray-50 p-2 font-mono text-xs dark:border-gray-600 dark:bg-gray-700"
|
|
232
|
+
>
|
|
233
|
+
<span className="font-semibold text-blue-600 dark:text-blue-400">
|
|
234
|
+
{log.event}
|
|
235
|
+
</span>
|
|
236
|
+
<span className="ml-2 text-gray-600 dark:text-gray-300">
|
|
237
|
+
{JSON.stringify(log.payload)}
|
|
238
|
+
</span>
|
|
239
|
+
<span className="ml-2 text-gray-400 dark:text-gray-500">
|
|
240
|
+
{log.timestamp.toLocaleTimeString()}
|
|
241
|
+
</span>
|
|
242
|
+
</div>
|
|
243
|
+
))
|
|
244
|
+
)}
|
|
245
|
+
</div>
|
|
246
|
+
</div>
|
|
247
|
+
);
|
|
248
|
+
};
|
|
249
|
+
|
|
188
250
|
/**
|
|
189
251
|
* Example App - demonstrates the store with styled components
|
|
190
252
|
*
|
|
@@ -192,27 +254,28 @@ const AddFooButton = () => {
|
|
|
192
254
|
* but we're explicitly passing it here for clarity in the example.
|
|
193
255
|
*/
|
|
194
256
|
export const ExampleApp = () => {
|
|
195
|
-
const
|
|
196
|
-
fooList: FooListResource(),
|
|
257
|
+
const aui = useAssistantClient({
|
|
258
|
+
fooList: FooListResource({ initialValues: true }),
|
|
197
259
|
});
|
|
198
260
|
|
|
199
261
|
return (
|
|
200
|
-
<AssistantProvider client={
|
|
262
|
+
<AssistantProvider client={aui}>
|
|
201
263
|
<div className="space-y-6">
|
|
202
264
|
<div className="rounded-lg border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-700 dark:bg-gray-800">
|
|
203
265
|
<div className="flex items-center justify-between">
|
|
204
|
-
<h2 className="
|
|
266
|
+
<h2 className="font-semibold text-gray-900 text-xl dark:text-white">
|
|
205
267
|
Foo List <FooListLength />
|
|
206
268
|
</h2>
|
|
207
269
|
<AddFooButton />
|
|
208
270
|
</div>
|
|
209
|
-
<p className="mt-1 text-
|
|
271
|
+
<p className="mt-1 text-gray-600 text-sm dark:text-gray-400">
|
|
210
272
|
Each item is rendered in its own FooProvider with scoped access
|
|
211
273
|
</p>
|
|
212
274
|
</div>
|
|
213
275
|
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
|
214
276
|
<FooList components={{ Foo }} />
|
|
215
277
|
</div>
|
|
278
|
+
<EventLog />
|
|
216
279
|
</div>
|
|
217
280
|
</AssistantProvider>
|
|
218
281
|
);
|
|
@@ -223,46 +286,48 @@ export const ExampleApp = () => {
|
|
|
223
286
|
## lib/store/foo-scope.ts
|
|
224
287
|
|
|
225
288
|
```typescript
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
289
|
+
type FooState = { id: string; bar: string };
|
|
290
|
+
type FooMethods = {
|
|
291
|
+
getState: () => FooState;
|
|
292
|
+
updateBar: (newBar: string) => void;
|
|
293
|
+
remove: () => void;
|
|
294
|
+
};
|
|
295
|
+
type FooMeta = {
|
|
296
|
+
source: "fooList";
|
|
297
|
+
query: { index: number } | { key: string };
|
|
298
|
+
};
|
|
299
|
+
type FooEvents = {
|
|
300
|
+
"foo.updated": { id: string; newValue: string };
|
|
301
|
+
"foo.removed": { id: string };
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
type FooListState = { foos: FooState[] };
|
|
305
|
+
type FooListMethods = {
|
|
306
|
+
getState: () => FooListState;
|
|
307
|
+
foo: (lookup: FooMeta["query"]) => FooMethods;
|
|
308
|
+
addFoo: () => void;
|
|
309
|
+
};
|
|
310
|
+
type FooListEvents = {
|
|
311
|
+
"fooList.added": { id: string };
|
|
312
|
+
};
|
|
231
313
|
|
|
232
|
-
/**
|
|
233
|
-
* Define scopes via module augmentation
|
|
234
|
-
* Implement the scope definition raw without importing ScopeDefinition
|
|
235
|
-
*/
|
|
236
314
|
declare module "@assistant-ui/store" {
|
|
237
|
-
interface
|
|
315
|
+
interface ClientRegistry {
|
|
238
316
|
foo: {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
};
|
|
244
|
-
source: "fooList";
|
|
245
|
-
query: { index: number } | { id: string };
|
|
317
|
+
state: FooState;
|
|
318
|
+
methods: FooMethods;
|
|
319
|
+
meta: FooMeta;
|
|
320
|
+
events: FooEvents;
|
|
246
321
|
};
|
|
247
322
|
fooList: {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
lookup: { index: number } | { id: string },
|
|
252
|
-
) => AssistantScopeRegistry["foo"]["value"];
|
|
253
|
-
addFoo: (id?: string) => void;
|
|
254
|
-
};
|
|
255
|
-
source: "root";
|
|
256
|
-
query: Record<string, never>;
|
|
323
|
+
state: FooListState;
|
|
324
|
+
methods: FooListMethods;
|
|
325
|
+
events: FooListEvents;
|
|
257
326
|
};
|
|
258
327
|
}
|
|
259
328
|
}
|
|
260
329
|
|
|
261
|
-
|
|
262
|
-
registerAssistantScope({
|
|
263
|
-
name: "fooList",
|
|
264
|
-
defaultInitialize: { error: "FooList is not configured" },
|
|
265
|
-
});
|
|
330
|
+
export default {};
|
|
266
331
|
|
|
267
332
|
```
|
|
268
333
|
|
|
@@ -271,77 +336,88 @@ registerAssistantScope({
|
|
|
271
336
|
```tsx
|
|
272
337
|
"use client";
|
|
273
338
|
|
|
339
|
+
import "./foo-scope";
|
|
340
|
+
|
|
274
341
|
import React from "react";
|
|
275
|
-
import { resource, tapState } from "@assistant-ui/tap";
|
|
342
|
+
import { resource, tapMemo, tapState } from "@assistant-ui/tap";
|
|
276
343
|
import {
|
|
277
344
|
useAssistantClient,
|
|
278
345
|
AssistantProvider,
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
DerivedScope,
|
|
346
|
+
tapClientList,
|
|
347
|
+
Derived,
|
|
282
348
|
useAssistantState,
|
|
349
|
+
tapAssistantEmit,
|
|
350
|
+
type ClientOutput,
|
|
283
351
|
} from "@assistant-ui/store";
|
|
284
352
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
* Manages the state and actions for a single foo item
|
|
288
|
-
*/
|
|
353
|
+
type FooData = { id: string; bar: string };
|
|
354
|
+
|
|
289
355
|
export const FooItemResource = resource(
|
|
290
356
|
({
|
|
291
|
-
|
|
357
|
+
getInitialData,
|
|
292
358
|
remove,
|
|
293
|
-
}: {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
const [state, setState] = tapState<{ id: string; bar: string }>({
|
|
298
|
-
id,
|
|
299
|
-
bar: initialBar,
|
|
300
|
-
});
|
|
359
|
+
}: tapClientList.ResourceProps<FooData>): ClientOutput<"foo"> => {
|
|
360
|
+
const emit = tapAssistantEmit();
|
|
361
|
+
|
|
362
|
+
const [state, setState] = tapState<FooData>(getInitialData);
|
|
301
363
|
|
|
302
364
|
const updateBar = (newBar: string) => {
|
|
303
365
|
setState({ ...state, bar: newBar });
|
|
366
|
+
emit("foo.updated", { id: state.id, newValue: newBar });
|
|
304
367
|
};
|
|
305
368
|
|
|
306
|
-
|
|
307
|
-
{
|
|
369
|
+
const handleRemove = () => {
|
|
370
|
+
emit("foo.removed", { id: state.id });
|
|
371
|
+
remove();
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
return {
|
|
375
|
+
state,
|
|
376
|
+
methods: {
|
|
308
377
|
getState: () => state,
|
|
309
378
|
updateBar,
|
|
310
|
-
remove,
|
|
379
|
+
remove: handleRemove,
|
|
311
380
|
},
|
|
312
|
-
|
|
313
|
-
);
|
|
381
|
+
};
|
|
314
382
|
},
|
|
315
383
|
);
|
|
316
384
|
|
|
317
|
-
/**
|
|
318
|
-
* FooList resource implementation
|
|
319
|
-
* Manages a list of foos using tapStoreList
|
|
320
|
-
*/
|
|
321
385
|
let counter = 3;
|
|
322
|
-
export const FooListResource = resource(
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
386
|
+
export const FooListResource = resource(
|
|
387
|
+
({ initialValues }: { initialValues: boolean }): ClientOutput<"fooList"> => {
|
|
388
|
+
const emit = tapAssistantEmit();
|
|
389
|
+
|
|
390
|
+
const foos = tapClientList({
|
|
391
|
+
initialValues: initialValues
|
|
392
|
+
? [
|
|
393
|
+
{ id: "foo-1", bar: "First Foo" },
|
|
394
|
+
{ id: "foo-2", bar: "Second Foo" },
|
|
395
|
+
{ id: "foo-3", bar: "Third Foo" },
|
|
396
|
+
]
|
|
397
|
+
: [],
|
|
398
|
+
getKey: (foo) => foo.id,
|
|
399
|
+
resource: FooItemResource,
|
|
400
|
+
});
|
|
334
401
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
402
|
+
const addFoo = () => {
|
|
403
|
+
const id = `foo-${++counter}`;
|
|
404
|
+
foos.add({ id: id, bar: `New Foo` });
|
|
405
|
+
emit("fooList.added", { id: id });
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
const state = tapMemo(() => ({ foos: foos.state }), [foos.state]);
|
|
409
|
+
|
|
410
|
+
return {
|
|
411
|
+
state,
|
|
412
|
+
methods: {
|
|
413
|
+
getState: () => state,
|
|
414
|
+
foo: foos.get,
|
|
415
|
+
addFoo,
|
|
416
|
+
},
|
|
417
|
+
};
|
|
418
|
+
},
|
|
419
|
+
);
|
|
341
420
|
|
|
342
|
-
/**
|
|
343
|
-
* FooProvider - Provides foo scope for a specific index
|
|
344
|
-
*/
|
|
345
421
|
export const FooProvider = ({
|
|
346
422
|
index,
|
|
347
423
|
children,
|
|
@@ -349,11 +425,10 @@ export const FooProvider = ({
|
|
|
349
425
|
index: number;
|
|
350
426
|
children: React.ReactNode;
|
|
351
427
|
}) => {
|
|
352
|
-
// Create a derived client with the foo scope at the specified index
|
|
353
428
|
const aui = useAssistantClient({
|
|
354
|
-
foo:
|
|
429
|
+
foo: Derived({
|
|
355
430
|
source: "fooList",
|
|
356
|
-
query: { index },
|
|
431
|
+
query: { index: index },
|
|
357
432
|
get: (aui) => aui.fooList().foo({ index }),
|
|
358
433
|
}),
|
|
359
434
|
});
|
|
@@ -361,10 +436,6 @@ export const FooProvider = ({
|
|
|
361
436
|
return <AssistantProvider client={aui}>{children}</AssistantProvider>;
|
|
362
437
|
};
|
|
363
438
|
|
|
364
|
-
/**
|
|
365
|
-
* FooList component - minimal mapping component
|
|
366
|
-
* Maps over the list and renders each item in a FooProvider
|
|
367
|
-
*/
|
|
368
439
|
export const FooList = ({
|
|
369
440
|
components,
|
|
370
441
|
}: {
|
|
@@ -408,24 +479,21 @@ export default nextConfig;
|
|
|
408
479
|
"scripts": {
|
|
409
480
|
"dev": "next dev",
|
|
410
481
|
"build": "next build",
|
|
411
|
-
"start": "next start"
|
|
412
|
-
"lint": "eslint"
|
|
482
|
+
"start": "next start"
|
|
413
483
|
},
|
|
414
484
|
"dependencies": {
|
|
415
485
|
"@assistant-ui/store": "workspace:*",
|
|
416
486
|
"@assistant-ui/tap": "workspace:*",
|
|
417
|
-
"next": "16.0.
|
|
418
|
-
"react": "19.2.
|
|
419
|
-
"react-dom": "19.2.
|
|
487
|
+
"next": "16.0.10",
|
|
488
|
+
"react": "19.2.3",
|
|
489
|
+
"react-dom": "19.2.3"
|
|
420
490
|
},
|
|
421
491
|
"devDependencies": {
|
|
422
492
|
"@assistant-ui/x-buildutils": "workspace:*",
|
|
423
493
|
"@tailwindcss/postcss": "^4",
|
|
424
|
-
"@types/node": "^
|
|
494
|
+
"@types/node": "^25",
|
|
425
495
|
"@types/react": "19.2.7",
|
|
426
496
|
"@types/react-dom": "19.2.3",
|
|
427
|
-
"eslint": "^9",
|
|
428
|
-
"eslint-config-next": "16.0.4",
|
|
429
497
|
"tailwindcss": "^4",
|
|
430
498
|
"typescript": "^5"
|
|
431
499
|
}
|
|
@@ -442,9 +510,10 @@ This is a Next.js application demonstrating the `@assistant-ui/store` package.
|
|
|
442
510
|
|
|
443
511
|
## Features Demonstrated
|
|
444
512
|
|
|
445
|
-
- **
|
|
446
|
-
- **
|
|
447
|
-
- **
|
|
513
|
+
- **Client Registry**: Module augmentation for type-safe client definitions
|
|
514
|
+
- **tapClientList**: Managing lists with index and key lookup
|
|
515
|
+
- **tapAssistantEmit**: Emitting and subscribing to scoped events
|
|
516
|
+
- **Derived**: Creating derived client scopes from parent resources
|
|
448
517
|
- **Provider Pattern**: Scoped access to list items via FooProvider
|
|
449
518
|
- **Component Composition**: Render props pattern with components prop
|
|
450
519
|
|
|
@@ -463,33 +532,42 @@ Open [http://localhost:3000](http://localhost:3000) to see the example.
|
|
|
463
532
|
|
|
464
533
|
## Project Structure
|
|
465
534
|
|
|
466
|
-
- `lib/store/foo-
|
|
467
|
-
-
|
|
535
|
+
- `lib/store/foo-scope.ts` - Type definitions via module augmentation:
|
|
536
|
+
- Client registry definitions (foo, fooList)
|
|
537
|
+
- State, methods, meta, and events types
|
|
538
|
+
- `lib/store/foo-store.tsx` - Store implementation with:
|
|
468
539
|
- Resource implementations (FooItemResource, FooListResource)
|
|
469
540
|
- Provider component (FooProvider)
|
|
470
|
-
-
|
|
541
|
+
- FooList mapping component
|
|
471
542
|
- `lib/example-app.tsx` - Example app with styled components:
|
|
472
|
-
-
|
|
543
|
+
- Foo component with update/delete actions
|
|
544
|
+
- EventLog component demonstrating event subscriptions
|
|
473
545
|
- ExampleApp with layout and styling
|
|
474
546
|
- `app/page.tsx` - Main page that renders the ExampleApp
|
|
475
547
|
|
|
476
548
|
## Key Concepts
|
|
477
549
|
|
|
478
|
-
###
|
|
550
|
+
### Client Registry
|
|
479
551
|
|
|
480
552
|
```typescript
|
|
481
553
|
declare module "@assistant-ui/store" {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
554
|
+
interface ClientRegistry {
|
|
555
|
+
foo: {
|
|
556
|
+
state: { id: string; bar: string };
|
|
557
|
+
methods: {
|
|
558
|
+
getState: () => FooState;
|
|
559
|
+
updateBar: (newBar: string) => void;
|
|
560
|
+
remove: () => void;
|
|
561
|
+
};
|
|
562
|
+
meta: {
|
|
489
563
|
source: "fooList";
|
|
490
|
-
query: { index: number } | {
|
|
564
|
+
query: { index: number } | { key: string };
|
|
491
565
|
};
|
|
492
|
-
|
|
566
|
+
events: {
|
|
567
|
+
"foo.updated": { id: string; newValue: string };
|
|
568
|
+
"foo.removed": { id: string };
|
|
569
|
+
};
|
|
570
|
+
};
|
|
493
571
|
}
|
|
494
572
|
}
|
|
495
573
|
```
|
|
@@ -497,33 +575,57 @@ declare module "@assistant-ui/store" {
|
|
|
497
575
|
### Resource Implementation
|
|
498
576
|
|
|
499
577
|
```typescript
|
|
500
|
-
const FooListResource = resource(
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
578
|
+
const FooListResource = resource(
|
|
579
|
+
({ initialValues }): ClientOutput<"fooList"> => {
|
|
580
|
+
const emit = tapAssistantEmit();
|
|
581
|
+
|
|
582
|
+
const foos = tapClientList({
|
|
583
|
+
initialValues: initialValues ? [/* ... */] : [],
|
|
584
|
+
getKey: (foo) => foo.id,
|
|
585
|
+
resource: FooItemResource,
|
|
586
|
+
});
|
|
507
587
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
588
|
+
return {
|
|
589
|
+
state: { foos: foos.state },
|
|
590
|
+
methods: {
|
|
591
|
+
getState: () => state,
|
|
592
|
+
foo: foos.get,
|
|
593
|
+
addFoo: () => { /* ... */ },
|
|
594
|
+
},
|
|
595
|
+
};
|
|
596
|
+
},
|
|
597
|
+
);
|
|
513
598
|
```
|
|
514
599
|
|
|
515
|
-
### Provider Pattern
|
|
600
|
+
### Provider Pattern with Derived
|
|
516
601
|
|
|
517
602
|
```typescript
|
|
518
603
|
const FooProvider = ({ index, children }) => {
|
|
519
|
-
const parentAui = useAssistantClient();
|
|
520
604
|
const aui = useAssistantClient({
|
|
521
|
-
foo:
|
|
605
|
+
foo: Derived({
|
|
606
|
+
source: "fooList",
|
|
607
|
+
query: { index },
|
|
608
|
+
get: (aui) => aui.fooList().foo({ index }),
|
|
609
|
+
}),
|
|
522
610
|
});
|
|
523
|
-
return <
|
|
611
|
+
return <AssistantProvider client={aui}>{children}</AssistantProvider>;
|
|
524
612
|
};
|
|
525
613
|
```
|
|
526
614
|
|
|
615
|
+
### Event Subscriptions
|
|
616
|
+
|
|
617
|
+
```typescript
|
|
618
|
+
// Subscribe to specific events within a scope
|
|
619
|
+
useAssistantEvent("foo.updated", (payload) => {
|
|
620
|
+
console.log(`Updated to: ${payload.newValue}`);
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
// Subscribe to all events using wildcard
|
|
624
|
+
useAssistantEvent("*", (data) => {
|
|
625
|
+
console.log(data.event, data.payload);
|
|
626
|
+
});
|
|
627
|
+
```
|
|
628
|
+
|
|
527
629
|
## Learn More
|
|
528
630
|
|
|
529
631
|
- [@assistant-ui/store Documentation](../store/README.md)
|