@zackbart/connecta 0.7.1 → 0.7.3
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 +72 -0
- package/README.md +2 -1
- package/dist/connectors/remote-mcp.d.ts.map +1 -1
- package/dist/connectors/remote-mcp.js +117 -79
- package/dist/connectors/remote-mcp.js.map +1 -1
- package/dist/credential-health.d.ts +8 -5
- package/dist/credential-health.d.ts.map +1 -1
- package/dist/credential-health.js +20 -13
- package/dist/credential-health.js.map +1 -1
- package/dist/executors/quickjs.d.ts.map +1 -1
- package/dist/executors/quickjs.js +57 -5
- package/dist/executors/quickjs.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/meta-tools.d.ts.map +1 -1
- package/dist/meta-tools.js +47 -11
- package/dist/meta-tools.js.map +1 -1
- package/dist/registry.d.ts +18 -22
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +33 -21
- package/dist/registry.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +9 -6
- package/dist/server.js.map +1 -1
- package/dist/timeout.d.ts +9 -4
- package/dist/timeout.d.ts.map +1 -1
- package/dist/timeout.js +34 -4
- package/dist/timeout.js.map +1 -1
- package/dist/toolkits.d.ts +8 -0
- package/dist/toolkits.d.ts.map +1 -1
- package/dist/toolkits.js +3 -0
- package/dist/toolkits.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/ui.d.ts +12 -1
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +187 -6
- 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/connectors/remote-mcp.ts +128 -83
- package/src/credential-health.ts +20 -18
- package/src/executors/quickjs.ts +65 -5
- package/src/index.ts +2 -1
- package/src/meta-tools.ts +75 -26
- package/src/registry.ts +48 -20
- package/src/server.ts +11 -8
- package/src/timeout.ts +41 -4
- package/src/toolkits.ts +11 -0
- package/src/types.ts +2 -2
- package/src/ui.ts +212 -11
- package/src/version.ts +1 -1
package/src/ui.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
import type { CredentialVault } from "./credentials.js";
|
|
7
7
|
import { closeConnectorScope } from "./connector-scope.js";
|
|
8
8
|
import type { Registry } from "./registry.js";
|
|
9
|
+
import type { Toolkit } from "./toolkits.js";
|
|
9
10
|
import type { ConnectaBranding, UiAuthConfig } from "./types.js";
|
|
10
11
|
|
|
11
12
|
/** Connecta's default monochrome "C" mark. */
|
|
@@ -296,10 +297,21 @@ export interface UiConnector {
|
|
|
296
297
|
export interface UiData {
|
|
297
298
|
serverInfo: { name: string; version: string };
|
|
298
299
|
connectors: UiConnector[];
|
|
300
|
+
/** Read-only projection of the validated deployment config. */
|
|
301
|
+
toolkits: UiToolkit[];
|
|
299
302
|
activityEnabled: boolean;
|
|
300
303
|
credentialManagement: CredentialManagementCapability;
|
|
301
304
|
}
|
|
302
305
|
|
|
306
|
+
export interface UiToolkit {
|
|
307
|
+
name: string;
|
|
308
|
+
connectors: string[];
|
|
309
|
+
includeTools: string[];
|
|
310
|
+
excludeTools: string[];
|
|
311
|
+
/** Tools currently loaded through healthy connectors and visible in this view. */
|
|
312
|
+
toolCount: number;
|
|
313
|
+
}
|
|
314
|
+
|
|
303
315
|
export type CredentialManagementCapability =
|
|
304
316
|
| "available"
|
|
305
317
|
| "requires_clerk"
|
|
@@ -391,10 +403,11 @@ export async function buildUiData(
|
|
|
391
403
|
credentialManagement: CredentialManagementCapability = credentialVault
|
|
392
404
|
? "available"
|
|
393
405
|
: "requires_clerk",
|
|
406
|
+
toolkits?: ReadonlyMap<string, Toolkit>,
|
|
394
407
|
): Promise<UiData> {
|
|
395
408
|
const requestScope = {};
|
|
396
409
|
const connectorSet = registry.listConnectors();
|
|
397
|
-
const
|
|
410
|
+
const settled = await Promise.allSettled(
|
|
398
411
|
connectorSet.map(async (c): Promise<UiConnector> => {
|
|
399
412
|
const status = await registry.statusFor(c.id, baseUrl, requestScope);
|
|
400
413
|
const credentialCheck = await registry.credentialHealthFor(c.id);
|
|
@@ -530,19 +543,41 @@ export async function buildUiData(
|
|
|
530
543
|
...(credential ? { credential } : {}),
|
|
531
544
|
};
|
|
532
545
|
}),
|
|
533
|
-
)
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
),
|
|
546
|
+
);
|
|
547
|
+
await Promise.all(
|
|
548
|
+
connectorSet.map((connector) =>
|
|
549
|
+
closeConnectorScope(
|
|
550
|
+
connector,
|
|
551
|
+
registry.contextFor(connector.id, baseUrl, requestScope),
|
|
540
552
|
),
|
|
541
|
-
)
|
|
553
|
+
),
|
|
554
|
+
);
|
|
555
|
+
const connectors = settled.map((result) => {
|
|
556
|
+
if (result.status === "rejected") throw result.reason;
|
|
557
|
+
return result.value;
|
|
542
558
|
});
|
|
559
|
+
const toolkitData: UiToolkit[] = [...(toolkits?.values() ?? [])].map(
|
|
560
|
+
(toolkit) => ({
|
|
561
|
+
name: toolkit.name,
|
|
562
|
+
connectors: [...toolkit.connectors],
|
|
563
|
+
includeTools: [...toolkit.includeTools],
|
|
564
|
+
excludeTools: [...toolkit.excludeTools],
|
|
565
|
+
toolCount: connectors.reduce(
|
|
566
|
+
(count, connector) =>
|
|
567
|
+
count +
|
|
568
|
+
(toolkit.hasConnector(connector.id)
|
|
569
|
+
? connector.tools.filter((tool) =>
|
|
570
|
+
toolkit.hasTool(connector.id, tool.name),
|
|
571
|
+
).length
|
|
572
|
+
: 0),
|
|
573
|
+
0,
|
|
574
|
+
),
|
|
575
|
+
}),
|
|
576
|
+
);
|
|
543
577
|
return {
|
|
544
578
|
serverInfo,
|
|
545
579
|
connectors,
|
|
580
|
+
toolkits: toolkitData,
|
|
546
581
|
activityEnabled,
|
|
547
582
|
credentialManagement,
|
|
548
583
|
};
|
|
@@ -876,6 +911,56 @@ ${clerkScript}
|
|
|
876
911
|
.connector-description { margin-top: .25rem; max-width: 40rem; }
|
|
877
912
|
.connector-message,
|
|
878
913
|
.connector-auth { margin-top: .75rem; }
|
|
914
|
+
.connector-toolkits {
|
|
915
|
+
align-items: baseline;
|
|
916
|
+
display: flex;
|
|
917
|
+
flex-wrap: wrap;
|
|
918
|
+
gap: .25rem .5rem;
|
|
919
|
+
margin-top: .5rem;
|
|
920
|
+
}
|
|
921
|
+
.scope-label {
|
|
922
|
+
border: 1px solid var(--rule);
|
|
923
|
+
display: inline-block;
|
|
924
|
+
font-family: var(--mono);
|
|
925
|
+
font-size: .72rem;
|
|
926
|
+
padding: .05rem .35rem;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
.toolkit-copy { margin-bottom: 1rem; max-width: 42rem; }
|
|
930
|
+
.toolkit-ledger { border-bottom: 1px solid var(--rule); }
|
|
931
|
+
.toolkit-card {
|
|
932
|
+
border-top: 1px solid var(--rule);
|
|
933
|
+
padding: .9rem 0 1rem;
|
|
934
|
+
}
|
|
935
|
+
.toolkit-head {
|
|
936
|
+
display: grid;
|
|
937
|
+
gap: var(--gap);
|
|
938
|
+
grid-template-columns: minmax(0, 2fr) minmax(10rem, 1fr);
|
|
939
|
+
}
|
|
940
|
+
.toolkit-name {
|
|
941
|
+
align-items: baseline;
|
|
942
|
+
display: flex;
|
|
943
|
+
flex-wrap: wrap;
|
|
944
|
+
gap: .5rem;
|
|
945
|
+
}
|
|
946
|
+
.toolkit-name h3 { overflow-wrap: anywhere; }
|
|
947
|
+
.toolkit-state { text-align: right; }
|
|
948
|
+
.toolkit-connectors {
|
|
949
|
+
display: flex;
|
|
950
|
+
flex-wrap: wrap;
|
|
951
|
+
gap: .5rem;
|
|
952
|
+
margin-top: .75rem;
|
|
953
|
+
}
|
|
954
|
+
.toolkit-connector {
|
|
955
|
+
border-left: 1px solid var(--ink);
|
|
956
|
+
display: inline-flex;
|
|
957
|
+
flex-wrap: wrap;
|
|
958
|
+
gap: .4rem;
|
|
959
|
+
padding-left: .5rem;
|
|
960
|
+
}
|
|
961
|
+
.toolkit-rules { margin-top: .75rem; }
|
|
962
|
+
.toolkit-rules > * + * { margin-top: .25rem; }
|
|
963
|
+
.toolkit-endpoint { margin-top: .75rem; }
|
|
879
964
|
|
|
880
965
|
.credential-ledger { border-bottom: 1px solid var(--rule); }
|
|
881
966
|
.credential-card { border-top: 1px solid var(--rule); padding-bottom: .75rem; padding-top: .75rem; }
|
|
@@ -991,9 +1076,11 @@ ${clerkScript}
|
|
|
991
1076
|
.section,
|
|
992
1077
|
.section + .section { margin-top: 2.5rem; }
|
|
993
1078
|
.connector-head,
|
|
1079
|
+
.toolkit-head,
|
|
994
1080
|
.tool,
|
|
995
1081
|
.activity-item { grid-template-columns: 1fr; }
|
|
996
|
-
.connector-state
|
|
1082
|
+
.connector-state,
|
|
1083
|
+
.toolkit-state { text-align: left; }
|
|
997
1084
|
.credential-field { align-items: start; grid-template-columns: 1fr; gap: .25rem; }
|
|
998
1085
|
input { min-height: 2.75rem; }
|
|
999
1086
|
}
|
|
@@ -1068,6 +1155,16 @@ ${clerkScript}
|
|
|
1068
1155
|
<div id="list" class="connector-tools" aria-busy="false"></div>
|
|
1069
1156
|
</div>
|
|
1070
1157
|
</section>
|
|
1158
|
+
<section class="section pgrid" aria-labelledby="toolkitLedgerHeading">
|
|
1159
|
+
<h2 class="pcap" id="toolkitLedgerHeading">Toolkits</h2>
|
|
1160
|
+
<div class="pbody">
|
|
1161
|
+
<p class="toolkit-copy meta">
|
|
1162
|
+
Read-only views from deployment config. Change the config and redeploy
|
|
1163
|
+
to update them.
|
|
1164
|
+
</p>
|
|
1165
|
+
<div id="toolkitList" class="toolkit-ledger"></div>
|
|
1166
|
+
</div>
|
|
1167
|
+
</section>
|
|
1071
1168
|
</section>
|
|
1072
1169
|
|
|
1073
1170
|
<section id="credentialsView"${page === "credentials" ? "" : ' class="hidden"'}>
|
|
@@ -1129,6 +1226,7 @@ let ACTIVITY_LOADED = false;
|
|
|
1129
1226
|
let CURRENT_PAGE = INITIAL_PAGE;
|
|
1130
1227
|
let SESSION_GENERATION = 0;
|
|
1131
1228
|
let ACTIVITY_GENERATION = 0;
|
|
1229
|
+
let CLERK_SESSION_ID = null;
|
|
1132
1230
|
$("mcpUrl").textContent = MCP_URL;
|
|
1133
1231
|
|
|
1134
1232
|
function esc(s) {
|
|
@@ -1184,6 +1282,7 @@ function clearIdentityState() {
|
|
|
1184
1282
|
DATA = null;
|
|
1185
1283
|
clearActivityState();
|
|
1186
1284
|
$("list").innerHTML = "";
|
|
1285
|
+
$("toolkitList").innerHTML = "";
|
|
1187
1286
|
$("filter").value = "";
|
|
1188
1287
|
$("credentialList").innerHTML = "";
|
|
1189
1288
|
$("credentialList").setAttribute("aria-busy", "false");
|
|
@@ -1267,7 +1366,10 @@ function activatePage(page, options) {
|
|
|
1267
1366
|
loadActivity(true);
|
|
1268
1367
|
}
|
|
1269
1368
|
}
|
|
1270
|
-
if (next !== "credentials")
|
|
1369
|
+
if (next !== "credentials") {
|
|
1370
|
+
$("credentialList").innerHTML = "";
|
|
1371
|
+
setNotice("");
|
|
1372
|
+
}
|
|
1271
1373
|
// Focus what is actually on screen. While gated the page views are hidden, so
|
|
1272
1374
|
// focusing their heading is a silent no-op that drops focus to <body> and
|
|
1273
1375
|
// restarts the next Tab from the top of the document — the gate's own h1 is
|
|
@@ -1452,6 +1554,71 @@ async function loadActivity(reset) {
|
|
|
1452
1554
|
}
|
|
1453
1555
|
}
|
|
1454
1556
|
|
|
1557
|
+
function toolkitMcpUrl(name) {
|
|
1558
|
+
const url = new URL(MCP_URL, window.location.href);
|
|
1559
|
+
url.searchParams.set("toolkit", name);
|
|
1560
|
+
return url.toString();
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
function renderToolkits() {
|
|
1564
|
+
const list = $("toolkitList");
|
|
1565
|
+
const toolkits = DATA.toolkits || [];
|
|
1566
|
+
list.innerHTML = "";
|
|
1567
|
+
if (!toolkits.length) {
|
|
1568
|
+
list.innerHTML =
|
|
1569
|
+
'<p class="empty">No toolkits are configured. Unscoped clients see the full connector registry.</p>';
|
|
1570
|
+
return;
|
|
1571
|
+
}
|
|
1572
|
+
const connectors = new Map(
|
|
1573
|
+
DATA.connectors.map((connector) => [connector.id, connector]),
|
|
1574
|
+
);
|
|
1575
|
+
for (const toolkit of toolkits) {
|
|
1576
|
+
const el = document.createElement("article");
|
|
1577
|
+
el.className = "toolkit-card";
|
|
1578
|
+
const connectorCount = toolkit.connectors.length;
|
|
1579
|
+
const toolCount = toolkit.toolCount || 0;
|
|
1580
|
+
let body =
|
|
1581
|
+
'<div class="toolkit-head"><div><div class="toolkit-name">' +
|
|
1582
|
+
'<h3 class="mono">' + esc(toolkit.name) + "</h3>" +
|
|
1583
|
+
'<span class="cap">configured view</span></div>';
|
|
1584
|
+
body += '</div><div class="toolkit-state cap">' +
|
|
1585
|
+
connectorCount + (connectorCount === 1 ? " connector" : " connectors") +
|
|
1586
|
+
" · " + toolCount + (toolCount === 1 ? " loaded tool" : " loaded tools") +
|
|
1587
|
+
"</div></div>";
|
|
1588
|
+
body += '<ul class="toolkit-connectors" aria-label="Included connectors">';
|
|
1589
|
+
for (const id of toolkit.connectors) {
|
|
1590
|
+
const connector = connectors.get(id);
|
|
1591
|
+
body += '<li class="toolkit-connector"><span>' +
|
|
1592
|
+
esc(connector?.title || id) + '</span><code class="mono">' +
|
|
1593
|
+
esc(id) + "</code></li>";
|
|
1594
|
+
}
|
|
1595
|
+
body += "</ul>";
|
|
1596
|
+
body += '<div class="toolkit-rules meta">';
|
|
1597
|
+
if (toolkit.includeTools.length) {
|
|
1598
|
+
body += '<p>Per-connector allowlist: <span class="mono">' +
|
|
1599
|
+
toolkit.includeTools.map(esc).join('</span>, <span class="mono">') +
|
|
1600
|
+
"</span>. Connectors without an allowlist keep all tools.</p>";
|
|
1601
|
+
}
|
|
1602
|
+
if (toolkit.excludeTools.length) {
|
|
1603
|
+
body += '<p>Hidden: <span class="mono">' +
|
|
1604
|
+
toolkit.excludeTools.map(esc).join('</span>, <span class="mono">') +
|
|
1605
|
+
"</span></p>";
|
|
1606
|
+
}
|
|
1607
|
+
if (!toolkit.includeTools.length && !toolkit.excludeTools.length) {
|
|
1608
|
+
body += "<p>All tools on the included connectors are visible.</p>";
|
|
1609
|
+
}
|
|
1610
|
+
body += "</div>";
|
|
1611
|
+
const endpoint = toolkitMcpUrl(toolkit.name);
|
|
1612
|
+
body += '<div class="endpoint toolkit-endpoint"><div class="endpoint-row">' +
|
|
1613
|
+
'<code class="mono">' + esc(endpoint) + "</code>" +
|
|
1614
|
+
'<button class="linklike" type="button" data-toolkit-copy="' +
|
|
1615
|
+
esc(toolkit.name) + '" aria-label="Copy endpoint for ' +
|
|
1616
|
+
esc(toolkit.name) + '">Copy URL</button></div></div>';
|
|
1617
|
+
el.innerHTML = body;
|
|
1618
|
+
list.appendChild(el);
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1455
1622
|
function renderConnections() {
|
|
1456
1623
|
const q = $("filter").value.trim().toLowerCase();
|
|
1457
1624
|
const list = $("list");
|
|
@@ -1472,6 +1639,15 @@ function renderConnections() {
|
|
|
1472
1639
|
if (c.description) {
|
|
1473
1640
|
head += '<p class="connector-description meta">' + esc(c.description) + "</p>";
|
|
1474
1641
|
}
|
|
1642
|
+
const memberships = (DATA.toolkits || [])
|
|
1643
|
+
.filter((toolkit) => toolkit.connectors.includes(c.id))
|
|
1644
|
+
.map((toolkit) => toolkit.name);
|
|
1645
|
+
if (memberships.length) {
|
|
1646
|
+
head += '<div class="connector-toolkits meta"><span>Toolkits</span>' +
|
|
1647
|
+
memberships.map((name) =>
|
|
1648
|
+
'<span class="scope-label">' + esc(name) + "</span>"
|
|
1649
|
+
).join("") + "</div>";
|
|
1650
|
+
}
|
|
1475
1651
|
head += '</div><div class="connector-state cap">' + esc(status) + " · " +
|
|
1476
1652
|
c.toolCount + (c.toolCount === 1 ? " tool" : " tools") +
|
|
1477
1653
|
'<br><span class="mono">' + esc(c.id) + "</span></div></div>";
|
|
@@ -1525,6 +1701,7 @@ function renderConnections() {
|
|
|
1525
1701
|
: "No connectors are declared in this deployment.") +
|
|
1526
1702
|
"</p>";
|
|
1527
1703
|
}
|
|
1704
|
+
renderToolkits();
|
|
1528
1705
|
}
|
|
1529
1706
|
|
|
1530
1707
|
function renderCredentials() {
|
|
@@ -1771,6 +1948,19 @@ $("copyMcpUrl").onclick = async () => {
|
|
|
1771
1948
|
}
|
|
1772
1949
|
window.setTimeout(() => { button.textContent = "Copy URL"; }, 1600);
|
|
1773
1950
|
};
|
|
1951
|
+
$("toolkitList").onclick = async (event) => {
|
|
1952
|
+
const button = event.target.closest("[data-toolkit-copy]");
|
|
1953
|
+
if (!button) return;
|
|
1954
|
+
try {
|
|
1955
|
+
await navigator.clipboard.writeText(
|
|
1956
|
+
toolkitMcpUrl(button.dataset.toolkitCopy),
|
|
1957
|
+
);
|
|
1958
|
+
button.textContent = "Copied";
|
|
1959
|
+
} catch (e) {
|
|
1960
|
+
button.textContent = "Copy failed";
|
|
1961
|
+
}
|
|
1962
|
+
window.setTimeout(() => { button.textContent = "Copy URL"; }, 1600);
|
|
1963
|
+
};
|
|
1774
1964
|
$("signin").onclick = () => Clerk.redirectToSignIn({
|
|
1775
1965
|
signInFallbackRedirectUrl: window.location.href,
|
|
1776
1966
|
signUpFallbackRedirectUrl: window.location.href,
|
|
@@ -1820,6 +2010,17 @@ async function init() {
|
|
|
1820
2010
|
signUpFallbackRedirectUrl: window.location.href,
|
|
1821
2011
|
afterSignOutUrl: window.location.href,
|
|
1822
2012
|
});
|
|
2013
|
+
CLERK_SESSION_ID = Clerk.session?.id ?? null;
|
|
2014
|
+
Clerk.addListener((resources) => {
|
|
2015
|
+
const nextSessionId = resources.session?.id ?? null;
|
|
2016
|
+
if (nextSessionId === CLERK_SESSION_ID) return;
|
|
2017
|
+
CLERK_SESSION_ID = nextSessionId;
|
|
2018
|
+
// Clerk has already updated its public session before notifying
|
|
2019
|
+
// listeners. Clear synchronously so stale identity-scoped data cannot
|
|
2020
|
+
// be repainted while the replacement identity is being fetched.
|
|
2021
|
+
showGate("");
|
|
2022
|
+
void load();
|
|
2023
|
+
});
|
|
1823
2024
|
} catch (e) {
|
|
1824
2025
|
return showGate("Clerk could not initialize: " + e.message);
|
|
1825
2026
|
}
|
package/src/version.ts
CHANGED