@hasna/connectors 0.2.5 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/bin/index.js +353 -3
- package/bin/mcp.js +1 -1
- package/dist/lib/test-endpoints.d.ts +12 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,6 +34,8 @@ npx @hasna/connectors
|
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
36
|
connectors install figma stripe github # Install connectors
|
|
37
|
+
connectors install --preset ai # Install a preset bundle
|
|
38
|
+
connectors install --category "AI & ML" # Install entire category
|
|
37
39
|
connectors install figma --overwrite # Overwrite existing
|
|
38
40
|
connectors remove figma # Remove a connector
|
|
39
41
|
```
|
|
@@ -49,6 +51,10 @@ connectors info stripe # Connector details
|
|
|
49
51
|
connectors docs gmail # Auth, env vars, CLI docs
|
|
50
52
|
connectors status # Auth status of installed connectors
|
|
51
53
|
connectors doctor # Health check and troubleshooting
|
|
54
|
+
connectors test # Verify API keys with real requests
|
|
55
|
+
connectors whoami # Show setup summary
|
|
56
|
+
connectors env # Generate .env.example
|
|
57
|
+
connectors presets # List preset bundles
|
|
52
58
|
```
|
|
53
59
|
|
|
54
60
|
### Dashboard
|
package/bin/index.js
CHANGED
|
@@ -6499,12 +6499,91 @@ init_auth();
|
|
|
6499
6499
|
import { readdirSync as readdirSync4, existsSync as existsSync5, statSync as statSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4 } from "fs";
|
|
6500
6500
|
import { homedir as homedir3 } from "os";
|
|
6501
6501
|
import { join as join5, relative } from "path";
|
|
6502
|
+
|
|
6503
|
+
// src/lib/test-endpoints.ts
|
|
6504
|
+
var TEST_ENDPOINTS = {
|
|
6505
|
+
anthropic: {
|
|
6506
|
+
url: "https://api.anthropic.com/v1/models",
|
|
6507
|
+
headers: (key) => ({ "x-api-key": key, "anthropic-version": "2023-06-01" })
|
|
6508
|
+
},
|
|
6509
|
+
openai: {
|
|
6510
|
+
url: "https://api.openai.com/v1/models",
|
|
6511
|
+
headers: (key) => ({ Authorization: `Bearer ${key}` })
|
|
6512
|
+
},
|
|
6513
|
+
xai: {
|
|
6514
|
+
url: "https://api.x.ai/v1/models",
|
|
6515
|
+
headers: (key) => ({ Authorization: `Bearer ${key}` })
|
|
6516
|
+
},
|
|
6517
|
+
mistral: {
|
|
6518
|
+
url: "https://api.mistral.ai/v1/models",
|
|
6519
|
+
headers: (key) => ({ Authorization: `Bearer ${key}` })
|
|
6520
|
+
},
|
|
6521
|
+
github: {
|
|
6522
|
+
url: "https://api.github.com/user",
|
|
6523
|
+
headers: (key) => ({ Authorization: `Bearer ${key}`, "User-Agent": "connectors-cli" })
|
|
6524
|
+
},
|
|
6525
|
+
stripe: {
|
|
6526
|
+
url: "https://api.stripe.com/v1/balance",
|
|
6527
|
+
headers: (key) => ({ Authorization: `Bearer ${key}` })
|
|
6528
|
+
},
|
|
6529
|
+
figma: {
|
|
6530
|
+
url: "https://api.figma.com/v1/me",
|
|
6531
|
+
headers: (key) => ({ "X-Figma-Token": key })
|
|
6532
|
+
},
|
|
6533
|
+
discord: {
|
|
6534
|
+
url: "https://discord.com/api/v10/users/@me",
|
|
6535
|
+
headers: (key) => ({ Authorization: `Bot ${key}` })
|
|
6536
|
+
},
|
|
6537
|
+
resend: {
|
|
6538
|
+
url: "https://api.resend.com/domains",
|
|
6539
|
+
headers: (key) => ({ Authorization: `Bearer ${key}` })
|
|
6540
|
+
},
|
|
6541
|
+
notion: {
|
|
6542
|
+
url: "https://api.notion.com/v1/users/me",
|
|
6543
|
+
headers: (key) => ({ Authorization: `Bearer ${key}`, "Notion-Version": "2022-06-28" })
|
|
6544
|
+
},
|
|
6545
|
+
exa: {
|
|
6546
|
+
url: "https://api.exa.ai/search",
|
|
6547
|
+
method: "POST",
|
|
6548
|
+
headers: (key) => ({ "x-api-key": key, "Content-Type": "application/json" })
|
|
6549
|
+
},
|
|
6550
|
+
sentry: {
|
|
6551
|
+
url: "https://sentry.io/api/0/",
|
|
6552
|
+
headers: (key) => ({ Authorization: `Bearer ${key}` })
|
|
6553
|
+
},
|
|
6554
|
+
huggingface: {
|
|
6555
|
+
url: "https://huggingface.co/api/whoami-v2",
|
|
6556
|
+
headers: (key) => ({ Authorization: `Bearer ${key}` })
|
|
6557
|
+
},
|
|
6558
|
+
elevenlabs: {
|
|
6559
|
+
url: "https://api.elevenlabs.io/v1/user",
|
|
6560
|
+
headers: (key) => ({ "xi-api-key": key })
|
|
6561
|
+
},
|
|
6562
|
+
cloudflare: {
|
|
6563
|
+
url: "https://api.cloudflare.com/client/v4/user/tokens/verify",
|
|
6564
|
+
headers: (key) => ({ Authorization: `Bearer ${key}` })
|
|
6565
|
+
},
|
|
6566
|
+
mixpanel: {
|
|
6567
|
+
url: "https://mixpanel.com/api/app/me",
|
|
6568
|
+
headers: (key) => ({ Authorization: `Bearer ${key}` })
|
|
6569
|
+
}
|
|
6570
|
+
};
|
|
6571
|
+
|
|
6572
|
+
// src/cli/index.tsx
|
|
6502
6573
|
import { createInterface } from "readline";
|
|
6503
6574
|
import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
|
|
6504
6575
|
loadConnectorVersions();
|
|
6505
6576
|
var isTTY = process.stdout.isTTY ?? false;
|
|
6577
|
+
var PRESETS = {
|
|
6578
|
+
fullstack: { description: "Full-stack web app essentials", connectors: ["stripe", "github", "resend", "anthropic", "figma"] },
|
|
6579
|
+
ai: { description: "AI and ML models", connectors: ["anthropic", "openai", "xai", "mistral", "googlegemini", "elevenlabs"] },
|
|
6580
|
+
google: { description: "Google Workspace suite", connectors: ["gmail", "googledrive", "googledocs", "googlesheets", "googlecalendar", "googletasks", "googlecontacts"] },
|
|
6581
|
+
social: { description: "Social media platforms", connectors: ["x", "reddit", "youtube", "tiktok", "meta", "discord", "substack"] },
|
|
6582
|
+
devtools: { description: "Developer tooling", connectors: ["github", "docker", "sentry", "cloudflare", "e2b", "firecrawl"] },
|
|
6583
|
+
commerce: { description: "Commerce and finance", connectors: ["stripe", "shopify", "revolut", "mercury", "pandadoc"] }
|
|
6584
|
+
};
|
|
6506
6585
|
var program2 = new Command;
|
|
6507
|
-
program2.name("connectors").description("Install API connectors for your project").version("0.2.
|
|
6586
|
+
program2.name("connectors").description("Install API connectors for your project").version("0.2.6");
|
|
6508
6587
|
program2.command("interactive", { isDefault: true }).alias("i").description("Interactive connector browser").action(() => {
|
|
6509
6588
|
if (!isTTY) {
|
|
6510
6589
|
console.log(`Non-interactive environment detected. Use a subcommand:
|
|
@@ -6534,7 +6613,7 @@ function listFilesRecursive(dir, base = dir) {
|
|
|
6534
6613
|
}
|
|
6535
6614
|
return files;
|
|
6536
6615
|
}
|
|
6537
|
-
program2.command("install").alias("add").argument("[connectors...]", "Connectors to install").option("-o, --overwrite", "Overwrite existing connectors", false).option("-d, --dry-run", "Preview what would be installed without making changes", false).option("-c, --category <category>", "Install all connectors in a category").option("--json", "Output results as JSON", false).description("Install one or more connectors").action((connectors, options) => {
|
|
6616
|
+
program2.command("install").alias("add").argument("[connectors...]", "Connectors to install").option("-o, --overwrite", "Overwrite existing connectors", false).option("-d, --dry-run", "Preview what would be installed without making changes", false).option("-c, --category <category>", "Install all connectors in a category").option("--preset <preset>", "Install a preset bundle (e.g. ai, fullstack, google)").option("--json", "Output results as JSON", false).description("Install one or more connectors").action((connectors, options) => {
|
|
6538
6617
|
if (options.category) {
|
|
6539
6618
|
const category = CATEGORIES.find((c) => c.toLowerCase() === options.category.toLowerCase());
|
|
6540
6619
|
if (!category) {
|
|
@@ -6550,6 +6629,20 @@ program2.command("install").alias("add").argument("[connectors...]", "Connectors
|
|
|
6550
6629
|
const categoryConnectors = getConnectorsByCategory(category).map((c) => c.name);
|
|
6551
6630
|
connectors.push(...categoryConnectors);
|
|
6552
6631
|
}
|
|
6632
|
+
if (options.preset) {
|
|
6633
|
+
const preset = PRESETS[options.preset.toLowerCase()];
|
|
6634
|
+
if (!preset) {
|
|
6635
|
+
if (options.json) {
|
|
6636
|
+
console.log(JSON.stringify({ error: `Unknown preset: ${options.preset}. Available: ${Object.keys(PRESETS).join(", ")}` }));
|
|
6637
|
+
} else {
|
|
6638
|
+
console.log(chalk2.red(`Unknown preset: ${options.preset}`));
|
|
6639
|
+
console.log(chalk2.dim(`Available: ${Object.keys(PRESETS).join(", ")}`));
|
|
6640
|
+
}
|
|
6641
|
+
process.exit(1);
|
|
6642
|
+
return;
|
|
6643
|
+
}
|
|
6644
|
+
connectors.push(...preset.connectors);
|
|
6645
|
+
}
|
|
6553
6646
|
if (connectors.length === 0) {
|
|
6554
6647
|
if (!isTTY) {
|
|
6555
6648
|
console.error("Error: specify connectors to install. Example: connectors install figma stripe");
|
|
@@ -7653,7 +7746,7 @@ program2.command("import").argument("<file>", "JSON backup file to import (use -
|
|
|
7653
7746
|
}
|
|
7654
7747
|
});
|
|
7655
7748
|
program2.command("upgrade").alias("self-update").option("--check", "Only check for updates, don't install", false).option("--json", "Output as JSON", false).description("Check for updates and upgrade to the latest version").action(async (options) => {
|
|
7656
|
-
const currentVersion = "0.2.
|
|
7749
|
+
const currentVersion = "0.2.6";
|
|
7657
7750
|
try {
|
|
7658
7751
|
const res = await fetch("https://registry.npmjs.org/@hasna/connectors/latest");
|
|
7659
7752
|
if (!res.ok)
|
|
@@ -7792,4 +7885,261 @@ complete -F _connectors connectors`);
|
|
|
7792
7885
|
process.exit(1);
|
|
7793
7886
|
}
|
|
7794
7887
|
});
|
|
7888
|
+
program2.command("env").option("-o, --output <file>", "Write to file instead of stdout").option("--json", "Output as JSON", false).description("Generate .env.example from installed connectors' required env vars").action((options) => {
|
|
7889
|
+
const installed = getInstalledConnectors();
|
|
7890
|
+
if (installed.length === 0) {
|
|
7891
|
+
if (options.json) {
|
|
7892
|
+
console.log(JSON.stringify({ vars: [], connectors: [] }));
|
|
7893
|
+
} else {
|
|
7894
|
+
console.log(chalk2.dim("No connectors installed. Run: connectors install <name>"));
|
|
7895
|
+
}
|
|
7896
|
+
return;
|
|
7897
|
+
}
|
|
7898
|
+
const vars = [];
|
|
7899
|
+
const seen = new Set;
|
|
7900
|
+
for (const name of installed) {
|
|
7901
|
+
const docs = getConnectorDocs(name);
|
|
7902
|
+
if (!docs?.envVars)
|
|
7903
|
+
continue;
|
|
7904
|
+
for (const v of docs.envVars) {
|
|
7905
|
+
if (!seen.has(v.variable)) {
|
|
7906
|
+
seen.add(v.variable);
|
|
7907
|
+
vars.push({ variable: v.variable, description: v.description, connector: name });
|
|
7908
|
+
}
|
|
7909
|
+
}
|
|
7910
|
+
}
|
|
7911
|
+
if (options.json) {
|
|
7912
|
+
console.log(JSON.stringify({ vars, connectors: installed }, null, 2));
|
|
7913
|
+
return;
|
|
7914
|
+
}
|
|
7915
|
+
const lines = [
|
|
7916
|
+
"# Environment Variables",
|
|
7917
|
+
`# Generated by connectors env (${installed.length} installed connectors)`,
|
|
7918
|
+
"#"
|
|
7919
|
+
];
|
|
7920
|
+
let lastConnector = "";
|
|
7921
|
+
for (const v of vars) {
|
|
7922
|
+
if (v.connector !== lastConnector) {
|
|
7923
|
+
lines.push("");
|
|
7924
|
+
lines.push(`# ${v.connector}`);
|
|
7925
|
+
lastConnector = v.connector;
|
|
7926
|
+
}
|
|
7927
|
+
if (v.description)
|
|
7928
|
+
lines.push(`# ${v.description}`);
|
|
7929
|
+
lines.push(`${v.variable}=`);
|
|
7930
|
+
}
|
|
7931
|
+
const output = lines.join(`
|
|
7932
|
+
`) + `
|
|
7933
|
+
`;
|
|
7934
|
+
if (options.output) {
|
|
7935
|
+
writeFileSync4(options.output, output);
|
|
7936
|
+
console.log(chalk2.green(`\u2713 Written to ${options.output} (${vars.length} variables)`));
|
|
7937
|
+
} else {
|
|
7938
|
+
console.log(output);
|
|
7939
|
+
}
|
|
7940
|
+
});
|
|
7941
|
+
program2.command("presets").option("--json", "Output as JSON", false).description("List available connector preset bundles").action((options) => {
|
|
7942
|
+
if (options.json) {
|
|
7943
|
+
console.log(JSON.stringify(Object.entries(PRESETS).map(([name, p]) => ({
|
|
7944
|
+
name,
|
|
7945
|
+
description: p.description,
|
|
7946
|
+
connectors: p.connectors,
|
|
7947
|
+
count: p.connectors.length
|
|
7948
|
+
})), null, 2));
|
|
7949
|
+
return;
|
|
7950
|
+
}
|
|
7951
|
+
console.log(chalk2.bold(`
|
|
7952
|
+
Available presets:
|
|
7953
|
+
`));
|
|
7954
|
+
for (const [name, preset] of Object.entries(PRESETS)) {
|
|
7955
|
+
console.log(` ${chalk2.cyan(name.padEnd(12))} ${preset.description}`);
|
|
7956
|
+
console.log(chalk2.dim(` ${"".padEnd(12)} ${preset.connectors.join(", ")}`));
|
|
7957
|
+
console.log();
|
|
7958
|
+
}
|
|
7959
|
+
console.log(chalk2.dim(` Install with: connectors install --preset <name>
|
|
7960
|
+
`));
|
|
7961
|
+
});
|
|
7962
|
+
program2.command("whoami").option("--json", "Output as JSON", false).description("Show current setup: config dir, installed connectors, auth status").action((options) => {
|
|
7963
|
+
const configDir = join5(homedir3(), ".connectors");
|
|
7964
|
+
const installed = getInstalledConnectors();
|
|
7965
|
+
const version = "0.2.6";
|
|
7966
|
+
let configured = 0;
|
|
7967
|
+
let unconfigured = 0;
|
|
7968
|
+
const connectorDetails = [];
|
|
7969
|
+
for (const name of installed) {
|
|
7970
|
+
const auth = getAuthStatus(name);
|
|
7971
|
+
if (auth.configured)
|
|
7972
|
+
configured++;
|
|
7973
|
+
else
|
|
7974
|
+
unconfigured++;
|
|
7975
|
+
const connectorConfigDir = join5(configDir, name.startsWith("connect-") ? name : `connect-${name}`);
|
|
7976
|
+
const currentProfileFile = join5(connectorConfigDir, "current_profile");
|
|
7977
|
+
let profile = "default";
|
|
7978
|
+
if (existsSync5(currentProfileFile)) {
|
|
7979
|
+
try {
|
|
7980
|
+
profile = readFileSync5(currentProfileFile, "utf-8").trim() || "default";
|
|
7981
|
+
} catch {}
|
|
7982
|
+
}
|
|
7983
|
+
connectorDetails.push({ name, configured: auth.configured, authType: auth.type, profile });
|
|
7984
|
+
}
|
|
7985
|
+
if (options.json) {
|
|
7986
|
+
console.log(JSON.stringify({
|
|
7987
|
+
version,
|
|
7988
|
+
configDir,
|
|
7989
|
+
configDirExists: existsSync5(configDir),
|
|
7990
|
+
installed: installed.length,
|
|
7991
|
+
configured,
|
|
7992
|
+
unconfigured,
|
|
7993
|
+
connectors: connectorDetails
|
|
7994
|
+
}, null, 2));
|
|
7995
|
+
return;
|
|
7996
|
+
}
|
|
7997
|
+
console.log(chalk2.bold(`
|
|
7998
|
+
Connectors Setup
|
|
7999
|
+
`));
|
|
8000
|
+
console.log(` Version: ${chalk2.cyan(version)}`);
|
|
8001
|
+
console.log(` Config: ${configDir}${existsSync5(configDir) ? "" : chalk2.dim(" (not created yet)")}`);
|
|
8002
|
+
console.log(` Installed: ${installed.length} connector${installed.length !== 1 ? "s" : ""}`);
|
|
8003
|
+
console.log(` Configured: ${chalk2.green(String(configured))} ready, ${unconfigured > 0 ? chalk2.red(String(unconfigured)) : chalk2.dim("0")} need auth`);
|
|
8004
|
+
if (connectorDetails.length > 0) {
|
|
8005
|
+
console.log(chalk2.bold(`
|
|
8006
|
+
Connectors:
|
|
8007
|
+
`));
|
|
8008
|
+
const nameWidth = Math.max(10, ...connectorDetails.map((c) => c.name.length)) + 2;
|
|
8009
|
+
for (const c of connectorDetails) {
|
|
8010
|
+
const status = c.configured ? chalk2.green("\u2713") : chalk2.red("\u2717");
|
|
8011
|
+
const profileLabel = c.profile !== "default" ? chalk2.dim(` [${c.profile}]`) : "";
|
|
8012
|
+
console.log(` ${status} ${chalk2.cyan(c.name.padEnd(nameWidth))}${c.authType.padEnd(8)}${profileLabel}`);
|
|
8013
|
+
}
|
|
8014
|
+
}
|
|
8015
|
+
console.log();
|
|
8016
|
+
});
|
|
8017
|
+
program2.command("test").argument("[connector]", "Connector to test (default: all installed)").option("--json", "Output as JSON", false).option("--timeout <ms>", "Request timeout in milliseconds", "10000").description("Verify API credentials by making a real request to the connector's API").action(async (connector, options) => {
|
|
8018
|
+
const timeout = parseInt(options.timeout, 10) || 1e4;
|
|
8019
|
+
const installed = getInstalledConnectors();
|
|
8020
|
+
let toTest;
|
|
8021
|
+
if (connector) {
|
|
8022
|
+
if (!getConnector(connector)) {
|
|
8023
|
+
if (options.json) {
|
|
8024
|
+
console.log(JSON.stringify({ error: `Connector '${connector}' not found` }));
|
|
8025
|
+
} else {
|
|
8026
|
+
console.log(chalk2.red(`Connector '${connector}' not found`));
|
|
8027
|
+
}
|
|
8028
|
+
process.exit(1);
|
|
8029
|
+
return;
|
|
8030
|
+
}
|
|
8031
|
+
toTest = [connector];
|
|
8032
|
+
} else {
|
|
8033
|
+
if (installed.length === 0) {
|
|
8034
|
+
if (options.json) {
|
|
8035
|
+
console.log(JSON.stringify({ results: [], tested: 0 }));
|
|
8036
|
+
} else {
|
|
8037
|
+
console.log(chalk2.dim("No connectors installed. Run: connectors install <name>"));
|
|
8038
|
+
}
|
|
8039
|
+
return;
|
|
8040
|
+
}
|
|
8041
|
+
toTest = installed;
|
|
8042
|
+
}
|
|
8043
|
+
if (!options.json)
|
|
8044
|
+
console.log(chalk2.bold(`
|
|
8045
|
+
Testing connector credentials...
|
|
8046
|
+
`));
|
|
8047
|
+
const results = [];
|
|
8048
|
+
for (const name of toTest) {
|
|
8049
|
+
const auth = getAuthStatus(name);
|
|
8050
|
+
const endpoint = TEST_ENDPOINTS[name];
|
|
8051
|
+
if (!auth.configured) {
|
|
8052
|
+
results.push({ name, status: "no-key", message: "No credentials configured" });
|
|
8053
|
+
if (!options.json)
|
|
8054
|
+
console.log(` ${chalk2.dim("\u25CB")} ${chalk2.dim(name)} \u2014 ${chalk2.dim("no credentials configured")}`);
|
|
8055
|
+
continue;
|
|
8056
|
+
}
|
|
8057
|
+
if (!endpoint) {
|
|
8058
|
+
results.push({ name, status: "skip", message: "No test endpoint defined" });
|
|
8059
|
+
if (!options.json)
|
|
8060
|
+
console.log(` ${chalk2.dim("\u25CB")} ${chalk2.dim(name)} \u2014 ${chalk2.dim("no test endpoint (key exists)")}`);
|
|
8061
|
+
continue;
|
|
8062
|
+
}
|
|
8063
|
+
const docs = getConnectorDocs(name);
|
|
8064
|
+
const envVars = docs?.envVars || [];
|
|
8065
|
+
let apiKey;
|
|
8066
|
+
for (const v of envVars) {
|
|
8067
|
+
if (process.env[v.variable]) {
|
|
8068
|
+
apiKey = process.env[v.variable];
|
|
8069
|
+
break;
|
|
8070
|
+
}
|
|
8071
|
+
}
|
|
8072
|
+
if (!apiKey) {
|
|
8073
|
+
const connectorConfigDir = join5(homedir3(), ".connectors", name.startsWith("connect-") ? name : `connect-${name}`);
|
|
8074
|
+
const profileFile = join5(connectorConfigDir, "profiles", "default.json");
|
|
8075
|
+
if (existsSync5(profileFile)) {
|
|
8076
|
+
try {
|
|
8077
|
+
const config = JSON.parse(readFileSync5(profileFile, "utf-8"));
|
|
8078
|
+
apiKey = Object.values(config).find((v) => typeof v === "string" && v.length > 0);
|
|
8079
|
+
} catch {}
|
|
8080
|
+
}
|
|
8081
|
+
if (!apiKey) {
|
|
8082
|
+
const profileDirConfig = join5(connectorConfigDir, "profiles", "default", "config.json");
|
|
8083
|
+
if (existsSync5(profileDirConfig)) {
|
|
8084
|
+
try {
|
|
8085
|
+
const config = JSON.parse(readFileSync5(profileDirConfig, "utf-8"));
|
|
8086
|
+
apiKey = Object.values(config).find((v) => typeof v === "string" && v.length > 0);
|
|
8087
|
+
} catch {}
|
|
8088
|
+
}
|
|
8089
|
+
}
|
|
8090
|
+
}
|
|
8091
|
+
if (!apiKey) {
|
|
8092
|
+
results.push({ name, status: "no-key", message: "Credentials configured but could not extract key" });
|
|
8093
|
+
if (!options.json)
|
|
8094
|
+
console.log(` ${chalk2.yellow("\u26A0")} ${chalk2.yellow(name)} \u2014 ${chalk2.dim("could not extract key")}`);
|
|
8095
|
+
continue;
|
|
8096
|
+
}
|
|
8097
|
+
const start = Date.now();
|
|
8098
|
+
try {
|
|
8099
|
+
const res = await fetch(endpoint.url, {
|
|
8100
|
+
method: endpoint.method || "GET",
|
|
8101
|
+
headers: endpoint.headers(apiKey),
|
|
8102
|
+
body: endpoint.method === "POST" ? JSON.stringify({ query: "test", num_results: 1 }) : undefined,
|
|
8103
|
+
signal: AbortSignal.timeout(timeout)
|
|
8104
|
+
});
|
|
8105
|
+
const ms = Date.now() - start;
|
|
8106
|
+
const successCodes = endpoint.successCodes || [200];
|
|
8107
|
+
if (successCodes.includes(res.status) || res.status >= 200 && res.status < 300) {
|
|
8108
|
+
results.push({ name, status: "pass", message: `OK (${res.status})`, ms });
|
|
8109
|
+
if (!options.json)
|
|
8110
|
+
console.log(` ${chalk2.green("\u2713")} ${chalk2.green(name)} \u2014 ${chalk2.dim(`${res.status} OK`)} ${chalk2.dim(`(${ms}ms)`)}`);
|
|
8111
|
+
} else {
|
|
8112
|
+
const body = await res.text().catch(() => "");
|
|
8113
|
+
const msg = res.status === 401 ? "Invalid or expired credentials" : `HTTP ${res.status}`;
|
|
8114
|
+
results.push({ name, status: "fail", message: msg, ms });
|
|
8115
|
+
if (!options.json)
|
|
8116
|
+
console.log(` ${chalk2.red("\u2717")} ${chalk2.red(name)} \u2014 ${chalk2.red(msg)} ${chalk2.dim(`(${ms}ms)`)}`);
|
|
8117
|
+
}
|
|
8118
|
+
} catch (e) {
|
|
8119
|
+
const ms = Date.now() - start;
|
|
8120
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
8121
|
+
results.push({ name, status: "fail", message: msg, ms });
|
|
8122
|
+
if (!options.json)
|
|
8123
|
+
console.log(` ${chalk2.red("\u2717")} ${chalk2.red(name)} \u2014 ${chalk2.red(msg)}`);
|
|
8124
|
+
}
|
|
8125
|
+
}
|
|
8126
|
+
if (options.json) {
|
|
8127
|
+
console.log(JSON.stringify({ results, tested: results.length, passed: results.filter((r) => r.status === "pass").length }, null, 2));
|
|
8128
|
+
} else {
|
|
8129
|
+
const passed = results.filter((r) => r.status === "pass").length;
|
|
8130
|
+
const failed = results.filter((r) => r.status === "fail").length;
|
|
8131
|
+
const skipped = results.filter((r) => r.status === "skip" || r.status === "no-key").length;
|
|
8132
|
+
console.log();
|
|
8133
|
+
const parts = [];
|
|
8134
|
+
if (passed > 0)
|
|
8135
|
+
parts.push(chalk2.green(`${passed} passed`));
|
|
8136
|
+
if (failed > 0)
|
|
8137
|
+
parts.push(chalk2.red(`${failed} failed`));
|
|
8138
|
+
if (skipped > 0)
|
|
8139
|
+
parts.push(chalk2.dim(`${skipped} skipped`));
|
|
8140
|
+
console.log(` ${parts.join(", ")}
|
|
8141
|
+
`);
|
|
8142
|
+
}
|
|
8143
|
+
process.exit(results.some((r) => r.status === "fail") ? 1 : 0);
|
|
8144
|
+
});
|
|
7795
8145
|
program2.parse();
|
package/bin/mcp.js
CHANGED
|
@@ -20275,7 +20275,7 @@ function guessKeyField(name) {
|
|
|
20275
20275
|
loadConnectorVersions();
|
|
20276
20276
|
var server = new McpServer({
|
|
20277
20277
|
name: "connectors",
|
|
20278
|
-
version: "0.2.
|
|
20278
|
+
version: "0.2.6"
|
|
20279
20279
|
});
|
|
20280
20280
|
server.registerTool("search_connectors", {
|
|
20281
20281
|
title: "Search Connectors",
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test endpoint definitions for verifying API credentials.
|
|
3
|
+
* Each entry maps a connector name to its health-check endpoint.
|
|
4
|
+
*/
|
|
5
|
+
export interface TestEndpoint {
|
|
6
|
+
url: string;
|
|
7
|
+
method?: string;
|
|
8
|
+
headers: (key: string) => Record<string, string>;
|
|
9
|
+
/** Expected successful status codes */
|
|
10
|
+
successCodes?: number[];
|
|
11
|
+
}
|
|
12
|
+
export declare const TEST_ENDPOINTS: Record<string, TestEndpoint>;
|