@zackbart/connecta 0.5.0 → 0.6.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/CHANGELOG.md +358 -0
- package/README.md +53 -12
- package/dist/auth/bearer.d.ts +10 -3
- package/dist/auth/bearer.d.ts.map +1 -1
- package/dist/auth/bearer.js +21 -0
- package/dist/auth/bearer.js.map +1 -1
- package/dist/auth/clerk.d.ts +26 -1
- package/dist/auth/clerk.d.ts.map +1 -1
- package/dist/auth/clerk.js +161 -4
- package/dist/auth/clerk.js.map +1 -1
- package/dist/connectors/remote-mcp.d.ts.map +1 -1
- package/dist/connectors/remote-mcp.js +8 -0
- package/dist/connectors/remote-mcp.js.map +1 -1
- package/dist/credential-health.d.ts +212 -0
- package/dist/credential-health.d.ts.map +1 -0
- package/dist/credential-health.js +535 -0
- package/dist/credential-health.js.map +1 -0
- package/dist/execute.d.ts.map +1 -1
- package/dist/execute.js +16 -4
- package/dist/execute.js.map +1 -1
- package/dist/index.d.ts +46 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +96 -13
- package/dist/index.js.map +1 -1
- package/dist/meta-tools.d.ts +56 -5
- package/dist/meta-tools.d.ts.map +1 -1
- package/dist/meta-tools.js +249 -92
- package/dist/meta-tools.js.map +1 -1
- package/dist/registry.d.ts +62 -0
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +85 -1
- package/dist/registry.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +292 -37
- package/dist/server.js.map +1 -1
- package/dist/skills.d.ts +1 -1
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +1 -1
- package/dist/timeout.d.ts +16 -0
- package/dist/timeout.d.ts.map +1 -0
- package/dist/timeout.js +38 -0
- package/dist/timeout.js.map +1 -0
- package/dist/toolkits.d.ts +95 -1
- package/dist/toolkits.d.ts.map +1 -1
- package/dist/toolkits.js +190 -5
- package/dist/toolkits.js.map +1 -1
- package/dist/types.d.ts +70 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/ui.d.ts +35 -0
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +87 -3
- package/dist/ui.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/src/auth/bearer.ts +35 -1
- package/src/auth/clerk.ts +202 -5
- package/src/connectors/remote-mcp.ts +9 -0
- package/src/credential-health.ts +736 -0
- package/src/execute.ts +28 -4
- package/src/index.ts +176 -20
- package/src/meta-tools.ts +286 -109
- package/src/registry.ts +125 -1
- package/src/server.ts +349 -34
- package/src/skills.ts +1 -1
- package/src/timeout.ts +49 -0
- package/src/toolkits.ts +241 -6
- package/src/types.ts +76 -1
- package/src/ui.ts +98 -3
- package/src/version.ts +1 -1
package/src/execute.ts
CHANGED
|
@@ -2,7 +2,12 @@ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { compactSchema, rankTools, summarizeDescription } from "./catalog.js";
|
|
4
4
|
import { recordToolActivity, type ActivityRequestContext } from "./activity.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
errorResult,
|
|
7
|
+
jsonResult,
|
|
8
|
+
serializeResultText,
|
|
9
|
+
type ToolResult,
|
|
10
|
+
} from "./meta-tools.js";
|
|
6
11
|
import { classifyCallError, ConnectorCallError } from "./errors.js";
|
|
7
12
|
import { unwrapMcpResult } from "./mcp-result.js";
|
|
8
13
|
import type { RegistryView } from "./registry.js";
|
|
@@ -132,6 +137,7 @@ export async function buildSandboxProviders(
|
|
|
132
137
|
"__log",
|
|
133
138
|
]);
|
|
134
139
|
const connectors = registry.listConnectors();
|
|
140
|
+
const catalogStarted = Date.now();
|
|
135
141
|
const loaded = await Promise.allSettled(
|
|
136
142
|
connectors.map((connector) =>
|
|
137
143
|
registry.getTools(connector.id, baseUrl, requestScope),
|
|
@@ -249,8 +255,25 @@ export async function buildSandboxProviders(
|
|
|
249
255
|
}
|
|
250
256
|
const loadedTools = loaded[i];
|
|
251
257
|
if (loadedTools.status === "rejected") {
|
|
258
|
+
// Same health accounting as the call_tool catalog catch: a connector whose
|
|
259
|
+
// catalog cannot be fetched is unusable, and dropping its namespace with
|
|
260
|
+
// only a warn would leave the cheap `list_connectors({ probe: false })`
|
|
261
|
+
// signal clean for a code-mode deployment whose downstream grant was
|
|
262
|
+
// revoked. Recorded through `registry` — this run's view — so a
|
|
263
|
+
// toolkit-scoped execute_code lands in that toolkit's log as well.
|
|
264
|
+
registry.recordFailure(
|
|
265
|
+
connector.id,
|
|
266
|
+
Date.now() - catalogStarted,
|
|
267
|
+
loadedTools.reason,
|
|
268
|
+
);
|
|
269
|
+
// classifyCallError so a typed auth_required thrown while listing tools
|
|
270
|
+
// keeps its code where an operator can see it; health stores the message.
|
|
271
|
+
const details = classifyCallError(
|
|
272
|
+
loadedTools.reason,
|
|
273
|
+
"catalog_lookup_failed",
|
|
274
|
+
);
|
|
252
275
|
logger.warn(
|
|
253
|
-
`[connecta] execute_code: connector "${connector.id}" skipped: ${msg(loadedTools.reason)}`,
|
|
276
|
+
`[connecta] execute_code: connector "${connector.id}" skipped (${details.code}): ${msg(loadedTools.reason)}`,
|
|
254
277
|
);
|
|
255
278
|
continue;
|
|
256
279
|
}
|
|
@@ -446,8 +469,9 @@ function truncate(text: string, max: number): string {
|
|
|
446
469
|
}
|
|
447
470
|
|
|
448
471
|
function guardResultValue(value: unknown): unknown {
|
|
449
|
-
|
|
450
|
-
|
|
472
|
+
// Same serialization the call_tool guards measure, so a program returning
|
|
473
|
+
// nothing is rendered one way across every result path (issue #42).
|
|
474
|
+
const text = serializeResultText(value);
|
|
451
475
|
if (text.length <= MAX_RESULT_CHARS) return value;
|
|
452
476
|
return {
|
|
453
477
|
truncated: true,
|
package/src/index.ts
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import { CredentialVault } from "./credentials.js";
|
|
2
2
|
import { Registry } from "./registry.js";
|
|
3
3
|
import { createFetchHandler } from "./server.js";
|
|
4
|
-
import { droppedBrandingUrls } from "./ui.js";
|
|
5
|
-
import {
|
|
4
|
+
import { droppedBrandingUrls, droppedUiAuthUrls } from "./ui.js";
|
|
5
|
+
import {
|
|
6
|
+
resolveToolkits,
|
|
7
|
+
validateToolkitBindings,
|
|
8
|
+
type Toolkit,
|
|
9
|
+
type ToolkitConfig,
|
|
10
|
+
} from "./toolkits.js";
|
|
6
11
|
import { memoryStorage } from "./storage/memory.js";
|
|
7
12
|
import { CONNECTA_VERSION } from "./version.js";
|
|
8
13
|
import type { ActivityReadGate, ActivityStore } from "./activity.js";
|
|
14
|
+
import type {
|
|
15
|
+
CredentialCheckResult,
|
|
16
|
+
CredentialHealthConfig,
|
|
17
|
+
} from "./credential-health.js";
|
|
9
18
|
import type {
|
|
10
19
|
Connector,
|
|
11
20
|
ConnectaBranding,
|
|
@@ -38,9 +47,11 @@ export interface ConnectaConfig {
|
|
|
38
47
|
* adding toolkits changes nothing for connections that don't ask for one; an
|
|
39
48
|
* unknown name is an error, never a silent fallback.
|
|
40
49
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
50
|
+
* Selection is self-service until a toolkit is BOUND to an inbound identity:
|
|
51
|
+
* pass `toolkits` to an auth adapter — `bearerToken(secret, { toolkits:
|
|
52
|
+
* ["support"] })` — and that credential may open only those toolkits, and may
|
|
53
|
+
* not connect unscoped unless it also passes `unscoped: true`. An unbound
|
|
54
|
+
* identity keeps the self-service behavior.
|
|
44
55
|
*
|
|
45
56
|
* Definitions are validated at construction: an unknown connector id, an
|
|
46
57
|
* empty connector selection, an empty `includeTools`, a malformed tool
|
|
@@ -127,6 +138,19 @@ export interface ConnectaConfig {
|
|
|
127
138
|
* real cancellation of the downstream request is a deferred follow-up.
|
|
128
139
|
*/
|
|
129
140
|
probeTimeoutMs?: number;
|
|
141
|
+
/**
|
|
142
|
+
* Tuning for the proactive credential liveness checks (issue #24) that let a
|
|
143
|
+
* connector's status flip to `auth_required` *before* an agent's call fails.
|
|
144
|
+
* Defaults are safe to leave alone: at most one check per connector per 15
|
|
145
|
+
* minutes, four in flight, 30 s each, triggered opportunistically by inbound
|
|
146
|
+
* authenticated traffic. Only connectors holding a credential connecta stores
|
|
147
|
+
* — an operator-managed `credential`, or a downstream-OAuth grant — are ever
|
|
148
|
+
* checked, and a check never calls a downstream tool.
|
|
149
|
+
*
|
|
150
|
+
* `Connecta.checkCredentials()` is the same check on demand, for a Worker cron
|
|
151
|
+
* trigger or a Node interval.
|
|
152
|
+
*/
|
|
153
|
+
credentialHealth?: CredentialHealthConfig;
|
|
130
154
|
serverInfo?: {
|
|
131
155
|
name?: string;
|
|
132
156
|
version?: string;
|
|
@@ -152,6 +176,29 @@ export interface Connecta {
|
|
|
152
176
|
/** Web-standard fetch handler. Usable as `export default { fetch: connecta.fetch }`. */
|
|
153
177
|
fetch: (request: Request, env?: unknown, ctx?: unknown) => Promise<Response>;
|
|
154
178
|
registry: Registry;
|
|
179
|
+
/**
|
|
180
|
+
* Check the stored downstream credentials now — the scheduler-facing half of
|
|
181
|
+
* credential health (issue #24). Wire it to whatever timer the runtime has:
|
|
182
|
+
*
|
|
183
|
+
* ```ts
|
|
184
|
+
* // Cloudflare Workers (wrangler.jsonc: "triggers": { "crons": ["*\/15 * * * *"] })
|
|
185
|
+
* async scheduled(_c, env, ctx) { ctx.waitUntil(build(env).checkCredentials()); }
|
|
186
|
+
* // Node
|
|
187
|
+
* setInterval(() => void connecta.checkCredentials(), 15 * 60_000).unref();
|
|
188
|
+
* ```
|
|
189
|
+
*
|
|
190
|
+
* Returns one outcome per connector considered, including why a connector was
|
|
191
|
+
* skipped (`fresh` is the rate limit: a connector checked less than
|
|
192
|
+
* `credentialHealth.intervalSeconds` ago is not re-checked unless `force`).
|
|
193
|
+
* Never rejects on a connector failure — a broken connector becomes an `error`
|
|
194
|
+
* verdict. Needs a base URL for connector contexts: `publicUrl` supplies it,
|
|
195
|
+
* or pass one.
|
|
196
|
+
*/
|
|
197
|
+
checkCredentials: (opts?: {
|
|
198
|
+
baseUrl?: string;
|
|
199
|
+
force?: boolean;
|
|
200
|
+
ids?: string[];
|
|
201
|
+
}) => Promise<CredentialCheckResult[]>;
|
|
155
202
|
}
|
|
156
203
|
|
|
157
204
|
function defaultLogger(): Logger {
|
|
@@ -180,6 +227,7 @@ function normalizeAuth(auth: ConnectaConfig["auth"]): InboundAuth[] {
|
|
|
180
227
|
function warnInsecureConfig(
|
|
181
228
|
config: ConnectaConfig,
|
|
182
229
|
inboundAuth: InboundAuth[],
|
|
230
|
+
toolkits: ReadonlyMap<string, Toolkit> | undefined,
|
|
183
231
|
logger: Logger,
|
|
184
232
|
): void {
|
|
185
233
|
const oauthConnectors = config.connectors.filter((c) => c.finishAuth);
|
|
@@ -210,17 +258,62 @@ function warnInsecureConfig(
|
|
|
210
258
|
);
|
|
211
259
|
}
|
|
212
260
|
|
|
213
|
-
// Toolkits
|
|
214
|
-
//
|
|
215
|
-
//
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
);
|
|
261
|
+
// Toolkits that nothing binds to an identity: selection is then self-service,
|
|
262
|
+
// and the boundary organizes the surface rather than protecting it. Three
|
|
263
|
+
// distinct shapes, so three distinct warnings — an operator can only act on
|
|
264
|
+
// the one they are actually in.
|
|
265
|
+
//
|
|
266
|
+
// All are keyed off the RESOLVED toolkits, which is the same map `?toolkit=`
|
|
267
|
+
// resolves against, rather than the presence of the config key: `toolkits: {}`
|
|
268
|
+
// is a truthy object that resolves to nothing selectable, so warning about a
|
|
269
|
+
// choice no caller can make would name a risk that does not exist.
|
|
270
|
+
if (toolkits) {
|
|
271
|
+
const unbound = inboundAuth.filter((provider) => !provider.toolkitBinding);
|
|
272
|
+
if (inboundAuth.length === 0) {
|
|
273
|
+
// No auth at all ⇒ no identity exists to bind, so binding is not even the
|
|
274
|
+
// fix here. The open-mode warning above covers the wider exposure.
|
|
275
|
+
logger.warn(
|
|
276
|
+
"[connecta] toolkits are configured but there is no inbound " +
|
|
277
|
+
"authentication: with no identity to bind a toolkit to, any caller " +
|
|
278
|
+
"can choose any toolkit or omit ?toolkit= and see every connector. " +
|
|
279
|
+
"Configure `auth` (for example bearerToken(...) or Clerk), then bind " +
|
|
280
|
+
"each credential with `toolkits: [...]`.",
|
|
281
|
+
);
|
|
282
|
+
} else if (unbound.length === inboundAuth.length) {
|
|
283
|
+
// Authenticated, but every credential may still select every view. This is
|
|
284
|
+
// the shape issue #37 exists to close, and it is invisible without a line
|
|
285
|
+
// saying so: nothing fails, the teams are simply not separated.
|
|
286
|
+
logger.warn(
|
|
287
|
+
"[connecta] toolkits are configured but no inbound identity is bound " +
|
|
288
|
+
"to one: every credential `auth` admits can select any toolkit, or " +
|
|
289
|
+
"omit ?toolkit= and see the whole deployment, so a token handed to " +
|
|
290
|
+
"one team also opens the others' views. Bind each credential with " +
|
|
291
|
+
"`toolkits: [...]` on its auth adapter (add `unscoped: true` for an " +
|
|
292
|
+
"operator credential that should still see everything).",
|
|
293
|
+
);
|
|
294
|
+
} else if (unbound.length > 0) {
|
|
295
|
+
// The dangerous middle: SOME credentials are bound, which is exactly when
|
|
296
|
+
// an operator believes the deployment is separated — while one forgotten
|
|
297
|
+
// provider still opens every view and the whole deployment-wide surface.
|
|
298
|
+
// Naming the unbound providers is the point; an intentionally unrestricted
|
|
299
|
+
// credential says so with `unscoped: true` and stops appearing here.
|
|
300
|
+
const counted = new Map<string, number>();
|
|
301
|
+
for (const provider of unbound) {
|
|
302
|
+
counted.set(provider.kind, (counted.get(provider.kind) ?? 0) + 1);
|
|
303
|
+
}
|
|
304
|
+
const named = [...counted]
|
|
305
|
+
.map(([kind, count]) => (count > 1 ? `${kind} x${count}` : kind))
|
|
306
|
+
.join(", ");
|
|
307
|
+
logger.warn(
|
|
308
|
+
`[connecta] toolkits are bound on some inbound auth providers but not ` +
|
|
309
|
+
`all: ${named} ${unbound.length === 1 ? "declares" : "declare"} no ` +
|
|
310
|
+
"binding, so a caller that provider admits can still select any " +
|
|
311
|
+
"toolkit, connect unscoped, and read the deployment-wide operator " +
|
|
312
|
+
"surfaces — whatever the bound credentials beside it allow. Bind it " +
|
|
313
|
+
"too, or declare the exemption with `toolkits: [...], unscoped: true` " +
|
|
314
|
+
"if it is meant to be an operator credential.",
|
|
315
|
+
);
|
|
316
|
+
}
|
|
224
317
|
}
|
|
225
318
|
|
|
226
319
|
// Branding URLs that failed their scheme gate. Rendering silently falls back
|
|
@@ -235,6 +328,25 @@ function warnInsecureConfig(
|
|
|
235
328
|
);
|
|
236
329
|
}
|
|
237
330
|
|
|
331
|
+
// /ui renders exactly one provider's browser sign-in config — the first that
|
|
332
|
+
// offers one, which is the same `find` the /ui route performs — and that
|
|
333
|
+
// provider's frontendApiUrl becomes the loader's `<script src>`. Gate-or-drop
|
|
334
|
+
// like a branding href: rendering omits the loader for a rejected value and
|
|
335
|
+
// the dashboard then reports that Clerk could not load, a confusing symptom
|
|
336
|
+
// without this line naming the cause. Checking only the rendered provider
|
|
337
|
+
// keeps the claim true — a later provider's uiAuth never reaches the page, so
|
|
338
|
+
// there is nothing there to warn about.
|
|
339
|
+
const uiAuthProvider = inboundAuth.find((provider) => provider.uiAuth);
|
|
340
|
+
const droppedUiAuth = droppedUiAuthUrls(uiAuthProvider?.uiAuth);
|
|
341
|
+
if (uiAuthProvider && droppedUiAuth.length > 0) {
|
|
342
|
+
logger.warn(
|
|
343
|
+
`[connecta] inbound auth provider "${uiAuthProvider.kind}" had ` +
|
|
344
|
+
`${droppedUiAuth.join(", ")} dropped: the browser sign-in loader is ` +
|
|
345
|
+
"fetched from this origin, so it must be an absolute https URL. /ui " +
|
|
346
|
+
"renders without the loader and cannot start a sign-in.",
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
|
|
238
350
|
// OAuth connectors whose callback performs no state/CSRF check: the public
|
|
239
351
|
// /oauth/callback/<id> route would exchange any delivered code.
|
|
240
352
|
for (const connector of oauthConnectors) {
|
|
@@ -269,6 +381,7 @@ export function createConnecta(config: ConnectaConfig): Connecta {
|
|
|
269
381
|
persistToolCatalog: config.persistToolCatalog,
|
|
270
382
|
toolCatalogStaleSeconds: config.toolCatalogStaleSeconds,
|
|
271
383
|
maxResultBytes: config.maxResultBytes,
|
|
384
|
+
credentialHealth: config.credentialHealth,
|
|
272
385
|
});
|
|
273
386
|
// Throws on every structural mistake it can see (see resolveToolkits): a
|
|
274
387
|
// typo must not become a scope the operator never wrote. Note this is about
|
|
@@ -276,7 +389,11 @@ export function createConnecta(config: ConnectaConfig): Connecta {
|
|
|
276
389
|
// scopes visibility, and `auth` remains the thing deciding who gets in.
|
|
277
390
|
const toolkits = resolveToolkits(config.toolkits, config.connectors);
|
|
278
391
|
const inboundAuth = normalizeAuth(config.auth);
|
|
279
|
-
|
|
392
|
+
// Same contract for the identity half: a binding that names a toolkit this
|
|
393
|
+
// deployment does not declare would deny that credential every connection,
|
|
394
|
+
// with a 403 its client reports as a transport failure. Throw here instead.
|
|
395
|
+
validateToolkitBindings(inboundAuth, toolkits);
|
|
396
|
+
warnInsecureConfig(config, inboundAuth, toolkits, logger);
|
|
280
397
|
const handler = createFetchHandler({
|
|
281
398
|
registry,
|
|
282
399
|
auth: inboundAuth,
|
|
@@ -307,6 +424,29 @@ export function createConnecta(config: ConnectaConfig): Connecta {
|
|
|
307
424
|
: undefined,
|
|
308
425
|
),
|
|
309
426
|
registry,
|
|
427
|
+
checkCredentials: (opts = {}) => {
|
|
428
|
+
// A scheduled check has no inbound request to derive an origin from, and
|
|
429
|
+
// a connector context without one would mint OAuth redirect URIs against
|
|
430
|
+
// a guess. Say so instead: the fix is one config line.
|
|
431
|
+
const baseUrl = opts.baseUrl ?? config.publicUrl;
|
|
432
|
+
if (!baseUrl) {
|
|
433
|
+
// Rejected, not thrown: the callers this is written for are
|
|
434
|
+
// `ctx.waitUntil(...)` and `.catch(...)` on the returned promise, and a
|
|
435
|
+
// synchronous throw escapes both — it would take down a scheduled
|
|
436
|
+
// handler instead of being reported by it.
|
|
437
|
+
return Promise.reject(
|
|
438
|
+
new Error(
|
|
439
|
+
"checkCredentials() needs a base URL: set `publicUrl` on the " +
|
|
440
|
+
"config (recommended — it is also what downstream OAuth " +
|
|
441
|
+
"callbacks use) or pass checkCredentials({ baseUrl }).",
|
|
442
|
+
),
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
return registry.checkCredentialHealth(baseUrl, {
|
|
446
|
+
...(opts.force !== undefined ? { force: opts.force } : {}),
|
|
447
|
+
...(opts.ids ? { ids: opts.ids } : {}),
|
|
448
|
+
});
|
|
449
|
+
},
|
|
310
450
|
};
|
|
311
451
|
}
|
|
312
452
|
|
|
@@ -320,15 +460,30 @@ export type { ConnectorCallErrorCode, CallErrorDetails } from "./errors.js";
|
|
|
320
460
|
export { validateToolInput } from "./validate.js";
|
|
321
461
|
export type { ValidateToolInputOptions } from "./validate.js";
|
|
322
462
|
export { bearerToken } from "./auth/bearer.js";
|
|
463
|
+
export type { BearerTokenOptions } from "./auth/bearer.js";
|
|
323
464
|
export { memoryStorage } from "./storage/memory.js";
|
|
324
465
|
export { CONNECTA_VERSION } from "./version.js";
|
|
325
466
|
// Registry is reachable through `Connecta.registry`, so its type is public;
|
|
326
467
|
// the class itself, the credential vault, and the meta-tool/sandbox factories
|
|
327
468
|
// are internal factoring and are deliberately not part of the API surface.
|
|
328
469
|
export type { Registry } from "./registry.js";
|
|
329
|
-
// Config-as-code shapes for `ConnectaConfig.toolkits
|
|
330
|
-
// and the `ScopedRegistry` that enforces
|
|
331
|
-
|
|
470
|
+
// Config-as-code shapes for `ConnectaConfig.toolkits` and the identity bindings
|
|
471
|
+
// that gate them. The resolved `Toolkit` and the `ScopedRegistry` that enforces
|
|
472
|
+
// it are internal factoring.
|
|
473
|
+
export type {
|
|
474
|
+
ToolkitBindingOptions,
|
|
475
|
+
ToolkitConfig,
|
|
476
|
+
ToolkitDefinition,
|
|
477
|
+
} from "./toolkits.js";
|
|
478
|
+
// Credential health: the config shape, and the result shape a scheduled
|
|
479
|
+
// `checkCredentials()` returns. The checker itself is internal factoring.
|
|
480
|
+
export type {
|
|
481
|
+
CredentialCheckResult,
|
|
482
|
+
CredentialCheckSkip,
|
|
483
|
+
CredentialCheckState,
|
|
484
|
+
CredentialHealthConfig,
|
|
485
|
+
CredentialHealthRecord,
|
|
486
|
+
} from "./credential-health.js";
|
|
332
487
|
|
|
333
488
|
export type { RemoteMcpOptions, RemoteMcpAuth } from "./connectors/remote-mcp.js";
|
|
334
489
|
export type { ApiOptions, ApiTool } from "./connectors/api.js";
|
|
@@ -346,6 +501,7 @@ export type {
|
|
|
346
501
|
Executor,
|
|
347
502
|
ExecutorProvider,
|
|
348
503
|
InboundAuth,
|
|
504
|
+
ToolkitBinding,
|
|
349
505
|
UiAuthConfig,
|
|
350
506
|
AuthResult,
|
|
351
507
|
JsonSchema,
|