@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/esm/index.mjs
CHANGED
|
@@ -10,11 +10,356 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
// libs/adapters/src/openapi/openapi.adapter.ts
|
|
13
|
-
import { Adapter, DynamicAdapter } from "@frontmcp/sdk";
|
|
14
13
|
import { OpenAPIToolGenerator } from "mcp-from-openapi";
|
|
14
|
+
import { Adapter, DynamicAdapter } from "@frontmcp/sdk";
|
|
15
|
+
|
|
16
|
+
// libs/adapters/src/openapi/openapi-spec-poller.ts
|
|
17
|
+
import { sha256Hex } from "@frontmcp/utils";
|
|
18
|
+
|
|
19
|
+
// libs/adapters/src/openapi/openapi.errors.ts
|
|
20
|
+
import { InternalMcpError } from "@frontmcp/sdk";
|
|
21
|
+
var OpenAPIFetchError = class extends InternalMcpError {
|
|
22
|
+
constructor(url, status, statusText) {
|
|
23
|
+
super(`OpenAPI spec fetch failed from "${url}": ${status} ${statusText}`, "OPENAPI_FETCH_FAILED");
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// libs/adapters/src/openapi/openapi-spec-poller.ts
|
|
28
|
+
var DEFAULT_RETRY = {
|
|
29
|
+
maxRetries: 3,
|
|
30
|
+
initialDelayMs: 1e3,
|
|
31
|
+
maxDelayMs: 1e4,
|
|
32
|
+
backoffMultiplier: 2
|
|
33
|
+
};
|
|
34
|
+
var OpenApiSpecPoller = class {
|
|
35
|
+
url;
|
|
36
|
+
intervalMs;
|
|
37
|
+
fetchTimeoutMs;
|
|
38
|
+
changeDetection;
|
|
39
|
+
retry;
|
|
40
|
+
unhealthyThreshold;
|
|
41
|
+
headers;
|
|
42
|
+
callbacks;
|
|
43
|
+
intervalTimer = null;
|
|
44
|
+
lastHash = null;
|
|
45
|
+
lastEtag = null;
|
|
46
|
+
lastModified = null;
|
|
47
|
+
consecutiveFailures = 0;
|
|
48
|
+
isPolling = false;
|
|
49
|
+
wasUnhealthy = false;
|
|
50
|
+
health = "unknown";
|
|
51
|
+
constructor(url, options = {}, callbacks = {}) {
|
|
52
|
+
this.url = url;
|
|
53
|
+
this.intervalMs = options.intervalMs ?? 6e4;
|
|
54
|
+
this.fetchTimeoutMs = options.fetchTimeoutMs ?? 1e4;
|
|
55
|
+
this.changeDetection = options.changeDetection ?? "auto";
|
|
56
|
+
this.retry = { ...DEFAULT_RETRY, ...options.retry };
|
|
57
|
+
this.unhealthyThreshold = options.unhealthyThreshold ?? 3;
|
|
58
|
+
this.headers = options.headers ?? {};
|
|
59
|
+
this.callbacks = callbacks;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Start polling for changes.
|
|
63
|
+
*/
|
|
64
|
+
start() {
|
|
65
|
+
if (this.intervalTimer) return;
|
|
66
|
+
this.poll().catch(() => {
|
|
67
|
+
});
|
|
68
|
+
this.intervalTimer = setInterval(() => {
|
|
69
|
+
this.poll().catch(() => {
|
|
70
|
+
});
|
|
71
|
+
}, this.intervalMs);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Stop polling.
|
|
75
|
+
*/
|
|
76
|
+
stop() {
|
|
77
|
+
if (this.intervalTimer) {
|
|
78
|
+
clearInterval(this.intervalTimer);
|
|
79
|
+
this.intervalTimer = null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get current stats.
|
|
84
|
+
*/
|
|
85
|
+
getStats() {
|
|
86
|
+
return {
|
|
87
|
+
hash: this.lastHash,
|
|
88
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
89
|
+
health: this.health,
|
|
90
|
+
isRunning: this.intervalTimer !== null
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Perform a single poll cycle.
|
|
95
|
+
*/
|
|
96
|
+
async poll() {
|
|
97
|
+
if (this.isPolling) return;
|
|
98
|
+
this.isPolling = true;
|
|
99
|
+
try {
|
|
100
|
+
await this.fetchWithRetry();
|
|
101
|
+
} finally {
|
|
102
|
+
this.isPolling = false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async fetchWithRetry() {
|
|
106
|
+
const { maxRetries, initialDelayMs, maxDelayMs, backoffMultiplier } = this.retry;
|
|
107
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
108
|
+
try {
|
|
109
|
+
await this.doFetch();
|
|
110
|
+
if (this.consecutiveFailures > 0) {
|
|
111
|
+
this.consecutiveFailures = 0;
|
|
112
|
+
if (this.wasUnhealthy) {
|
|
113
|
+
this.wasUnhealthy = false;
|
|
114
|
+
this.health = "healthy";
|
|
115
|
+
this.callbacks.onRecovered?.();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
this.health = "healthy";
|
|
119
|
+
return;
|
|
120
|
+
} catch (error) {
|
|
121
|
+
if (attempt === maxRetries) {
|
|
122
|
+
this.consecutiveFailures++;
|
|
123
|
+
this.callbacks.onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
124
|
+
if (this.consecutiveFailures >= this.unhealthyThreshold && !this.wasUnhealthy) {
|
|
125
|
+
this.wasUnhealthy = true;
|
|
126
|
+
this.health = "unhealthy";
|
|
127
|
+
this.callbacks.onUnhealthy?.(this.consecutiveFailures);
|
|
128
|
+
}
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const delay = Math.min(initialDelayMs * Math.pow(backoffMultiplier, attempt), maxDelayMs);
|
|
132
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async doFetch() {
|
|
137
|
+
const headers = { ...this.headers };
|
|
138
|
+
if (this.changeDetection !== "content-hash") {
|
|
139
|
+
if (this.lastEtag) {
|
|
140
|
+
headers["If-None-Match"] = this.lastEtag;
|
|
141
|
+
}
|
|
142
|
+
if (this.lastModified) {
|
|
143
|
+
headers["If-Modified-Since"] = this.lastModified;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const controller = new AbortController();
|
|
147
|
+
const timeout = setTimeout(() => controller.abort(), this.fetchTimeoutMs);
|
|
148
|
+
try {
|
|
149
|
+
const response = await fetch(this.url, {
|
|
150
|
+
headers,
|
|
151
|
+
signal: controller.signal
|
|
152
|
+
});
|
|
153
|
+
if (response.status === 304) {
|
|
154
|
+
this.callbacks.onUnchanged?.();
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (!response.ok) {
|
|
158
|
+
throw new OpenAPIFetchError(this.url, response.status, response.statusText);
|
|
159
|
+
}
|
|
160
|
+
const etag = response.headers.get("etag");
|
|
161
|
+
const lastModified = response.headers.get("last-modified");
|
|
162
|
+
if (etag) this.lastEtag = etag;
|
|
163
|
+
if (lastModified) this.lastModified = lastModified;
|
|
164
|
+
const body = await response.text();
|
|
165
|
+
const hash = sha256Hex(body);
|
|
166
|
+
if (this.lastHash && this.lastHash === hash) {
|
|
167
|
+
this.callbacks.onUnchanged?.();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
this.lastHash = hash;
|
|
171
|
+
this.callbacks.onChanged?.(body, hash);
|
|
172
|
+
} finally {
|
|
173
|
+
clearTimeout(timeout);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Dispose the poller and release resources.
|
|
178
|
+
*/
|
|
179
|
+
dispose() {
|
|
180
|
+
this.stop();
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// libs/adapters/src/openapi/openapi.security.ts
|
|
185
|
+
import { SecurityResolver, createSecurityContext } from "mcp-from-openapi";
|
|
186
|
+
async function createSecurityContextFromAuth(tool2, ctx, options) {
|
|
187
|
+
if (options.securityResolver) {
|
|
188
|
+
return await options.securityResolver(tool2, ctx);
|
|
189
|
+
}
|
|
190
|
+
if (options.authProviderMapper) {
|
|
191
|
+
const context = createSecurityContext({});
|
|
192
|
+
const securitySchemes = /* @__PURE__ */ new Set();
|
|
193
|
+
for (const mapper of tool2.mapper) {
|
|
194
|
+
if (mapper.security?.scheme) {
|
|
195
|
+
securitySchemes.add(mapper.security.scheme);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
for (const scheme of securitySchemes) {
|
|
199
|
+
const authExtractor = options.authProviderMapper[scheme];
|
|
200
|
+
if (authExtractor) {
|
|
201
|
+
try {
|
|
202
|
+
const token = authExtractor(ctx);
|
|
203
|
+
if (token !== void 0 && token !== null && typeof token !== "string") {
|
|
204
|
+
throw new Error(
|
|
205
|
+
`authProviderMapper['${scheme}'] must return a string or undefined, but returned: ${typeof token}`
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
if (token === "") {
|
|
209
|
+
throw new Error(
|
|
210
|
+
`authProviderMapper['${scheme}'] returned empty string. Return undefined/null if no token is available, or provide a valid token.`
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
if (token) {
|
|
214
|
+
const schemeMapper = tool2.mapper.find((m) => m.security?.scheme === scheme);
|
|
215
|
+
const schemeType = schemeMapper?.security?.type?.toLowerCase();
|
|
216
|
+
const httpScheme = schemeMapper?.security?.httpScheme?.toLowerCase();
|
|
217
|
+
if (schemeType === "apikey") {
|
|
218
|
+
if (!context.apiKey) {
|
|
219
|
+
context.apiKey = token;
|
|
220
|
+
}
|
|
221
|
+
} else if (schemeType === "http" && httpScheme === "basic") {
|
|
222
|
+
if (!context.basic) {
|
|
223
|
+
context.basic = token;
|
|
224
|
+
}
|
|
225
|
+
} else if (schemeType === "oauth2") {
|
|
226
|
+
if (!context.oauth2Token) {
|
|
227
|
+
context.oauth2Token = token;
|
|
228
|
+
}
|
|
229
|
+
} else {
|
|
230
|
+
if (!context.jwt) {
|
|
231
|
+
context.jwt = token;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
} catch (err) {
|
|
236
|
+
if (err instanceof Error && err.message.includes("authProviderMapper")) {
|
|
237
|
+
throw err;
|
|
238
|
+
}
|
|
239
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
240
|
+
throw new Error(`authProviderMapper['${scheme}'] threw an error: ${errorMessage}`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
const hasAnyAuth = context.jwt || context.apiKey || context.basic || context.oauth2Token;
|
|
245
|
+
const authToken = ctx.authInfo?.token;
|
|
246
|
+
if (!hasAnyAuth && authToken) {
|
|
247
|
+
if (typeof authToken !== "string") {
|
|
248
|
+
throw new Error(`authInfo.token must be a string, but got: ${typeof authToken}`);
|
|
249
|
+
}
|
|
250
|
+
context.jwt = authToken;
|
|
251
|
+
}
|
|
252
|
+
return context;
|
|
253
|
+
}
|
|
254
|
+
if (options.staticAuth) {
|
|
255
|
+
return createSecurityContext(options.staticAuth);
|
|
256
|
+
}
|
|
257
|
+
return createSecurityContext({
|
|
258
|
+
jwt: ctx.authInfo?.token
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
function extractSecuritySchemes(tools) {
|
|
262
|
+
const schemes = /* @__PURE__ */ new Set();
|
|
263
|
+
for (const tool2 of tools) {
|
|
264
|
+
for (const mapper of tool2.mapper) {
|
|
265
|
+
if (mapper.security?.scheme) {
|
|
266
|
+
schemes.add(mapper.security.scheme);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return schemes;
|
|
271
|
+
}
|
|
272
|
+
function validateSecurityConfiguration(tools, options) {
|
|
273
|
+
const result = {
|
|
274
|
+
valid: true,
|
|
275
|
+
missingMappings: [],
|
|
276
|
+
warnings: [],
|
|
277
|
+
securityRiskScore: "low"
|
|
278
|
+
};
|
|
279
|
+
const securitySchemes = extractSecuritySchemes(tools);
|
|
280
|
+
const includeSecurityInInput = options.generateOptions?.includeSecurityInInput ?? false;
|
|
281
|
+
if (includeSecurityInInput) {
|
|
282
|
+
result.securityRiskScore = "high";
|
|
283
|
+
result.warnings.push(
|
|
284
|
+
"SECURITY WARNING: includeSecurityInInput is enabled. Users will provide authentication directly in tool inputs. This increases security risk as credentials may be logged or exposed."
|
|
285
|
+
);
|
|
286
|
+
return result;
|
|
287
|
+
}
|
|
288
|
+
if (options.securityResolver) {
|
|
289
|
+
result.securityRiskScore = "low";
|
|
290
|
+
result.warnings.push(
|
|
291
|
+
"INFO: Using custom securityResolver. Ensure your resolver properly validates and secures credentials from context."
|
|
292
|
+
);
|
|
293
|
+
return result;
|
|
294
|
+
}
|
|
295
|
+
if (options.staticAuth && Object.keys(options.staticAuth).length > 0) {
|
|
296
|
+
result.securityRiskScore = "medium";
|
|
297
|
+
result.warnings.push(
|
|
298
|
+
"SECURITY INFO: Using staticAuth with hardcoded credentials. Ensure credentials are stored securely (environment variables, secrets manager)."
|
|
299
|
+
);
|
|
300
|
+
return result;
|
|
301
|
+
}
|
|
302
|
+
const schemesInInput = new Set(options.securitySchemesInInput || []);
|
|
303
|
+
if (options.authProviderMapper || schemesInInput.size > 0) {
|
|
304
|
+
result.securityRiskScore = schemesInInput.size > 0 ? "medium" : "low";
|
|
305
|
+
if (schemesInInput.size > 0) {
|
|
306
|
+
result.warnings.push(
|
|
307
|
+
`INFO: Per-scheme security control enabled. Schemes in input: ${Array.from(schemesInInput).join(", ")}`
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
for (const scheme of securitySchemes) {
|
|
311
|
+
if (schemesInInput.has(scheme)) {
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
if (!options.authProviderMapper?.[scheme]) {
|
|
315
|
+
result.valid = false;
|
|
316
|
+
result.missingMappings.push(scheme);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
if (!result.valid) {
|
|
320
|
+
result.warnings.push(
|
|
321
|
+
`ERROR: Missing auth provider mappings for security schemes: ${result.missingMappings.join(", ")}`
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
return result;
|
|
325
|
+
}
|
|
326
|
+
if (securitySchemes.size > 0) {
|
|
327
|
+
result.securityRiskScore = "medium";
|
|
328
|
+
result.warnings.push(
|
|
329
|
+
`INFO: No auth configuration provided. Using default ctx.authInfo.token for all security schemes: ${Array.from(
|
|
330
|
+
securitySchemes
|
|
331
|
+
).join(", ")}`
|
|
332
|
+
);
|
|
333
|
+
result.warnings.push(
|
|
334
|
+
"RECOMMENDATION: For multiple auth providers, use authProviderMapper or securityResolver to map each security scheme to the correct auth provider."
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
return result;
|
|
338
|
+
}
|
|
339
|
+
async function resolveToolSecurity(tool2, ctx, options) {
|
|
340
|
+
const securityResolver = new SecurityResolver();
|
|
341
|
+
const securityContext = await createSecurityContextFromAuth(tool2, ctx, options);
|
|
342
|
+
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;
|
|
343
|
+
const requiresSecurity = tool2.mapper.some((m) => m.security && m.required === true);
|
|
344
|
+
if (requiresSecurity && !hasAuth) {
|
|
345
|
+
const requiredSchemes = tool2.mapper.filter((m) => m.security && m.required === true).map((m) => m.security?.scheme ?? "unknown");
|
|
346
|
+
const uniqueSchemes = [...new Set(requiredSchemes)];
|
|
347
|
+
const schemesStr = uniqueSchemes.join(", ") || "unknown";
|
|
348
|
+
const firstScheme = uniqueSchemes[0] || "BearerAuth";
|
|
349
|
+
throw new Error(
|
|
350
|
+
`Authentication required for tool '${tool2.name}' but no auth configuration found.
|
|
351
|
+
Required security schemes: ${schemesStr}
|
|
352
|
+
Solutions:
|
|
353
|
+
1. Add authProviderMapper: { '${firstScheme}': (ctx) => ctx.authInfo.user?.token }
|
|
354
|
+
2. Add securityResolver: (tool, ctx) => ({ jwt: ctx.authInfo.token })
|
|
355
|
+
3. Add staticAuth: { jwt: process.env.API_TOKEN }
|
|
356
|
+
4. Set generateOptions.includeSecurityInInput: true (not recommended for production)`
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
return await securityResolver.resolve(tool2.mapper, securityContext);
|
|
360
|
+
}
|
|
15
361
|
|
|
16
362
|
// libs/adapters/src/openapi/openapi.tool.ts
|
|
17
|
-
import { convertJsonSchemaToZod } from "zod-from-json-schema";
|
|
18
363
|
import { z as z2 } from "@frontmcp/lazy-zod";
|
|
19
364
|
import { tool } from "@frontmcp/sdk";
|
|
20
365
|
|
|
@@ -218,227 +563,49 @@ function extractValidCodeCall(data, warnings) {
|
|
|
218
563
|
} else if (obj["enabledInCodeCall"] !== void 0) {
|
|
219
564
|
warnings.push(`Invalid 'codecall.enabledInCodeCall': expected boolean`);
|
|
220
565
|
}
|
|
221
|
-
if (typeof obj["visibleInListTools"] === "boolean") {
|
|
222
|
-
result.visibleInListTools = obj["visibleInListTools"];
|
|
223
|
-
} else if (obj["visibleInListTools"] !== void 0) {
|
|
224
|
-
warnings.push(`Invalid 'codecall.visibleInListTools': expected boolean`);
|
|
225
|
-
}
|
|
226
|
-
for (const key of Object.keys(obj)) {
|
|
227
|
-
if (!KNOWN_CODECALL_FIELDS.has(key)) {
|
|
228
|
-
warnings.push(`Unknown field 'codecall.${key}' (will be ignored)`);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
return Object.keys(result).length > 0 ? result : void 0;
|
|
232
|
-
}
|
|
233
|
-
function extractValidTags(data) {
|
|
234
|
-
if (!Array.isArray(data)) return void 0;
|
|
235
|
-
const validTags = data.filter((item) => typeof item === "string");
|
|
236
|
-
return validTags.length > 0 ? validTags : void 0;
|
|
237
|
-
}
|
|
238
|
-
function extractValidExamples(data, warnings) {
|
|
239
|
-
if (!Array.isArray(data)) return void 0;
|
|
240
|
-
const validExamples = [];
|
|
241
|
-
for (let i = 0; i < data.length; i++) {
|
|
242
|
-
const item = data[i];
|
|
243
|
-
const result = FrontMcpExampleSchema.safeParse(item);
|
|
244
|
-
if (result.success) {
|
|
245
|
-
validExamples.push(result.data);
|
|
246
|
-
} else {
|
|
247
|
-
warnings.push(
|
|
248
|
-
`Invalid example at index ${i}: ${formatZodIssues(result.error.issues, `examples[${i}]`).join(", ")}`
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
return validExamples.length > 0 ? validExamples : void 0;
|
|
253
|
-
}
|
|
254
|
-
function formatZodIssues(issues, prefix) {
|
|
255
|
-
return issues.map((issue) => {
|
|
256
|
-
const path = issue.path.length > 0 ? `${prefix}.${issue.path.join(".")}` : prefix;
|
|
257
|
-
return `Invalid '${path}': ${issue.message}`;
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// libs/adapters/src/openapi/openapi.security.ts
|
|
262
|
-
import { SecurityResolver, createSecurityContext } from "mcp-from-openapi";
|
|
263
|
-
async function createSecurityContextFromAuth(tool2, ctx, options) {
|
|
264
|
-
if (options.securityResolver) {
|
|
265
|
-
return await options.securityResolver(tool2, ctx);
|
|
266
|
-
}
|
|
267
|
-
if (options.authProviderMapper) {
|
|
268
|
-
const context = createSecurityContext({});
|
|
269
|
-
const securitySchemes = /* @__PURE__ */ new Set();
|
|
270
|
-
for (const mapper of tool2.mapper) {
|
|
271
|
-
if (mapper.security?.scheme) {
|
|
272
|
-
securitySchemes.add(mapper.security.scheme);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
for (const scheme of securitySchemes) {
|
|
276
|
-
const authExtractor = options.authProviderMapper[scheme];
|
|
277
|
-
if (authExtractor) {
|
|
278
|
-
try {
|
|
279
|
-
const token = authExtractor(ctx);
|
|
280
|
-
if (token !== void 0 && token !== null && typeof token !== "string") {
|
|
281
|
-
throw new Error(
|
|
282
|
-
`authProviderMapper['${scheme}'] must return a string or undefined, but returned: ${typeof token}`
|
|
283
|
-
);
|
|
284
|
-
}
|
|
285
|
-
if (token === "") {
|
|
286
|
-
throw new Error(
|
|
287
|
-
`authProviderMapper['${scheme}'] returned empty string. Return undefined/null if no token is available, or provide a valid token.`
|
|
288
|
-
);
|
|
289
|
-
}
|
|
290
|
-
if (token) {
|
|
291
|
-
const schemeMapper = tool2.mapper.find((m) => m.security?.scheme === scheme);
|
|
292
|
-
const schemeType = schemeMapper?.security?.type?.toLowerCase();
|
|
293
|
-
const httpScheme = schemeMapper?.security?.httpScheme?.toLowerCase();
|
|
294
|
-
if (schemeType === "apikey") {
|
|
295
|
-
if (!context.apiKey) {
|
|
296
|
-
context.apiKey = token;
|
|
297
|
-
}
|
|
298
|
-
} else if (schemeType === "http" && httpScheme === "basic") {
|
|
299
|
-
if (!context.basic) {
|
|
300
|
-
context.basic = token;
|
|
301
|
-
}
|
|
302
|
-
} else if (schemeType === "oauth2") {
|
|
303
|
-
if (!context.oauth2Token) {
|
|
304
|
-
context.oauth2Token = token;
|
|
305
|
-
}
|
|
306
|
-
} else {
|
|
307
|
-
if (!context.jwt) {
|
|
308
|
-
context.jwt = token;
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
} catch (err) {
|
|
313
|
-
if (err instanceof Error && err.message.includes("authProviderMapper")) {
|
|
314
|
-
throw err;
|
|
315
|
-
}
|
|
316
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
317
|
-
throw new Error(`authProviderMapper['${scheme}'] threw an error: ${errorMessage}`);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
const hasAnyAuth = context.jwt || context.apiKey || context.basic || context.oauth2Token;
|
|
322
|
-
const authToken = ctx.authInfo?.token;
|
|
323
|
-
if (!hasAnyAuth && authToken) {
|
|
324
|
-
if (typeof authToken !== "string") {
|
|
325
|
-
throw new Error(`authInfo.token must be a string, but got: ${typeof authToken}`);
|
|
326
|
-
}
|
|
327
|
-
context.jwt = authToken;
|
|
328
|
-
}
|
|
329
|
-
return context;
|
|
330
|
-
}
|
|
331
|
-
if (options.staticAuth) {
|
|
332
|
-
return createSecurityContext(options.staticAuth);
|
|
333
|
-
}
|
|
334
|
-
return createSecurityContext({
|
|
335
|
-
jwt: ctx.authInfo?.token
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
function extractSecuritySchemes(tools) {
|
|
339
|
-
const schemes = /* @__PURE__ */ new Set();
|
|
340
|
-
for (const tool2 of tools) {
|
|
341
|
-
for (const mapper of tool2.mapper) {
|
|
342
|
-
if (mapper.security?.scheme) {
|
|
343
|
-
schemes.add(mapper.security.scheme);
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
return schemes;
|
|
348
|
-
}
|
|
349
|
-
function validateSecurityConfiguration(tools, options) {
|
|
350
|
-
const result = {
|
|
351
|
-
valid: true,
|
|
352
|
-
missingMappings: [],
|
|
353
|
-
warnings: [],
|
|
354
|
-
securityRiskScore: "low"
|
|
355
|
-
};
|
|
356
|
-
const securitySchemes = extractSecuritySchemes(tools);
|
|
357
|
-
const includeSecurityInInput = options.generateOptions?.includeSecurityInInput ?? false;
|
|
358
|
-
if (includeSecurityInInput) {
|
|
359
|
-
result.securityRiskScore = "high";
|
|
360
|
-
result.warnings.push(
|
|
361
|
-
"SECURITY WARNING: includeSecurityInInput is enabled. Users will provide authentication directly in tool inputs. This increases security risk as credentials may be logged or exposed."
|
|
362
|
-
);
|
|
363
|
-
return result;
|
|
364
|
-
}
|
|
365
|
-
if (options.securityResolver) {
|
|
366
|
-
result.securityRiskScore = "low";
|
|
367
|
-
result.warnings.push(
|
|
368
|
-
"INFO: Using custom securityResolver. Ensure your resolver properly validates and secures credentials from context."
|
|
369
|
-
);
|
|
370
|
-
return result;
|
|
371
|
-
}
|
|
372
|
-
if (options.staticAuth && Object.keys(options.staticAuth).length > 0) {
|
|
373
|
-
result.securityRiskScore = "medium";
|
|
374
|
-
result.warnings.push(
|
|
375
|
-
"SECURITY INFO: Using staticAuth with hardcoded credentials. Ensure credentials are stored securely (environment variables, secrets manager)."
|
|
376
|
-
);
|
|
377
|
-
return result;
|
|
378
|
-
}
|
|
379
|
-
const schemesInInput = new Set(options.securitySchemesInInput || []);
|
|
380
|
-
if (options.authProviderMapper || schemesInInput.size > 0) {
|
|
381
|
-
result.securityRiskScore = schemesInInput.size > 0 ? "medium" : "low";
|
|
382
|
-
if (schemesInInput.size > 0) {
|
|
383
|
-
result.warnings.push(
|
|
384
|
-
`INFO: Per-scheme security control enabled. Schemes in input: ${Array.from(schemesInInput).join(", ")}`
|
|
385
|
-
);
|
|
386
|
-
}
|
|
387
|
-
for (const scheme of securitySchemes) {
|
|
388
|
-
if (schemesInInput.has(scheme)) {
|
|
389
|
-
continue;
|
|
390
|
-
}
|
|
391
|
-
if (!options.authProviderMapper?.[scheme]) {
|
|
392
|
-
result.valid = false;
|
|
393
|
-
result.missingMappings.push(scheme);
|
|
394
|
-
}
|
|
566
|
+
if (typeof obj["visibleInListTools"] === "boolean") {
|
|
567
|
+
result.visibleInListTools = obj["visibleInListTools"];
|
|
568
|
+
} else if (obj["visibleInListTools"] !== void 0) {
|
|
569
|
+
warnings.push(`Invalid 'codecall.visibleInListTools': expected boolean`);
|
|
570
|
+
}
|
|
571
|
+
for (const key of Object.keys(obj)) {
|
|
572
|
+
if (!KNOWN_CODECALL_FIELDS.has(key)) {
|
|
573
|
+
warnings.push(`Unknown field 'codecall.${key}' (will be ignored)`);
|
|
395
574
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
575
|
+
}
|
|
576
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
577
|
+
}
|
|
578
|
+
function extractValidTags(data) {
|
|
579
|
+
if (!Array.isArray(data)) return void 0;
|
|
580
|
+
const validTags = data.filter((item) => typeof item === "string");
|
|
581
|
+
return validTags.length > 0 ? validTags : void 0;
|
|
582
|
+
}
|
|
583
|
+
function extractValidExamples(data, warnings) {
|
|
584
|
+
if (!Array.isArray(data)) return void 0;
|
|
585
|
+
const validExamples = [];
|
|
586
|
+
for (let i = 0; i < data.length; i++) {
|
|
587
|
+
const item = data[i];
|
|
588
|
+
const result = FrontMcpExampleSchema.safeParse(item);
|
|
589
|
+
if (result.success) {
|
|
590
|
+
validExamples.push(result.data);
|
|
591
|
+
} else {
|
|
592
|
+
warnings.push(
|
|
593
|
+
`Invalid example at index ${i}: ${formatZodIssues(result.error.issues, `examples[${i}]`).join(", ")}`
|
|
399
594
|
);
|
|
400
595
|
}
|
|
401
|
-
return result;
|
|
402
|
-
}
|
|
403
|
-
if (securitySchemes.size > 0) {
|
|
404
|
-
result.securityRiskScore = "medium";
|
|
405
|
-
result.warnings.push(
|
|
406
|
-
`INFO: No auth configuration provided. Using default ctx.authInfo.token for all security schemes: ${Array.from(
|
|
407
|
-
securitySchemes
|
|
408
|
-
).join(", ")}`
|
|
409
|
-
);
|
|
410
|
-
result.warnings.push(
|
|
411
|
-
"RECOMMENDATION: For multiple auth providers, use authProviderMapper or securityResolver to map each security scheme to the correct auth provider."
|
|
412
|
-
);
|
|
413
596
|
}
|
|
414
|
-
return
|
|
597
|
+
return validExamples.length > 0 ? validExamples : void 0;
|
|
415
598
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
if (requiresSecurity && !hasAuth) {
|
|
422
|
-
const requiredSchemes = tool2.mapper.filter((m) => m.security && m.required === true).map((m) => m.security?.scheme ?? "unknown");
|
|
423
|
-
const uniqueSchemes = [...new Set(requiredSchemes)];
|
|
424
|
-
const schemesStr = uniqueSchemes.join(", ") || "unknown";
|
|
425
|
-
const firstScheme = uniqueSchemes[0] || "BearerAuth";
|
|
426
|
-
throw new Error(
|
|
427
|
-
`Authentication required for tool '${tool2.name}' but no auth configuration found.
|
|
428
|
-
Required security schemes: ${schemesStr}
|
|
429
|
-
Solutions:
|
|
430
|
-
1. Add authProviderMapper: { '${firstScheme}': (ctx) => ctx.authInfo.user?.token }
|
|
431
|
-
2. Add securityResolver: (tool, ctx) => ({ jwt: ctx.authInfo.token })
|
|
432
|
-
3. Add staticAuth: { jwt: process.env.API_TOKEN }
|
|
433
|
-
4. Set generateOptions.includeSecurityInInput: true (not recommended for production)`
|
|
434
|
-
);
|
|
435
|
-
}
|
|
436
|
-
return await securityResolver.resolve(tool2.mapper, securityContext);
|
|
599
|
+
function formatZodIssues(issues, prefix) {
|
|
600
|
+
return issues.map((issue) => {
|
|
601
|
+
const path = issue.path.length > 0 ? `${prefix}.${issue.path.join(".")}` : prefix;
|
|
602
|
+
return `Invalid '${path}': ${issue.message}`;
|
|
603
|
+
});
|
|
437
604
|
}
|
|
438
605
|
|
|
439
606
|
// libs/adapters/src/openapi/openapi.utils.ts
|
|
440
|
-
import { validateBaseUrl } from "@frontmcp/utils";
|
|
441
607
|
import { PublicMcpError } from "@frontmcp/sdk";
|
|
608
|
+
import { trimTrailing, validateBaseUrl } from "@frontmcp/utils";
|
|
442
609
|
function coerceToString(value, paramName, location) {
|
|
443
610
|
if (value === null || value === void 0) {
|
|
444
611
|
return "";
|
|
@@ -466,7 +633,7 @@ function appendCookie(headers, name, value) {
|
|
|
466
633
|
function buildRequest(tool2, input, security, baseUrl) {
|
|
467
634
|
const rawBaseUrl = tool2.metadata.servers?.[0]?.url || baseUrl;
|
|
468
635
|
validateBaseUrl(rawBaseUrl);
|
|
469
|
-
const apiBaseUrl = rawBaseUrl
|
|
636
|
+
const apiBaseUrl = trimTrailing(rawBaseUrl, "/");
|
|
470
637
|
let path = tool2.metadata.path;
|
|
471
638
|
const queryParams = new URLSearchParams();
|
|
472
639
|
const headers = new Headers({
|
|
@@ -849,7 +1016,12 @@ function getZodSchemaFromJsonSchema(jsonSchema, toolName, logger) {
|
|
|
849
1016
|
return { schema: z2.looseObject({}), conversionFailed: true, error: "No valid JSON schema" };
|
|
850
1017
|
}
|
|
851
1018
|
try {
|
|
852
|
-
const zodSchema =
|
|
1019
|
+
const zodSchema = z2.fromJSONSchema(
|
|
1020
|
+
jsonSchema,
|
|
1021
|
+
{
|
|
1022
|
+
defaultTarget: "draft-2020-12"
|
|
1023
|
+
}
|
|
1024
|
+
);
|
|
853
1025
|
if (typeof zodSchema?.parse !== "function") {
|
|
854
1026
|
throw new Error("Conversion did not produce a valid Zod schema.");
|
|
855
1027
|
}
|
|
@@ -863,174 +1035,6 @@ function getZodSchemaFromJsonSchema(jsonSchema, toolName, logger) {
|
|
|
863
1035
|
}
|
|
864
1036
|
}
|
|
865
1037
|
|
|
866
|
-
// libs/adapters/src/openapi/openapi-spec-poller.ts
|
|
867
|
-
import { sha256Hex } from "@frontmcp/utils";
|
|
868
|
-
|
|
869
|
-
// libs/adapters/src/openapi/openapi.errors.ts
|
|
870
|
-
import { InternalMcpError } from "@frontmcp/sdk";
|
|
871
|
-
var OpenAPIFetchError = class extends InternalMcpError {
|
|
872
|
-
constructor(url, status, statusText) {
|
|
873
|
-
super(`OpenAPI spec fetch failed from "${url}": ${status} ${statusText}`, "OPENAPI_FETCH_FAILED");
|
|
874
|
-
}
|
|
875
|
-
};
|
|
876
|
-
|
|
877
|
-
// libs/adapters/src/openapi/openapi-spec-poller.ts
|
|
878
|
-
var DEFAULT_RETRY = {
|
|
879
|
-
maxRetries: 3,
|
|
880
|
-
initialDelayMs: 1e3,
|
|
881
|
-
maxDelayMs: 1e4,
|
|
882
|
-
backoffMultiplier: 2
|
|
883
|
-
};
|
|
884
|
-
var OpenApiSpecPoller = class {
|
|
885
|
-
url;
|
|
886
|
-
intervalMs;
|
|
887
|
-
fetchTimeoutMs;
|
|
888
|
-
changeDetection;
|
|
889
|
-
retry;
|
|
890
|
-
unhealthyThreshold;
|
|
891
|
-
headers;
|
|
892
|
-
callbacks;
|
|
893
|
-
intervalTimer = null;
|
|
894
|
-
lastHash = null;
|
|
895
|
-
lastEtag = null;
|
|
896
|
-
lastModified = null;
|
|
897
|
-
consecutiveFailures = 0;
|
|
898
|
-
isPolling = false;
|
|
899
|
-
wasUnhealthy = false;
|
|
900
|
-
health = "unknown";
|
|
901
|
-
constructor(url, options = {}, callbacks = {}) {
|
|
902
|
-
this.url = url;
|
|
903
|
-
this.intervalMs = options.intervalMs ?? 6e4;
|
|
904
|
-
this.fetchTimeoutMs = options.fetchTimeoutMs ?? 1e4;
|
|
905
|
-
this.changeDetection = options.changeDetection ?? "auto";
|
|
906
|
-
this.retry = { ...DEFAULT_RETRY, ...options.retry };
|
|
907
|
-
this.unhealthyThreshold = options.unhealthyThreshold ?? 3;
|
|
908
|
-
this.headers = options.headers ?? {};
|
|
909
|
-
this.callbacks = callbacks;
|
|
910
|
-
}
|
|
911
|
-
/**
|
|
912
|
-
* Start polling for changes.
|
|
913
|
-
*/
|
|
914
|
-
start() {
|
|
915
|
-
if (this.intervalTimer) return;
|
|
916
|
-
this.poll().catch(() => {
|
|
917
|
-
});
|
|
918
|
-
this.intervalTimer = setInterval(() => {
|
|
919
|
-
this.poll().catch(() => {
|
|
920
|
-
});
|
|
921
|
-
}, this.intervalMs);
|
|
922
|
-
}
|
|
923
|
-
/**
|
|
924
|
-
* Stop polling.
|
|
925
|
-
*/
|
|
926
|
-
stop() {
|
|
927
|
-
if (this.intervalTimer) {
|
|
928
|
-
clearInterval(this.intervalTimer);
|
|
929
|
-
this.intervalTimer = null;
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
/**
|
|
933
|
-
* Get current stats.
|
|
934
|
-
*/
|
|
935
|
-
getStats() {
|
|
936
|
-
return {
|
|
937
|
-
hash: this.lastHash,
|
|
938
|
-
consecutiveFailures: this.consecutiveFailures,
|
|
939
|
-
health: this.health,
|
|
940
|
-
isRunning: this.intervalTimer !== null
|
|
941
|
-
};
|
|
942
|
-
}
|
|
943
|
-
/**
|
|
944
|
-
* Perform a single poll cycle.
|
|
945
|
-
*/
|
|
946
|
-
async poll() {
|
|
947
|
-
if (this.isPolling) return;
|
|
948
|
-
this.isPolling = true;
|
|
949
|
-
try {
|
|
950
|
-
await this.fetchWithRetry();
|
|
951
|
-
} finally {
|
|
952
|
-
this.isPolling = false;
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
async fetchWithRetry() {
|
|
956
|
-
const { maxRetries, initialDelayMs, maxDelayMs, backoffMultiplier } = this.retry;
|
|
957
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
958
|
-
try {
|
|
959
|
-
await this.doFetch();
|
|
960
|
-
if (this.consecutiveFailures > 0) {
|
|
961
|
-
this.consecutiveFailures = 0;
|
|
962
|
-
if (this.wasUnhealthy) {
|
|
963
|
-
this.wasUnhealthy = false;
|
|
964
|
-
this.health = "healthy";
|
|
965
|
-
this.callbacks.onRecovered?.();
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
this.health = "healthy";
|
|
969
|
-
return;
|
|
970
|
-
} catch (error) {
|
|
971
|
-
if (attempt === maxRetries) {
|
|
972
|
-
this.consecutiveFailures++;
|
|
973
|
-
this.callbacks.onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
974
|
-
if (this.consecutiveFailures >= this.unhealthyThreshold && !this.wasUnhealthy) {
|
|
975
|
-
this.wasUnhealthy = true;
|
|
976
|
-
this.health = "unhealthy";
|
|
977
|
-
this.callbacks.onUnhealthy?.(this.consecutiveFailures);
|
|
978
|
-
}
|
|
979
|
-
return;
|
|
980
|
-
}
|
|
981
|
-
const delay = Math.min(initialDelayMs * Math.pow(backoffMultiplier, attempt), maxDelayMs);
|
|
982
|
-
await new Promise((r) => setTimeout(r, delay));
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
async doFetch() {
|
|
987
|
-
const headers = { ...this.headers };
|
|
988
|
-
if (this.changeDetection !== "content-hash") {
|
|
989
|
-
if (this.lastEtag) {
|
|
990
|
-
headers["If-None-Match"] = this.lastEtag;
|
|
991
|
-
}
|
|
992
|
-
if (this.lastModified) {
|
|
993
|
-
headers["If-Modified-Since"] = this.lastModified;
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
const controller = new AbortController();
|
|
997
|
-
const timeout = setTimeout(() => controller.abort(), this.fetchTimeoutMs);
|
|
998
|
-
try {
|
|
999
|
-
const response = await fetch(this.url, {
|
|
1000
|
-
headers,
|
|
1001
|
-
signal: controller.signal
|
|
1002
|
-
});
|
|
1003
|
-
if (response.status === 304) {
|
|
1004
|
-
this.callbacks.onUnchanged?.();
|
|
1005
|
-
return;
|
|
1006
|
-
}
|
|
1007
|
-
if (!response.ok) {
|
|
1008
|
-
throw new OpenAPIFetchError(this.url, response.status, response.statusText);
|
|
1009
|
-
}
|
|
1010
|
-
const etag = response.headers.get("etag");
|
|
1011
|
-
const lastModified = response.headers.get("last-modified");
|
|
1012
|
-
if (etag) this.lastEtag = etag;
|
|
1013
|
-
if (lastModified) this.lastModified = lastModified;
|
|
1014
|
-
const body = await response.text();
|
|
1015
|
-
const hash = sha256Hex(body);
|
|
1016
|
-
if (this.lastHash && this.lastHash === hash) {
|
|
1017
|
-
this.callbacks.onUnchanged?.();
|
|
1018
|
-
return;
|
|
1019
|
-
}
|
|
1020
|
-
this.lastHash = hash;
|
|
1021
|
-
this.callbacks.onChanged?.(body, hash);
|
|
1022
|
-
} finally {
|
|
1023
|
-
clearTimeout(timeout);
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
/**
|
|
1027
|
-
* Dispose the poller and release resources.
|
|
1028
|
-
*/
|
|
1029
|
-
dispose() {
|
|
1030
|
-
this.stop();
|
|
1031
|
-
}
|
|
1032
|
-
};
|
|
1033
|
-
|
|
1034
1038
|
// libs/adapters/src/openapi/openapi.adapter.ts
|
|
1035
1039
|
var RESERVED_KEYS2 = ["__proto__", "constructor", "prototype"];
|
|
1036
1040
|
function createConsoleLogger(prefix) {
|
|
@@ -1873,6 +1877,13 @@ export {
|
|
|
1873
1877
|
OpenAPIFetchError,
|
|
1874
1878
|
OpenApiSpecPoller,
|
|
1875
1879
|
OpenapiAdapter,
|
|
1880
|
+
applyAdditionalHeaders,
|
|
1881
|
+
buildRequest,
|
|
1882
|
+
createSecurityContextFromAuth,
|
|
1883
|
+
extractSecuritySchemes,
|
|
1876
1884
|
forceJwtSecurity,
|
|
1877
|
-
|
|
1885
|
+
parseResponse,
|
|
1886
|
+
removeSecurityFromOperations,
|
|
1887
|
+
resolveToolSecurity,
|
|
1888
|
+
validateSecurityConfiguration
|
|
1878
1889
|
};
|