@frontmcp/adapters 1.1.2 → 1.2.0
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/esm/index.mjs +396 -385
- package/esm/openapi/index.mjs +396 -385
- package/esm/package.json +18 -6
- package/esm/skills/index.mjs +2117 -0
- package/index.js +407 -389
- package/openapi/index.d.ts +11 -1
- package/openapi/index.d.ts.map +1 -1
- package/openapi/index.js +407 -389
- package/openapi/openapi.adapter.d.ts +2 -2
- package/openapi/openapi.adapter.d.ts.map +1 -1
- package/openapi/openapi.tool.d.ts.map +1 -1
- package/openapi/openapi.types.d.ts +3 -3
- package/openapi/openapi.types.d.ts.map +1 -1
- package/openapi/openapi.utils.d.ts.map +1 -1
- package/package.json +18 -6
- package/skills/audit/audit-chain.d.ts +81 -0
- package/skills/audit/audit-chain.d.ts.map +1 -0
- package/skills/audit/audit-config.d.ts +87 -0
- package/skills/audit/audit-config.d.ts.map +1 -0
- package/skills/audit/audit-record.types.d.ts +114 -0
- package/skills/audit/audit-record.types.d.ts.map +1 -0
- package/skills/audit/audit-signer.d.ts +72 -0
- package/skills/audit/audit-signer.d.ts.map +1 -0
- package/skills/audit/audit-store.d.ts +84 -0
- package/skills/audit/audit-store.d.ts.map +1 -0
- package/skills/audit/audit-writer.d.ts +175 -0
- package/skills/audit/audit-writer.d.ts.map +1 -0
- package/skills/audit/index.d.ts +7 -0
- package/skills/audit/index.d.ts.map +1 -0
- package/skills/bundle/bundle-diff.d.ts +30 -0
- package/skills/bundle/bundle-diff.d.ts.map +1 -0
- package/skills/bundle/bundle.schema.d.ts +101 -0
- package/skills/bundle/bundle.schema.d.ts.map +1 -0
- package/skills/bundle/bundle.store.d.ts +143 -0
- package/skills/bundle/bundle.store.d.ts.map +1 -0
- package/skills/bundle/bundle.types.d.ts +143 -0
- package/skills/bundle/bundle.types.d.ts.map +1 -0
- package/skills/bundle/overlay-parser.d.ts +42 -0
- package/skills/bundle/overlay-parser.d.ts.map +1 -0
- package/skills/dependency/skill-dag.d.ts +39 -0
- package/skills/dependency/skill-dag.d.ts.map +1 -0
- package/skills/index.d.ts +17 -0
- package/skills/index.d.ts.map +1 -0
- package/skills/index.js +2192 -0
- package/skills/security/bundle-signature.d.ts +44 -0
- package/skills/security/bundle-signature.d.ts.map +1 -0
- package/skills/security/jwt-verifier.d.ts +38 -0
- package/skills/security/jwt-verifier.d.ts.map +1 -0
- package/skills/security/webhook-replay-guard.d.ts +52 -0
- package/skills/security/webhook-replay-guard.d.ts.map +1 -0
- package/skills/source-options.d.ts +55 -0
- package/skills/source-options.d.ts.map +1 -0
- package/skills/sources/filesystem-skills.source.d.ts +127 -0
- package/skills/sources/filesystem-skills.source.d.ts.map +1 -0
- package/skills/sources/index.d.ts +10 -0
- package/skills/sources/index.d.ts.map +1 -0
- package/skills/sources/npm.source.d.ts +30 -0
- package/skills/sources/npm.source.d.ts.map +1 -0
- package/skills/sources/saas-pull.source.d.ts +47 -0
- package/skills/sources/saas-pull.source.d.ts.map +1 -0
- package/skills/sources/skill-bundle-source.interface.d.ts +36 -0
- package/skills/sources/skill-bundle-source.interface.d.ts.map +1 -0
- package/skills/sources/static.source.d.ts +30 -0
- package/skills/sources/static.source.d.ts.map +1 -0
package/index.js
CHANGED
|
@@ -32,19 +32,371 @@ __export(index_exports, {
|
|
|
32
32
|
OpenAPIFetchError: () => OpenAPIFetchError,
|
|
33
33
|
OpenApiSpecPoller: () => OpenApiSpecPoller,
|
|
34
34
|
OpenapiAdapter: () => OpenapiAdapter,
|
|
35
|
+
applyAdditionalHeaders: () => applyAdditionalHeaders,
|
|
36
|
+
buildRequest: () => buildRequest,
|
|
37
|
+
createSecurityContextFromAuth: () => createSecurityContextFromAuth,
|
|
38
|
+
extractSecuritySchemes: () => extractSecuritySchemes,
|
|
35
39
|
forceJwtSecurity: () => forceJwtSecurity,
|
|
36
|
-
|
|
40
|
+
parseResponse: () => parseResponse,
|
|
41
|
+
removeSecurityFromOperations: () => removeSecurityFromOperations,
|
|
42
|
+
resolveToolSecurity: () => resolveToolSecurity,
|
|
43
|
+
validateSecurityConfiguration: () => validateSecurityConfiguration
|
|
37
44
|
});
|
|
38
45
|
module.exports = __toCommonJS(index_exports);
|
|
39
46
|
|
|
40
47
|
// libs/adapters/src/openapi/openapi.adapter.ts
|
|
41
|
-
var import_sdk4 = require("@frontmcp/sdk");
|
|
42
48
|
var import_mcp_from_openapi2 = require("mcp-from-openapi");
|
|
49
|
+
var import_sdk4 = require("@frontmcp/sdk");
|
|
50
|
+
|
|
51
|
+
// libs/adapters/src/openapi/openapi-spec-poller.ts
|
|
52
|
+
var import_utils = require("@frontmcp/utils");
|
|
53
|
+
|
|
54
|
+
// libs/adapters/src/openapi/openapi.errors.ts
|
|
55
|
+
var import_sdk = require("@frontmcp/sdk");
|
|
56
|
+
var OpenAPIFetchError = class extends import_sdk.InternalMcpError {
|
|
57
|
+
constructor(url, status, statusText) {
|
|
58
|
+
super(`OpenAPI spec fetch failed from "${url}": ${status} ${statusText}`, "OPENAPI_FETCH_FAILED");
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// libs/adapters/src/openapi/openapi-spec-poller.ts
|
|
63
|
+
var DEFAULT_RETRY = {
|
|
64
|
+
maxRetries: 3,
|
|
65
|
+
initialDelayMs: 1e3,
|
|
66
|
+
maxDelayMs: 1e4,
|
|
67
|
+
backoffMultiplier: 2
|
|
68
|
+
};
|
|
69
|
+
var OpenApiSpecPoller = class {
|
|
70
|
+
url;
|
|
71
|
+
intervalMs;
|
|
72
|
+
fetchTimeoutMs;
|
|
73
|
+
changeDetection;
|
|
74
|
+
retry;
|
|
75
|
+
unhealthyThreshold;
|
|
76
|
+
headers;
|
|
77
|
+
callbacks;
|
|
78
|
+
intervalTimer = null;
|
|
79
|
+
lastHash = null;
|
|
80
|
+
lastEtag = null;
|
|
81
|
+
lastModified = null;
|
|
82
|
+
consecutiveFailures = 0;
|
|
83
|
+
isPolling = false;
|
|
84
|
+
wasUnhealthy = false;
|
|
85
|
+
health = "unknown";
|
|
86
|
+
constructor(url, options = {}, callbacks = {}) {
|
|
87
|
+
this.url = url;
|
|
88
|
+
this.intervalMs = options.intervalMs ?? 6e4;
|
|
89
|
+
this.fetchTimeoutMs = options.fetchTimeoutMs ?? 1e4;
|
|
90
|
+
this.changeDetection = options.changeDetection ?? "auto";
|
|
91
|
+
this.retry = { ...DEFAULT_RETRY, ...options.retry };
|
|
92
|
+
this.unhealthyThreshold = options.unhealthyThreshold ?? 3;
|
|
93
|
+
this.headers = options.headers ?? {};
|
|
94
|
+
this.callbacks = callbacks;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Start polling for changes.
|
|
98
|
+
*/
|
|
99
|
+
start() {
|
|
100
|
+
if (this.intervalTimer) return;
|
|
101
|
+
this.poll().catch(() => {
|
|
102
|
+
});
|
|
103
|
+
this.intervalTimer = setInterval(() => {
|
|
104
|
+
this.poll().catch(() => {
|
|
105
|
+
});
|
|
106
|
+
}, this.intervalMs);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Stop polling.
|
|
110
|
+
*/
|
|
111
|
+
stop() {
|
|
112
|
+
if (this.intervalTimer) {
|
|
113
|
+
clearInterval(this.intervalTimer);
|
|
114
|
+
this.intervalTimer = null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get current stats.
|
|
119
|
+
*/
|
|
120
|
+
getStats() {
|
|
121
|
+
return {
|
|
122
|
+
hash: this.lastHash,
|
|
123
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
124
|
+
health: this.health,
|
|
125
|
+
isRunning: this.intervalTimer !== null
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Perform a single poll cycle.
|
|
130
|
+
*/
|
|
131
|
+
async poll() {
|
|
132
|
+
if (this.isPolling) return;
|
|
133
|
+
this.isPolling = true;
|
|
134
|
+
try {
|
|
135
|
+
await this.fetchWithRetry();
|
|
136
|
+
} finally {
|
|
137
|
+
this.isPolling = false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
async fetchWithRetry() {
|
|
141
|
+
const { maxRetries, initialDelayMs, maxDelayMs, backoffMultiplier } = this.retry;
|
|
142
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
143
|
+
try {
|
|
144
|
+
await this.doFetch();
|
|
145
|
+
if (this.consecutiveFailures > 0) {
|
|
146
|
+
this.consecutiveFailures = 0;
|
|
147
|
+
if (this.wasUnhealthy) {
|
|
148
|
+
this.wasUnhealthy = false;
|
|
149
|
+
this.health = "healthy";
|
|
150
|
+
this.callbacks.onRecovered?.();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
this.health = "healthy";
|
|
154
|
+
return;
|
|
155
|
+
} catch (error) {
|
|
156
|
+
if (attempt === maxRetries) {
|
|
157
|
+
this.consecutiveFailures++;
|
|
158
|
+
this.callbacks.onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
159
|
+
if (this.consecutiveFailures >= this.unhealthyThreshold && !this.wasUnhealthy) {
|
|
160
|
+
this.wasUnhealthy = true;
|
|
161
|
+
this.health = "unhealthy";
|
|
162
|
+
this.callbacks.onUnhealthy?.(this.consecutiveFailures);
|
|
163
|
+
}
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const delay = Math.min(initialDelayMs * Math.pow(backoffMultiplier, attempt), maxDelayMs);
|
|
167
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async doFetch() {
|
|
172
|
+
const headers = { ...this.headers };
|
|
173
|
+
if (this.changeDetection !== "content-hash") {
|
|
174
|
+
if (this.lastEtag) {
|
|
175
|
+
headers["If-None-Match"] = this.lastEtag;
|
|
176
|
+
}
|
|
177
|
+
if (this.lastModified) {
|
|
178
|
+
headers["If-Modified-Since"] = this.lastModified;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const controller = new AbortController();
|
|
182
|
+
const timeout = setTimeout(() => controller.abort(), this.fetchTimeoutMs);
|
|
183
|
+
try {
|
|
184
|
+
const response = await fetch(this.url, {
|
|
185
|
+
headers,
|
|
186
|
+
signal: controller.signal
|
|
187
|
+
});
|
|
188
|
+
if (response.status === 304) {
|
|
189
|
+
this.callbacks.onUnchanged?.();
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (!response.ok) {
|
|
193
|
+
throw new OpenAPIFetchError(this.url, response.status, response.statusText);
|
|
194
|
+
}
|
|
195
|
+
const etag = response.headers.get("etag");
|
|
196
|
+
const lastModified = response.headers.get("last-modified");
|
|
197
|
+
if (etag) this.lastEtag = etag;
|
|
198
|
+
if (lastModified) this.lastModified = lastModified;
|
|
199
|
+
const body = await response.text();
|
|
200
|
+
const hash = (0, import_utils.sha256Hex)(body);
|
|
201
|
+
if (this.lastHash && this.lastHash === hash) {
|
|
202
|
+
this.callbacks.onUnchanged?.();
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
this.lastHash = hash;
|
|
206
|
+
this.callbacks.onChanged?.(body, hash);
|
|
207
|
+
} finally {
|
|
208
|
+
clearTimeout(timeout);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Dispose the poller and release resources.
|
|
213
|
+
*/
|
|
214
|
+
dispose() {
|
|
215
|
+
this.stop();
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
// libs/adapters/src/openapi/openapi.security.ts
|
|
220
|
+
var import_mcp_from_openapi = require("mcp-from-openapi");
|
|
221
|
+
async function createSecurityContextFromAuth(tool2, ctx, options) {
|
|
222
|
+
if (options.securityResolver) {
|
|
223
|
+
return await options.securityResolver(tool2, ctx);
|
|
224
|
+
}
|
|
225
|
+
if (options.authProviderMapper) {
|
|
226
|
+
const context = (0, import_mcp_from_openapi.createSecurityContext)({});
|
|
227
|
+
const securitySchemes = /* @__PURE__ */ new Set();
|
|
228
|
+
for (const mapper of tool2.mapper) {
|
|
229
|
+
if (mapper.security?.scheme) {
|
|
230
|
+
securitySchemes.add(mapper.security.scheme);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
for (const scheme of securitySchemes) {
|
|
234
|
+
const authExtractor = options.authProviderMapper[scheme];
|
|
235
|
+
if (authExtractor) {
|
|
236
|
+
try {
|
|
237
|
+
const token = authExtractor(ctx);
|
|
238
|
+
if (token !== void 0 && token !== null && typeof token !== "string") {
|
|
239
|
+
throw new Error(
|
|
240
|
+
`authProviderMapper['${scheme}'] must return a string or undefined, but returned: ${typeof token}`
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
if (token === "") {
|
|
244
|
+
throw new Error(
|
|
245
|
+
`authProviderMapper['${scheme}'] returned empty string. Return undefined/null if no token is available, or provide a valid token.`
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
if (token) {
|
|
249
|
+
const schemeMapper = tool2.mapper.find((m) => m.security?.scheme === scheme);
|
|
250
|
+
const schemeType = schemeMapper?.security?.type?.toLowerCase();
|
|
251
|
+
const httpScheme = schemeMapper?.security?.httpScheme?.toLowerCase();
|
|
252
|
+
if (schemeType === "apikey") {
|
|
253
|
+
if (!context.apiKey) {
|
|
254
|
+
context.apiKey = token;
|
|
255
|
+
}
|
|
256
|
+
} else if (schemeType === "http" && httpScheme === "basic") {
|
|
257
|
+
if (!context.basic) {
|
|
258
|
+
context.basic = token;
|
|
259
|
+
}
|
|
260
|
+
} else if (schemeType === "oauth2") {
|
|
261
|
+
if (!context.oauth2Token) {
|
|
262
|
+
context.oauth2Token = token;
|
|
263
|
+
}
|
|
264
|
+
} else {
|
|
265
|
+
if (!context.jwt) {
|
|
266
|
+
context.jwt = token;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
} catch (err) {
|
|
271
|
+
if (err instanceof Error && err.message.includes("authProviderMapper")) {
|
|
272
|
+
throw err;
|
|
273
|
+
}
|
|
274
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
275
|
+
throw new Error(`authProviderMapper['${scheme}'] threw an error: ${errorMessage}`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const hasAnyAuth = context.jwt || context.apiKey || context.basic || context.oauth2Token;
|
|
280
|
+
const authToken = ctx.authInfo?.token;
|
|
281
|
+
if (!hasAnyAuth && authToken) {
|
|
282
|
+
if (typeof authToken !== "string") {
|
|
283
|
+
throw new Error(`authInfo.token must be a string, but got: ${typeof authToken}`);
|
|
284
|
+
}
|
|
285
|
+
context.jwt = authToken;
|
|
286
|
+
}
|
|
287
|
+
return context;
|
|
288
|
+
}
|
|
289
|
+
if (options.staticAuth) {
|
|
290
|
+
return (0, import_mcp_from_openapi.createSecurityContext)(options.staticAuth);
|
|
291
|
+
}
|
|
292
|
+
return (0, import_mcp_from_openapi.createSecurityContext)({
|
|
293
|
+
jwt: ctx.authInfo?.token
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
function extractSecuritySchemes(tools) {
|
|
297
|
+
const schemes = /* @__PURE__ */ new Set();
|
|
298
|
+
for (const tool2 of tools) {
|
|
299
|
+
for (const mapper of tool2.mapper) {
|
|
300
|
+
if (mapper.security?.scheme) {
|
|
301
|
+
schemes.add(mapper.security.scheme);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return schemes;
|
|
306
|
+
}
|
|
307
|
+
function validateSecurityConfiguration(tools, options) {
|
|
308
|
+
const result = {
|
|
309
|
+
valid: true,
|
|
310
|
+
missingMappings: [],
|
|
311
|
+
warnings: [],
|
|
312
|
+
securityRiskScore: "low"
|
|
313
|
+
};
|
|
314
|
+
const securitySchemes = extractSecuritySchemes(tools);
|
|
315
|
+
const includeSecurityInInput = options.generateOptions?.includeSecurityInInput ?? false;
|
|
316
|
+
if (includeSecurityInInput) {
|
|
317
|
+
result.securityRiskScore = "high";
|
|
318
|
+
result.warnings.push(
|
|
319
|
+
"SECURITY WARNING: includeSecurityInInput is enabled. Users will provide authentication directly in tool inputs. This increases security risk as credentials may be logged or exposed."
|
|
320
|
+
);
|
|
321
|
+
return result;
|
|
322
|
+
}
|
|
323
|
+
if (options.securityResolver) {
|
|
324
|
+
result.securityRiskScore = "low";
|
|
325
|
+
result.warnings.push(
|
|
326
|
+
"INFO: Using custom securityResolver. Ensure your resolver properly validates and secures credentials from context."
|
|
327
|
+
);
|
|
328
|
+
return result;
|
|
329
|
+
}
|
|
330
|
+
if (options.staticAuth && Object.keys(options.staticAuth).length > 0) {
|
|
331
|
+
result.securityRiskScore = "medium";
|
|
332
|
+
result.warnings.push(
|
|
333
|
+
"SECURITY INFO: Using staticAuth with hardcoded credentials. Ensure credentials are stored securely (environment variables, secrets manager)."
|
|
334
|
+
);
|
|
335
|
+
return result;
|
|
336
|
+
}
|
|
337
|
+
const schemesInInput = new Set(options.securitySchemesInInput || []);
|
|
338
|
+
if (options.authProviderMapper || schemesInInput.size > 0) {
|
|
339
|
+
result.securityRiskScore = schemesInInput.size > 0 ? "medium" : "low";
|
|
340
|
+
if (schemesInInput.size > 0) {
|
|
341
|
+
result.warnings.push(
|
|
342
|
+
`INFO: Per-scheme security control enabled. Schemes in input: ${Array.from(schemesInInput).join(", ")}`
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
for (const scheme of securitySchemes) {
|
|
346
|
+
if (schemesInInput.has(scheme)) {
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
if (!options.authProviderMapper?.[scheme]) {
|
|
350
|
+
result.valid = false;
|
|
351
|
+
result.missingMappings.push(scheme);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (!result.valid) {
|
|
355
|
+
result.warnings.push(
|
|
356
|
+
`ERROR: Missing auth provider mappings for security schemes: ${result.missingMappings.join(", ")}`
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
return result;
|
|
360
|
+
}
|
|
361
|
+
if (securitySchemes.size > 0) {
|
|
362
|
+
result.securityRiskScore = "medium";
|
|
363
|
+
result.warnings.push(
|
|
364
|
+
`INFO: No auth configuration provided. Using default ctx.authInfo.token for all security schemes: ${Array.from(
|
|
365
|
+
securitySchemes
|
|
366
|
+
).join(", ")}`
|
|
367
|
+
);
|
|
368
|
+
result.warnings.push(
|
|
369
|
+
"RECOMMENDATION: For multiple auth providers, use authProviderMapper or securityResolver to map each security scheme to the correct auth provider."
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
return result;
|
|
373
|
+
}
|
|
374
|
+
async function resolveToolSecurity(tool2, ctx, options) {
|
|
375
|
+
const securityResolver = new import_mcp_from_openapi.SecurityResolver();
|
|
376
|
+
const securityContext = await createSecurityContextFromAuth(tool2, ctx, options);
|
|
377
|
+
const hasAuth = securityContext.jwt || securityContext.apiKey || securityContext.basic || securityContext.oauth2Token || securityContext.apiKeys && Object.keys(securityContext.apiKeys).length > 0 || securityContext.customHeaders && Object.keys(securityContext.customHeaders).length > 0;
|
|
378
|
+
const requiresSecurity = tool2.mapper.some((m) => m.security && m.required === true);
|
|
379
|
+
if (requiresSecurity && !hasAuth) {
|
|
380
|
+
const requiredSchemes = tool2.mapper.filter((m) => m.security && m.required === true).map((m) => m.security?.scheme ?? "unknown");
|
|
381
|
+
const uniqueSchemes = [...new Set(requiredSchemes)];
|
|
382
|
+
const schemesStr = uniqueSchemes.join(", ") || "unknown";
|
|
383
|
+
const firstScheme = uniqueSchemes[0] || "BearerAuth";
|
|
384
|
+
throw new Error(
|
|
385
|
+
`Authentication required for tool '${tool2.name}' but no auth configuration found.
|
|
386
|
+
Required security schemes: ${schemesStr}
|
|
387
|
+
Solutions:
|
|
388
|
+
1. Add authProviderMapper: { '${firstScheme}': (ctx) => ctx.authInfo.user?.token }
|
|
389
|
+
2. Add securityResolver: (tool, ctx) => ({ jwt: ctx.authInfo.token })
|
|
390
|
+
3. Add staticAuth: { jwt: process.env.API_TOKEN }
|
|
391
|
+
4. Set generateOptions.includeSecurityInInput: true (not recommended for production)`
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
return await securityResolver.resolve(tool2.mapper, securityContext);
|
|
395
|
+
}
|
|
43
396
|
|
|
44
397
|
// libs/adapters/src/openapi/openapi.tool.ts
|
|
45
|
-
var import_zod_from_json_schema = require("zod-from-json-schema");
|
|
46
398
|
var import_lazy_zod2 = require("@frontmcp/lazy-zod");
|
|
47
|
-
var
|
|
399
|
+
var import_sdk3 = require("@frontmcp/sdk");
|
|
48
400
|
|
|
49
401
|
// libs/adapters/src/openapi/openapi.frontmcp-schema.ts
|
|
50
402
|
var import_lazy_zod = require("@frontmcp/lazy-zod");
|
|
@@ -247,226 +599,48 @@ function extractValidCodeCall(data, warnings) {
|
|
|
247
599
|
warnings.push(`Invalid 'codecall.enabledInCodeCall': expected boolean`);
|
|
248
600
|
}
|
|
249
601
|
if (typeof obj["visibleInListTools"] === "boolean") {
|
|
250
|
-
result.visibleInListTools = obj["visibleInListTools"];
|
|
251
|
-
} else if (obj["visibleInListTools"] !== void 0) {
|
|
252
|
-
warnings.push(`Invalid 'codecall.visibleInListTools': expected boolean`);
|
|
253
|
-
}
|
|
254
|
-
for (const key of Object.keys(obj)) {
|
|
255
|
-
if (!KNOWN_CODECALL_FIELDS.has(key)) {
|
|
256
|
-
warnings.push(`Unknown field 'codecall.${key}' (will be ignored)`);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
return Object.keys(result).length > 0 ? result : void 0;
|
|
260
|
-
}
|
|
261
|
-
function extractValidTags(data) {
|
|
262
|
-
if (!Array.isArray(data)) return void 0;
|
|
263
|
-
const validTags = data.filter((item) => typeof item === "string");
|
|
264
|
-
return validTags.length > 0 ? validTags : void 0;
|
|
265
|
-
}
|
|
266
|
-
function extractValidExamples(data, warnings) {
|
|
267
|
-
if (!Array.isArray(data)) return void 0;
|
|
268
|
-
const validExamples = [];
|
|
269
|
-
for (let i = 0; i < data.length; i++) {
|
|
270
|
-
const item = data[i];
|
|
271
|
-
const result = FrontMcpExampleSchema.safeParse(item);
|
|
272
|
-
if (result.success) {
|
|
273
|
-
validExamples.push(result.data);
|
|
274
|
-
} else {
|
|
275
|
-
warnings.push(
|
|
276
|
-
`Invalid example at index ${i}: ${formatZodIssues(result.error.issues, `examples[${i}]`).join(", ")}`
|
|
277
|
-
);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
return validExamples.length > 0 ? validExamples : void 0;
|
|
281
|
-
}
|
|
282
|
-
function formatZodIssues(issues, prefix) {
|
|
283
|
-
return issues.map((issue) => {
|
|
284
|
-
const path = issue.path.length > 0 ? `${prefix}.${issue.path.join(".")}` : prefix;
|
|
285
|
-
return `Invalid '${path}': ${issue.message}`;
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// libs/adapters/src/openapi/openapi.security.ts
|
|
290
|
-
var import_mcp_from_openapi = require("mcp-from-openapi");
|
|
291
|
-
async function createSecurityContextFromAuth(tool2, ctx, options) {
|
|
292
|
-
if (options.securityResolver) {
|
|
293
|
-
return await options.securityResolver(tool2, ctx);
|
|
294
|
-
}
|
|
295
|
-
if (options.authProviderMapper) {
|
|
296
|
-
const context = (0, import_mcp_from_openapi.createSecurityContext)({});
|
|
297
|
-
const securitySchemes = /* @__PURE__ */ new Set();
|
|
298
|
-
for (const mapper of tool2.mapper) {
|
|
299
|
-
if (mapper.security?.scheme) {
|
|
300
|
-
securitySchemes.add(mapper.security.scheme);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
for (const scheme of securitySchemes) {
|
|
304
|
-
const authExtractor = options.authProviderMapper[scheme];
|
|
305
|
-
if (authExtractor) {
|
|
306
|
-
try {
|
|
307
|
-
const token = authExtractor(ctx);
|
|
308
|
-
if (token !== void 0 && token !== null && typeof token !== "string") {
|
|
309
|
-
throw new Error(
|
|
310
|
-
`authProviderMapper['${scheme}'] must return a string or undefined, but returned: ${typeof token}`
|
|
311
|
-
);
|
|
312
|
-
}
|
|
313
|
-
if (token === "") {
|
|
314
|
-
throw new Error(
|
|
315
|
-
`authProviderMapper['${scheme}'] returned empty string. Return undefined/null if no token is available, or provide a valid token.`
|
|
316
|
-
);
|
|
317
|
-
}
|
|
318
|
-
if (token) {
|
|
319
|
-
const schemeMapper = tool2.mapper.find((m) => m.security?.scheme === scheme);
|
|
320
|
-
const schemeType = schemeMapper?.security?.type?.toLowerCase();
|
|
321
|
-
const httpScheme = schemeMapper?.security?.httpScheme?.toLowerCase();
|
|
322
|
-
if (schemeType === "apikey") {
|
|
323
|
-
if (!context.apiKey) {
|
|
324
|
-
context.apiKey = token;
|
|
325
|
-
}
|
|
326
|
-
} else if (schemeType === "http" && httpScheme === "basic") {
|
|
327
|
-
if (!context.basic) {
|
|
328
|
-
context.basic = token;
|
|
329
|
-
}
|
|
330
|
-
} else if (schemeType === "oauth2") {
|
|
331
|
-
if (!context.oauth2Token) {
|
|
332
|
-
context.oauth2Token = token;
|
|
333
|
-
}
|
|
334
|
-
} else {
|
|
335
|
-
if (!context.jwt) {
|
|
336
|
-
context.jwt = token;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
} catch (err) {
|
|
341
|
-
if (err instanceof Error && err.message.includes("authProviderMapper")) {
|
|
342
|
-
throw err;
|
|
343
|
-
}
|
|
344
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
345
|
-
throw new Error(`authProviderMapper['${scheme}'] threw an error: ${errorMessage}`);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
const hasAnyAuth = context.jwt || context.apiKey || context.basic || context.oauth2Token;
|
|
350
|
-
const authToken = ctx.authInfo?.token;
|
|
351
|
-
if (!hasAnyAuth && authToken) {
|
|
352
|
-
if (typeof authToken !== "string") {
|
|
353
|
-
throw new Error(`authInfo.token must be a string, but got: ${typeof authToken}`);
|
|
354
|
-
}
|
|
355
|
-
context.jwt = authToken;
|
|
356
|
-
}
|
|
357
|
-
return context;
|
|
358
|
-
}
|
|
359
|
-
if (options.staticAuth) {
|
|
360
|
-
return (0, import_mcp_from_openapi.createSecurityContext)(options.staticAuth);
|
|
361
|
-
}
|
|
362
|
-
return (0, import_mcp_from_openapi.createSecurityContext)({
|
|
363
|
-
jwt: ctx.authInfo?.token
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
function extractSecuritySchemes(tools) {
|
|
367
|
-
const schemes = /* @__PURE__ */ new Set();
|
|
368
|
-
for (const tool2 of tools) {
|
|
369
|
-
for (const mapper of tool2.mapper) {
|
|
370
|
-
if (mapper.security?.scheme) {
|
|
371
|
-
schemes.add(mapper.security.scheme);
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
return schemes;
|
|
376
|
-
}
|
|
377
|
-
function validateSecurityConfiguration(tools, options) {
|
|
378
|
-
const result = {
|
|
379
|
-
valid: true,
|
|
380
|
-
missingMappings: [],
|
|
381
|
-
warnings: [],
|
|
382
|
-
securityRiskScore: "low"
|
|
383
|
-
};
|
|
384
|
-
const securitySchemes = extractSecuritySchemes(tools);
|
|
385
|
-
const includeSecurityInInput = options.generateOptions?.includeSecurityInInput ?? false;
|
|
386
|
-
if (includeSecurityInInput) {
|
|
387
|
-
result.securityRiskScore = "high";
|
|
388
|
-
result.warnings.push(
|
|
389
|
-
"SECURITY WARNING: includeSecurityInInput is enabled. Users will provide authentication directly in tool inputs. This increases security risk as credentials may be logged or exposed."
|
|
390
|
-
);
|
|
391
|
-
return result;
|
|
392
|
-
}
|
|
393
|
-
if (options.securityResolver) {
|
|
394
|
-
result.securityRiskScore = "low";
|
|
395
|
-
result.warnings.push(
|
|
396
|
-
"INFO: Using custom securityResolver. Ensure your resolver properly validates and secures credentials from context."
|
|
397
|
-
);
|
|
398
|
-
return result;
|
|
399
|
-
}
|
|
400
|
-
if (options.staticAuth && Object.keys(options.staticAuth).length > 0) {
|
|
401
|
-
result.securityRiskScore = "medium";
|
|
402
|
-
result.warnings.push(
|
|
403
|
-
"SECURITY INFO: Using staticAuth with hardcoded credentials. Ensure credentials are stored securely (environment variables, secrets manager)."
|
|
404
|
-
);
|
|
405
|
-
return result;
|
|
602
|
+
result.visibleInListTools = obj["visibleInListTools"];
|
|
603
|
+
} else if (obj["visibleInListTools"] !== void 0) {
|
|
604
|
+
warnings.push(`Invalid 'codecall.visibleInListTools': expected boolean`);
|
|
406
605
|
}
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
if (schemesInInput.size > 0) {
|
|
411
|
-
result.warnings.push(
|
|
412
|
-
`INFO: Per-scheme security control enabled. Schemes in input: ${Array.from(schemesInInput).join(", ")}`
|
|
413
|
-
);
|
|
414
|
-
}
|
|
415
|
-
for (const scheme of securitySchemes) {
|
|
416
|
-
if (schemesInInput.has(scheme)) {
|
|
417
|
-
continue;
|
|
418
|
-
}
|
|
419
|
-
if (!options.authProviderMapper?.[scheme]) {
|
|
420
|
-
result.valid = false;
|
|
421
|
-
result.missingMappings.push(scheme);
|
|
422
|
-
}
|
|
606
|
+
for (const key of Object.keys(obj)) {
|
|
607
|
+
if (!KNOWN_CODECALL_FIELDS.has(key)) {
|
|
608
|
+
warnings.push(`Unknown field 'codecall.${key}' (will be ignored)`);
|
|
423
609
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
610
|
+
}
|
|
611
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
612
|
+
}
|
|
613
|
+
function extractValidTags(data) {
|
|
614
|
+
if (!Array.isArray(data)) return void 0;
|
|
615
|
+
const validTags = data.filter((item) => typeof item === "string");
|
|
616
|
+
return validTags.length > 0 ? validTags : void 0;
|
|
617
|
+
}
|
|
618
|
+
function extractValidExamples(data, warnings) {
|
|
619
|
+
if (!Array.isArray(data)) return void 0;
|
|
620
|
+
const validExamples = [];
|
|
621
|
+
for (let i = 0; i < data.length; i++) {
|
|
622
|
+
const item = data[i];
|
|
623
|
+
const result = FrontMcpExampleSchema.safeParse(item);
|
|
624
|
+
if (result.success) {
|
|
625
|
+
validExamples.push(result.data);
|
|
626
|
+
} else {
|
|
627
|
+
warnings.push(
|
|
628
|
+
`Invalid example at index ${i}: ${formatZodIssues(result.error.issues, `examples[${i}]`).join(", ")}`
|
|
427
629
|
);
|
|
428
630
|
}
|
|
429
|
-
return result;
|
|
430
|
-
}
|
|
431
|
-
if (securitySchemes.size > 0) {
|
|
432
|
-
result.securityRiskScore = "medium";
|
|
433
|
-
result.warnings.push(
|
|
434
|
-
`INFO: No auth configuration provided. Using default ctx.authInfo.token for all security schemes: ${Array.from(
|
|
435
|
-
securitySchemes
|
|
436
|
-
).join(", ")}`
|
|
437
|
-
);
|
|
438
|
-
result.warnings.push(
|
|
439
|
-
"RECOMMENDATION: For multiple auth providers, use authProviderMapper or securityResolver to map each security scheme to the correct auth provider."
|
|
440
|
-
);
|
|
441
631
|
}
|
|
442
|
-
return
|
|
632
|
+
return validExamples.length > 0 ? validExamples : void 0;
|
|
443
633
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
if (requiresSecurity && !hasAuth) {
|
|
450
|
-
const requiredSchemes = tool2.mapper.filter((m) => m.security && m.required === true).map((m) => m.security?.scheme ?? "unknown");
|
|
451
|
-
const uniqueSchemes = [...new Set(requiredSchemes)];
|
|
452
|
-
const schemesStr = uniqueSchemes.join(", ") || "unknown";
|
|
453
|
-
const firstScheme = uniqueSchemes[0] || "BearerAuth";
|
|
454
|
-
throw new Error(
|
|
455
|
-
`Authentication required for tool '${tool2.name}' but no auth configuration found.
|
|
456
|
-
Required security schemes: ${schemesStr}
|
|
457
|
-
Solutions:
|
|
458
|
-
1. Add authProviderMapper: { '${firstScheme}': (ctx) => ctx.authInfo.user?.token }
|
|
459
|
-
2. Add securityResolver: (tool, ctx) => ({ jwt: ctx.authInfo.token })
|
|
460
|
-
3. Add staticAuth: { jwt: process.env.API_TOKEN }
|
|
461
|
-
4. Set generateOptions.includeSecurityInInput: true (not recommended for production)`
|
|
462
|
-
);
|
|
463
|
-
}
|
|
464
|
-
return await securityResolver.resolve(tool2.mapper, securityContext);
|
|
634
|
+
function formatZodIssues(issues, prefix) {
|
|
635
|
+
return issues.map((issue) => {
|
|
636
|
+
const path = issue.path.length > 0 ? `${prefix}.${issue.path.join(".")}` : prefix;
|
|
637
|
+
return `Invalid '${path}': ${issue.message}`;
|
|
638
|
+
});
|
|
465
639
|
}
|
|
466
640
|
|
|
467
641
|
// libs/adapters/src/openapi/openapi.utils.ts
|
|
468
|
-
var
|
|
469
|
-
var
|
|
642
|
+
var import_sdk2 = require("@frontmcp/sdk");
|
|
643
|
+
var import_utils2 = require("@frontmcp/utils");
|
|
470
644
|
function coerceToString(value, paramName, location) {
|
|
471
645
|
if (value === null || value === void 0) {
|
|
472
646
|
return "";
|
|
@@ -493,8 +667,8 @@ function appendCookie(headers, name, value) {
|
|
|
493
667
|
}
|
|
494
668
|
function buildRequest(tool2, input, security, baseUrl) {
|
|
495
669
|
const rawBaseUrl = tool2.metadata.servers?.[0]?.url || baseUrl;
|
|
496
|
-
(0,
|
|
497
|
-
const apiBaseUrl =
|
|
670
|
+
(0, import_utils2.validateBaseUrl)(rawBaseUrl);
|
|
671
|
+
const apiBaseUrl = (0, import_utils2.trimTrailing)(rawBaseUrl, "/");
|
|
498
672
|
let path = tool2.metadata.path;
|
|
499
673
|
const queryParams = new URLSearchParams();
|
|
500
674
|
const headers = new Headers({
|
|
@@ -523,7 +697,7 @@ function buildRequest(tool2, input, security, baseUrl) {
|
|
|
523
697
|
case "header": {
|
|
524
698
|
const headerValue = coerceToString(value, mapper.key, "header");
|
|
525
699
|
if (/[\r\n\x00\f\v]/.test(headerValue)) {
|
|
526
|
-
throw new
|
|
700
|
+
throw new import_sdk2.PublicMcpError(
|
|
527
701
|
`Invalid header value for '${mapper.key}': contains control characters (possible header injection attack)`,
|
|
528
702
|
"INVALID_HEADER_VALUE",
|
|
529
703
|
400
|
|
@@ -688,7 +862,7 @@ function createOpenApiTool(openapiTool, options, logger) {
|
|
|
688
862
|
if (toolTransform.ui) {
|
|
689
863
|
toolMetadata["ui"] = toolTransform.ui;
|
|
690
864
|
}
|
|
691
|
-
return (0,
|
|
865
|
+
return (0, import_sdk3.tool)(toolMetadata)(async (input, toolCtx) => {
|
|
692
866
|
const ctx = toolCtx.context;
|
|
693
867
|
const transformContext = {
|
|
694
868
|
ctx,
|
|
@@ -877,7 +1051,12 @@ function getZodSchemaFromJsonSchema(jsonSchema, toolName, logger) {
|
|
|
877
1051
|
return { schema: import_lazy_zod2.z.looseObject({}), conversionFailed: true, error: "No valid JSON schema" };
|
|
878
1052
|
}
|
|
879
1053
|
try {
|
|
880
|
-
const zodSchema =
|
|
1054
|
+
const zodSchema = import_lazy_zod2.z.fromJSONSchema(
|
|
1055
|
+
jsonSchema,
|
|
1056
|
+
{
|
|
1057
|
+
defaultTarget: "draft-2020-12"
|
|
1058
|
+
}
|
|
1059
|
+
);
|
|
881
1060
|
if (typeof zodSchema?.parse !== "function") {
|
|
882
1061
|
throw new Error("Conversion did not produce a valid Zod schema.");
|
|
883
1062
|
}
|
|
@@ -891,174 +1070,6 @@ function getZodSchemaFromJsonSchema(jsonSchema, toolName, logger) {
|
|
|
891
1070
|
}
|
|
892
1071
|
}
|
|
893
1072
|
|
|
894
|
-
// libs/adapters/src/openapi/openapi-spec-poller.ts
|
|
895
|
-
var import_utils2 = require("@frontmcp/utils");
|
|
896
|
-
|
|
897
|
-
// libs/adapters/src/openapi/openapi.errors.ts
|
|
898
|
-
var import_sdk3 = require("@frontmcp/sdk");
|
|
899
|
-
var OpenAPIFetchError = class extends import_sdk3.InternalMcpError {
|
|
900
|
-
constructor(url, status, statusText) {
|
|
901
|
-
super(`OpenAPI spec fetch failed from "${url}": ${status} ${statusText}`, "OPENAPI_FETCH_FAILED");
|
|
902
|
-
}
|
|
903
|
-
};
|
|
904
|
-
|
|
905
|
-
// libs/adapters/src/openapi/openapi-spec-poller.ts
|
|
906
|
-
var DEFAULT_RETRY = {
|
|
907
|
-
maxRetries: 3,
|
|
908
|
-
initialDelayMs: 1e3,
|
|
909
|
-
maxDelayMs: 1e4,
|
|
910
|
-
backoffMultiplier: 2
|
|
911
|
-
};
|
|
912
|
-
var OpenApiSpecPoller = class {
|
|
913
|
-
url;
|
|
914
|
-
intervalMs;
|
|
915
|
-
fetchTimeoutMs;
|
|
916
|
-
changeDetection;
|
|
917
|
-
retry;
|
|
918
|
-
unhealthyThreshold;
|
|
919
|
-
headers;
|
|
920
|
-
callbacks;
|
|
921
|
-
intervalTimer = null;
|
|
922
|
-
lastHash = null;
|
|
923
|
-
lastEtag = null;
|
|
924
|
-
lastModified = null;
|
|
925
|
-
consecutiveFailures = 0;
|
|
926
|
-
isPolling = false;
|
|
927
|
-
wasUnhealthy = false;
|
|
928
|
-
health = "unknown";
|
|
929
|
-
constructor(url, options = {}, callbacks = {}) {
|
|
930
|
-
this.url = url;
|
|
931
|
-
this.intervalMs = options.intervalMs ?? 6e4;
|
|
932
|
-
this.fetchTimeoutMs = options.fetchTimeoutMs ?? 1e4;
|
|
933
|
-
this.changeDetection = options.changeDetection ?? "auto";
|
|
934
|
-
this.retry = { ...DEFAULT_RETRY, ...options.retry };
|
|
935
|
-
this.unhealthyThreshold = options.unhealthyThreshold ?? 3;
|
|
936
|
-
this.headers = options.headers ?? {};
|
|
937
|
-
this.callbacks = callbacks;
|
|
938
|
-
}
|
|
939
|
-
/**
|
|
940
|
-
* Start polling for changes.
|
|
941
|
-
*/
|
|
942
|
-
start() {
|
|
943
|
-
if (this.intervalTimer) return;
|
|
944
|
-
this.poll().catch(() => {
|
|
945
|
-
});
|
|
946
|
-
this.intervalTimer = setInterval(() => {
|
|
947
|
-
this.poll().catch(() => {
|
|
948
|
-
});
|
|
949
|
-
}, this.intervalMs);
|
|
950
|
-
}
|
|
951
|
-
/**
|
|
952
|
-
* Stop polling.
|
|
953
|
-
*/
|
|
954
|
-
stop() {
|
|
955
|
-
if (this.intervalTimer) {
|
|
956
|
-
clearInterval(this.intervalTimer);
|
|
957
|
-
this.intervalTimer = null;
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
/**
|
|
961
|
-
* Get current stats.
|
|
962
|
-
*/
|
|
963
|
-
getStats() {
|
|
964
|
-
return {
|
|
965
|
-
hash: this.lastHash,
|
|
966
|
-
consecutiveFailures: this.consecutiveFailures,
|
|
967
|
-
health: this.health,
|
|
968
|
-
isRunning: this.intervalTimer !== null
|
|
969
|
-
};
|
|
970
|
-
}
|
|
971
|
-
/**
|
|
972
|
-
* Perform a single poll cycle.
|
|
973
|
-
*/
|
|
974
|
-
async poll() {
|
|
975
|
-
if (this.isPolling) return;
|
|
976
|
-
this.isPolling = true;
|
|
977
|
-
try {
|
|
978
|
-
await this.fetchWithRetry();
|
|
979
|
-
} finally {
|
|
980
|
-
this.isPolling = false;
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
async fetchWithRetry() {
|
|
984
|
-
const { maxRetries, initialDelayMs, maxDelayMs, backoffMultiplier } = this.retry;
|
|
985
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
986
|
-
try {
|
|
987
|
-
await this.doFetch();
|
|
988
|
-
if (this.consecutiveFailures > 0) {
|
|
989
|
-
this.consecutiveFailures = 0;
|
|
990
|
-
if (this.wasUnhealthy) {
|
|
991
|
-
this.wasUnhealthy = false;
|
|
992
|
-
this.health = "healthy";
|
|
993
|
-
this.callbacks.onRecovered?.();
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
this.health = "healthy";
|
|
997
|
-
return;
|
|
998
|
-
} catch (error) {
|
|
999
|
-
if (attempt === maxRetries) {
|
|
1000
|
-
this.consecutiveFailures++;
|
|
1001
|
-
this.callbacks.onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
1002
|
-
if (this.consecutiveFailures >= this.unhealthyThreshold && !this.wasUnhealthy) {
|
|
1003
|
-
this.wasUnhealthy = true;
|
|
1004
|
-
this.health = "unhealthy";
|
|
1005
|
-
this.callbacks.onUnhealthy?.(this.consecutiveFailures);
|
|
1006
|
-
}
|
|
1007
|
-
return;
|
|
1008
|
-
}
|
|
1009
|
-
const delay = Math.min(initialDelayMs * Math.pow(backoffMultiplier, attempt), maxDelayMs);
|
|
1010
|
-
await new Promise((r) => setTimeout(r, delay));
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1014
|
-
async doFetch() {
|
|
1015
|
-
const headers = { ...this.headers };
|
|
1016
|
-
if (this.changeDetection !== "content-hash") {
|
|
1017
|
-
if (this.lastEtag) {
|
|
1018
|
-
headers["If-None-Match"] = this.lastEtag;
|
|
1019
|
-
}
|
|
1020
|
-
if (this.lastModified) {
|
|
1021
|
-
headers["If-Modified-Since"] = this.lastModified;
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
const controller = new AbortController();
|
|
1025
|
-
const timeout = setTimeout(() => controller.abort(), this.fetchTimeoutMs);
|
|
1026
|
-
try {
|
|
1027
|
-
const response = await fetch(this.url, {
|
|
1028
|
-
headers,
|
|
1029
|
-
signal: controller.signal
|
|
1030
|
-
});
|
|
1031
|
-
if (response.status === 304) {
|
|
1032
|
-
this.callbacks.onUnchanged?.();
|
|
1033
|
-
return;
|
|
1034
|
-
}
|
|
1035
|
-
if (!response.ok) {
|
|
1036
|
-
throw new OpenAPIFetchError(this.url, response.status, response.statusText);
|
|
1037
|
-
}
|
|
1038
|
-
const etag = response.headers.get("etag");
|
|
1039
|
-
const lastModified = response.headers.get("last-modified");
|
|
1040
|
-
if (etag) this.lastEtag = etag;
|
|
1041
|
-
if (lastModified) this.lastModified = lastModified;
|
|
1042
|
-
const body = await response.text();
|
|
1043
|
-
const hash = (0, import_utils2.sha256Hex)(body);
|
|
1044
|
-
if (this.lastHash && this.lastHash === hash) {
|
|
1045
|
-
this.callbacks.onUnchanged?.();
|
|
1046
|
-
return;
|
|
1047
|
-
}
|
|
1048
|
-
this.lastHash = hash;
|
|
1049
|
-
this.callbacks.onChanged?.(body, hash);
|
|
1050
|
-
} finally {
|
|
1051
|
-
clearTimeout(timeout);
|
|
1052
|
-
}
|
|
1053
|
-
}
|
|
1054
|
-
/**
|
|
1055
|
-
* Dispose the poller and release resources.
|
|
1056
|
-
*/
|
|
1057
|
-
dispose() {
|
|
1058
|
-
this.stop();
|
|
1059
|
-
}
|
|
1060
|
-
};
|
|
1061
|
-
|
|
1062
1073
|
// libs/adapters/src/openapi/openapi.adapter.ts
|
|
1063
1074
|
var RESERVED_KEYS2 = ["__proto__", "constructor", "prototype"];
|
|
1064
1075
|
function createConsoleLogger(prefix) {
|
|
@@ -1902,6 +1913,13 @@ function removeSecurityFromOperations(spec, operations) {
|
|
|
1902
1913
|
OpenAPIFetchError,
|
|
1903
1914
|
OpenApiSpecPoller,
|
|
1904
1915
|
OpenapiAdapter,
|
|
1916
|
+
applyAdditionalHeaders,
|
|
1917
|
+
buildRequest,
|
|
1918
|
+
createSecurityContextFromAuth,
|
|
1919
|
+
extractSecuritySchemes,
|
|
1905
1920
|
forceJwtSecurity,
|
|
1906
|
-
|
|
1921
|
+
parseResponse,
|
|
1922
|
+
removeSecurityFromOperations,
|
|
1923
|
+
resolveToolSecurity,
|
|
1924
|
+
validateSecurityConfiguration
|
|
1907
1925
|
});
|