@qikdev/mcp 6.7.8 → 6.8.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/build/src/tools/create.d.ts.map +1 -1
- package/build/src/tools/create.js +6 -2
- package/build/src/tools/create.js.map +1 -1
- package/build/src/tools/definition.js +1 -1
- package/build/src/tools/definition.js.map +1 -1
- package/build/src/tools/list.d.ts.map +1 -1
- package/build/src/tools/list.js +4 -1
- package/build/src/tools/list.js.map +1 -1
- package/build/src/tools/schema-validator.d.ts +57 -0
- package/build/src/tools/schema-validator.d.ts.map +1 -0
- package/build/src/tools/schema-validator.js +390 -0
- package/build/src/tools/schema-validator.js.map +1 -0
- package/build/src/tools/update.d.ts.map +1 -1
- package/build/src/tools/update.js +59 -1
- package/build/src/tools/update.js.map +1 -1
- package/build/src/tools/user.d.ts +36 -0
- package/build/src/tools/user.d.ts.map +1 -1
- package/build/src/tools/user.js +77 -0
- package/build/src/tools/user.js.map +1 -1
- package/build/src/tools/utils.d.ts +24 -0
- package/build/src/tools/utils.d.ts.map +1 -0
- package/build/src/tools/utils.js +56 -0
- package/build/src/tools/utils.js.map +1 -0
- package/build/src/tools/workflow.d.ts.map +1 -1
- package/build/src/tools/workflow.js +78 -4
- package/build/src/tools/workflow.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema-based validation for content payloads.
|
|
3
|
+
* Fetches content type schemas from the glossary API and validates/coerces payloads.
|
|
4
|
+
*/
|
|
5
|
+
import { ConfigManager } from "../config.js";
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// CACHE
|
|
8
|
+
// ============================================================================
|
|
9
|
+
const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
10
|
+
const schemaCache = {
|
|
11
|
+
index: null,
|
|
12
|
+
schemas: new Map()
|
|
13
|
+
};
|
|
14
|
+
function isCacheValid(entry) {
|
|
15
|
+
return entry !== null && (Date.now() - entry.fetchedAt) < CACHE_TTL_MS;
|
|
16
|
+
}
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// SCHEMA FETCHING
|
|
19
|
+
// ============================================================================
|
|
20
|
+
async function getConfig() {
|
|
21
|
+
const configManager = new ConfigManager();
|
|
22
|
+
const config = await configManager.loadConfig();
|
|
23
|
+
if (!config) {
|
|
24
|
+
throw new Error('Qik MCP server not configured');
|
|
25
|
+
}
|
|
26
|
+
return config;
|
|
27
|
+
}
|
|
28
|
+
async function fetchGlossaryIndex() {
|
|
29
|
+
if (isCacheValid(schemaCache.index)) {
|
|
30
|
+
return schemaCache.index.data;
|
|
31
|
+
}
|
|
32
|
+
const config = await getConfig();
|
|
33
|
+
const response = await fetch(`${config.apiUrl || 'https://api.qik.dev'}/glossary/ai`, {
|
|
34
|
+
headers: {
|
|
35
|
+
'Authorization': `Bearer ${config.accessToken}`,
|
|
36
|
+
'Content-Type': 'application/json',
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
throw new Error(`Failed to fetch glossary: ${response.status}`);
|
|
41
|
+
}
|
|
42
|
+
const data = await response.json();
|
|
43
|
+
schemaCache.index = { data, fetchedAt: Date.now() };
|
|
44
|
+
return data;
|
|
45
|
+
}
|
|
46
|
+
export async function getContentTypeSchema(typeKey) {
|
|
47
|
+
// Check cache
|
|
48
|
+
const cached = schemaCache.schemas.get(typeKey) || null;
|
|
49
|
+
if (isCacheValid(cached)) {
|
|
50
|
+
return cached.data;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
// Get glossary index
|
|
54
|
+
const index = await fetchGlossaryIndex();
|
|
55
|
+
// Find the content type
|
|
56
|
+
const contentType = index.find(ct => ct.key === typeKey);
|
|
57
|
+
if (!contentType) {
|
|
58
|
+
return null; // Unknown content type
|
|
59
|
+
}
|
|
60
|
+
// Fetch detailed schema
|
|
61
|
+
const config = await getConfig();
|
|
62
|
+
const schemaUrl = contentType.urls.documentation.url;
|
|
63
|
+
const response = await fetch(schemaUrl, {
|
|
64
|
+
headers: {
|
|
65
|
+
'Authorization': `Bearer ${config.accessToken}`,
|
|
66
|
+
'Content-Type': 'application/json',
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
if (!response.ok) {
|
|
70
|
+
throw new Error(`Failed to fetch schema for ${typeKey}: ${response.status}`);
|
|
71
|
+
}
|
|
72
|
+
const schema = await response.json();
|
|
73
|
+
schemaCache.schemas.set(typeKey, { data: schema, fetchedAt: Date.now() });
|
|
74
|
+
return schema;
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
console.error(`Error fetching schema for ${typeKey}:`, error);
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// ============================================================================
|
|
82
|
+
// TYPE COERCION
|
|
83
|
+
// ============================================================================
|
|
84
|
+
/**
|
|
85
|
+
* Try to parse a string as JSON
|
|
86
|
+
*/
|
|
87
|
+
function tryParseJson(value) {
|
|
88
|
+
const trimmed = value.trim();
|
|
89
|
+
if ((trimmed.startsWith('{') && trimmed.endsWith('}')) ||
|
|
90
|
+
(trimmed.startsWith('[') && trimmed.endsWith(']'))) {
|
|
91
|
+
try {
|
|
92
|
+
return JSON.parse(value);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Coerce a value to boolean
|
|
102
|
+
*/
|
|
103
|
+
function coerceToBoolean(value) {
|
|
104
|
+
if (typeof value === 'boolean') {
|
|
105
|
+
return { value };
|
|
106
|
+
}
|
|
107
|
+
if (typeof value === 'string') {
|
|
108
|
+
const lower = value.toLowerCase().trim();
|
|
109
|
+
if (['true', 'yes', '1', 'on'].includes(lower)) {
|
|
110
|
+
return { value: true };
|
|
111
|
+
}
|
|
112
|
+
if (['false', 'no', '0', 'off', ''].includes(lower)) {
|
|
113
|
+
return { value: false };
|
|
114
|
+
}
|
|
115
|
+
return { value, error: `Cannot convert "${value}" to boolean` };
|
|
116
|
+
}
|
|
117
|
+
if (typeof value === 'number') {
|
|
118
|
+
return { value: value !== 0 };
|
|
119
|
+
}
|
|
120
|
+
return { value: Boolean(value) };
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Coerce a value to date (ISO string)
|
|
124
|
+
*/
|
|
125
|
+
function coerceToDate(value) {
|
|
126
|
+
if (value instanceof Date) {
|
|
127
|
+
return { value: value.toISOString() };
|
|
128
|
+
}
|
|
129
|
+
if (typeof value === 'string') {
|
|
130
|
+
const date = new Date(value);
|
|
131
|
+
if (!isNaN(date.getTime())) {
|
|
132
|
+
return { value: value }; // Keep original string if valid
|
|
133
|
+
}
|
|
134
|
+
return { value, error: `Cannot parse "${value}" as date` };
|
|
135
|
+
}
|
|
136
|
+
if (typeof value === 'number') {
|
|
137
|
+
const date = new Date(value);
|
|
138
|
+
if (!isNaN(date.getTime())) {
|
|
139
|
+
return { value: date.toISOString() };
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { value, error: `Cannot convert to date` };
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Coerce a value to the expected type based on field definition
|
|
146
|
+
*/
|
|
147
|
+
export function coerceValue(value, field) {
|
|
148
|
+
// Handle null/undefined
|
|
149
|
+
if (value === null || value === undefined) {
|
|
150
|
+
return { value };
|
|
151
|
+
}
|
|
152
|
+
// First, try to parse JSON strings (LLM sends nested objects as strings)
|
|
153
|
+
if (typeof value === 'string' && field.type !== 'string') {
|
|
154
|
+
const parsed = tryParseJson(value);
|
|
155
|
+
if (parsed !== null) {
|
|
156
|
+
value = parsed;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Handle array wrapping based on field cardinality
|
|
160
|
+
const isArrayField = field.maximum === 0 || (field.maximum !== undefined && field.maximum > 1);
|
|
161
|
+
switch (field.type) {
|
|
162
|
+
case 'string':
|
|
163
|
+
case 'email':
|
|
164
|
+
case 'url':
|
|
165
|
+
if (typeof value !== 'string') {
|
|
166
|
+
return { value: String(value) };
|
|
167
|
+
}
|
|
168
|
+
return { value };
|
|
169
|
+
case 'number':
|
|
170
|
+
if (typeof value === 'number') {
|
|
171
|
+
return { value };
|
|
172
|
+
}
|
|
173
|
+
if (typeof value === 'string') {
|
|
174
|
+
// Handle currency formatting (remove $, commas, etc.)
|
|
175
|
+
const cleaned = value.replace(/[$,\s]/g, '');
|
|
176
|
+
const num = parseFloat(cleaned);
|
|
177
|
+
if (!isNaN(num)) {
|
|
178
|
+
return { value: num };
|
|
179
|
+
}
|
|
180
|
+
return { value, error: `Cannot convert "${value}" to number` };
|
|
181
|
+
}
|
|
182
|
+
return { value, error: `Cannot convert to number` };
|
|
183
|
+
case 'integer':
|
|
184
|
+
if (typeof value === 'number') {
|
|
185
|
+
return { value: Math.round(value) };
|
|
186
|
+
}
|
|
187
|
+
if (typeof value === 'string') {
|
|
188
|
+
const int = parseInt(value, 10);
|
|
189
|
+
if (!isNaN(int)) {
|
|
190
|
+
return { value: int };
|
|
191
|
+
}
|
|
192
|
+
return { value, error: `Cannot convert "${value}" to integer` };
|
|
193
|
+
}
|
|
194
|
+
return { value, error: `Cannot convert to integer` };
|
|
195
|
+
case 'boolean':
|
|
196
|
+
return coerceToBoolean(value);
|
|
197
|
+
case 'date':
|
|
198
|
+
return coerceToDate(value);
|
|
199
|
+
case 'reference':
|
|
200
|
+
// References should be arrays of IDs (or single ID for maximum: 1)
|
|
201
|
+
if (Array.isArray(value)) {
|
|
202
|
+
// Recursively coerce array items (handle stringified arrays)
|
|
203
|
+
const coerced = value.map(v => {
|
|
204
|
+
if (typeof v === 'string') {
|
|
205
|
+
const parsed = tryParseJson(v);
|
|
206
|
+
return parsed !== null ? parsed : v;
|
|
207
|
+
}
|
|
208
|
+
return v;
|
|
209
|
+
});
|
|
210
|
+
return { value: coerced };
|
|
211
|
+
}
|
|
212
|
+
if (typeof value === 'string') {
|
|
213
|
+
// Single ID - wrap in array if needed
|
|
214
|
+
if (isArrayField) {
|
|
215
|
+
return { value: [value] };
|
|
216
|
+
}
|
|
217
|
+
return { value };
|
|
218
|
+
}
|
|
219
|
+
return { value };
|
|
220
|
+
case 'object':
|
|
221
|
+
// Already handled JSON parsing above
|
|
222
|
+
if (typeof value === 'object') {
|
|
223
|
+
return { value };
|
|
224
|
+
}
|
|
225
|
+
return { value, error: `Expected object for field "${field.title}"` };
|
|
226
|
+
case 'group':
|
|
227
|
+
// Visual-only field, no data
|
|
228
|
+
return { value: undefined };
|
|
229
|
+
default:
|
|
230
|
+
return { value };
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// ============================================================================
|
|
234
|
+
// FIELD VALIDATION
|
|
235
|
+
// ============================================================================
|
|
236
|
+
function isEmpty(value) {
|
|
237
|
+
if (value === null || value === undefined)
|
|
238
|
+
return true;
|
|
239
|
+
if (value === '')
|
|
240
|
+
return true;
|
|
241
|
+
if (Array.isArray(value) && value.length === 0)
|
|
242
|
+
return true;
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Validate a field value against its definition
|
|
247
|
+
*/
|
|
248
|
+
export function validateField(value, field) {
|
|
249
|
+
const errors = [];
|
|
250
|
+
// Skip group fields (visual only)
|
|
251
|
+
if (field.type === 'group') {
|
|
252
|
+
return errors;
|
|
253
|
+
}
|
|
254
|
+
// Required check
|
|
255
|
+
if (field.minimum !== undefined && field.minimum >= 1) {
|
|
256
|
+
if (isEmpty(value)) {
|
|
257
|
+
errors.push(`"${field.title}" is required`);
|
|
258
|
+
return errors; // No point continuing
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
// Skip further validation if empty and optional
|
|
262
|
+
if (isEmpty(value)) {
|
|
263
|
+
return errors;
|
|
264
|
+
}
|
|
265
|
+
// Cardinality check
|
|
266
|
+
const values = Array.isArray(value) ? value : [value];
|
|
267
|
+
if (field.maximum === 1 && values.length > 1) {
|
|
268
|
+
errors.push(`"${field.title}" accepts only one value (received ${values.length})`);
|
|
269
|
+
}
|
|
270
|
+
if (field.maximum !== undefined && field.maximum > 1 && values.length > field.maximum) {
|
|
271
|
+
errors.push(`"${field.title}" accepts at most ${field.maximum} values (received ${values.length})`);
|
|
272
|
+
}
|
|
273
|
+
// Options validation (for select/button widgets)
|
|
274
|
+
if (field.options && field.options.length > 0) {
|
|
275
|
+
const validValues = new Set(field.options.map(o => o.value));
|
|
276
|
+
for (const v of values) {
|
|
277
|
+
if (!validValues.has(v)) {
|
|
278
|
+
const optionsList = field.options.map(o => o.value).join(', ');
|
|
279
|
+
errors.push(`"${field.title}" value "${v}" is not valid. Options: ${optionsList}`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return errors;
|
|
284
|
+
}
|
|
285
|
+
// ============================================================================
|
|
286
|
+
// MAIN VALIDATION FUNCTION
|
|
287
|
+
// ============================================================================
|
|
288
|
+
// System fields that shouldn't be validated
|
|
289
|
+
const SYSTEM_FIELDS = new Set(['_id', 'meta', 'organisation', 'createdAt', 'updatedAt']);
|
|
290
|
+
/**
|
|
291
|
+
* Coerce a payload using content type schema for type information.
|
|
292
|
+
* Does NOT validate - just coerces types. Let the API handle validation.
|
|
293
|
+
*/
|
|
294
|
+
export async function validateAndCoercePayload(typeKey, payload, options = {}) {
|
|
295
|
+
const result = {
|
|
296
|
+
valid: true, // Always valid - we just coerce, don't validate
|
|
297
|
+
errors: [],
|
|
298
|
+
warnings: [],
|
|
299
|
+
coercedPayload: {}
|
|
300
|
+
};
|
|
301
|
+
// Try to get schema for type coercion
|
|
302
|
+
let schema = null;
|
|
303
|
+
try {
|
|
304
|
+
schema = await getContentTypeSchema(typeKey);
|
|
305
|
+
}
|
|
306
|
+
catch (error) {
|
|
307
|
+
result.warnings.push(`Could not fetch schema: ${error.message}`);
|
|
308
|
+
}
|
|
309
|
+
// If no schema, pass through with JSON string parsing only
|
|
310
|
+
if (!schema) {
|
|
311
|
+
result.coercedPayload = parsePayloadJsonStrings(payload);
|
|
312
|
+
return result;
|
|
313
|
+
}
|
|
314
|
+
// Build a map of field keys for quick lookup
|
|
315
|
+
const fieldMap = new Map();
|
|
316
|
+
for (const field of schema.fields) {
|
|
317
|
+
if (field.key) {
|
|
318
|
+
fieldMap.set(field.key, field);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
// Process all fields in the payload - coerce types but don't validate
|
|
322
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
323
|
+
// System fields - just parse JSON strings
|
|
324
|
+
if (SYSTEM_FIELDS.has(key)) {
|
|
325
|
+
result.coercedPayload[key] = parseValueJsonStrings(value);
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
const field = fieldMap.get(key);
|
|
329
|
+
if (!field) {
|
|
330
|
+
// Unknown field - pass through with JSON parsing
|
|
331
|
+
result.coercedPayload[key] = parseValueJsonStrings(value);
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
// Coerce the value to the correct type
|
|
335
|
+
const coerced = coerceValue(value, field);
|
|
336
|
+
if (coerced.error) {
|
|
337
|
+
result.warnings.push(`${field.title}: ${coerced.error}`);
|
|
338
|
+
}
|
|
339
|
+
result.coercedPayload[key] = coerced.value;
|
|
340
|
+
}
|
|
341
|
+
// No validation - let the API handle it
|
|
342
|
+
return result;
|
|
343
|
+
}
|
|
344
|
+
// ============================================================================
|
|
345
|
+
// HELPER FUNCTIONS
|
|
346
|
+
// ============================================================================
|
|
347
|
+
/**
|
|
348
|
+
* Recursively parse JSON strings in a value
|
|
349
|
+
*/
|
|
350
|
+
function parseValueJsonStrings(value) {
|
|
351
|
+
if (value === null || value === undefined) {
|
|
352
|
+
return value;
|
|
353
|
+
}
|
|
354
|
+
if (typeof value === 'string') {
|
|
355
|
+
const parsed = tryParseJson(value);
|
|
356
|
+
if (parsed !== null) {
|
|
357
|
+
return parseValueJsonStrings(parsed);
|
|
358
|
+
}
|
|
359
|
+
return value;
|
|
360
|
+
}
|
|
361
|
+
if (Array.isArray(value)) {
|
|
362
|
+
return value.map(v => parseValueJsonStrings(v));
|
|
363
|
+
}
|
|
364
|
+
if (typeof value === 'object') {
|
|
365
|
+
const result = {};
|
|
366
|
+
for (const [k, v] of Object.entries(value)) {
|
|
367
|
+
result[k] = parseValueJsonStrings(v);
|
|
368
|
+
}
|
|
369
|
+
return result;
|
|
370
|
+
}
|
|
371
|
+
return value;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Parse JSON strings throughout a payload object
|
|
375
|
+
*/
|
|
376
|
+
function parsePayloadJsonStrings(payload) {
|
|
377
|
+
const result = {};
|
|
378
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
379
|
+
result[key] = parseValueJsonStrings(value);
|
|
380
|
+
}
|
|
381
|
+
return result;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Clear the schema cache (useful for testing)
|
|
385
|
+
*/
|
|
386
|
+
export function clearSchemaCache() {
|
|
387
|
+
schemaCache.index = null;
|
|
388
|
+
schemaCache.schemas.clear();
|
|
389
|
+
}
|
|
390
|
+
//# sourceMappingURL=schema-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-validator.js","sourceRoot":"","sources":["../../../src/tools/schema-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/tools/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/tools/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAI1D,eAAO,MAAM,iBAAiB,EAAE,IAgD/B,CAAC;AAEF,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CA4DhH"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ConfigManager } from "../config.js";
|
|
2
|
+
import { validateAndCoercePayload } from "./schema-validator.js";
|
|
2
3
|
export const updateContentTool = {
|
|
3
4
|
name: "update_content",
|
|
4
5
|
description: `Update existing content items in Qik.
|
|
@@ -10,8 +11,10 @@ export const updateContentTool = {
|
|
|
10
11
|
|
|
11
12
|
**Optional:**
|
|
12
13
|
- updateMethod: "patch" (default) for partial updates, "put" for full replacement
|
|
14
|
+
- typeKey: Content type key for schema validation (e.g., 'article', 'profile'). If provided, payload will be validated and coerced against the schema.
|
|
13
15
|
|
|
14
16
|
All other properties are passed directly to the API as the update payload.
|
|
17
|
+
The MCP server will automatically validate and coerce values if typeKey is provided.
|
|
15
18
|
|
|
16
19
|
**Tags Shorthand:**
|
|
17
20
|
Pass \`tags: ['green', 'red']\` as string names and the backend auto-creates tags.
|
|
@@ -20,6 +23,7 @@ Pass \`tags: ['green', 'red']\` as string names and the backend auto-creates tag
|
|
|
20
23
|
\`\`\`json
|
|
21
24
|
{
|
|
22
25
|
"contentId": "abc123",
|
|
26
|
+
"typeKey": "article",
|
|
23
27
|
"title": "Updated Title",
|
|
24
28
|
"tags": ["featured", "breaking"]
|
|
25
29
|
}
|
|
@@ -31,6 +35,10 @@ Pass \`tags: ['green', 'red']\` as string names and the backend auto-creates tag
|
|
|
31
35
|
type: "string",
|
|
32
36
|
description: "The ID of the content item to update"
|
|
33
37
|
},
|
|
38
|
+
typeKey: {
|
|
39
|
+
type: "string",
|
|
40
|
+
description: "Content type key for schema validation (e.g., 'article', 'profile')"
|
|
41
|
+
},
|
|
34
42
|
updateMethod: {
|
|
35
43
|
type: "string",
|
|
36
44
|
enum: ["patch", "put"],
|
|
@@ -48,11 +56,22 @@ export async function handleUpdateContent(args) {
|
|
|
48
56
|
if (!config) {
|
|
49
57
|
throw new Error('Qik MCP server not configured. Run setup first.');
|
|
50
58
|
}
|
|
51
|
-
const { contentId, updateMethod, ...
|
|
59
|
+
const { contentId, typeKey, updateMethod, ...rawPayload } = args;
|
|
52
60
|
if (!contentId) {
|
|
53
61
|
throw new Error('contentId is required');
|
|
54
62
|
}
|
|
55
63
|
const method = (updateMethod || 'patch').toUpperCase();
|
|
64
|
+
const isPartialUpdate = method === 'PATCH';
|
|
65
|
+
let payload;
|
|
66
|
+
// If typeKey is provided, coerce using schema (fixes stringified JSON from LLMs)
|
|
67
|
+
if (typeKey) {
|
|
68
|
+
const validation = await validateAndCoercePayload(typeKey, rawPayload);
|
|
69
|
+
payload = validation.coercedPayload;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// No typeKey provided - just do basic JSON string parsing
|
|
73
|
+
payload = parsePayloadJsonStrings(rawPayload);
|
|
74
|
+
}
|
|
56
75
|
const response = await fetch(`${config.apiUrl || 'https://api.qik.dev'}/content/${contentId}`, {
|
|
57
76
|
method,
|
|
58
77
|
headers: {
|
|
@@ -82,4 +101,43 @@ export async function handleUpdateContent(args) {
|
|
|
82
101
|
};
|
|
83
102
|
}
|
|
84
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Basic JSON string parsing for payloads without schema validation
|
|
106
|
+
*/
|
|
107
|
+
function parsePayloadJsonStrings(payload) {
|
|
108
|
+
const result = {};
|
|
109
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
110
|
+
result[key] = parseValueJsonStrings(value);
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
function parseValueJsonStrings(value) {
|
|
115
|
+
if (value === null || value === undefined) {
|
|
116
|
+
return value;
|
|
117
|
+
}
|
|
118
|
+
if (typeof value === 'string') {
|
|
119
|
+
const trimmed = value.trim();
|
|
120
|
+
if ((trimmed.startsWith('{') && trimmed.endsWith('}')) ||
|
|
121
|
+
(trimmed.startsWith('[') && trimmed.endsWith(']'))) {
|
|
122
|
+
try {
|
|
123
|
+
return parseValueJsonStrings(JSON.parse(value));
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return value;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return value;
|
|
130
|
+
}
|
|
131
|
+
if (Array.isArray(value)) {
|
|
132
|
+
return value.map(v => parseValueJsonStrings(v));
|
|
133
|
+
}
|
|
134
|
+
if (typeof value === 'object') {
|
|
135
|
+
const result = {};
|
|
136
|
+
for (const [k, v] of Object.entries(value)) {
|
|
137
|
+
result[k] = parseValueJsonStrings(v);
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
return value;
|
|
142
|
+
}
|
|
85
143
|
//# sourceMappingURL=update.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../../src/tools/update.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../../src/tools/update.ts"],"names":[],"mappings":"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"}
|
|
@@ -40,5 +40,41 @@ export declare function hasPermission(userSession: UserSession, permission: stri
|
|
|
40
40
|
export declare function getAvailableScopes(userSession: UserSession, permission: string): string[];
|
|
41
41
|
export declare function hasPermissionInScope(userSession: UserSession, permission: string, scopeId: string): boolean;
|
|
42
42
|
export declare function getScopeTitle(userSession: UserSession, scopeId: string): string;
|
|
43
|
+
export declare function hasAnyPermission(userSession: UserSession, permissions: string[]): boolean;
|
|
44
|
+
export declare function hasFieldPermission(userSession: UserSession, basePermission: string): boolean;
|
|
45
|
+
export interface PermissionCheck {
|
|
46
|
+
permission: string;
|
|
47
|
+
alternatives?: string[];
|
|
48
|
+
description: string;
|
|
49
|
+
}
|
|
50
|
+
export declare function checkPermissions(userSession: UserSession, required: PermissionCheck[]): {
|
|
51
|
+
hasAll: boolean;
|
|
52
|
+
missing: PermissionCheck[];
|
|
53
|
+
};
|
|
54
|
+
export declare function formatPermissionError(operation: string, missing: PermissionCheck[]): string;
|
|
55
|
+
export declare const WORKFLOW_PERMISSIONS: {
|
|
56
|
+
view: ({
|
|
57
|
+
permission: string;
|
|
58
|
+
alternatives: string[];
|
|
59
|
+
description: string;
|
|
60
|
+
} | {
|
|
61
|
+
permission: string;
|
|
62
|
+
description: string;
|
|
63
|
+
alternatives?: never;
|
|
64
|
+
})[];
|
|
65
|
+
edit: ({
|
|
66
|
+
permission: string;
|
|
67
|
+
alternatives: string[];
|
|
68
|
+
description: string;
|
|
69
|
+
} | {
|
|
70
|
+
permission: string;
|
|
71
|
+
description: string;
|
|
72
|
+
alternatives?: never;
|
|
73
|
+
})[];
|
|
74
|
+
create: {
|
|
75
|
+
permission: string;
|
|
76
|
+
description: string;
|
|
77
|
+
}[];
|
|
78
|
+
};
|
|
43
79
|
export declare function getUserSessionData(): Promise<UserSession>;
|
|
44
80
|
//# sourceMappingURL=user.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../../src/tools/user.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAG1D,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,CAAC,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC,EAAE,CAAC;IAC3D,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE;QACb,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,WAAW,EAAE;QACX,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAAC;KACrC,CAAC;IACF,kBAAkB,CAAC,EAAE,GAAG,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,eAAO,MAAM,kBAAkB,EAAE,IAOhC,CAAC;AAEF,wBAAsB,oBAAoB,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAqCxG;AAGD,wBAAgB,aAAa,CAAC,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAiBnF;AAGD,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CA+BzF;AAGD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAW3G;AAGD,wBAAgB,aAAa,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAO/E;AAGD,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,WAAW,CAAC,CAoB/D"}
|
|
1
|
+
{"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../../src/tools/user.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAG1D,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,CAAC,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC,EAAE,CAAC;IAC3D,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE;QACb,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,WAAW,EAAE;QACX,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAAC;KACrC,CAAC;IACF,kBAAkB,CAAC,EAAE,GAAG,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,eAAO,MAAM,kBAAkB,EAAE,IAOhC,CAAC;AAEF,wBAAsB,oBAAoB,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAqCxG;AAGD,wBAAgB,aAAa,CAAC,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAiBnF;AAGD,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CA+BzF;AAGD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAW3G;AAGD,wBAAgB,aAAa,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAO/E;AAGD,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAOzF;AAGD,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAuB5F;AAGD,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,eAAe,EAAE,GAAG;IACvF,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B,CAoBA;AAGD,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,MAAM,CAe3F;AAGD,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;CAYhC,CAAC;AAGF,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,WAAW,CAAC,CAoB/D"}
|
package/build/src/tools/user.js
CHANGED
|
@@ -106,6 +106,83 @@ export function getScopeTitle(userSession, scopeId) {
|
|
|
106
106
|
const scope = userSession.permissions[scopeId];
|
|
107
107
|
return scope?.title || scopeId;
|
|
108
108
|
}
|
|
109
|
+
// Helper function to check if user has any matching permission (supports wildcards)
|
|
110
|
+
export function hasAnyPermission(userSession, permissions) {
|
|
111
|
+
for (const perm of permissions) {
|
|
112
|
+
if (hasPermission(userSession, perm)) {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
// Helper function to check for wildcard field permissions (e.g., definition.viewfield.*)
|
|
119
|
+
export function hasFieldPermission(userSession, basePermission) {
|
|
120
|
+
// Check for wildcard permission (e.g., definition.viewfield.*)
|
|
121
|
+
if (hasPermission(userSession, `${basePermission}.*`)) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
// Check if any specific field permission exists
|
|
125
|
+
if (!userSession.permissions || typeof userSession.permissions !== 'object') {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
for (const scopeId in userSession.permissions) {
|
|
129
|
+
const scope = userSession.permissions[scopeId];
|
|
130
|
+
if (scope.permissions && Array.isArray(scope.permissions)) {
|
|
131
|
+
for (const perm of scope.permissions) {
|
|
132
|
+
if (perm.startsWith(`${basePermission}.`)) {
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
export function checkPermissions(userSession, required) {
|
|
141
|
+
const missing = [];
|
|
142
|
+
for (const req of required) {
|
|
143
|
+
const allToCheck = [req.permission, ...(req.alternatives || [])];
|
|
144
|
+
const hasPerm = allToCheck.some(p => {
|
|
145
|
+
// Handle field permissions specially
|
|
146
|
+
if (p.includes('.viewfield.') || p.includes('.editfield.')) {
|
|
147
|
+
const basePerm = p.replace('.*', '');
|
|
148
|
+
return hasFieldPermission(userSession, basePerm);
|
|
149
|
+
}
|
|
150
|
+
return hasPermission(userSession, p);
|
|
151
|
+
});
|
|
152
|
+
if (!hasPerm) {
|
|
153
|
+
missing.push(req);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return { hasAll: missing.length === 0, missing };
|
|
157
|
+
}
|
|
158
|
+
// Generate user-friendly permission error message
|
|
159
|
+
export function formatPermissionError(operation, missing) {
|
|
160
|
+
let message = `**Permission Error:** Cannot ${operation}.\n\n`;
|
|
161
|
+
message += `The following permissions are missing:\n\n`;
|
|
162
|
+
for (const m of missing) {
|
|
163
|
+
message += `- \`${m.permission}\``;
|
|
164
|
+
if (m.alternatives?.length) {
|
|
165
|
+
message += ` (or ${m.alternatives.map(a => `\`${a}\``).join(', ')})`;
|
|
166
|
+
}
|
|
167
|
+
message += ` - ${m.description}\n`;
|
|
168
|
+
}
|
|
169
|
+
message += `\n**To fix:** Update the application token permissions in the Qik admin panel.`;
|
|
170
|
+
return message;
|
|
171
|
+
}
|
|
172
|
+
// Pre-defined permission requirements for common operations
|
|
173
|
+
export const WORKFLOW_PERMISSIONS = {
|
|
174
|
+
view: [
|
|
175
|
+
{ permission: 'definition.viewany', alternatives: ['definition.viewown'], description: 'View workflow definitions' },
|
|
176
|
+
{ permission: 'definition.viewfield.*', description: 'View definition fields (title, workflow structure, etc.)' }
|
|
177
|
+
],
|
|
178
|
+
edit: [
|
|
179
|
+
{ permission: 'definition.editany', alternatives: ['definition.editown'], description: 'Edit workflow definitions' },
|
|
180
|
+
{ permission: 'definition.editfield.*', description: 'Edit definition fields (title, workflow structure, etc.)' }
|
|
181
|
+
],
|
|
182
|
+
create: [
|
|
183
|
+
{ permission: 'definition.create', description: 'Create new definitions' }
|
|
184
|
+
]
|
|
185
|
+
};
|
|
109
186
|
// Helper function to get user session data
|
|
110
187
|
export async function getUserSessionData() {
|
|
111
188
|
const configManager = new ConfigManager();
|