@mcp-web/core 0.1.0 → 0.1.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.
- package/dist/web.d.ts +1 -1
- package/dist/web.js +1 -1
- package/package.json +9 -4
- package/dist/expanded-schema-tools/generate-fixed-shape-tools.d.ts +0 -8
- package/dist/expanded-schema-tools/generate-fixed-shape-tools.d.ts.map +0 -1
- package/dist/expanded-schema-tools/generate-fixed-shape-tools.js +0 -53
- package/dist/expanded-schema-tools/generate-fixed-shape-tools.test.d.ts +0 -2
- package/dist/expanded-schema-tools/generate-fixed-shape-tools.test.d.ts.map +0 -1
- package/dist/expanded-schema-tools/generate-fixed-shape-tools.test.js +0 -331
- package/dist/expanded-schema-tools/index.d.ts +0 -4
- package/dist/expanded-schema-tools/index.d.ts.map +0 -1
- package/dist/expanded-schema-tools/index.js +0 -2
- package/dist/expanded-schema-tools/integration.test.d.ts +0 -2
- package/dist/expanded-schema-tools/integration.test.d.ts.map +0 -1
- package/dist/expanded-schema-tools/integration.test.js +0 -599
- package/dist/expanded-schema-tools/schema-analysis.d.ts +0 -18
- package/dist/expanded-schema-tools/schema-analysis.d.ts.map +0 -1
- package/dist/expanded-schema-tools/schema-analysis.js +0 -142
- package/dist/expanded-schema-tools/schema-analysis.test.d.ts +0 -2
- package/dist/expanded-schema-tools/schema-analysis.test.d.ts.map +0 -1
- package/dist/expanded-schema-tools/schema-analysis.test.js +0 -314
- package/dist/expanded-schema-tools/schema-helpers.d.ts +0 -69
- package/dist/expanded-schema-tools/schema-helpers.d.ts.map +0 -1
- package/dist/expanded-schema-tools/schema-helpers.js +0 -139
- package/dist/expanded-schema-tools/schema-helpers.test.d.ts +0 -2
- package/dist/expanded-schema-tools/schema-helpers.test.d.ts.map +0 -1
- package/dist/expanded-schema-tools/schema-helpers.test.js +0 -223
- package/dist/expanded-schema-tools/tool-generator.d.ts +0 -10
- package/dist/expanded-schema-tools/tool-generator.d.ts.map +0 -1
- package/dist/expanded-schema-tools/tool-generator.js +0 -430
- package/dist/expanded-schema-tools/tool-generator.test.d.ts +0 -2
- package/dist/expanded-schema-tools/tool-generator.test.d.ts.map +0 -1
- package/dist/expanded-schema-tools/tool-generator.test.js +0 -689
- package/dist/expanded-schema-tools/types.d.ts +0 -26
- package/dist/expanded-schema-tools/types.d.ts.map +0 -1
- package/dist/expanded-schema-tools/types.js +0 -1
- package/dist/expanded-schema-tools/utils.d.ts +0 -16
- package/dist/expanded-schema-tools/utils.d.ts.map +0 -1
- package/dist/expanded-schema-tools/utils.js +0 -35
- package/dist/expanded-schema-tools/utils.test.d.ts +0 -2
- package/dist/expanded-schema-tools/utils.test.d.ts.map +0 -1
- package/dist/expanded-schema-tools/utils.test.js +0 -169
- package/dist/schema-helpers.d.ts +0 -69
- package/dist/schema-helpers.d.ts.map +0 -1
- package/dist/schema-helpers.js +0 -139
- package/dist/zod-to-tools.d.ts +0 -49
- package/dist/zod-to-tools.d.ts.map +0 -1
- package/dist/zod-to-tools.js +0 -623
|
@@ -1,599 +0,0 @@
|
|
|
1
|
-
import { test, expect } from 'bun:test';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import { id, system } from './schema-helpers.js';
|
|
4
|
-
import { generateToolsForSchema } from './tool-generator.js';
|
|
5
|
-
// Mock MCPWeb instance
|
|
6
|
-
const mockMCPWeb = {};
|
|
7
|
-
// ============================================================================
|
|
8
|
-
// Todo App Scenario (from documentation)
|
|
9
|
-
// ============================================================================
|
|
10
|
-
// Schema definitions from docs/expanded-state-tools.md
|
|
11
|
-
const TodoSchema = z.object({
|
|
12
|
-
id: id(system(z.string().default(() => crypto.randomUUID()))),
|
|
13
|
-
projectId: z.string().nullable().default(null),
|
|
14
|
-
value: z.string(),
|
|
15
|
-
created_at: system(z.number().default(() => Date.now())),
|
|
16
|
-
updated_at: system(z.number().default(() => Date.now())),
|
|
17
|
-
completed_at: z.number().nullable().default(null),
|
|
18
|
-
priority: z.number().min(1).max(5).default(3),
|
|
19
|
-
tags: z.array(z.string()).default([]),
|
|
20
|
-
});
|
|
21
|
-
const ProjectSchema = z.object({
|
|
22
|
-
id: id(system(z.string().default(() => crypto.randomUUID()))),
|
|
23
|
-
title: z.string(),
|
|
24
|
-
description: z.string().nullable().default(null),
|
|
25
|
-
color: z.string().nullable().default(null),
|
|
26
|
-
created_at: system(z.number().default(() => Date.now())),
|
|
27
|
-
updated_at: system(z.number().default(() => Date.now())),
|
|
28
|
-
});
|
|
29
|
-
const AppSchema = z.object({
|
|
30
|
-
todos: z.array(TodoSchema),
|
|
31
|
-
projects: z.record(z.string(), ProjectSchema),
|
|
32
|
-
sortBy: z.enum(['created_at', 'completed_at', 'priority']),
|
|
33
|
-
sortOrder: z.enum(['asc', 'desc']),
|
|
34
|
-
showCompleted: z.boolean(),
|
|
35
|
-
theme: z.enum(['system', 'light', 'dark']),
|
|
36
|
-
});
|
|
37
|
-
test('integration - todo app generates 13 tools as documented', () => {
|
|
38
|
-
let state = {
|
|
39
|
-
todos: [],
|
|
40
|
-
projects: {},
|
|
41
|
-
sortBy: 'created_at',
|
|
42
|
-
sortOrder: 'asc',
|
|
43
|
-
showCompleted: true,
|
|
44
|
-
theme: 'system',
|
|
45
|
-
};
|
|
46
|
-
const result = generateToolsForSchema({
|
|
47
|
-
name: 'app',
|
|
48
|
-
description: 'todo app',
|
|
49
|
-
get: () => state,
|
|
50
|
-
set: (value) => {
|
|
51
|
-
state = value;
|
|
52
|
-
},
|
|
53
|
-
schema: AppSchema,
|
|
54
|
-
}, mockMCPWeb);
|
|
55
|
-
// Root (get, set) = 2
|
|
56
|
-
// todos array (get, add, set, delete) = 4
|
|
57
|
-
// projects record (get, set, delete) = 3
|
|
58
|
-
// Total = 9
|
|
59
|
-
// Note: Nested array tools (todos.tags) are not generated in current implementation
|
|
60
|
-
expect(result.tools).toHaveLength(9);
|
|
61
|
-
});
|
|
62
|
-
test('integration - todo app has expected tool names', () => {
|
|
63
|
-
let state = {
|
|
64
|
-
todos: [],
|
|
65
|
-
projects: {},
|
|
66
|
-
sortBy: 'created_at',
|
|
67
|
-
sortOrder: 'asc',
|
|
68
|
-
showCompleted: true,
|
|
69
|
-
theme: 'system',
|
|
70
|
-
};
|
|
71
|
-
const result = generateToolsForSchema({
|
|
72
|
-
name: 'app',
|
|
73
|
-
description: 'todo app',
|
|
74
|
-
get: () => state,
|
|
75
|
-
set: (value) => {
|
|
76
|
-
state = value;
|
|
77
|
-
},
|
|
78
|
-
schema: AppSchema,
|
|
79
|
-
}, mockMCPWeb);
|
|
80
|
-
const toolNames = result.tools.map((t) => t.name);
|
|
81
|
-
// Root tools
|
|
82
|
-
expect(toolNames).toContain('get_app');
|
|
83
|
-
expect(toolNames).toContain('set_app');
|
|
84
|
-
// Todos array tools
|
|
85
|
-
expect(toolNames).toContain('get_app_todos');
|
|
86
|
-
expect(toolNames).toContain('add_app_todos');
|
|
87
|
-
expect(toolNames).toContain('set_app_todos');
|
|
88
|
-
expect(toolNames).toContain('delete_app_todos');
|
|
89
|
-
// Projects record tools
|
|
90
|
-
expect(toolNames).toContain('get_app_projects');
|
|
91
|
-
expect(toolNames).toContain('set_app_projects');
|
|
92
|
-
expect(toolNames).toContain('delete_app_projects');
|
|
93
|
-
// Note: Nested array tools (todos.tags) are not generated in current implementation
|
|
94
|
-
expect(toolNames).not.toContain('get_app_todos_tags');
|
|
95
|
-
});
|
|
96
|
-
test('integration - add todo returns complete object with generated ID', async () => {
|
|
97
|
-
let state = {
|
|
98
|
-
todos: [],
|
|
99
|
-
projects: {},
|
|
100
|
-
sortBy: 'created_at',
|
|
101
|
-
sortOrder: 'asc',
|
|
102
|
-
showCompleted: true,
|
|
103
|
-
theme: 'system',
|
|
104
|
-
};
|
|
105
|
-
const result = generateToolsForSchema({
|
|
106
|
-
name: 'app',
|
|
107
|
-
description: 'todo app',
|
|
108
|
-
get: () => state,
|
|
109
|
-
set: (value) => {
|
|
110
|
-
state = value;
|
|
111
|
-
},
|
|
112
|
-
schema: AppSchema,
|
|
113
|
-
}, mockMCPWeb);
|
|
114
|
-
const addTodo = result.tools.find((t) => t.name === 'add_app_todos');
|
|
115
|
-
if (!addTodo)
|
|
116
|
-
throw new Error('add_app_todos not found');
|
|
117
|
-
const response = (await addTodo.handler({
|
|
118
|
-
value: {
|
|
119
|
-
value: 'Buy milk',
|
|
120
|
-
priority: 2,
|
|
121
|
-
},
|
|
122
|
-
}));
|
|
123
|
-
expect(response.success).toBe(true);
|
|
124
|
-
expect(response.value.id).toBeDefined();
|
|
125
|
-
expect(response.value.value).toBe('Buy milk');
|
|
126
|
-
expect(response.value.priority).toBe(2);
|
|
127
|
-
expect(response.value.created_at).toBeDefined();
|
|
128
|
-
expect(response.value.updated_at).toBeDefined();
|
|
129
|
-
expect(response.value.completed_at).toBe(null);
|
|
130
|
-
expect(response.value.projectId).toBe(null);
|
|
131
|
-
// Verify state was updated
|
|
132
|
-
expect(state.todos).toHaveLength(1);
|
|
133
|
-
expect(state.todos[0].value).toBe('Buy milk');
|
|
134
|
-
});
|
|
135
|
-
test('integration - update todo by ID with partial update', async () => {
|
|
136
|
-
let state = {
|
|
137
|
-
todos: [
|
|
138
|
-
{
|
|
139
|
-
id: 'todo-1',
|
|
140
|
-
value: 'Buy milk',
|
|
141
|
-
priority: 3,
|
|
142
|
-
projectId: null,
|
|
143
|
-
created_at: 123456,
|
|
144
|
-
updated_at: 123456,
|
|
145
|
-
completed_at: null,
|
|
146
|
-
tags: [],
|
|
147
|
-
},
|
|
148
|
-
],
|
|
149
|
-
projects: {},
|
|
150
|
-
sortBy: 'created_at',
|
|
151
|
-
sortOrder: 'asc',
|
|
152
|
-
showCompleted: true,
|
|
153
|
-
theme: 'system',
|
|
154
|
-
};
|
|
155
|
-
const result = generateToolsForSchema({
|
|
156
|
-
name: 'app',
|
|
157
|
-
description: 'todo app',
|
|
158
|
-
get: () => state,
|
|
159
|
-
set: (value) => {
|
|
160
|
-
state = value;
|
|
161
|
-
},
|
|
162
|
-
schema: AppSchema,
|
|
163
|
-
}, mockMCPWeb);
|
|
164
|
-
const setTodo = result.tools.find((t) => t.name === 'set_app_todos');
|
|
165
|
-
if (!setTodo)
|
|
166
|
-
throw new Error('set_app_todos not found');
|
|
167
|
-
// Update only priority
|
|
168
|
-
await setTodo.handler({
|
|
169
|
-
id: 'todo-1',
|
|
170
|
-
value: { priority: 5 },
|
|
171
|
-
});
|
|
172
|
-
expect(state.todos[0].priority).toBe(5);
|
|
173
|
-
expect(state.todos[0].value).toBe('Buy milk'); // Unchanged
|
|
174
|
-
expect(state.todos[0].id).toBe('todo-1'); // Unchanged
|
|
175
|
-
});
|
|
176
|
-
test('integration - update todo with tags (since nested tools not implemented)', async () => {
|
|
177
|
-
let state = {
|
|
178
|
-
todos: [
|
|
179
|
-
{
|
|
180
|
-
id: 'todo-1',
|
|
181
|
-
value: 'Buy milk',
|
|
182
|
-
priority: 3,
|
|
183
|
-
projectId: null,
|
|
184
|
-
created_at: 123456,
|
|
185
|
-
updated_at: 123456,
|
|
186
|
-
completed_at: null,
|
|
187
|
-
tags: ['shopping'],
|
|
188
|
-
},
|
|
189
|
-
],
|
|
190
|
-
projects: {},
|
|
191
|
-
sortBy: 'created_at',
|
|
192
|
-
sortOrder: 'asc',
|
|
193
|
-
showCompleted: true,
|
|
194
|
-
theme: 'system',
|
|
195
|
-
};
|
|
196
|
-
const result = generateToolsForSchema({
|
|
197
|
-
name: 'app',
|
|
198
|
-
description: 'todo app',
|
|
199
|
-
get: () => state,
|
|
200
|
-
set: (value) => {
|
|
201
|
-
state = value;
|
|
202
|
-
},
|
|
203
|
-
schema: AppSchema,
|
|
204
|
-
}, mockMCPWeb);
|
|
205
|
-
const setTodo = result.tools.find((t) => t.name === 'set_app_todos');
|
|
206
|
-
if (!setTodo)
|
|
207
|
-
throw new Error('set_app_todos not found');
|
|
208
|
-
// Since nested array tools are not implemented, update tags via todo setter
|
|
209
|
-
await setTodo.handler({
|
|
210
|
-
id: 'todo-1',
|
|
211
|
-
value: { tags: ['shopping', 'urgent'] },
|
|
212
|
-
});
|
|
213
|
-
expect(state.todos[0].tags).toEqual(['shopping', 'urgent']);
|
|
214
|
-
});
|
|
215
|
-
test('integration - upsert project (record set)', async () => {
|
|
216
|
-
let state = {
|
|
217
|
-
todos: [],
|
|
218
|
-
projects: {},
|
|
219
|
-
sortBy: 'created_at',
|
|
220
|
-
sortOrder: 'asc',
|
|
221
|
-
showCompleted: true,
|
|
222
|
-
theme: 'system',
|
|
223
|
-
};
|
|
224
|
-
const result = generateToolsForSchema({
|
|
225
|
-
name: 'app',
|
|
226
|
-
description: 'todo app',
|
|
227
|
-
get: () => state,
|
|
228
|
-
set: (value) => {
|
|
229
|
-
state = value;
|
|
230
|
-
},
|
|
231
|
-
schema: AppSchema,
|
|
232
|
-
}, mockMCPWeb);
|
|
233
|
-
const setProject = result.tools.find((t) => t.name === 'set_app_projects');
|
|
234
|
-
if (!setProject)
|
|
235
|
-
throw new Error('set_app_projects not found');
|
|
236
|
-
// Add new project
|
|
237
|
-
const response1 = (await setProject.handler({
|
|
238
|
-
key: 'work',
|
|
239
|
-
value: {
|
|
240
|
-
title: 'Work Projects',
|
|
241
|
-
description: 'Work-related tasks',
|
|
242
|
-
},
|
|
243
|
-
}));
|
|
244
|
-
expect(response1.success).toBe(true);
|
|
245
|
-
expect(response1.value.id).toBeDefined();
|
|
246
|
-
expect(response1.value.title).toBe('Work Projects');
|
|
247
|
-
expect('work' in state.projects).toBe(true);
|
|
248
|
-
// Update existing project (upsert)
|
|
249
|
-
await setProject.handler({
|
|
250
|
-
key: 'work',
|
|
251
|
-
value: {
|
|
252
|
-
color: '#ff0000',
|
|
253
|
-
},
|
|
254
|
-
});
|
|
255
|
-
expect(state.projects.work.title).toBe('Work Projects'); // Preserved
|
|
256
|
-
expect(state.projects.work.color).toBe('#ff0000'); // Updated
|
|
257
|
-
});
|
|
258
|
-
test('integration - update settings (root set)', async () => {
|
|
259
|
-
let state = {
|
|
260
|
-
todos: [],
|
|
261
|
-
projects: {},
|
|
262
|
-
sortBy: 'created_at',
|
|
263
|
-
sortOrder: 'asc',
|
|
264
|
-
showCompleted: true,
|
|
265
|
-
theme: 'system',
|
|
266
|
-
};
|
|
267
|
-
const result = generateToolsForSchema({
|
|
268
|
-
name: 'app',
|
|
269
|
-
description: 'todo app',
|
|
270
|
-
get: () => state,
|
|
271
|
-
set: (value) => {
|
|
272
|
-
state = value;
|
|
273
|
-
},
|
|
274
|
-
schema: AppSchema,
|
|
275
|
-
}, mockMCPWeb);
|
|
276
|
-
const setApp = result.tools.find((t) => t.name === 'set_app');
|
|
277
|
-
if (!setApp)
|
|
278
|
-
throw new Error('set_app not found');
|
|
279
|
-
// Update only settings
|
|
280
|
-
await setApp.handler({
|
|
281
|
-
theme: 'dark',
|
|
282
|
-
showCompleted: false,
|
|
283
|
-
});
|
|
284
|
-
expect(state.theme).toBe('dark');
|
|
285
|
-
expect(state.showCompleted).toBe(false);
|
|
286
|
-
expect(state.sortBy).toBe('created_at'); // Unchanged
|
|
287
|
-
expect(state.todos).toEqual([]); // Collections unchanged
|
|
288
|
-
expect(state.projects).toEqual({}); // Collections unchanged
|
|
289
|
-
});
|
|
290
|
-
test('integration - get overview returns full state', async () => {
|
|
291
|
-
let state = {
|
|
292
|
-
todos: [
|
|
293
|
-
{
|
|
294
|
-
id: 'todo-1',
|
|
295
|
-
value: 'Buy milk',
|
|
296
|
-
priority: 3,
|
|
297
|
-
projectId: null,
|
|
298
|
-
created_at: 123456,
|
|
299
|
-
updated_at: 123456,
|
|
300
|
-
completed_at: null,
|
|
301
|
-
tags: [],
|
|
302
|
-
},
|
|
303
|
-
],
|
|
304
|
-
projects: {
|
|
305
|
-
work: {
|
|
306
|
-
id: 'proj-1',
|
|
307
|
-
title: 'Work',
|
|
308
|
-
description: null,
|
|
309
|
-
color: null,
|
|
310
|
-
created_at: 123456,
|
|
311
|
-
updated_at: 123456,
|
|
312
|
-
},
|
|
313
|
-
},
|
|
314
|
-
sortBy: 'created_at',
|
|
315
|
-
sortOrder: 'asc',
|
|
316
|
-
showCompleted: true,
|
|
317
|
-
theme: 'system',
|
|
318
|
-
};
|
|
319
|
-
const result = generateToolsForSchema({
|
|
320
|
-
name: 'app',
|
|
321
|
-
description: 'todo app',
|
|
322
|
-
get: () => state,
|
|
323
|
-
set: (value) => {
|
|
324
|
-
state = value;
|
|
325
|
-
},
|
|
326
|
-
schema: AppSchema,
|
|
327
|
-
}, mockMCPWeb);
|
|
328
|
-
const getApp = result.tools.find((t) => t.name === 'get_app');
|
|
329
|
-
if (!getApp)
|
|
330
|
-
throw new Error('get_app not found');
|
|
331
|
-
const fullState = await getApp.handler({});
|
|
332
|
-
expect(fullState).toEqual(state);
|
|
333
|
-
expect(fullState.todos).toHaveLength(1);
|
|
334
|
-
expect(Object.keys(fullState.projects)).toHaveLength(1);
|
|
335
|
-
});
|
|
336
|
-
test('integration - get overview with excludeCollections returns only settings', async () => {
|
|
337
|
-
let state = {
|
|
338
|
-
todos: [
|
|
339
|
-
{
|
|
340
|
-
id: 'todo-1',
|
|
341
|
-
value: 'Buy milk',
|
|
342
|
-
priority: 3,
|
|
343
|
-
projectId: null,
|
|
344
|
-
created_at: 123456,
|
|
345
|
-
updated_at: 123456,
|
|
346
|
-
completed_at: null,
|
|
347
|
-
tags: [],
|
|
348
|
-
},
|
|
349
|
-
],
|
|
350
|
-
projects: {
|
|
351
|
-
work: {
|
|
352
|
-
id: 'proj-1',
|
|
353
|
-
title: 'Work',
|
|
354
|
-
description: null,
|
|
355
|
-
color: null,
|
|
356
|
-
created_at: 123456,
|
|
357
|
-
updated_at: 123456,
|
|
358
|
-
},
|
|
359
|
-
},
|
|
360
|
-
sortBy: 'created_at',
|
|
361
|
-
sortOrder: 'asc',
|
|
362
|
-
showCompleted: true,
|
|
363
|
-
theme: 'system',
|
|
364
|
-
};
|
|
365
|
-
const result = generateToolsForSchema({
|
|
366
|
-
name: 'app',
|
|
367
|
-
description: 'todo app',
|
|
368
|
-
get: () => state,
|
|
369
|
-
set: (value) => {
|
|
370
|
-
state = value;
|
|
371
|
-
},
|
|
372
|
-
schema: AppSchema,
|
|
373
|
-
}, mockMCPWeb);
|
|
374
|
-
const getApp = result.tools.find((t) => t.name === 'get_app');
|
|
375
|
-
if (!getApp)
|
|
376
|
-
throw new Error('get_app not found');
|
|
377
|
-
const settings = await getApp.handler({ excludeCollections: true });
|
|
378
|
-
expect(settings).toEqual({
|
|
379
|
-
sortBy: 'created_at',
|
|
380
|
-
sortOrder: 'asc',
|
|
381
|
-
showCompleted: true,
|
|
382
|
-
theme: 'system',
|
|
383
|
-
});
|
|
384
|
-
expect(settings.todos).toBeUndefined();
|
|
385
|
-
expect(settings.projects).toBeUndefined();
|
|
386
|
-
});
|
|
387
|
-
// ============================================================================
|
|
388
|
-
// Complete Workflow Test
|
|
389
|
-
// ============================================================================
|
|
390
|
-
test('integration - complete todo app workflow', async () => {
|
|
391
|
-
let state = {
|
|
392
|
-
todos: [],
|
|
393
|
-
projects: {},
|
|
394
|
-
sortBy: 'created_at',
|
|
395
|
-
sortOrder: 'asc',
|
|
396
|
-
showCompleted: true,
|
|
397
|
-
theme: 'system',
|
|
398
|
-
};
|
|
399
|
-
const result = generateToolsForSchema({
|
|
400
|
-
name: 'app',
|
|
401
|
-
description: 'todo app',
|
|
402
|
-
get: () => state,
|
|
403
|
-
set: (value) => {
|
|
404
|
-
state = value;
|
|
405
|
-
},
|
|
406
|
-
schema: AppSchema,
|
|
407
|
-
}, mockMCPWeb);
|
|
408
|
-
// Find all tools
|
|
409
|
-
const addTodo = result.tools.find((t) => t.name === 'add_app_todos');
|
|
410
|
-
const setTodo = result.tools.find((t) => t.name === 'set_app_todos');
|
|
411
|
-
const setProject = result.tools.find((t) => t.name === 'set_app_projects');
|
|
412
|
-
const setApp = result.tools.find((t) => t.name === 'set_app');
|
|
413
|
-
const getApp = result.tools.find((t) => t.name === 'get_app');
|
|
414
|
-
// 1. Add a project
|
|
415
|
-
const projectResponse = (await setProject.handler({
|
|
416
|
-
key: 'work',
|
|
417
|
-
value: { title: 'Work Projects' },
|
|
418
|
-
}));
|
|
419
|
-
const projectId = projectResponse.value.id;
|
|
420
|
-
// 2. Add a todo with tags
|
|
421
|
-
const todoResponse = (await addTodo.handler({
|
|
422
|
-
value: {
|
|
423
|
-
value: 'Buy milk',
|
|
424
|
-
priority: 2,
|
|
425
|
-
projectId,
|
|
426
|
-
tags: ['shopping', 'urgent'],
|
|
427
|
-
},
|
|
428
|
-
}));
|
|
429
|
-
const todoId = todoResponse.value.id;
|
|
430
|
-
// 3. Update the todo
|
|
431
|
-
await setTodo.handler({
|
|
432
|
-
id: todoId,
|
|
433
|
-
value: { priority: 5 },
|
|
434
|
-
});
|
|
435
|
-
// 4. Update app settings
|
|
436
|
-
if (setApp) {
|
|
437
|
-
await setApp.handler({
|
|
438
|
-
theme: 'dark',
|
|
439
|
-
sortBy: 'priority',
|
|
440
|
-
});
|
|
441
|
-
}
|
|
442
|
-
// 5. Verify final state
|
|
443
|
-
const finalState = (await getApp.handler({}));
|
|
444
|
-
expect(finalState.todos).toHaveLength(1);
|
|
445
|
-
expect(finalState.todos[0].value).toBe('Buy milk');
|
|
446
|
-
expect(finalState.todos[0].priority).toBe(5);
|
|
447
|
-
expect(finalState.todos[0].tags).toEqual(['shopping', 'urgent']);
|
|
448
|
-
expect(finalState.todos[0].projectId).toBe(projectId);
|
|
449
|
-
expect(Object.keys(finalState.projects)).toHaveLength(1);
|
|
450
|
-
expect(finalState.projects.work.title).toBe('Work Projects');
|
|
451
|
-
expect(finalState.theme).toBe('dark');
|
|
452
|
-
expect(finalState.sortBy).toBe('priority');
|
|
453
|
-
});
|
|
454
|
-
// ============================================================================
|
|
455
|
-
// Edge Cases
|
|
456
|
-
// ============================================================================
|
|
457
|
-
test('integration - empty arrays and records', async () => {
|
|
458
|
-
let state = {
|
|
459
|
-
todos: [],
|
|
460
|
-
projects: {},
|
|
461
|
-
sortBy: 'created_at',
|
|
462
|
-
sortOrder: 'asc',
|
|
463
|
-
showCompleted: true,
|
|
464
|
-
theme: 'system',
|
|
465
|
-
};
|
|
466
|
-
const result = generateToolsForSchema({
|
|
467
|
-
name: 'app',
|
|
468
|
-
description: 'todo app',
|
|
469
|
-
get: () => state,
|
|
470
|
-
set: (value) => {
|
|
471
|
-
state = value;
|
|
472
|
-
},
|
|
473
|
-
schema: AppSchema,
|
|
474
|
-
}, mockMCPWeb);
|
|
475
|
-
const getTodos = result.tools.find((t) => t.name === 'get_app_todos');
|
|
476
|
-
const getProjects = result.tools.find((t) => t.name === 'get_app_projects');
|
|
477
|
-
expect(await getTodos.handler({})).toEqual([]);
|
|
478
|
-
expect(await getProjects.handler({})).toEqual({});
|
|
479
|
-
});
|
|
480
|
-
test('integration - null vs undefined handling in deep merge', async () => {
|
|
481
|
-
let state = {
|
|
482
|
-
todos: [
|
|
483
|
-
{
|
|
484
|
-
id: 'todo-1',
|
|
485
|
-
value: 'Buy milk',
|
|
486
|
-
priority: 3,
|
|
487
|
-
projectId: 'proj-1',
|
|
488
|
-
created_at: 123456,
|
|
489
|
-
updated_at: 123456,
|
|
490
|
-
completed_at: 123456,
|
|
491
|
-
tags: [],
|
|
492
|
-
},
|
|
493
|
-
],
|
|
494
|
-
projects: {},
|
|
495
|
-
sortBy: 'created_at',
|
|
496
|
-
sortOrder: 'asc',
|
|
497
|
-
showCompleted: true,
|
|
498
|
-
theme: 'system',
|
|
499
|
-
};
|
|
500
|
-
const result = generateToolsForSchema({
|
|
501
|
-
name: 'app',
|
|
502
|
-
description: 'todo app',
|
|
503
|
-
get: () => state,
|
|
504
|
-
set: (value) => {
|
|
505
|
-
state = value;
|
|
506
|
-
},
|
|
507
|
-
schema: AppSchema,
|
|
508
|
-
}, mockMCPWeb);
|
|
509
|
-
const setTodo = result.tools.find((t) => t.name === 'set_app_todos');
|
|
510
|
-
// Set completed_at to null (explicit clear)
|
|
511
|
-
await setTodo.handler({
|
|
512
|
-
id: 'todo-1',
|
|
513
|
-
value: { completed_at: null },
|
|
514
|
-
});
|
|
515
|
-
expect(state.todos[0].completed_at).toBe(null);
|
|
516
|
-
expect(state.todos[0].projectId).toBe('proj-1'); // Unchanged
|
|
517
|
-
});
|
|
518
|
-
test('integration - delete all todos', async () => {
|
|
519
|
-
let state = {
|
|
520
|
-
todos: [
|
|
521
|
-
{
|
|
522
|
-
id: 'todo-1',
|
|
523
|
-
value: 'Buy milk',
|
|
524
|
-
priority: 3,
|
|
525
|
-
projectId: null,
|
|
526
|
-
created_at: 123456,
|
|
527
|
-
updated_at: 123456,
|
|
528
|
-
completed_at: null,
|
|
529
|
-
tags: [],
|
|
530
|
-
},
|
|
531
|
-
{
|
|
532
|
-
id: 'todo-2',
|
|
533
|
-
value: 'Walk dog',
|
|
534
|
-
priority: 2,
|
|
535
|
-
projectId: null,
|
|
536
|
-
created_at: 123457,
|
|
537
|
-
updated_at: 123457,
|
|
538
|
-
completed_at: null,
|
|
539
|
-
tags: [],
|
|
540
|
-
},
|
|
541
|
-
],
|
|
542
|
-
projects: {},
|
|
543
|
-
sortBy: 'created_at',
|
|
544
|
-
sortOrder: 'asc',
|
|
545
|
-
showCompleted: true,
|
|
546
|
-
theme: 'system',
|
|
547
|
-
};
|
|
548
|
-
const result = generateToolsForSchema({
|
|
549
|
-
name: 'app',
|
|
550
|
-
description: 'todo app',
|
|
551
|
-
get: () => state,
|
|
552
|
-
set: (value) => {
|
|
553
|
-
state = value;
|
|
554
|
-
},
|
|
555
|
-
schema: AppSchema,
|
|
556
|
-
}, mockMCPWeb);
|
|
557
|
-
const deleteTodos = result.tools.find((t) => t.name === 'delete_app_todos');
|
|
558
|
-
await deleteTodos.handler({ all: true });
|
|
559
|
-
expect(state.todos).toEqual([]);
|
|
560
|
-
});
|
|
561
|
-
test('integration - delete all projects', async () => {
|
|
562
|
-
let state = {
|
|
563
|
-
todos: [],
|
|
564
|
-
projects: {
|
|
565
|
-
work: {
|
|
566
|
-
id: 'proj-1',
|
|
567
|
-
title: 'Work',
|
|
568
|
-
description: null,
|
|
569
|
-
color: null,
|
|
570
|
-
created_at: 123456,
|
|
571
|
-
updated_at: 123456,
|
|
572
|
-
},
|
|
573
|
-
personal: {
|
|
574
|
-
id: 'proj-2',
|
|
575
|
-
title: 'Personal',
|
|
576
|
-
description: null,
|
|
577
|
-
color: null,
|
|
578
|
-
created_at: 123456,
|
|
579
|
-
updated_at: 123456,
|
|
580
|
-
},
|
|
581
|
-
},
|
|
582
|
-
sortBy: 'created_at',
|
|
583
|
-
sortOrder: 'asc',
|
|
584
|
-
showCompleted: true,
|
|
585
|
-
theme: 'system',
|
|
586
|
-
};
|
|
587
|
-
const result = generateToolsForSchema({
|
|
588
|
-
name: 'app',
|
|
589
|
-
description: 'todo app',
|
|
590
|
-
get: () => state,
|
|
591
|
-
set: (value) => {
|
|
592
|
-
state = value;
|
|
593
|
-
},
|
|
594
|
-
schema: AppSchema,
|
|
595
|
-
}, mockMCPWeb);
|
|
596
|
-
const deleteProjects = result.tools.find((t) => t.name === 'delete_app_projects');
|
|
597
|
-
await deleteProjects.handler({ all: true });
|
|
598
|
-
expect(state.projects).toEqual({});
|
|
599
|
-
});
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import type { KeyFieldResult, SchemaShape } from './types.js';
|
|
3
|
-
/**
|
|
4
|
-
* Analyzes a schema to determine its shape characteristics.
|
|
5
|
-
*/
|
|
6
|
-
export declare function analyzeSchemaShape(schema: z.ZodTypeAny): SchemaShape;
|
|
7
|
-
/**
|
|
8
|
-
* Detects the ID field in an object schema.
|
|
9
|
-
* Returns information about explicit id() markers.
|
|
10
|
-
* Throws an error if multiple id() markers are found.
|
|
11
|
-
*/
|
|
12
|
-
export declare function findIdField(schema: z.ZodObject<z.ZodRawShape>): KeyFieldResult;
|
|
13
|
-
/**
|
|
14
|
-
* Validates that a schema only uses supported types.
|
|
15
|
-
* Throws an error if unsupported types are found.
|
|
16
|
-
*/
|
|
17
|
-
export declare function validateSupportedTypes(schema: z.ZodTypeAny, path?: string): string[];
|
|
18
|
-
//# sourceMappingURL=schema-analysis.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"schema-analysis.d.ts","sourceRoot":"","sources":["../../src/expanded-schema-tools/schema-analysis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9D;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,GAAG,WAAW,CA+EpE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,cAAc,CAuB9E;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,EAAE,IAAI,SAAS,GAAG,MAAM,EAAE,CA0CpF"}
|