@topolo/mcp 0.14.3 → 0.14.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/README.md +1 -1
- package/dist/index.js +177 -40
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -59,7 +59,7 @@ must not use an `npx` launcher because that makes startup network-dependent.
|
|
|
59
59
|
|
|
60
60
|
Local stdio action results return `topolo-secret:<id>` references instead of
|
|
61
61
|
bearer credentials. Pass these references unchanged to subsequent published
|
|
62
|
-
actions; SDK 0.21.
|
|
62
|
+
actions; SDK 0.21.4 resolves nonempty string credentials internally using the OS protected store and
|
|
63
63
|
masks them in plans and diagnostics. Entries are bound to the verified
|
|
64
64
|
principal, organization, API key identity when present, and environment.
|
|
65
65
|
References expire after 30 minutes; accessing an expired entry deletes it.
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
5
|
|
|
6
|
-
// node_modules/.pnpm/@topolo+sdk@0.
|
|
6
|
+
// node_modules/.pnpm/@topolo+sdk@0.22.0/node_modules/@topolo/sdk/dist/index.js
|
|
7
7
|
function applyAuthHeaders(headers, credential) {
|
|
8
8
|
if (credential.kind === "api_key") {
|
|
9
9
|
headers.set("X-Api-Key", credential.apiKey);
|
|
@@ -77,6 +77,9 @@ var PUBLIC_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
|
77
77
|
"unknown_service"
|
|
78
78
|
]);
|
|
79
79
|
var ERROR_CODE_PATTERN = /^[a-z][a-z0-9_]{0,63}$/;
|
|
80
|
+
var SERVICE_ERROR_CODE_PATTERN = /^[a-z][a-z0-9]*(?:_[a-z][a-z0-9]*){1,9}$/;
|
|
81
|
+
var SERVICE_MESSAGE_MAX_LENGTH = 300;
|
|
82
|
+
var SERVICE_ISSUE_LIMIT = 32;
|
|
80
83
|
var TOPOLO_REQUEST_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
81
84
|
var CLOUDFLARE_RAY_ID_PATTERN = /^[0-9a-f]{16}-[A-Z]{3}$/;
|
|
82
85
|
var PERMISSION_PATTERN = /^[a-z][a-z0-9_-]{0,63}(?:\.[a-z][a-z0-9_-]{0,63})*:(?:[a-z][a-z0-9_-]{0,63}|\*)$/;
|
|
@@ -101,6 +104,24 @@ function canonicalTopoloErrorCode(value) {
|
|
|
101
104
|
if (!ERROR_CODE_PATTERN.test(candidate) || !PUBLIC_ERROR_CODES.has(candidate)) return null;
|
|
102
105
|
return candidate;
|
|
103
106
|
}
|
|
107
|
+
function canonicalTopoloServiceErrorCode(value) {
|
|
108
|
+
const platform2 = canonicalTopoloErrorCode(value);
|
|
109
|
+
if (platform2) return platform2;
|
|
110
|
+
if (typeof value !== "string") return null;
|
|
111
|
+
const candidate = value.trim();
|
|
112
|
+
if (candidate.length > 64 || !SERVICE_ERROR_CODE_PATTERN.test(candidate)) return null;
|
|
113
|
+
const wordLike = candidate.split("_").every((segment) => {
|
|
114
|
+
const digits = segment.replace(/[a-z]/g, "").length;
|
|
115
|
+
return digits === 0 || digits < segment.length - digits && segment.length <= 8;
|
|
116
|
+
});
|
|
117
|
+
return wordLike ? candidate : null;
|
|
118
|
+
}
|
|
119
|
+
function sanitizeTopoloServiceMessage(value) {
|
|
120
|
+
if (typeof value !== "string") return void 0;
|
|
121
|
+
const text2 = value.replace(/[\u0000-\u001f\u007f-\u009f\u200b-\u200f\u2028-\u202e\u2066-\u2069\ufeff]/g, " ").replace(/\b[a-z][a-z0-9+.-]*:\/\/\S+/gi, "[url]").replace(/[^\s@<>()[\],;:"']+@[^\s@<>()[\],;:"']+\.[a-z]{2,}/gi, "[email]").replace(/[A-Za-z0-9_\-+/=.]{20,}/g, (run) => /[0-9]/.test(run) && /[A-Za-z]/.test(run) ? "[redacted]" : run).replace(/\s+/g, " ").trim();
|
|
122
|
+
if (!text2) return void 0;
|
|
123
|
+
return text2.length > SERVICE_MESSAGE_MAX_LENGTH ? `${text2.slice(0, SERVICE_MESSAGE_MAX_LENGTH - 1).trimEnd()}\u2026` : text2;
|
|
124
|
+
}
|
|
104
125
|
function canonicalTopoloRequestId(value) {
|
|
105
126
|
if (typeof value !== "string") return void 0;
|
|
106
127
|
const candidate = value.trim();
|
|
@@ -125,7 +146,7 @@ var TopoloAuthError = class extends TopoloSdkError {
|
|
|
125
146
|
retryAfter;
|
|
126
147
|
details;
|
|
127
148
|
constructor(message, code = "auth_error", options = {}) {
|
|
128
|
-
super(
|
|
149
|
+
super(canonicalTopoloServiceErrorCode(code) ?? "auth_error", message);
|
|
129
150
|
this.name = "TopoloAuthError";
|
|
130
151
|
this.status = options.status ?? 401;
|
|
131
152
|
this.body = options.body;
|
|
@@ -149,7 +170,7 @@ var TopoloPermissionError = class extends TopoloSdkError {
|
|
|
149
170
|
details;
|
|
150
171
|
constructor(message, required, options = {}) {
|
|
151
172
|
super(
|
|
152
|
-
|
|
173
|
+
canonicalTopoloServiceErrorCode(options.code) ?? serviceErrorCode(options.body, "permission_denied"),
|
|
153
174
|
message
|
|
154
175
|
);
|
|
155
176
|
this.name = "TopoloPermissionError";
|
|
@@ -168,18 +189,34 @@ var TopoloPermissionError = class extends TopoloSdkError {
|
|
|
168
189
|
function extractTopoloServiceErrorCode(body) {
|
|
169
190
|
if (!body || typeof body !== "object" || Array.isArray(body)) return null;
|
|
170
191
|
const record2 = body;
|
|
171
|
-
const topLevel =
|
|
192
|
+
const topLevel = canonicalTopoloServiceErrorCode(record2.code);
|
|
172
193
|
if (topLevel) return topLevel;
|
|
173
194
|
const nested = record2.error;
|
|
174
|
-
const nestedString =
|
|
195
|
+
const nestedString = canonicalTopoloServiceErrorCode(nested);
|
|
175
196
|
if (nestedString) return nestedString;
|
|
176
197
|
if (nested && typeof nested === "object" && !Array.isArray(nested)) {
|
|
177
198
|
const code = nested.code;
|
|
178
|
-
const nestedCode =
|
|
199
|
+
const nestedCode = canonicalTopoloServiceErrorCode(code);
|
|
179
200
|
if (nestedCode) return nestedCode;
|
|
180
201
|
}
|
|
181
202
|
return null;
|
|
182
203
|
}
|
|
204
|
+
function extractTopoloServiceErrorMessage(body) {
|
|
205
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) return void 0;
|
|
206
|
+
const record2 = body;
|
|
207
|
+
const nested = record2.error;
|
|
208
|
+
const candidates = [];
|
|
209
|
+
if (nested && typeof nested === "object" && !Array.isArray(nested)) {
|
|
210
|
+
candidates.push(nested.message);
|
|
211
|
+
}
|
|
212
|
+
candidates.push(record2.message, record2.error_description);
|
|
213
|
+
if (typeof nested === "string" && !canonicalTopoloServiceErrorCode(nested)) candidates.push(nested);
|
|
214
|
+
for (const candidate of candidates) {
|
|
215
|
+
const message = sanitizeTopoloServiceMessage(candidate);
|
|
216
|
+
if (message) return message;
|
|
217
|
+
}
|
|
218
|
+
return void 0;
|
|
219
|
+
}
|
|
183
220
|
function serviceErrorCode(body, fallback) {
|
|
184
221
|
return extractTopoloServiceErrorCode(body) ?? fallback;
|
|
185
222
|
}
|
|
@@ -193,10 +230,7 @@ function extractTopoloServiceErrorDetails(body) {
|
|
|
193
230
|
if (candidate === void 0) candidate = nestedRecord.details ?? nestedRecord;
|
|
194
231
|
}
|
|
195
232
|
if (candidate === void 0) candidate = record2;
|
|
196
|
-
if (Array.isArray(candidate))
|
|
197
|
-
const paths = canonicalTopoloValidationPaths(candidate);
|
|
198
|
-
return paths.length ? { paths } : void 0;
|
|
199
|
-
}
|
|
233
|
+
if (Array.isArray(candidate)) return validationIssueDetails(canonicalTopoloValidationIssues(candidate)) ?? void 0;
|
|
200
234
|
if (!candidate || typeof candidate !== "object") return void 0;
|
|
201
235
|
const source = candidate;
|
|
202
236
|
const safe = {};
|
|
@@ -238,18 +272,59 @@ function extractTopoloServiceErrorDetails(body) {
|
|
|
238
272
|
if (paths.length) safe[key] = paths;
|
|
239
273
|
}
|
|
240
274
|
}
|
|
275
|
+
const issues = [
|
|
276
|
+
...Array.isArray(source.issues) ? canonicalTopoloValidationIssues(source.issues) : [],
|
|
277
|
+
...flattenedValidationIssues(source.formErrors, source.fieldErrors)
|
|
278
|
+
].slice(0, SERVICE_ISSUE_LIMIT);
|
|
279
|
+
Object.assign(safe, validationIssueDetails(issues));
|
|
241
280
|
return Object.keys(safe).length ? safe : void 0;
|
|
242
281
|
}
|
|
243
|
-
function
|
|
282
|
+
function validationIssueDetails(issues) {
|
|
283
|
+
if (!issues.length) return null;
|
|
244
284
|
const paths = [];
|
|
245
|
-
for (const
|
|
246
|
-
if (
|
|
247
|
-
|
|
285
|
+
for (const issue22 of issues) {
|
|
286
|
+
if (issue22.path && !paths.includes(issue22.path)) paths.push(issue22.path);
|
|
287
|
+
}
|
|
288
|
+
return paths.length ? { paths, issues } : { issues };
|
|
289
|
+
}
|
|
290
|
+
function issue(path, message) {
|
|
291
|
+
const text2 = sanitizeTopoloServiceMessage(message);
|
|
292
|
+
if (!path && !text2) return null;
|
|
293
|
+
return { ...path ? { path } : {}, ...text2 ? { message: text2 } : {} };
|
|
294
|
+
}
|
|
295
|
+
function canonicalTopoloValidationIssues(values) {
|
|
296
|
+
const issues = [];
|
|
297
|
+
for (const value of values) {
|
|
298
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) continue;
|
|
299
|
+
const record2 = value;
|
|
248
300
|
const path = canonicalTopoloValidationPath(record2.field) ?? canonicalTopoloValidationPath(record2.path);
|
|
249
|
-
if (
|
|
250
|
-
|
|
301
|
+
if (!path) continue;
|
|
302
|
+
const projected = issue(path, record2.message);
|
|
303
|
+
if (projected) issues.push(projected);
|
|
304
|
+
if (issues.length === SERVICE_ISSUE_LIMIT) break;
|
|
305
|
+
}
|
|
306
|
+
return issues;
|
|
307
|
+
}
|
|
308
|
+
function flattenedValidationIssues(formErrors, fieldErrors) {
|
|
309
|
+
const issues = [];
|
|
310
|
+
if (Array.isArray(formErrors)) {
|
|
311
|
+
for (const message of formErrors) {
|
|
312
|
+
const projected = issue(void 0, message);
|
|
313
|
+
if (projected) issues.push(projected);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (fieldErrors && typeof fieldErrors === "object" && !Array.isArray(fieldErrors)) {
|
|
317
|
+
for (const [key, messages] of Object.entries(fieldErrors)) {
|
|
318
|
+
const path = canonicalTopoloValidationPath(key);
|
|
319
|
+
if (!path) continue;
|
|
320
|
+
const list = Array.isArray(messages) && messages.length ? messages : [void 0];
|
|
321
|
+
for (const message of list) {
|
|
322
|
+
const projected = issue(path, message);
|
|
323
|
+
if (projected) issues.push(projected);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
251
326
|
}
|
|
252
|
-
return
|
|
327
|
+
return issues;
|
|
253
328
|
}
|
|
254
329
|
function canonicalTopoloValidationPath(value) {
|
|
255
330
|
if (typeof value === "string") {
|
|
@@ -271,7 +346,9 @@ function canonicalTopoloValidationPath(value) {
|
|
|
271
346
|
return PUBLIC_FIELD_PATH_PATTERN.test(path) ? path : void 0;
|
|
272
347
|
}
|
|
273
348
|
function publicTopoloErrorMessage(error) {
|
|
274
|
-
const
|
|
349
|
+
const serviceMessage = typeof error === "string" ? void 0 : extractTopoloServiceErrorMessage(error.body);
|
|
350
|
+
if (serviceMessage) return serviceMessage;
|
|
351
|
+
const code = canonicalTopoloServiceErrorCode(
|
|
275
352
|
typeof error === "string" ? error : error.code ?? extractTopoloServiceErrorCode(error.body)
|
|
276
353
|
) ?? "request_failed";
|
|
277
354
|
if (/(?:organization|org).*(?:enroll|membership|member|admission)/.test(code)) {
|
|
@@ -288,7 +365,7 @@ function publicTopoloErrorMessage(error) {
|
|
|
288
365
|
return `Topolo request failed (${code}).`;
|
|
289
366
|
}
|
|
290
367
|
function topoloErrorHint(error) {
|
|
291
|
-
const code =
|
|
368
|
+
const code = canonicalTopoloServiceErrorCode(
|
|
292
369
|
typeof error === "string" ? error : error.code ?? extractTopoloServiceErrorCode(error.body)
|
|
293
370
|
);
|
|
294
371
|
if (!code) return void 0;
|
|
@@ -372,7 +449,8 @@ async function resolveActionSecrets(value, store, secrets) {
|
|
|
372
449
|
if (isActionSecretReference(value)) {
|
|
373
450
|
if (!store) throw new TopoloSdkError("action_secret_store_required", "Protected action references require a secret store.");
|
|
374
451
|
const resolved = await store.load(value);
|
|
375
|
-
if (typeof resolved
|
|
452
|
+
if (typeof resolved !== "string" || !resolved) throw new TopoloSdkError("action_secret_unsupported_type", "Protected action handoff requires a nonempty string credential.");
|
|
453
|
+
secrets.set(resolved, value);
|
|
376
454
|
return resolved;
|
|
377
455
|
}
|
|
378
456
|
if (Array.isArray(value)) return Promise.all(value.map((item) => resolveActionSecrets(item, store, secrets)));
|
|
@@ -654,8 +732,8 @@ function inspectSchema(schema, path, root, depth) {
|
|
|
654
732
|
);
|
|
655
733
|
for (const [key, child] of children) {
|
|
656
734
|
if (!isRecord2(child)) continue;
|
|
657
|
-
const
|
|
658
|
-
if (
|
|
735
|
+
const issue22 = inspectSchema(child, `${path}.${key}`, root, depth + 1);
|
|
736
|
+
if (issue22) return issue22;
|
|
659
737
|
}
|
|
660
738
|
return null;
|
|
661
739
|
}
|
|
@@ -1971,7 +2049,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
1971
2049
|
input: selectedInput,
|
|
1972
2050
|
inputSource: input ? "provided" : example ? "example" : "empty",
|
|
1973
2051
|
missingFields: [...new Set(
|
|
1974
|
-
plan.validation.errors.filter((
|
|
2052
|
+
plan.validation.errors.filter((issue22) => issue22.code === "required").map((issue22) => issue22.path)
|
|
1975
2053
|
)],
|
|
1976
2054
|
plan
|
|
1977
2055
|
};
|
|
@@ -2036,7 +2114,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
2036
2114
|
if (!validation.valid) {
|
|
2037
2115
|
throw new TopoloSdkError(
|
|
2038
2116
|
"invalid_action_input",
|
|
2039
|
-
`Topolo action "${entry.actionId}" input is invalid: ${validation.errors.map((
|
|
2117
|
+
`Topolo action "${entry.actionId}" input is invalid: ${validation.errors.map((issue22) => `${issue22.path} ${issue22.message}`).join("; ")}`
|
|
2040
2118
|
);
|
|
2041
2119
|
}
|
|
2042
2120
|
const resourceIssue = validateActionResource(entry, options.resource);
|
|
@@ -3327,7 +3405,7 @@ function createTopolo(options) {
|
|
|
3327
3405
|
};
|
|
3328
3406
|
}
|
|
3329
3407
|
|
|
3330
|
-
// node_modules/.pnpm/@topolo+sdk@0.
|
|
3408
|
+
// node_modules/.pnpm/@topolo+sdk@0.22.0/node_modules/@topolo/sdk/dist/node/credential-store.js
|
|
3331
3409
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2, chmod as chmod2, rm as rm2, stat } from "fs/promises";
|
|
3332
3410
|
import { existsSync as existsSync2 } from "fs";
|
|
3333
3411
|
import { homedir as homedir2, platform } from "os";
|
|
@@ -3394,6 +3472,9 @@ var PUBLIC_ERROR_CODES2 = /* @__PURE__ */ new Set([
|
|
|
3394
3472
|
"unknown_service"
|
|
3395
3473
|
]);
|
|
3396
3474
|
var ERROR_CODE_PATTERN2 = /^[a-z][a-z0-9_]{0,63}$/;
|
|
3475
|
+
var SERVICE_ERROR_CODE_PATTERN2 = /^[a-z][a-z0-9]*(?:_[a-z][a-z0-9]*){1,9}$/;
|
|
3476
|
+
var SERVICE_MESSAGE_MAX_LENGTH2 = 300;
|
|
3477
|
+
var SERVICE_ISSUE_LIMIT2 = 32;
|
|
3397
3478
|
var TOPOLO_REQUEST_ID_PATTERN2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
3398
3479
|
var CLOUDFLARE_RAY_ID_PATTERN2 = /^[0-9a-f]{16}-[A-Z]{3}$/;
|
|
3399
3480
|
var PERMISSION_PATTERN2 = /^[a-z][a-z0-9_-]{0,63}(?:\.[a-z][a-z0-9_-]{0,63})*:(?:[a-z][a-z0-9_-]{0,63}|\*)$/;
|
|
@@ -3418,6 +3499,24 @@ function canonicalTopoloErrorCode2(value) {
|
|
|
3418
3499
|
if (!ERROR_CODE_PATTERN2.test(candidate) || !PUBLIC_ERROR_CODES2.has(candidate)) return null;
|
|
3419
3500
|
return candidate;
|
|
3420
3501
|
}
|
|
3502
|
+
function canonicalTopoloServiceErrorCode2(value) {
|
|
3503
|
+
const platform2 = canonicalTopoloErrorCode2(value);
|
|
3504
|
+
if (platform2) return platform2;
|
|
3505
|
+
if (typeof value !== "string") return null;
|
|
3506
|
+
const candidate = value.trim();
|
|
3507
|
+
if (candidate.length > 64 || !SERVICE_ERROR_CODE_PATTERN2.test(candidate)) return null;
|
|
3508
|
+
const wordLike = candidate.split("_").every((segment) => {
|
|
3509
|
+
const digits = segment.replace(/[a-z]/g, "").length;
|
|
3510
|
+
return digits === 0 || digits < segment.length - digits && segment.length <= 8;
|
|
3511
|
+
});
|
|
3512
|
+
return wordLike ? candidate : null;
|
|
3513
|
+
}
|
|
3514
|
+
function sanitizeTopoloServiceMessage2(value) {
|
|
3515
|
+
if (typeof value !== "string") return void 0;
|
|
3516
|
+
const text2 = value.replace(/[\u0000-\u001f\u007f-\u009f\u200b-\u200f\u2028-\u202e\u2066-\u2069\ufeff]/g, " ").replace(/\b[a-z][a-z0-9+.-]*:\/\/\S+/gi, "[url]").replace(/[^\s@<>()[\],;:"']+@[^\s@<>()[\],;:"']+\.[a-z]{2,}/gi, "[email]").replace(/[A-Za-z0-9_\-+/=.]{20,}/g, (run) => /[0-9]/.test(run) && /[A-Za-z]/.test(run) ? "[redacted]" : run).replace(/\s+/g, " ").trim();
|
|
3517
|
+
if (!text2) return void 0;
|
|
3518
|
+
return text2.length > SERVICE_MESSAGE_MAX_LENGTH2 ? `${text2.slice(0, SERVICE_MESSAGE_MAX_LENGTH2 - 1).trimEnd()}\u2026` : text2;
|
|
3519
|
+
}
|
|
3421
3520
|
function canonicalTopoloRequestId2(value) {
|
|
3422
3521
|
if (typeof value !== "string") return void 0;
|
|
3423
3522
|
const candidate = value.trim();
|
|
@@ -3442,7 +3541,7 @@ var TopoloAuthError2 = class extends TopoloSdkError2 {
|
|
|
3442
3541
|
retryAfter;
|
|
3443
3542
|
details;
|
|
3444
3543
|
constructor(message, code = "auth_error", options = {}) {
|
|
3445
|
-
super(
|
|
3544
|
+
super(canonicalTopoloServiceErrorCode2(code) ?? "auth_error", message);
|
|
3446
3545
|
this.name = "TopoloAuthError";
|
|
3447
3546
|
this.status = options.status ?? 401;
|
|
3448
3547
|
this.body = options.body;
|
|
@@ -3458,14 +3557,14 @@ var TopoloAuthError2 = class extends TopoloSdkError2 {
|
|
|
3458
3557
|
function extractTopoloServiceErrorCode2(body) {
|
|
3459
3558
|
if (!body || typeof body !== "object" || Array.isArray(body)) return null;
|
|
3460
3559
|
const record2 = body;
|
|
3461
|
-
const topLevel =
|
|
3560
|
+
const topLevel = canonicalTopoloServiceErrorCode2(record2.code);
|
|
3462
3561
|
if (topLevel) return topLevel;
|
|
3463
3562
|
const nested = record2.error;
|
|
3464
|
-
const nestedString =
|
|
3563
|
+
const nestedString = canonicalTopoloServiceErrorCode2(nested);
|
|
3465
3564
|
if (nestedString) return nestedString;
|
|
3466
3565
|
if (nested && typeof nested === "object" && !Array.isArray(nested)) {
|
|
3467
3566
|
const code = nested.code;
|
|
3468
|
-
const nestedCode =
|
|
3567
|
+
const nestedCode = canonicalTopoloServiceErrorCode2(code);
|
|
3469
3568
|
if (nestedCode) return nestedCode;
|
|
3470
3569
|
}
|
|
3471
3570
|
return null;
|
|
@@ -3483,10 +3582,7 @@ function extractTopoloServiceErrorDetails2(body) {
|
|
|
3483
3582
|
if (candidate === void 0) candidate = nestedRecord.details ?? nestedRecord;
|
|
3484
3583
|
}
|
|
3485
3584
|
if (candidate === void 0) candidate = record2;
|
|
3486
|
-
if (Array.isArray(candidate))
|
|
3487
|
-
const paths = canonicalTopoloValidationPaths2(candidate);
|
|
3488
|
-
return paths.length ? { paths } : void 0;
|
|
3489
|
-
}
|
|
3585
|
+
if (Array.isArray(candidate)) return validationIssueDetails2(canonicalTopoloValidationIssues2(candidate)) ?? void 0;
|
|
3490
3586
|
if (!candidate || typeof candidate !== "object") return void 0;
|
|
3491
3587
|
const source = candidate;
|
|
3492
3588
|
const safe = {};
|
|
@@ -3528,18 +3624,59 @@ function extractTopoloServiceErrorDetails2(body) {
|
|
|
3528
3624
|
if (paths.length) safe[key] = paths;
|
|
3529
3625
|
}
|
|
3530
3626
|
}
|
|
3627
|
+
const issues = [
|
|
3628
|
+
...Array.isArray(source.issues) ? canonicalTopoloValidationIssues2(source.issues) : [],
|
|
3629
|
+
...flattenedValidationIssues2(source.formErrors, source.fieldErrors)
|
|
3630
|
+
].slice(0, SERVICE_ISSUE_LIMIT2);
|
|
3631
|
+
Object.assign(safe, validationIssueDetails2(issues));
|
|
3531
3632
|
return Object.keys(safe).length ? safe : void 0;
|
|
3532
3633
|
}
|
|
3533
|
-
function
|
|
3634
|
+
function validationIssueDetails2(issues) {
|
|
3635
|
+
if (!issues.length) return null;
|
|
3534
3636
|
const paths = [];
|
|
3535
|
-
for (const
|
|
3536
|
-
if (
|
|
3537
|
-
|
|
3637
|
+
for (const issue22 of issues) {
|
|
3638
|
+
if (issue22.path && !paths.includes(issue22.path)) paths.push(issue22.path);
|
|
3639
|
+
}
|
|
3640
|
+
return paths.length ? { paths, issues } : { issues };
|
|
3641
|
+
}
|
|
3642
|
+
function issue2(path, message) {
|
|
3643
|
+
const text2 = sanitizeTopoloServiceMessage2(message);
|
|
3644
|
+
if (!path && !text2) return null;
|
|
3645
|
+
return { ...path ? { path } : {}, ...text2 ? { message: text2 } : {} };
|
|
3646
|
+
}
|
|
3647
|
+
function canonicalTopoloValidationIssues2(values) {
|
|
3648
|
+
const issues = [];
|
|
3649
|
+
for (const value of values) {
|
|
3650
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) continue;
|
|
3651
|
+
const record2 = value;
|
|
3538
3652
|
const path = canonicalTopoloValidationPath2(record2.field) ?? canonicalTopoloValidationPath2(record2.path);
|
|
3539
|
-
if (
|
|
3540
|
-
|
|
3653
|
+
if (!path) continue;
|
|
3654
|
+
const projected = issue2(path, record2.message);
|
|
3655
|
+
if (projected) issues.push(projected);
|
|
3656
|
+
if (issues.length === SERVICE_ISSUE_LIMIT2) break;
|
|
3657
|
+
}
|
|
3658
|
+
return issues;
|
|
3659
|
+
}
|
|
3660
|
+
function flattenedValidationIssues2(formErrors, fieldErrors) {
|
|
3661
|
+
const issues = [];
|
|
3662
|
+
if (Array.isArray(formErrors)) {
|
|
3663
|
+
for (const message of formErrors) {
|
|
3664
|
+
const projected = issue2(void 0, message);
|
|
3665
|
+
if (projected) issues.push(projected);
|
|
3666
|
+
}
|
|
3667
|
+
}
|
|
3668
|
+
if (fieldErrors && typeof fieldErrors === "object" && !Array.isArray(fieldErrors)) {
|
|
3669
|
+
for (const [key, messages] of Object.entries(fieldErrors)) {
|
|
3670
|
+
const path = canonicalTopoloValidationPath2(key);
|
|
3671
|
+
if (!path) continue;
|
|
3672
|
+
const list = Array.isArray(messages) && messages.length ? messages : [void 0];
|
|
3673
|
+
for (const message of list) {
|
|
3674
|
+
const projected = issue2(path, message);
|
|
3675
|
+
if (projected) issues.push(projected);
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3541
3678
|
}
|
|
3542
|
-
return
|
|
3679
|
+
return issues;
|
|
3543
3680
|
}
|
|
3544
3681
|
function canonicalTopoloValidationPath2(value) {
|
|
3545
3682
|
if (typeof value === "string") {
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topolo/mcp",
|
|
3
3
|
"packageManager": "pnpm@10.17.1",
|
|
4
|
-
"version": "0.14.
|
|
5
|
-
"topoloPublishedVersion": "0.14.
|
|
4
|
+
"version": "0.14.5",
|
|
5
|
+
"topoloPublishedVersion": "0.14.5",
|
|
6
6
|
"description": "Model Context Protocol server for the Topolo platform. Exposes scope-gated tools that third-party agents (Claude, Codex, etc.) can call natively.",
|
|
7
7
|
"license": "UNLICENSED",
|
|
8
8
|
"author": "Topolo",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
39
|
-
"@topolo/sdk": "0.
|
|
39
|
+
"@topolo/sdk": "0.22.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/node": "^20.12.0",
|