@happyvertical/smrt-svelte 0.43.3 → 0.43.5
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/AGENTS.md +45 -0
- package/README.md +73 -0
- package/dist/Provider.svelte +83 -26
- package/dist/Provider.svelte.d.ts +4 -12
- package/dist/Provider.svelte.d.ts.map +1 -1
- package/dist/__tests__/provider-webmcp-harness.svelte +14 -0
- package/dist/__tests__/provider-webmcp-harness.svelte.d.ts +8 -0
- package/dist/__tests__/provider-webmcp-harness.svelte.d.ts.map +1 -0
- package/dist/components/forms/AddressInput.svelte +155 -42
- package/dist/components/forms/AddressInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/CheckboxInput.svelte +40 -13
- package/dist/components/forms/CheckboxInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/DateRangeInput.svelte +132 -16
- package/dist/components/forms/DateRangeInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/DateTimeInput.svelte +48 -14
- package/dist/components/forms/DateTimeInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/Form.svelte +667 -61
- package/dist/components/forms/Form.svelte.d.ts +6 -2
- package/dist/components/forms/Form.svelte.d.ts.map +1 -1
- package/dist/components/forms/MeasurementInput.svelte +137 -31
- package/dist/components/forms/MeasurementInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/MoneyInput.svelte +42 -23
- package/dist/components/forms/MoneyInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/NumberInput.svelte +59 -27
- package/dist/components/forms/NumberInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/PhoneInput.svelte +51 -22
- package/dist/components/forms/PhoneInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/SelectInput.svelte +38 -22
- package/dist/components/forms/SelectInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/TextInput.svelte +32 -18
- package/dist/components/forms/TextInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/TextareaInput.svelte +25 -18
- package/dist/components/forms/TextareaInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/__tests__/AddressInput.behavior.test.js +94 -0
- package/dist/components/forms/__tests__/Form.behavior.test.js +1 -1
- package/dist/components/forms/__tests__/Form.extraction.test.js +68 -0
- package/dist/components/forms/__tests__/Form.test.js +28 -0
- package/dist/components/forms/__tests__/Form.webmcp.test.js +2120 -111
- package/dist/components/forms/__tests__/FormMicButton.test.js +0 -1
- package/dist/components/forms/__tests__/async-invalid-field.fixture.svelte +30 -0
- package/dist/components/forms/__tests__/async-invalid-field.fixture.svelte.d.ts +7 -0
- package/dist/components/forms/__tests__/async-invalid-field.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/async-validation-form.fixture.svelte +19 -0
- package/dist/components/forms/__tests__/async-validation-form.fixture.svelte.d.ts +9 -0
- package/dist/components/forms/__tests__/async-validation-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/async-validation-snapshot-form.fixture.svelte +21 -0
- package/dist/components/forms/__tests__/async-validation-snapshot-form.fixture.svelte.d.ts +8 -0
- package/dist/components/forms/__tests__/async-validation-snapshot-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/compound-registration-wrapper.fixture.svelte +27 -0
- package/dist/components/forms/__tests__/compound-registration-wrapper.fixture.svelte.d.ts +9 -0
- package/dist/components/forms/__tests__/compound-registration-wrapper.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/custom-registration-field.fixture.svelte +48 -0
- package/dist/components/forms/__tests__/custom-registration-field.fixture.svelte.d.ts +10 -0
- package/dist/components/forms/__tests__/custom-registration-field.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/form-extraction-values.fixture.svelte +26 -0
- package/dist/components/forms/__tests__/form-extraction-values.fixture.svelte.d.ts +13 -0
- package/dist/components/forms/__tests__/form-extraction-values.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/form-registration-lifecycle.fixture.svelte +52 -0
- package/dist/components/forms/__tests__/form-registration-lifecycle.fixture.svelte.d.ts +16 -0
- package/dist/components/forms/__tests__/form-registration-lifecycle.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte +108 -5
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte.d.ts +34 -0
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte.d.ts.map +1 -1
- package/dist/components/forms/__tests__/form-with-policy-field.fixture.svelte +24 -0
- package/dist/components/forms/__tests__/form-with-policy-field.fixture.svelte.d.ts +11 -0
- package/dist/components/forms/__tests__/form-with-policy-field.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/form-with-structured-fields.fixture.svelte +69 -4
- package/dist/components/forms/__tests__/form-with-structured-fields.fixture.svelte.d.ts +32 -0
- package/dist/components/forms/__tests__/form-with-structured-fields.fixture.svelte.d.ts.map +1 -1
- package/dist/components/forms/__tests__/legacy-form-context.fixture.svelte +44 -0
- package/dist/components/forms/__tests__/legacy-form-context.fixture.svelte.d.ts +9 -0
- package/dist/components/forms/__tests__/legacy-form-context.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/policy-field.fixture.svelte +35 -0
- package/dist/components/forms/__tests__/policy-field.fixture.svelte.d.ts +8 -0
- package/dist/components/forms/__tests__/policy-field.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/prepare-field-value.d.ts +5 -0
- package/dist/components/forms/prepare-field-value.d.ts.map +1 -0
- package/dist/components/forms/prepare-field-value.js +15 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/provider-webmcp.test.js +244 -0
- package/dist/state/form-context.d.ts +28 -6
- package/dist/state/form-context.d.ts.map +1 -1
- package/dist/state/form-context.js +75 -7
- package/dist/web/__tests__/provider-ui-registry.fixture.svelte +43 -0
- package/dist/web/__tests__/provider-ui-registry.fixture.svelte.d.ts +13 -0
- package/dist/web/__tests__/provider-ui-registry.fixture.svelte.d.ts.map +1 -0
- package/dist/web/__tests__/provider-ui-registry.test.js +235 -0
- package/dist/web/__tests__/webmcp-composed.child.fixture.svelte +62 -0
- package/dist/web/__tests__/webmcp-composed.child.fixture.svelte.d.ts +8 -0
- package/dist/web/__tests__/webmcp-composed.child.fixture.svelte.d.ts.map +1 -0
- package/dist/web/__tests__/webmcp-composed.fixture.svelte +52 -0
- package/dist/web/__tests__/webmcp-composed.fixture.svelte.d.ts +12 -0
- package/dist/web/__tests__/webmcp-composed.fixture.svelte.d.ts.map +1 -0
- package/dist/web/__tests__/webmcp-composed.integration.svelte.test.js +247 -0
- package/dist/web/__tests__/webmcp-ssr.fixture.svelte +13 -0
- package/dist/web/__tests__/webmcp-ssr.fixture.svelte.d.ts +19 -0
- package/dist/web/__tests__/webmcp-ssr.fixture.svelte.d.ts.map +1 -0
- package/dist/web/__tests__/webmcp-ui.test.js +586 -0
- package/dist/web/__tests__/webmcp.test.js +21 -1
- package/dist/web/index.d.ts +3 -0
- package/dist/web/index.d.ts.map +1 -1
- package/dist/web/index.js +2 -0
- package/dist/web/webmcp-provider.d.ts +23 -0
- package/dist/web/webmcp-provider.d.ts.map +1 -0
- package/dist/web/webmcp-provider.js +1 -0
- package/dist/web/webmcp-ui-context.d.ts +12 -0
- package/dist/web/webmcp-ui-context.d.ts.map +1 -0
- package/dist/web/webmcp-ui-context.js +16 -0
- package/dist/web/webmcp-ui.d.ts +21 -0
- package/dist/web/webmcp-ui.d.ts.map +1 -0
- package/dist/web/webmcp-ui.js +474 -0
- package/dist/web/webmcp.d.ts +1 -1
- package/dist/web/webmcp.svelte.d.ts +4 -1
- package/dist/web/webmcp.svelte.d.ts.map +1 -1
- package/dist/web/webmcp.svelte.js +6 -1
- package/package.json +8 -6
|
@@ -0,0 +1,586 @@
|
|
|
1
|
+
import { createDataSurfaceRegistry, } from '@happyvertical/smrt-ui/data';
|
|
2
|
+
import { createControlInteractionRegistry, } from '@happyvertical/smrt-ui/forms';
|
|
3
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import { registerWebMcpUiTools } from '../webmcp-ui.js';
|
|
5
|
+
function modelContext() {
|
|
6
|
+
const registered = [];
|
|
7
|
+
const signals = [];
|
|
8
|
+
const document = {
|
|
9
|
+
modelContext: {
|
|
10
|
+
async registerTool(tool, options) {
|
|
11
|
+
registered.push(tool);
|
|
12
|
+
if (options?.signal)
|
|
13
|
+
signals.push(options.signal);
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
return { document, registered, signals };
|
|
18
|
+
}
|
|
19
|
+
function parse(value) {
|
|
20
|
+
return Promise.resolve(value).then((result) => JSON.parse(result));
|
|
21
|
+
}
|
|
22
|
+
function findTool(tools, name) {
|
|
23
|
+
const tool = tools.find((candidate) => candidate.name === name);
|
|
24
|
+
if (!tool)
|
|
25
|
+
throw new Error(`Missing tool: ${name}`);
|
|
26
|
+
return tool;
|
|
27
|
+
}
|
|
28
|
+
function descriptor() {
|
|
29
|
+
return {
|
|
30
|
+
version: 1,
|
|
31
|
+
identity: { surfaceId: 'content', kind: 'table' },
|
|
32
|
+
schemaVersion: 1,
|
|
33
|
+
label: 'Content',
|
|
34
|
+
rowKey: 'id',
|
|
35
|
+
columns: [
|
|
36
|
+
{
|
|
37
|
+
id: 'id',
|
|
38
|
+
label: 'ID',
|
|
39
|
+
capabilities: ['read', 'project'],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: 'internal',
|
|
43
|
+
label: 'Internal',
|
|
44
|
+
visibility: 'hidden',
|
|
45
|
+
capabilities: ['read', 'project'],
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
query: {
|
|
49
|
+
modes: ['rows'],
|
|
50
|
+
projectableColumnIds: ['id', 'internal'],
|
|
51
|
+
},
|
|
52
|
+
controls: [{ id: 'next-page', label: 'Next page' }],
|
|
53
|
+
actions: [],
|
|
54
|
+
limits: { maxQueryRows: 50, maxQueryBytes: 10_000, maxSelectionSize: 10 },
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
describe('registerWebMcpUiTools', () => {
|
|
58
|
+
it('registers one fixed tool set and resolves mounted controls dynamically', async () => {
|
|
59
|
+
const browser = modelContext();
|
|
60
|
+
const controls = createControlInteractionRegistry();
|
|
61
|
+
const surfaces = createDataSurfaceRegistry();
|
|
62
|
+
const dispose = registerWebMcpUiTools({
|
|
63
|
+
controlRegistry: controls,
|
|
64
|
+
dataSurfaceRegistry: surfaces,
|
|
65
|
+
document: browser.document,
|
|
66
|
+
});
|
|
67
|
+
expect(browser.registered.map((tool) => tool.name)).toEqual([
|
|
68
|
+
'smrt_ui_list_form_controls',
|
|
69
|
+
'smrt_ui_inspect_form_control',
|
|
70
|
+
'smrt_ui_execute_form_control',
|
|
71
|
+
'smrt_ui_list_data_surfaces',
|
|
72
|
+
'smrt_ui_inspect_data_surface',
|
|
73
|
+
'smrt_ui_execute_data_surface_control',
|
|
74
|
+
]);
|
|
75
|
+
expect(browser.registered).toHaveLength(6);
|
|
76
|
+
const list = findTool(browser.registered, 'smrt_ui_list_form_controls');
|
|
77
|
+
expect(await parse(list.execute({}))).toEqual({ ok: true, result: [] });
|
|
78
|
+
let value = 'Ada';
|
|
79
|
+
const unregister = controls.register({
|
|
80
|
+
identity: { formId: 'profile', controlId: 'name' },
|
|
81
|
+
metadata: { kind: 'text', label: 'Name' },
|
|
82
|
+
getValue: () => value,
|
|
83
|
+
setValue: (next) => {
|
|
84
|
+
value = String(next);
|
|
85
|
+
},
|
|
86
|
+
focus: vi.fn(),
|
|
87
|
+
});
|
|
88
|
+
expect((await parse(list.execute({}))).result).toHaveLength(1);
|
|
89
|
+
expect(browser.registered).toHaveLength(6);
|
|
90
|
+
unregister();
|
|
91
|
+
expect(await parse(list.execute({}))).toEqual({ ok: true, result: [] });
|
|
92
|
+
dispose();
|
|
93
|
+
expect(browser.signals).toHaveLength(6);
|
|
94
|
+
expect(browser.signals.every((signal) => signal.aborted)).toBe(true);
|
|
95
|
+
});
|
|
96
|
+
it('uses agent consent semantics and cannot be tricked into confirmation', async () => {
|
|
97
|
+
const browser = modelContext();
|
|
98
|
+
const controls = createControlInteractionRegistry();
|
|
99
|
+
let value = 'Ada';
|
|
100
|
+
controls.register({
|
|
101
|
+
identity: { formId: 'profile', controlId: 'name' },
|
|
102
|
+
metadata: { kind: 'text', label: 'Name' },
|
|
103
|
+
getValue: () => value,
|
|
104
|
+
setValue: (next) => {
|
|
105
|
+
value = String(next);
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
registerWebMcpUiTools({
|
|
109
|
+
controlRegistry: controls,
|
|
110
|
+
dataSurfaceRegistry: createDataSurfaceRegistry(),
|
|
111
|
+
document: browser.document,
|
|
112
|
+
});
|
|
113
|
+
const execute = findTool(browser.registered, 'smrt_ui_execute_form_control');
|
|
114
|
+
const identity = { formId: 'profile', controlId: 'name' };
|
|
115
|
+
expect((await parse(execute.execute({ action: 'stage', identity, value: 'Grace' }))).result).toMatchObject({ ok: true, action: 'stage' });
|
|
116
|
+
expect(value).toBe('Ada');
|
|
117
|
+
expect((await parse(execute.execute({ action: 'apply', identity }))).result).toMatchObject({ ok: false, reason: 'human_confirmation_required' });
|
|
118
|
+
expect(value).toBe('Ada');
|
|
119
|
+
expect(await parse(execute.execute({
|
|
120
|
+
action: 'apply',
|
|
121
|
+
identity,
|
|
122
|
+
confirmed: true,
|
|
123
|
+
}))).toEqual({ ok: false, reason: 'invalid_request', details: 'confirmed' });
|
|
124
|
+
expect(value).toBe('Ada');
|
|
125
|
+
});
|
|
126
|
+
it('returns the canonical values staged by general form-control tools', async () => {
|
|
127
|
+
const browser = modelContext();
|
|
128
|
+
const controls = createControlInteractionRegistry();
|
|
129
|
+
const identities = {
|
|
130
|
+
checkbox: { formId: 'base', controlId: 'enabled' },
|
|
131
|
+
number: { formId: 'base', controlId: 'count' },
|
|
132
|
+
option: { formId: 'base', controlId: 'role' },
|
|
133
|
+
};
|
|
134
|
+
controls.register({
|
|
135
|
+
identity: identities.checkbox,
|
|
136
|
+
metadata: { kind: 'checkbox' },
|
|
137
|
+
getValue: () => false,
|
|
138
|
+
setValue: () => undefined,
|
|
139
|
+
prepareValue: (next) => {
|
|
140
|
+
if (typeof next !== 'boolean')
|
|
141
|
+
throw new Error('staged_value_invalid');
|
|
142
|
+
return next;
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
controls.register({
|
|
146
|
+
identity: identities.number,
|
|
147
|
+
metadata: { kind: 'number' },
|
|
148
|
+
getValue: () => 0,
|
|
149
|
+
setValue: () => undefined,
|
|
150
|
+
prepareValue: (next) => Number(next),
|
|
151
|
+
});
|
|
152
|
+
controls.register({
|
|
153
|
+
identity: identities.option,
|
|
154
|
+
metadata: {
|
|
155
|
+
kind: 'listbox',
|
|
156
|
+
options: [{ value: 1, label: 'Admin' }],
|
|
157
|
+
},
|
|
158
|
+
getValue: () => 1,
|
|
159
|
+
setValue: () => undefined,
|
|
160
|
+
prepareValue: (next) => {
|
|
161
|
+
if (String(next) !== '1')
|
|
162
|
+
throw new Error('staged_value_invalid');
|
|
163
|
+
return 1;
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
registerWebMcpUiTools({
|
|
167
|
+
controlRegistry: controls,
|
|
168
|
+
dataSurfaceRegistry: createDataSurfaceRegistry(),
|
|
169
|
+
document: browser.document,
|
|
170
|
+
});
|
|
171
|
+
const execute = findTool(browser.registered, 'smrt_ui_execute_form_control');
|
|
172
|
+
expect(await parse(execute.execute({
|
|
173
|
+
action: 'stage',
|
|
174
|
+
identity: identities.checkbox,
|
|
175
|
+
value: {},
|
|
176
|
+
}))).toMatchObject({
|
|
177
|
+
ok: true,
|
|
178
|
+
result: { ok: false, reason: 'execution_failed' },
|
|
179
|
+
});
|
|
180
|
+
expect(controls.get(identities.checkbox)?.state.staged).toBeUndefined();
|
|
181
|
+
for (const [identity, value, staged] of [
|
|
182
|
+
[identities.number, '42', 42],
|
|
183
|
+
[identities.option, '1', 1],
|
|
184
|
+
]) {
|
|
185
|
+
const response = await parse(execute.execute({ action: 'stage', identity, value }));
|
|
186
|
+
expect(response).toMatchObject({ ok: true, result: { ok: true } });
|
|
187
|
+
expect(response.result.snapshot.state.staged.value).toEqual(staged);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
it('keeps secret values redacted from list, inspect, and execute responses', async () => {
|
|
191
|
+
const browser = modelContext();
|
|
192
|
+
const controls = createControlInteractionRegistry();
|
|
193
|
+
controls.register({
|
|
194
|
+
identity: { formId: 'account', controlId: 'password' },
|
|
195
|
+
metadata: {
|
|
196
|
+
kind: 'password',
|
|
197
|
+
label: 'Password',
|
|
198
|
+
sensitivity: 'secret',
|
|
199
|
+
},
|
|
200
|
+
getValue: () => 'never-serialize-this',
|
|
201
|
+
setValue: () => { },
|
|
202
|
+
getState: () => ({
|
|
203
|
+
valid: false,
|
|
204
|
+
validationMessage: 'never-serialize-this is invalid',
|
|
205
|
+
}),
|
|
206
|
+
focus: () => {
|
|
207
|
+
throw new Error('never-serialize-this cannot be focused');
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
registerWebMcpUiTools({
|
|
211
|
+
controlRegistry: controls,
|
|
212
|
+
dataSurfaceRegistry: createDataSurfaceRegistry(),
|
|
213
|
+
document: browser.document,
|
|
214
|
+
});
|
|
215
|
+
const list = findTool(browser.registered, 'smrt_ui_list_form_controls');
|
|
216
|
+
const inspect = findTool(browser.registered, 'smrt_ui_inspect_form_control');
|
|
217
|
+
const execute = findTool(browser.registered, 'smrt_ui_execute_form_control');
|
|
218
|
+
const listed = await parse(list.execute({ formId: 'account' }));
|
|
219
|
+
const inspected = await parse(inspect.execute({
|
|
220
|
+
identity: { formId: 'account', controlId: 'password' },
|
|
221
|
+
}));
|
|
222
|
+
const executed = await parse(execute.execute({
|
|
223
|
+
action: 'focus',
|
|
224
|
+
identity: { formId: 'account', controlId: 'password' },
|
|
225
|
+
}));
|
|
226
|
+
expect(JSON.stringify([listed, inspected, executed])).not.toContain('never-serialize-this');
|
|
227
|
+
expect(listed.result[0].state.valueRedacted).toBe(true);
|
|
228
|
+
expect(inspected.result.state.valueRedacted).toBe(true);
|
|
229
|
+
expect(executed.result.snapshot.state.valueRedacted).toBe(true);
|
|
230
|
+
expect(executed.result.snapshot.state).not.toHaveProperty('validationMessage');
|
|
231
|
+
expect(executed.result.reason).toBe('execution_failed');
|
|
232
|
+
});
|
|
233
|
+
it('does not expose host error messages that mimic public failures', async () => {
|
|
234
|
+
const browser = modelContext();
|
|
235
|
+
const controls = createControlInteractionRegistry();
|
|
236
|
+
controls.register({
|
|
237
|
+
identity: { formId: 'profile', controlId: 'unstable' },
|
|
238
|
+
metadata: { kind: 'text', label: 'Unstable' },
|
|
239
|
+
getValue: () => {
|
|
240
|
+
throw new Error('not_found: private customer 4711');
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
registerWebMcpUiTools({
|
|
244
|
+
controlRegistry: controls,
|
|
245
|
+
dataSurfaceRegistry: createDataSurfaceRegistry(),
|
|
246
|
+
document: browser.document,
|
|
247
|
+
});
|
|
248
|
+
const inspect = findTool(browser.registered, 'smrt_ui_inspect_form_control');
|
|
249
|
+
const result = await parse(inspect.execute({
|
|
250
|
+
identity: { formId: 'profile', controlId: 'unstable' },
|
|
251
|
+
}));
|
|
252
|
+
expect(result).toEqual({ ok: false, reason: 'execution_failed' });
|
|
253
|
+
expect(JSON.stringify(result)).not.toContain('customer 4711');
|
|
254
|
+
});
|
|
255
|
+
it('redacts sensitive injected snapshots and result text despite inconsistent flags', async () => {
|
|
256
|
+
for (const sensitivity of ['secret', 'sensitive']) {
|
|
257
|
+
const marker = `injected-${sensitivity}-value`;
|
|
258
|
+
const browser = modelContext();
|
|
259
|
+
const snapshot = {
|
|
260
|
+
identity: { formId: 'injected', controlId: sensitivity },
|
|
261
|
+
metadata: {
|
|
262
|
+
kind: 'password',
|
|
263
|
+
sensitivity,
|
|
264
|
+
capabilities: ['discard'],
|
|
265
|
+
},
|
|
266
|
+
state: {
|
|
267
|
+
value: marker,
|
|
268
|
+
valueRedacted: false,
|
|
269
|
+
stagedValue: `${marker}-staged`,
|
|
270
|
+
stagedValueRedacted: false,
|
|
271
|
+
validationMessage: `${marker} validation`,
|
|
272
|
+
staged: {
|
|
273
|
+
value: `${marker}-nested`,
|
|
274
|
+
valueRedacted: false,
|
|
275
|
+
provenance: { source: 'agent' },
|
|
276
|
+
stagedAt: 1,
|
|
277
|
+
revision: 1,
|
|
278
|
+
stale: false,
|
|
279
|
+
validationMessage: `${marker} nested validation`,
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
};
|
|
283
|
+
const controls = {
|
|
284
|
+
register: () => () => { },
|
|
285
|
+
unregister: () => { },
|
|
286
|
+
list: () => [snapshot],
|
|
287
|
+
get: () => snapshot,
|
|
288
|
+
execute: async (command) => ({
|
|
289
|
+
ok: false,
|
|
290
|
+
action: command.action,
|
|
291
|
+
identity: command.identity,
|
|
292
|
+
reason: `${marker} reason`,
|
|
293
|
+
validationMessage: `${marker} result validation`,
|
|
294
|
+
snapshot,
|
|
295
|
+
}),
|
|
296
|
+
subscribe: () => () => { },
|
|
297
|
+
};
|
|
298
|
+
registerWebMcpUiTools({
|
|
299
|
+
controlRegistry: controls,
|
|
300
|
+
dataSurfaceRegistry: createDataSurfaceRegistry(),
|
|
301
|
+
document: browser.document,
|
|
302
|
+
});
|
|
303
|
+
const identity = { formId: 'injected', controlId: sensitivity };
|
|
304
|
+
const list = await parse(findTool(browser.registered, 'smrt_ui_list_form_controls').execute({}));
|
|
305
|
+
const inspect = await parse(findTool(browser.registered, 'smrt_ui_inspect_form_control').execute({
|
|
306
|
+
identity,
|
|
307
|
+
}));
|
|
308
|
+
const executed = await parse(findTool(browser.registered, 'smrt_ui_execute_form_control').execute({
|
|
309
|
+
action: 'focus',
|
|
310
|
+
identity,
|
|
311
|
+
}));
|
|
312
|
+
expect(JSON.stringify([list, inspect, executed])).not.toContain(marker);
|
|
313
|
+
for (const result of [
|
|
314
|
+
list.result[0],
|
|
315
|
+
inspect.result,
|
|
316
|
+
executed.result.snapshot,
|
|
317
|
+
]) {
|
|
318
|
+
expect(result.metadata.capabilities).toEqual(['discard']);
|
|
319
|
+
expect(result.state).toMatchObject({
|
|
320
|
+
valueRedacted: true,
|
|
321
|
+
stagedValueRedacted: true,
|
|
322
|
+
staged: {
|
|
323
|
+
valueRedacted: true,
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
expect(result.state).not.toHaveProperty('value');
|
|
327
|
+
expect(result.state).not.toHaveProperty('stagedValue');
|
|
328
|
+
expect(result.state).not.toHaveProperty('validationMessage');
|
|
329
|
+
expect(result.state.staged).not.toHaveProperty('value');
|
|
330
|
+
expect(result.state.staged).not.toHaveProperty('validationMessage');
|
|
331
|
+
}
|
|
332
|
+
expect(executed.result.reason).toBe('execution_failed');
|
|
333
|
+
expect(executed.result).not.toHaveProperty('validationMessage');
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
it('filters hidden columns and preserves surface revision and replay failures', async () => {
|
|
337
|
+
const browser = modelContext();
|
|
338
|
+
const surfaces = createDataSurfaceRegistry();
|
|
339
|
+
let revision = 2;
|
|
340
|
+
let page = 1;
|
|
341
|
+
surfaces.register({
|
|
342
|
+
descriptor: descriptor(),
|
|
343
|
+
getSnapshot: () => ({
|
|
344
|
+
revision,
|
|
345
|
+
state: {
|
|
346
|
+
page,
|
|
347
|
+
internal: 'never-serialize-this',
|
|
348
|
+
table: {
|
|
349
|
+
version: 3,
|
|
350
|
+
state: {
|
|
351
|
+
filters: [
|
|
352
|
+
{ columnId: 'internal', value: 'nested-hidden-filter' },
|
|
353
|
+
{ columnId: 'id', value: ['internal'] },
|
|
354
|
+
],
|
|
355
|
+
sorting: [{ columnId: 'internal', direction: 'asc' }],
|
|
356
|
+
columnOrder: ['id', 'internal'],
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
},
|
|
360
|
+
}),
|
|
361
|
+
execute: (_command) => {
|
|
362
|
+
page += 1;
|
|
363
|
+
revision += 1;
|
|
364
|
+
},
|
|
365
|
+
});
|
|
366
|
+
registerWebMcpUiTools({
|
|
367
|
+
controlRegistry: createControlInteractionRegistry(),
|
|
368
|
+
dataSurfaceRegistry: surfaces,
|
|
369
|
+
document: browser.document,
|
|
370
|
+
});
|
|
371
|
+
const list = findTool(browser.registered, 'smrt_ui_list_data_surfaces');
|
|
372
|
+
const inspect = findTool(browser.registered, 'smrt_ui_inspect_data_surface');
|
|
373
|
+
const execute = findTool(browser.registered, 'smrt_ui_execute_data_surface_control');
|
|
374
|
+
const identity = { surfaceId: 'content', kind: 'table' };
|
|
375
|
+
expect((await parse(list.execute({}))).result[0].columns).toHaveLength(1);
|
|
376
|
+
const snapshot = (await parse(inspect.execute({ identity }))).result;
|
|
377
|
+
expect(snapshot.descriptor.query.projectableColumnIds).toEqual(['id']);
|
|
378
|
+
expect(snapshot.state).not.toHaveProperty('internal');
|
|
379
|
+
expect(JSON.stringify(snapshot)).not.toContain('nested-hidden-filter');
|
|
380
|
+
expect(snapshot.state.table.state.columnOrder).toEqual(['id']);
|
|
381
|
+
expect(snapshot.state.table.state.filters).toEqual([
|
|
382
|
+
{ columnId: 'id', value: ['internal'] },
|
|
383
|
+
]);
|
|
384
|
+
const hiddenRowKeyDescriptor = descriptor();
|
|
385
|
+
hiddenRowKeyDescriptor.rowKey = 'internal';
|
|
386
|
+
const hiddenRowKeySurfaces = createDataSurfaceRegistry();
|
|
387
|
+
hiddenRowKeySurfaces.register({
|
|
388
|
+
descriptor: hiddenRowKeyDescriptor,
|
|
389
|
+
getSnapshot: () => ({
|
|
390
|
+
revision: 0,
|
|
391
|
+
state: {
|
|
392
|
+
table: {
|
|
393
|
+
state: {
|
|
394
|
+
selection: {
|
|
395
|
+
scope: 'explicit',
|
|
396
|
+
rowIds: ['nested-private-row-id'],
|
|
397
|
+
},
|
|
398
|
+
selectedRowIds: ['nested-private-row-id'],
|
|
399
|
+
expandedRowIds: ['nested-private-row-id'],
|
|
400
|
+
},
|
|
401
|
+
},
|
|
402
|
+
},
|
|
403
|
+
selection: { scope: 'explicit-ids', rowIds: ['private-row-id'] },
|
|
404
|
+
}),
|
|
405
|
+
});
|
|
406
|
+
const hiddenRowKeyBrowser = modelContext();
|
|
407
|
+
registerWebMcpUiTools({
|
|
408
|
+
controlRegistry: createControlInteractionRegistry(),
|
|
409
|
+
dataSurfaceRegistry: hiddenRowKeySurfaces,
|
|
410
|
+
document: hiddenRowKeyBrowser.document,
|
|
411
|
+
});
|
|
412
|
+
const hiddenRowKeyList = await parse(findTool(hiddenRowKeyBrowser.registered, 'smrt_ui_list_data_surfaces').execute({}));
|
|
413
|
+
expect(hiddenRowKeyList.result[0]).not.toHaveProperty('rowKey');
|
|
414
|
+
const hiddenRowKeyInspect = await parse(findTool(hiddenRowKeyBrowser.registered, 'smrt_ui_inspect_data_surface').execute({ identity }));
|
|
415
|
+
expect(hiddenRowKeyInspect.result.selection).toBeNull();
|
|
416
|
+
expect(JSON.stringify(hiddenRowKeyInspect)).not.toContain('private-row-id');
|
|
417
|
+
expect(JSON.stringify(hiddenRowKeyInspect)).not.toContain('nested-private-row-id');
|
|
418
|
+
const command = {
|
|
419
|
+
version: 1,
|
|
420
|
+
commandId: 'page-1',
|
|
421
|
+
identity,
|
|
422
|
+
expectedRevision: 2,
|
|
423
|
+
controlId: 'next-page',
|
|
424
|
+
};
|
|
425
|
+
const completed = (await parse(execute.execute(command))).result;
|
|
426
|
+
expect(completed).toMatchObject({
|
|
427
|
+
ok: true,
|
|
428
|
+
revision: 3,
|
|
429
|
+
});
|
|
430
|
+
expect(completed.snapshot.descriptor.columns).toHaveLength(1);
|
|
431
|
+
expect(completed.snapshot.state).not.toHaveProperty('internal');
|
|
432
|
+
expect((await parse(execute.execute(command))).result).toMatchObject({
|
|
433
|
+
ok: true,
|
|
434
|
+
revision: 3,
|
|
435
|
+
});
|
|
436
|
+
expect((await parse(execute.execute({ ...command, controlId: 'different-control' }))).result).toMatchObject({ ok: false, reason: 'idempotency_conflict' });
|
|
437
|
+
const stale = (await parse(execute.execute({ ...command, commandId: 'page-2' }))).result;
|
|
438
|
+
expect(stale).toMatchObject({ ok: false, reason: 'stale_revision' });
|
|
439
|
+
expect(stale.snapshot.descriptor.columns).toHaveLength(1);
|
|
440
|
+
});
|
|
441
|
+
it('rejects invalid and oversized requests with distinct failures', async () => {
|
|
442
|
+
const browser = modelContext();
|
|
443
|
+
const controls = createControlInteractionRegistry();
|
|
444
|
+
registerWebMcpUiTools({
|
|
445
|
+
controlRegistry: controls,
|
|
446
|
+
dataSurfaceRegistry: createDataSurfaceRegistry(),
|
|
447
|
+
document: browser.document,
|
|
448
|
+
});
|
|
449
|
+
const inspect = findTool(browser.registered, 'smrt_ui_inspect_form_control');
|
|
450
|
+
expect(await parse(inspect.execute({ identity: { formId: '', controlId: 'name' } }))).toEqual({
|
|
451
|
+
ok: false,
|
|
452
|
+
reason: 'invalid_identifier',
|
|
453
|
+
details: 'formId',
|
|
454
|
+
});
|
|
455
|
+
expect(await parse(inspect.execute({ payload: 'x'.repeat(100_001) }))).toEqual({ ok: false, reason: 'limit_exceeded' });
|
|
456
|
+
controls.register({
|
|
457
|
+
identity: { formId: 'broken', controlId: 'value' },
|
|
458
|
+
metadata: { kind: 'text' },
|
|
459
|
+
getValue: () => {
|
|
460
|
+
throw new Error('private host detail');
|
|
461
|
+
},
|
|
462
|
+
});
|
|
463
|
+
const list = findTool(browser.registered, 'smrt_ui_list_form_controls');
|
|
464
|
+
const failed = await parse(list.execute({ formId: 'broken' }));
|
|
465
|
+
expect(failed).toEqual({ ok: false, reason: 'execution_failed' });
|
|
466
|
+
expect(JSON.stringify(failed)).not.toContain('private host detail');
|
|
467
|
+
});
|
|
468
|
+
it('locks a prefix atomically, permits distinct prefixes, and no-ops without WebMCP', () => {
|
|
469
|
+
const browser = modelContext();
|
|
470
|
+
const registries = {
|
|
471
|
+
controlRegistry: createControlInteractionRegistry(),
|
|
472
|
+
dataSurfaceRegistry: createDataSurfaceRegistry(),
|
|
473
|
+
};
|
|
474
|
+
const dispose = registerWebMcpUiTools({
|
|
475
|
+
...registries,
|
|
476
|
+
document: browser.document,
|
|
477
|
+
});
|
|
478
|
+
expect(() => registerWebMcpUiTools({ ...registries, document: browser.document })).toThrow('already registered');
|
|
479
|
+
expect(browser.registered).toHaveLength(6);
|
|
480
|
+
const disposeOther = registerWebMcpUiTools({
|
|
481
|
+
...registries,
|
|
482
|
+
prefix: 'other_',
|
|
483
|
+
document: browser.document,
|
|
484
|
+
});
|
|
485
|
+
expect(browser.registered).toHaveLength(12);
|
|
486
|
+
disposeOther();
|
|
487
|
+
dispose();
|
|
488
|
+
expect(() => registerWebMcpUiTools({
|
|
489
|
+
...registries,
|
|
490
|
+
document: {},
|
|
491
|
+
})).not.toThrow();
|
|
492
|
+
});
|
|
493
|
+
it('aborts every partial registration and releases the lock when a host rejects a tool', () => {
|
|
494
|
+
const signals = [];
|
|
495
|
+
let calls = 0;
|
|
496
|
+
const document = {
|
|
497
|
+
modelContext: {
|
|
498
|
+
registerTool(_tool, options) {
|
|
499
|
+
calls += 1;
|
|
500
|
+
if (options?.signal)
|
|
501
|
+
signals.push(options.signal);
|
|
502
|
+
if (calls === 3)
|
|
503
|
+
throw new Error('host collision');
|
|
504
|
+
},
|
|
505
|
+
},
|
|
506
|
+
};
|
|
507
|
+
const registries = {
|
|
508
|
+
controlRegistry: createControlInteractionRegistry(),
|
|
509
|
+
dataSurfaceRegistry: createDataSurfaceRegistry(),
|
|
510
|
+
};
|
|
511
|
+
expect(() => registerWebMcpUiTools({ ...registries, document })).toThrow('host collision');
|
|
512
|
+
expect(signals.every((signal) => signal.aborted)).toBe(true);
|
|
513
|
+
calls = 0;
|
|
514
|
+
document.modelContext.registerTool = (_tool, options) => {
|
|
515
|
+
calls += 1;
|
|
516
|
+
if (options?.signal)
|
|
517
|
+
signals.push(options.signal);
|
|
518
|
+
};
|
|
519
|
+
expect(() => registerWebMcpUiTools({ ...registries, document })).not.toThrow();
|
|
520
|
+
expect(calls).toBe(6);
|
|
521
|
+
});
|
|
522
|
+
it('observes asynchronous host rejection, aborts tools, and releases only its own lock', async () => {
|
|
523
|
+
let rejectFirstRegistration;
|
|
524
|
+
const signals = [];
|
|
525
|
+
let calls = 0;
|
|
526
|
+
const document = {
|
|
527
|
+
modelContext: {
|
|
528
|
+
registerTool(_tool, options) {
|
|
529
|
+
calls += 1;
|
|
530
|
+
if (options?.signal)
|
|
531
|
+
signals.push(options.signal);
|
|
532
|
+
if (calls === 1) {
|
|
533
|
+
return new Promise((_resolve, reject) => {
|
|
534
|
+
rejectFirstRegistration = reject;
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
},
|
|
538
|
+
},
|
|
539
|
+
};
|
|
540
|
+
const registries = {
|
|
541
|
+
controlRegistry: createControlInteractionRegistry(),
|
|
542
|
+
dataSurfaceRegistry: createDataSurfaceRegistry(),
|
|
543
|
+
};
|
|
544
|
+
const disposeFirst = registerWebMcpUiTools({ ...registries, document });
|
|
545
|
+
disposeFirst();
|
|
546
|
+
const disposeReplacement = registerWebMcpUiTools({
|
|
547
|
+
...registries,
|
|
548
|
+
document,
|
|
549
|
+
});
|
|
550
|
+
rejectFirstRegistration?.(new Error('late host collision'));
|
|
551
|
+
await Promise.resolve();
|
|
552
|
+
await Promise.resolve();
|
|
553
|
+
expect(signals.slice(0, 6).every((signal) => signal.aborted)).toBe(true);
|
|
554
|
+
expect(signals.slice(6).every((signal) => !signal.aborted)).toBe(true);
|
|
555
|
+
expect(() => registerWebMcpUiTools({ ...registries, document })).toThrow('already registered');
|
|
556
|
+
disposeReplacement();
|
|
557
|
+
expect(() => registerWebMcpUiTools({ ...registries, document })).not.toThrow();
|
|
558
|
+
});
|
|
559
|
+
it('releases an active prefix when asynchronous host registration fails', async () => {
|
|
560
|
+
const signals = [];
|
|
561
|
+
let rejectRegistration;
|
|
562
|
+
const document = {
|
|
563
|
+
modelContext: {
|
|
564
|
+
registerTool(_tool, options) {
|
|
565
|
+
if (options?.signal)
|
|
566
|
+
signals.push(options.signal);
|
|
567
|
+
if (!rejectRegistration) {
|
|
568
|
+
return new Promise((_resolve, reject) => {
|
|
569
|
+
rejectRegistration = reject;
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
},
|
|
573
|
+
},
|
|
574
|
+
};
|
|
575
|
+
const registries = {
|
|
576
|
+
controlRegistry: createControlInteractionRegistry(),
|
|
577
|
+
dataSurfaceRegistry: createDataSurfaceRegistry(),
|
|
578
|
+
};
|
|
579
|
+
registerWebMcpUiTools({ ...registries, document });
|
|
580
|
+
rejectRegistration?.(new Error('host collision'));
|
|
581
|
+
await Promise.resolve();
|
|
582
|
+
await Promise.resolve();
|
|
583
|
+
expect(signals.every((signal) => signal.aborted)).toBe(true);
|
|
584
|
+
expect(() => registerWebMcpUiTools({ ...registries, document })).not.toThrow();
|
|
585
|
+
});
|
|
586
|
+
});
|
|
@@ -5,7 +5,7 @@ import Harness from './webmcp-harness.svelte';
|
|
|
5
5
|
function installModelContext() {
|
|
6
6
|
const registered = [];
|
|
7
7
|
document.modelContext = {
|
|
8
|
-
registerTool(tool, options) {
|
|
8
|
+
async registerTool(tool, options) {
|
|
9
9
|
registered.push({ name: tool.name, signal: options?.signal });
|
|
10
10
|
},
|
|
11
11
|
};
|
|
@@ -30,6 +30,26 @@ describe('useWebMcpTool', () => {
|
|
|
30
30
|
view.unmount();
|
|
31
31
|
expect(registered[1].signal?.aborted).toBe(true);
|
|
32
32
|
});
|
|
33
|
+
it('observes asynchronous host rejection and aborts the failed registration', async () => {
|
|
34
|
+
let rejectRegistration;
|
|
35
|
+
let signal;
|
|
36
|
+
document.modelContext = {
|
|
37
|
+
registerTool(_tool, options) {
|
|
38
|
+
signal = options?.signal;
|
|
39
|
+
return new Promise((_resolve, reject) => {
|
|
40
|
+
rejectRegistration = reject;
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
const view = render(Harness);
|
|
45
|
+
await tick();
|
|
46
|
+
expect(signal?.aborted).toBe(false);
|
|
47
|
+
rejectRegistration?.(new Error('host collision'));
|
|
48
|
+
await Promise.resolve();
|
|
49
|
+
await Promise.resolve();
|
|
50
|
+
expect(signal?.aborted).toBe(true);
|
|
51
|
+
view.unmount();
|
|
52
|
+
});
|
|
33
53
|
it('is a no-op when WebMCP is unavailable', async () => {
|
|
34
54
|
const view = render(Harness);
|
|
35
55
|
await tick();
|
package/dist/web/index.d.ts
CHANGED
|
@@ -18,4 +18,7 @@ export { type ActivityFeedHandle, type ActivityFeedMap, type ActivityFeedOptions
|
|
|
18
18
|
export { type LiveCollection, type LiveCollectionMutation, type LiveCollectionOptions, type LiveCollectionStatus, liveCollection, } from './live-collection.svelte.js';
|
|
19
19
|
export { type RemoteQueryBinding, remoteQuery, } from './remote-query.svelte.js';
|
|
20
20
|
export { type UpdateAvailableView, type UseUpdateAvailableOptions, useUpdateAvailable, } from './update-available.svelte.js';
|
|
21
|
+
export type { WebMcpProviderConfig, WebMcpUiProviderConfig, } from './webmcp-provider.js';
|
|
22
|
+
export { type RegisterWebMcpUiToolsOptions, registerWebMcpUiTools, } from './webmcp-ui.js';
|
|
23
|
+
export { useWebMcpUi, type WebMcpUiContext, } from './webmcp-ui-context.js';
|
|
21
24
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/web/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/web/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,YAAY,EACZ,KAAK,kBAAkB,GACxB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,cAAc,GACf,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,KAAK,kBAAkB,EACvB,WAAW,GACZ,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,kBAAkB,GACnB,MAAM,8BAA8B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/web/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,YAAY,EACZ,KAAK,kBAAkB,GACxB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,cAAc,GACf,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,KAAK,kBAAkB,EACvB,WAAW,GACZ,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,kBAAkB,GACnB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,4BAA4B,EACjC,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,WAAW,EACX,KAAK,eAAe,GACrB,MAAM,wBAAwB,CAAC"}
|
package/dist/web/index.js
CHANGED
|
@@ -18,3 +18,5 @@ export { activityFeed, } from './activity-feed.svelte.js';
|
|
|
18
18
|
export { liveCollection, } from './live-collection.svelte.js';
|
|
19
19
|
export { remoteQuery, } from './remote-query.svelte.js';
|
|
20
20
|
export { useUpdateAvailable, } from './update-available.svelte.js';
|
|
21
|
+
export { registerWebMcpUiTools, } from './webmcp-ui.js';
|
|
22
|
+
export { useWebMcpUi, } from './webmcp-ui-context.js';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DataSurfaceRegistry } from '@happyvertical/smrt-ui/data';
|
|
2
|
+
import type { ControlInteractionRegistry } from '@happyvertical/smrt-ui/forms';
|
|
3
|
+
import type { RegisterWebMcpToolsOptions, SmrtWebClient, WebMcpExposurePolicy, WebMcpRegistrationDefinition } from '@happyvertical/smrt-web';
|
|
4
|
+
export interface WebMcpUiProviderConfig {
|
|
5
|
+
controlRegistry?: ControlInteractionRegistry;
|
|
6
|
+
dataSurfaceRegistry?: DataSurfaceRegistry;
|
|
7
|
+
/** Document-global namespace prefix. @default 'smrt_ui_' */
|
|
8
|
+
prefix?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface WebMcpProviderConfig extends WebMcpExposurePolicy {
|
|
11
|
+
definitions?: readonly WebMcpRegistrationDefinition[];
|
|
12
|
+
client?: SmrtWebClient;
|
|
13
|
+
basePath?: string;
|
|
14
|
+
fetchFn?: typeof fetch;
|
|
15
|
+
scope?: string;
|
|
16
|
+
filter?: RegisterWebMcpToolsOptions['filter'];
|
|
17
|
+
filterTool?: RegisterWebMcpToolsOptions['filterTool'];
|
|
18
|
+
resolveFetchers?: RegisterWebMcpToolsOptions['resolveFetchers'];
|
|
19
|
+
resolveToolFetchers?: RegisterWebMcpToolsOptions['resolveToolFetchers'];
|
|
20
|
+
/** Fixed browser-native tools over the mounted form/data registries. */
|
|
21
|
+
ui?: false | WebMcpUiProviderConfig;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=webmcp-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webmcp-provider.d.ts","sourceRoot":"","sources":["../../src/web/webmcp-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC/E,OAAO,KAAK,EACV,0BAA0B,EAC1B,aAAa,EACb,oBAAoB,EACpB,4BAA4B,EAC7B,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,sBAAsB;IACrC,eAAe,CAAC,EAAE,0BAA0B,CAAC;IAC7C,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAC1C,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAqB,SAAQ,oBAAoB;IAChE,WAAW,CAAC,EAAE,SAAS,4BAA4B,EAAE,CAAC;IACtD,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,0BAA0B,CAAC,QAAQ,CAAC,CAAC;IAC9C,UAAU,CAAC,EAAE,0BAA0B,CAAC,YAAY,CAAC,CAAC;IACtD,eAAe,CAAC,EAAE,0BAA0B,CAAC,iBAAiB,CAAC,CAAC;IAChE,mBAAmB,CAAC,EAAE,0BAA0B,CAAC,qBAAqB,CAAC,CAAC;IACxE,wEAAwE;IACxE,EAAE,CAAC,EAAE,KAAK,GAAG,sBAAsB,CAAC;CACrC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|