@hasna/connectors 0.2.3 → 0.2.5
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 +5 -3
- package/bin/index.js +1363 -48
- package/bin/mcp.js +161 -6
- package/bin/serve.js +379 -9
- package/connectors/connect-anthropic/AGENTS.md +1 -1
- package/connectors/connect-anthropic/CLAUDE.md +1 -1
- package/connectors/connect-anthropic/GEMINI.md +1 -1
- package/connectors/connect-anthropic/README.md +2 -2
- package/connectors/connect-anthropic/src/utils/config.ts +2 -2
- package/connectors/connect-aws/AGENTS.md +2 -2
- package/connectors/connect-aws/CLAUDE.md +2 -2
- package/connectors/connect-aws/GEMINI.md +2 -2
- package/connectors/connect-aws/README.md +2 -2
- package/connectors/connect-aws/src/utils/config.ts +2 -2
- package/connectors/connect-brandsight/AGENTS.md +2 -2
- package/connectors/connect-brandsight/CLAUDE.md +2 -2
- package/connectors/connect-brandsight/GEMINI.md +2 -2
- package/connectors/connect-brandsight/README.md +3 -3
- package/connectors/connect-brandsight/src/utils/config.ts +1 -1
- package/connectors/connect-brandsight/src/utils/contacts.ts +1 -1
- package/connectors/connect-cloudflare/AGENTS.md +1 -1
- package/connectors/connect-cloudflare/CLAUDE.md +1 -1
- package/connectors/connect-cloudflare/GEMINI.md +1 -1
- package/connectors/connect-cloudflare/README.md +2 -2
- package/connectors/connect-cloudflare/src/utils/config.ts +2 -2
- package/connectors/connect-discord/AGENTS.md +2 -2
- package/connectors/connect-discord/CLAUDE.md +2 -2
- package/connectors/connect-discord/GEMINI.md +2 -2
- package/connectors/connect-discord/README.md +2 -2
- package/connectors/connect-discord/src/utils/config.ts +2 -2
- package/connectors/connect-docker/AGENTS.md +2 -2
- package/connectors/connect-docker/CLAUDE.md +2 -2
- package/connectors/connect-docker/GEMINI.md +2 -2
- package/connectors/connect-docker/README.md +2 -2
- package/connectors/connect-docker/src/utils/config.ts +2 -2
- package/connectors/connect-e2b/AGENTS.md +1 -1
- package/connectors/connect-e2b/CLAUDE.md +1 -1
- package/connectors/connect-e2b/GEMINI.md +1 -1
- package/connectors/connect-e2b/README.md +2 -2
- package/connectors/connect-e2b/src/utils/config.ts +2 -2
- package/connectors/connect-elevenlabs/AGENTS.md +1 -1
- package/connectors/connect-elevenlabs/CLAUDE.md +1 -1
- package/connectors/connect-elevenlabs/GEMINI.md +1 -1
- package/connectors/connect-elevenlabs/README.md +2 -2
- package/connectors/connect-elevenlabs/src/utils/config.ts +2 -2
- package/connectors/connect-exa/AGENTS.md +1 -1
- package/connectors/connect-exa/CLAUDE.md +1 -1
- package/connectors/connect-exa/GEMINI.md +1 -1
- package/connectors/connect-exa/README.md +2 -2
- package/connectors/connect-exa/src/utils/config.ts +2 -2
- package/connectors/connect-figma/AGENTS.md +2 -2
- package/connectors/connect-figma/CLAUDE.md +2 -2
- package/connectors/connect-figma/GEMINI.md +2 -2
- package/connectors/connect-figma/README.md +2 -2
- package/connectors/connect-figma/src/utils/config.ts +2 -2
- package/connectors/connect-firecrawl/AGENTS.md +1 -1
- package/connectors/connect-firecrawl/CLAUDE.md +1 -1
- package/connectors/connect-firecrawl/GEMINI.md +1 -1
- package/connectors/connect-firecrawl/README.md +2 -2
- package/connectors/connect-firecrawl/src/utils/config.ts +2 -2
- package/connectors/connect-github/AGENTS.md +2 -2
- package/connectors/connect-github/CLAUDE.md +2 -2
- package/connectors/connect-github/GEMINI.md +2 -2
- package/connectors/connect-github/README.md +2 -2
- package/connectors/connect-github/src/utils/config.ts +2 -2
- package/connectors/connect-gmail/AGENTS.md +2 -2
- package/connectors/connect-gmail/CLAUDE.md +2 -2
- package/connectors/connect-gmail/GEMINI.md +2 -2
- package/connectors/connect-gmail/README.md +2 -2
- package/connectors/connect-gmail/src/utils/config.ts +2 -2
- package/connectors/connect-google/AGENTS.md +1 -1
- package/connectors/connect-google/CLAUDE.md +1 -1
- package/connectors/connect-google/GEMINI.md +1 -1
- package/connectors/connect-google/README.md +2 -2
- package/connectors/connect-google/src/utils/config.ts +2 -2
- package/connectors/connect-googlecalendar/AGENTS.md +2 -2
- package/connectors/connect-googlecalendar/CLAUDE.md +2 -2
- package/connectors/connect-googlecalendar/GEMINI.md +2 -2
- package/connectors/connect-googlecalendar/README.md +2 -2
- package/connectors/connect-googlecalendar/src/utils/config.ts +2 -2
- package/connectors/connect-googlecloud/AGENTS.md +2 -2
- package/connectors/connect-googlecloud/CLAUDE.md +2 -2
- package/connectors/connect-googlecloud/GEMINI.md +2 -2
- package/connectors/connect-googlecloud/README.md +2 -2
- package/connectors/connect-googlecloud/src/utils/config.ts +2 -2
- package/connectors/connect-googlecontacts/AGENTS.md +4 -4
- package/connectors/connect-googlecontacts/CLAUDE.md +4 -4
- package/connectors/connect-googlecontacts/GEMINI.md +4 -4
- package/connectors/connect-googlecontacts/README.md +2 -2
- package/connectors/connect-googlecontacts/src/utils/config.ts +2 -2
- package/connectors/connect-googledocs/AGENTS.md +1 -1
- package/connectors/connect-googledocs/CLAUDE.md +1 -1
- package/connectors/connect-googledocs/GEMINI.md +1 -1
- package/connectors/connect-googledocs/README.md +2 -2
- package/connectors/connect-googledocs/src/utils/config.ts +2 -2
- package/connectors/connect-googledrive/AGENTS.md +1 -1
- package/connectors/connect-googledrive/CLAUDE.md +6 -6
- package/connectors/connect-googledrive/GEMINI.md +1 -1
- package/connectors/connect-googledrive/README.md +2 -2
- package/connectors/connect-googledrive/src/utils/config.ts +2 -2
- package/connectors/connect-googlegemini/AGENTS.md +2 -2
- package/connectors/connect-googlegemini/CLAUDE.md +2 -2
- package/connectors/connect-googlegemini/GEMINI.md +2 -2
- package/connectors/connect-googlegemini/README.md +2 -2
- package/connectors/connect-googlegemini/src/utils/config.ts +1 -1
- package/connectors/connect-googlemaps/AGENTS.md +1 -1
- package/connectors/connect-googlemaps/CLAUDE.md +1 -1
- package/connectors/connect-googlemaps/GEMINI.md +1 -1
- package/connectors/connect-googlemaps/README.md +2 -2
- package/connectors/connect-googlemaps/src/utils/config.ts +1 -1
- package/connectors/connect-googlesheets/AGENTS.md +1 -1
- package/connectors/connect-googlesheets/CLAUDE.md +1 -1
- package/connectors/connect-googlesheets/GEMINI.md +1 -1
- package/connectors/connect-googlesheets/README.md +2 -2
- package/connectors/connect-googlesheets/src/utils/config.ts +2 -2
- package/connectors/connect-googletasks/AGENTS.md +1 -1
- package/connectors/connect-googletasks/CLAUDE.md +1 -1
- package/connectors/connect-googletasks/GEMINI.md +1 -1
- package/connectors/connect-googletasks/README.md +2 -2
- package/connectors/connect-googletasks/src/utils/config.ts +1 -1
- package/connectors/connect-hedra/AGENTS.md +2 -2
- package/connectors/connect-hedra/CLAUDE.md +2 -2
- package/connectors/connect-hedra/GEMINI.md +2 -2
- package/connectors/connect-hedra/README.md +2 -2
- package/connectors/connect-hedra/src/utils/config.ts +2 -2
- package/connectors/connect-heygen/AGENTS.md +2 -2
- package/connectors/connect-heygen/CLAUDE.md +2 -2
- package/connectors/connect-heygen/GEMINI.md +2 -2
- package/connectors/connect-heygen/README.md +2 -2
- package/connectors/connect-heygen/src/utils/config.ts +2 -2
- package/connectors/connect-huggingface/AGENTS.md +2 -2
- package/connectors/connect-huggingface/CLAUDE.md +2 -2
- package/connectors/connect-huggingface/GEMINI.md +2 -2
- package/connectors/connect-huggingface/README.md +2 -2
- package/connectors/connect-huggingface/src/utils/config.ts +2 -2
- package/connectors/connect-icons8/AGENTS.md +2 -2
- package/connectors/connect-icons8/CLAUDE.md +2 -2
- package/connectors/connect-icons8/GEMINI.md +2 -2
- package/connectors/connect-icons8/README.md +2 -2
- package/connectors/connect-icons8/src/utils/config.ts +2 -2
- package/connectors/connect-maropost/AGENTS.md +1 -1
- package/connectors/connect-maropost/CLAUDE.md +1 -1
- package/connectors/connect-maropost/GEMINI.md +1 -1
- package/connectors/connect-maropost/README.md +2 -2
- package/connectors/connect-maropost/src/utils/config.ts +2 -2
- package/connectors/connect-mercury/AGENTS.md +1 -1
- package/connectors/connect-mercury/CLAUDE.md +1 -1
- package/connectors/connect-mercury/GEMINI.md +1 -1
- package/connectors/connect-mercury/README.md +2 -2
- package/connectors/connect-mercury/src/utils/config.ts +2 -2
- package/connectors/connect-meta/AGENTS.md +1 -1
- package/connectors/connect-meta/CLAUDE.md +1 -1
- package/connectors/connect-meta/GEMINI.md +1 -1
- package/connectors/connect-meta/README.md +2 -2
- package/connectors/connect-meta/src/utils/config.ts +2 -2
- package/connectors/connect-midjourney/AGENTS.md +2 -2
- package/connectors/connect-midjourney/CLAUDE.md +2 -2
- package/connectors/connect-midjourney/GEMINI.md +2 -2
- package/connectors/connect-midjourney/README.md +2 -2
- package/connectors/connect-midjourney/src/utils/config.ts +2 -2
- package/connectors/connect-mistral/AGENTS.md +1 -1
- package/connectors/connect-mistral/CLAUDE.md +1 -1
- package/connectors/connect-mistral/GEMINI.md +1 -1
- package/connectors/connect-mistral/README.md +2 -2
- package/connectors/connect-mistral/src/utils/config.ts +2 -2
- package/connectors/connect-mixpanel/AGENTS.md +2 -2
- package/connectors/connect-mixpanel/CLAUDE.md +2 -2
- package/connectors/connect-mixpanel/GEMINI.md +2 -2
- package/connectors/connect-mixpanel/README.md +2 -2
- package/connectors/connect-mixpanel/src/utils/config.ts +2 -2
- package/connectors/connect-notion/CLAUDE.md +2 -2
- package/connectors/connect-notion/src/utils/config.ts +2 -2
- package/connectors/connect-openai/AGENTS.md +1 -1
- package/connectors/connect-openai/CLAUDE.md +1 -1
- package/connectors/connect-openai/GEMINI.md +1 -1
- package/connectors/connect-openai/README.md +2 -2
- package/connectors/connect-openai/src/utils/config.ts +2 -2
- package/connectors/connect-openweathermap/AGENTS.md +1 -1
- package/connectors/connect-openweathermap/CLAUDE.md +1 -1
- package/connectors/connect-openweathermap/GEMINI.md +1 -1
- package/connectors/connect-openweathermap/README.md +2 -2
- package/connectors/connect-openweathermap/src/utils/config.ts +1 -1
- package/connectors/connect-pandadoc/AGENTS.md +1 -1
- package/connectors/connect-pandadoc/CLAUDE.md +1 -1
- package/connectors/connect-pandadoc/GEMINI.md +1 -1
- package/connectors/connect-pandadoc/README.md +2 -2
- package/connectors/connect-pandadoc/src/utils/config.ts +2 -2
- package/connectors/connect-quo/AGENTS.md +1 -1
- package/connectors/connect-quo/CLAUDE.md +1 -1
- package/connectors/connect-quo/GEMINI.md +1 -1
- package/connectors/connect-quo/README.md +2 -2
- package/connectors/connect-quo/src/utils/config.ts +2 -2
- package/connectors/connect-reddit/AGENTS.md +2 -2
- package/connectors/connect-reddit/CLAUDE.md +2 -2
- package/connectors/connect-reddit/GEMINI.md +2 -2
- package/connectors/connect-reddit/README.md +2 -2
- package/connectors/connect-reddit/src/utils/config.ts +2 -2
- package/connectors/connect-reducto/AGENTS.md +1 -1
- package/connectors/connect-reducto/CLAUDE.md +1 -1
- package/connectors/connect-reducto/GEMINI.md +1 -1
- package/connectors/connect-reducto/README.md +2 -2
- package/connectors/connect-reducto/src/utils/config.ts +1 -1
- package/connectors/connect-resend/AGENTS.md +1 -1
- package/connectors/connect-resend/CLAUDE.md +1 -1
- package/connectors/connect-resend/GEMINI.md +1 -1
- package/connectors/connect-resend/README.md +2 -2
- package/connectors/connect-resend/src/utils/config.ts +2 -2
- package/connectors/connect-revolut/AGENTS.md +2 -2
- package/connectors/connect-revolut/CLAUDE.md +2 -2
- package/connectors/connect-revolut/GEMINI.md +2 -2
- package/connectors/connect-revolut/README.md +2 -2
- package/connectors/connect-revolut/src/utils/config.ts +2 -2
- package/connectors/connect-sedo/AGENTS.md +1 -1
- package/connectors/connect-sedo/CLAUDE.md +1 -1
- package/connectors/connect-sedo/GEMINI.md +1 -1
- package/connectors/connect-sedo/README.md +2 -2
- package/connectors/connect-sedo/src/utils/config.ts +1 -1
- package/connectors/connect-sentry/AGENTS.md +2 -2
- package/connectors/connect-sentry/CLAUDE.md +2 -2
- package/connectors/connect-sentry/GEMINI.md +2 -2
- package/connectors/connect-sentry/README.md +2 -2
- package/connectors/connect-sentry/src/utils/config.ts +2 -2
- package/connectors/connect-shadcn/AGENTS.md +2 -2
- package/connectors/connect-shadcn/CLAUDE.md +2 -2
- package/connectors/connect-shadcn/GEMINI.md +2 -2
- package/connectors/connect-shadcn/README.md +2 -2
- package/connectors/connect-shadcn/src/utils/config.ts +2 -2
- package/connectors/connect-shopify/AGENTS.md +2 -2
- package/connectors/connect-shopify/CLAUDE.md +2 -2
- package/connectors/connect-shopify/GEMINI.md +2 -2
- package/connectors/connect-shopify/README.md +2 -2
- package/connectors/connect-shopify/src/utils/config.ts +2 -2
- package/connectors/connect-snap/AGENTS.md +1 -1
- package/connectors/connect-snap/CLAUDE.md +1 -1
- package/connectors/connect-snap/GEMINI.md +1 -1
- package/connectors/connect-snap/README.md +2 -2
- package/connectors/connect-snap/src/utils/config.ts +2 -2
- package/connectors/connect-stabilityai/AGENTS.md +1 -1
- package/connectors/connect-stabilityai/CLAUDE.md +1 -1
- package/connectors/connect-stabilityai/GEMINI.md +1 -1
- package/connectors/connect-stabilityai/README.md +2 -2
- package/connectors/connect-stabilityai/src/utils/config.ts +2 -2
- package/connectors/connect-stripe/AGENTS.md +2 -2
- package/connectors/connect-stripe/CLAUDE.md +2 -2
- package/connectors/connect-stripe/GEMINI.md +2 -2
- package/connectors/connect-stripe/README.md +2 -2
- package/connectors/connect-stripe/src/utils/config.ts +2 -2
- package/connectors/connect-stripeatlas/AGENTS.md +2 -2
- package/connectors/connect-stripeatlas/CLAUDE.md +2 -2
- package/connectors/connect-stripeatlas/GEMINI.md +2 -2
- package/connectors/connect-stripeatlas/README.md +2 -2
- package/connectors/connect-stripeatlas/src/utils/config.ts +2 -2
- package/connectors/connect-substack/AGENTS.md +2 -2
- package/connectors/connect-substack/CLAUDE.md +2 -2
- package/connectors/connect-substack/GEMINI.md +2 -2
- package/connectors/connect-substack/README.md +2 -2
- package/connectors/connect-substack/src/utils/config.ts +2 -2
- package/connectors/connect-tiktok/AGENTS.md +1 -1
- package/connectors/connect-tiktok/CLAUDE.md +1 -1
- package/connectors/connect-tiktok/GEMINI.md +1 -1
- package/connectors/connect-tiktok/README.md +2 -2
- package/connectors/connect-tiktok/src/utils/config.ts +2 -2
- package/connectors/connect-tinker/AGENTS.md +2 -2
- package/connectors/connect-tinker/CLAUDE.md +2 -2
- package/connectors/connect-tinker/GEMINI.md +2 -2
- package/connectors/connect-tinker/README.md +2 -2
- package/connectors/connect-tinker/src/utils/config.ts +2 -2
- package/connectors/connect-twilio/AGENTS.md +1 -1
- package/connectors/connect-twilio/CLAUDE.md +1 -1
- package/connectors/connect-twilio/GEMINI.md +1 -1
- package/connectors/connect-twilio/README.md +2 -2
- package/connectors/connect-twilio/src/utils/config.ts +3 -3
- package/connectors/connect-uspto/AGENTS.md +1 -1
- package/connectors/connect-uspto/CLAUDE.md +1 -1
- package/connectors/connect-uspto/GEMINI.md +1 -1
- package/connectors/connect-uspto/README.md +2 -2
- package/connectors/connect-uspto/src/utils/config.ts +2 -2
- package/connectors/connect-webflow/AGENTS.md +2 -2
- package/connectors/connect-webflow/CLAUDE.md +2 -2
- package/connectors/connect-webflow/GEMINI.md +2 -2
- package/connectors/connect-webflow/README.md +2 -2
- package/connectors/connect-webflow/src/utils/config.ts +2 -2
- package/connectors/connect-wix/AGENTS.md +2 -2
- package/connectors/connect-wix/CLAUDE.md +2 -2
- package/connectors/connect-wix/GEMINI.md +2 -2
- package/connectors/connect-wix/README.md +2 -2
- package/connectors/connect-wix/src/utils/config.ts +2 -2
- package/connectors/connect-x/AGENTS.md +1 -1
- package/connectors/connect-x/CLAUDE.md +1 -1
- package/connectors/connect-x/GEMINI.md +1 -1
- package/connectors/connect-x/README.md +2 -2
- package/connectors/connect-x/src/utils/config.ts +2 -2
- package/connectors/connect-xads/AGENTS.md +2 -2
- package/connectors/connect-xads/CLAUDE.md +2 -2
- package/connectors/connect-xads/GEMINI.md +2 -2
- package/connectors/connect-xads/README.md +2 -2
- package/connectors/connect-xads/src/utils/config.ts +1 -1
- package/connectors/connect-xai/AGENTS.md +1 -1
- package/connectors/connect-xai/CLAUDE.md +1 -1
- package/connectors/connect-xai/GEMINI.md +1 -1
- package/connectors/connect-xai/README.md +2 -2
- package/connectors/connect-xai/src/utils/config.ts +2 -2
- package/connectors/connect-youtube/AGENTS.md +1 -1
- package/connectors/connect-youtube/CLAUDE.md +1 -1
- package/connectors/connect-youtube/GEMINI.md +1 -1
- package/connectors/connect-youtube/README.md +2 -2
- package/connectors/connect-youtube/src/utils/config.ts +2 -2
- package/connectors/connect-zoom/AGENTS.md +2 -2
- package/connectors/connect-zoom/CLAUDE.md +2 -2
- package/connectors/connect-zoom/GEMINI.md +2 -2
- package/connectors/connect-zoom/README.md +2 -2
- package/connectors/connect-zoom/src/utils/config.ts +2 -2
- package/dashboard/dist/assets/index-DmR_QNtT.css +1 -0
- package/dashboard/dist/assets/index-Dp-apHbC.js +284 -0
- package/dashboard/dist/index.html +2 -2
- package/dist/server/auth.d.ts +20 -0
- package/dist/server/serve.d.ts +1 -1
- package/package.json +2 -2
- package/dashboard/dist/assets/index-CMPMQfHL.js +0 -234
- package/dashboard/dist/assets/index-D0alGsGP.css +0 -1
package/bin/serve.js
CHANGED
|
@@ -1,11 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
9
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
10
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
11
|
+
for (let key of __getOwnPropNames(mod))
|
|
12
|
+
if (!__hasOwnProp.call(to, key))
|
|
13
|
+
__defProp(to, key, {
|
|
14
|
+
get: () => mod[key],
|
|
15
|
+
enumerable: true
|
|
16
|
+
});
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
3
19
|
var __require = import.meta.require;
|
|
4
20
|
|
|
5
21
|
// src/server/serve.ts
|
|
6
|
-
import { existsSync as existsSync4 } from "fs";
|
|
7
|
-
import { join as join4, dirname as dirname3, extname } from "path";
|
|
22
|
+
import { existsSync as existsSync4, readdirSync as readdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
23
|
+
import { join as join4, dirname as dirname3, extname, basename } from "path";
|
|
8
24
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
25
|
+
import { homedir as homedir2 } from "os";
|
|
9
26
|
|
|
10
27
|
// src/lib/registry.ts
|
|
11
28
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -493,6 +510,70 @@ function getConnectorPath(name) {
|
|
|
493
510
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
494
511
|
return join2(CONNECTORS_DIR, connectorName);
|
|
495
512
|
}
|
|
513
|
+
function installConnector(name, options = {}) {
|
|
514
|
+
const { targetDir = process.cwd(), overwrite = false } = options;
|
|
515
|
+
if (!/^[a-z0-9-]+$/.test(name)) {
|
|
516
|
+
return {
|
|
517
|
+
connector: name,
|
|
518
|
+
success: false,
|
|
519
|
+
error: `Invalid connector name '${name}'`
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
523
|
+
const sourcePath = getConnectorPath(name);
|
|
524
|
+
const destDir = join2(targetDir, ".connectors");
|
|
525
|
+
const destPath = join2(destDir, connectorName);
|
|
526
|
+
if (!existsSync2(sourcePath)) {
|
|
527
|
+
return {
|
|
528
|
+
connector: name,
|
|
529
|
+
success: false,
|
|
530
|
+
error: `Connector '${name}' not found`
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
if (existsSync2(destPath) && !overwrite) {
|
|
534
|
+
return {
|
|
535
|
+
connector: name,
|
|
536
|
+
success: false,
|
|
537
|
+
error: `Already installed. Use --overwrite to replace.`,
|
|
538
|
+
path: destPath
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
try {
|
|
542
|
+
if (!existsSync2(destDir)) {
|
|
543
|
+
mkdirSync(destDir, { recursive: true });
|
|
544
|
+
}
|
|
545
|
+
cpSync(sourcePath, destPath, { recursive: true });
|
|
546
|
+
updateConnectorsIndex(destDir);
|
|
547
|
+
return {
|
|
548
|
+
connector: name,
|
|
549
|
+
success: true,
|
|
550
|
+
path: destPath
|
|
551
|
+
};
|
|
552
|
+
} catch (error) {
|
|
553
|
+
return {
|
|
554
|
+
connector: name,
|
|
555
|
+
success: false,
|
|
556
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
function updateConnectorsIndex(connectorsDir) {
|
|
561
|
+
const indexPath = join2(connectorsDir, "index.ts");
|
|
562
|
+
const connectors = readdirSync(connectorsDir).filter((f) => f.startsWith("connect-") && !f.includes("."));
|
|
563
|
+
const exports = connectors.map((c) => {
|
|
564
|
+
const name = c.replace("connect-", "");
|
|
565
|
+
return `export * as ${name} from './${c}/src/index.js';`;
|
|
566
|
+
}).join(`
|
|
567
|
+
`);
|
|
568
|
+
const content = `/**
|
|
569
|
+
* Auto-generated index of installed connectors
|
|
570
|
+
* Do not edit manually - run 'connectors install' to update
|
|
571
|
+
*/
|
|
572
|
+
|
|
573
|
+
${exports}
|
|
574
|
+
`;
|
|
575
|
+
writeFileSync(indexPath, content);
|
|
576
|
+
}
|
|
496
577
|
function getInstalledConnectors(targetDir = process.cwd()) {
|
|
497
578
|
const connectorsDir = join2(targetDir, ".connectors");
|
|
498
579
|
if (!existsSync2(connectorsDir)) {
|
|
@@ -545,9 +626,20 @@ function parseEnvVarsTable(section) {
|
|
|
545
626
|
}
|
|
546
627
|
return vars;
|
|
547
628
|
}
|
|
629
|
+
function removeConnector(name, targetDir = process.cwd()) {
|
|
630
|
+
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
631
|
+
const connectorsDir = join2(targetDir, ".connectors");
|
|
632
|
+
const connectorPath = join2(connectorsDir, connectorName);
|
|
633
|
+
if (!existsSync2(connectorPath)) {
|
|
634
|
+
return false;
|
|
635
|
+
}
|
|
636
|
+
rmSync(connectorPath, { recursive: true });
|
|
637
|
+
updateConnectorsIndex(connectorsDir);
|
|
638
|
+
return true;
|
|
639
|
+
}
|
|
548
640
|
|
|
549
641
|
// src/server/auth.ts
|
|
550
|
-
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
642
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, readdirSync as readdirSync2, rmSync as rmSync2, statSync as statSync2 } from "fs";
|
|
551
643
|
import { randomBytes } from "crypto";
|
|
552
644
|
import { homedir } from "os";
|
|
553
645
|
import { join as join3 } from "path";
|
|
@@ -606,7 +698,7 @@ function getAuthType(name) {
|
|
|
606
698
|
}
|
|
607
699
|
function getConnectorConfigDir(name) {
|
|
608
700
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
609
|
-
return join3(homedir(), ".
|
|
701
|
+
return join3(homedir(), ".connectors", connectorName);
|
|
610
702
|
}
|
|
611
703
|
function getCurrentProfile(name) {
|
|
612
704
|
const configDir = getConnectorConfigDir(name);
|
|
@@ -658,6 +750,8 @@ function getAuthStatus(name) {
|
|
|
658
750
|
description: v.description,
|
|
659
751
|
set: !!process.env[v.variable]
|
|
660
752
|
}));
|
|
753
|
+
const envVarTotalCount = envVars.length;
|
|
754
|
+
const envVarSetCount = envVars.filter((v) => v.set).length;
|
|
661
755
|
if (authType === "oauth") {
|
|
662
756
|
const tokens = loadTokens(name);
|
|
663
757
|
const config2 = loadProfileConfig(name);
|
|
@@ -669,7 +763,9 @@ function getAuthStatus(name) {
|
|
|
669
763
|
configured: hasTokens || hasRefreshToken,
|
|
670
764
|
tokenExpiry,
|
|
671
765
|
hasRefreshToken,
|
|
672
|
-
envVars
|
|
766
|
+
envVars,
|
|
767
|
+
envVarSetCount,
|
|
768
|
+
envVarTotalCount
|
|
673
769
|
};
|
|
674
770
|
}
|
|
675
771
|
const config = loadProfileConfig(name);
|
|
@@ -678,7 +774,9 @@ function getAuthStatus(name) {
|
|
|
678
774
|
return {
|
|
679
775
|
type: authType,
|
|
680
776
|
configured: hasKey || hasEnvVar,
|
|
681
|
-
envVars
|
|
777
|
+
envVars,
|
|
778
|
+
envVarSetCount,
|
|
779
|
+
envVarTotalCount
|
|
682
780
|
};
|
|
683
781
|
}
|
|
684
782
|
function saveApiKey(name, key, field) {
|
|
@@ -849,8 +947,65 @@ async function refreshOAuthToken(name) {
|
|
|
849
947
|
saveOAuthTokens(name, tokens);
|
|
850
948
|
return tokens;
|
|
851
949
|
}
|
|
950
|
+
function listProfiles(name) {
|
|
951
|
+
const configDir = getConnectorConfigDir(name);
|
|
952
|
+
const profilesDir = join3(configDir, "profiles");
|
|
953
|
+
if (!existsSync3(profilesDir))
|
|
954
|
+
return ["default"];
|
|
955
|
+
const seen = new Set;
|
|
956
|
+
try {
|
|
957
|
+
const entries = readdirSync2(profilesDir);
|
|
958
|
+
for (const entry of entries) {
|
|
959
|
+
const fullPath = join3(profilesDir, entry);
|
|
960
|
+
const stat = statSync2(fullPath);
|
|
961
|
+
if (stat.isDirectory()) {
|
|
962
|
+
seen.add(entry);
|
|
963
|
+
} else if (entry.endsWith(".json")) {
|
|
964
|
+
seen.add(entry.replace(/\.json$/, ""));
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
} catch {}
|
|
968
|
+
seen.add("default");
|
|
969
|
+
return Array.from(seen).sort();
|
|
970
|
+
}
|
|
971
|
+
function switchProfile(name, profile) {
|
|
972
|
+
const configDir = getConnectorConfigDir(name);
|
|
973
|
+
mkdirSync2(configDir, { recursive: true });
|
|
974
|
+
writeFileSync2(join3(configDir, "current_profile"), profile);
|
|
975
|
+
}
|
|
976
|
+
function deleteProfile(name, profile) {
|
|
977
|
+
if (profile === "default")
|
|
978
|
+
return false;
|
|
979
|
+
const configDir = getConnectorConfigDir(name);
|
|
980
|
+
const profilesDir = join3(configDir, "profiles");
|
|
981
|
+
const profileFile = join3(profilesDir, `${profile}.json`);
|
|
982
|
+
if (existsSync3(profileFile)) {
|
|
983
|
+
rmSync2(profileFile);
|
|
984
|
+
if (getCurrentProfile(name) === profile) {
|
|
985
|
+
switchProfile(name, "default");
|
|
986
|
+
}
|
|
987
|
+
return true;
|
|
988
|
+
}
|
|
989
|
+
const profileDir = join3(profilesDir, profile);
|
|
990
|
+
if (existsSync3(profileDir)) {
|
|
991
|
+
rmSync2(profileDir, { recursive: true });
|
|
992
|
+
if (getCurrentProfile(name) === profile) {
|
|
993
|
+
switchProfile(name, "default");
|
|
994
|
+
}
|
|
995
|
+
return true;
|
|
996
|
+
}
|
|
997
|
+
return false;
|
|
998
|
+
}
|
|
852
999
|
|
|
853
1000
|
// src/server/serve.ts
|
|
1001
|
+
var activityLog = [];
|
|
1002
|
+
var MAX_ACTIVITY_LOG = 100;
|
|
1003
|
+
function logActivity(action, connector, detail) {
|
|
1004
|
+
activityLog.unshift({ action, connector, timestamp: Date.now(), detail });
|
|
1005
|
+
if (activityLog.length > MAX_ACTIVITY_LOG) {
|
|
1006
|
+
activityLog.length = MAX_ACTIVITY_LOG;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
854
1009
|
function resolveDashboardDir() {
|
|
855
1010
|
const candidates = [];
|
|
856
1011
|
try {
|
|
@@ -941,7 +1096,19 @@ function serveStaticFile(filePath) {
|
|
|
941
1096
|
headers: { "Content-Type": contentType }
|
|
942
1097
|
});
|
|
943
1098
|
}
|
|
944
|
-
async function
|
|
1099
|
+
async function findAvailablePort(preferred) {
|
|
1100
|
+
for (let port = preferred;port < preferred + 100; port++) {
|
|
1101
|
+
try {
|
|
1102
|
+
const server = Bun.serve({ port, fetch() {
|
|
1103
|
+
return new Response;
|
|
1104
|
+
} });
|
|
1105
|
+
server.stop(true);
|
|
1106
|
+
return port;
|
|
1107
|
+
} catch {}
|
|
1108
|
+
}
|
|
1109
|
+
throw new Error(`No available port found in range ${preferred}-${preferred + 99}`);
|
|
1110
|
+
}
|
|
1111
|
+
async function startServer(requestedPort, options) {
|
|
945
1112
|
const shouldOpen = options?.open ?? true;
|
|
946
1113
|
loadConnectorVersions();
|
|
947
1114
|
const dashboardDir = resolveDashboardDir();
|
|
@@ -958,6 +1125,10 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
958
1125
|
console.error(` bun run build:dashboard
|
|
959
1126
|
`);
|
|
960
1127
|
}
|
|
1128
|
+
const port = await findAvailablePort(requestedPort);
|
|
1129
|
+
if (port !== requestedPort) {
|
|
1130
|
+
console.log(`Port ${requestedPort} is in use, using port ${port} instead`);
|
|
1131
|
+
}
|
|
961
1132
|
const server = Bun.serve({
|
|
962
1133
|
port,
|
|
963
1134
|
async fetch(req) {
|
|
@@ -1000,6 +1171,7 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
1000
1171
|
if (!body.key)
|
|
1001
1172
|
return json({ error: "Missing 'key' in request body" }, 400, port);
|
|
1002
1173
|
saveApiKey(name, body.key, body.field);
|
|
1174
|
+
logActivity("key_saved", name, body.field ? `Field: ${body.field}` : undefined);
|
|
1003
1175
|
return json({ success: true }, 200, port);
|
|
1004
1176
|
} catch (e) {
|
|
1005
1177
|
return json({ error: e instanceof Error ? e.message : "Failed to save key" }, 500, port);
|
|
@@ -1012,18 +1184,215 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
1012
1184
|
return json({ error: "Invalid connector name" }, 400, port);
|
|
1013
1185
|
try {
|
|
1014
1186
|
const tokens = await refreshOAuthToken(name);
|
|
1187
|
+
logActivity("token_refreshed", name, tokens.expiresAt ? `Expires: ${new Date(tokens.expiresAt).toISOString()}` : undefined);
|
|
1015
1188
|
return json({ success: true, expiresAt: tokens.expiresAt }, 200, port);
|
|
1016
1189
|
} catch (e) {
|
|
1017
1190
|
return json({ success: false, error: e instanceof Error ? e.message : "Failed to refresh" }, 500, port);
|
|
1018
1191
|
}
|
|
1019
1192
|
}
|
|
1193
|
+
const installMatch = path.match(/^\/api\/connectors\/([^/]+)\/install$/);
|
|
1194
|
+
if (installMatch && method === "POST") {
|
|
1195
|
+
const name = installMatch[1];
|
|
1196
|
+
if (!isValidConnectorName(name))
|
|
1197
|
+
return json({ error: "Invalid connector name" }, 400, port);
|
|
1198
|
+
const meta = getConnector(name);
|
|
1199
|
+
if (!meta)
|
|
1200
|
+
return json({ error: `Connector '${name}' not found` }, 404, port);
|
|
1201
|
+
try {
|
|
1202
|
+
const result = installConnector(name);
|
|
1203
|
+
if (!result.success) {
|
|
1204
|
+
return json({ error: result.error || "Failed to install connector" }, 500, port);
|
|
1205
|
+
}
|
|
1206
|
+
logActivity("installed", name);
|
|
1207
|
+
return json({ success: true, name }, 200, port);
|
|
1208
|
+
} catch (e) {
|
|
1209
|
+
return json({ error: e instanceof Error ? e.message : "Failed to install connector" }, 500, port);
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
const uninstallMatch = path.match(/^\/api\/connectors\/([^/]+)\/uninstall$/);
|
|
1213
|
+
if (uninstallMatch && method === "POST") {
|
|
1214
|
+
const name = uninstallMatch[1];
|
|
1215
|
+
if (!isValidConnectorName(name))
|
|
1216
|
+
return json({ error: "Invalid connector name" }, 400, port);
|
|
1217
|
+
try {
|
|
1218
|
+
const removed = removeConnector(name);
|
|
1219
|
+
if (!removed) {
|
|
1220
|
+
return json({ error: `Connector '${name}' is not installed` }, 404, port);
|
|
1221
|
+
}
|
|
1222
|
+
logActivity("uninstalled", name);
|
|
1223
|
+
return json({ success: true, name }, 200, port);
|
|
1224
|
+
} catch (e) {
|
|
1225
|
+
return json({ error: e instanceof Error ? e.message : "Failed to uninstall connector" }, 500, port);
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
if (path === "/api/update" && method === "POST") {
|
|
1229
|
+
try {
|
|
1230
|
+
const installed = getInstalledConnectors();
|
|
1231
|
+
if (installed.length === 0) {
|
|
1232
|
+
return json({ updated: [], count: 0 }, 200, port);
|
|
1233
|
+
}
|
|
1234
|
+
const results = installed.map((name) => installConnector(name, { overwrite: true }));
|
|
1235
|
+
return json({
|
|
1236
|
+
results,
|
|
1237
|
+
count: results.filter((r) => r.success).length,
|
|
1238
|
+
total: installed.length
|
|
1239
|
+
}, 200, port);
|
|
1240
|
+
} catch (e) {
|
|
1241
|
+
return json({ error: e instanceof Error ? e.message : "Failed to update" }, 500, port);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
if (path === "/api/activity" && method === "GET") {
|
|
1245
|
+
return json(activityLog, 200, port);
|
|
1246
|
+
}
|
|
1247
|
+
const profilesMatch = path.match(/^\/api\/connectors\/([^/]+)\/profiles$/);
|
|
1248
|
+
if (profilesMatch && method === "GET") {
|
|
1249
|
+
const name = profilesMatch[1];
|
|
1250
|
+
if (!isValidConnectorName(name))
|
|
1251
|
+
return json({ error: "Invalid connector name" }, 400, port);
|
|
1252
|
+
try {
|
|
1253
|
+
const profiles = listProfiles(name);
|
|
1254
|
+
const configDir = join4(homedir2(), ".connectors", name.startsWith("connect-") ? name : `connect-${name}`);
|
|
1255
|
+
const currentProfileFile = join4(configDir, "current_profile");
|
|
1256
|
+
let current = "default";
|
|
1257
|
+
if (existsSync4(currentProfileFile)) {
|
|
1258
|
+
try {
|
|
1259
|
+
current = readFileSync4(currentProfileFile, "utf-8").trim() || "default";
|
|
1260
|
+
} catch {}
|
|
1261
|
+
}
|
|
1262
|
+
return json({ current, profiles }, 200, port);
|
|
1263
|
+
} catch (e) {
|
|
1264
|
+
return json({ error: e instanceof Error ? e.message : "Failed to list profiles" }, 500, port);
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
const profileSwitchMatch = path.match(/^\/api\/connectors\/([^/]+)\/profiles\/switch$/);
|
|
1268
|
+
if (profileSwitchMatch && method === "POST") {
|
|
1269
|
+
const name = profileSwitchMatch[1];
|
|
1270
|
+
if (!isValidConnectorName(name))
|
|
1271
|
+
return json({ error: "Invalid connector name" }, 400, port);
|
|
1272
|
+
try {
|
|
1273
|
+
const contentLength = parseInt(req.headers.get("content-length") || "0", 10);
|
|
1274
|
+
if (contentLength > MAX_BODY_SIZE)
|
|
1275
|
+
return json({ error: "Request body too large" }, 413, port);
|
|
1276
|
+
const body = await req.json();
|
|
1277
|
+
if (!body.profile)
|
|
1278
|
+
return json({ error: "Missing 'profile' in request body" }, 400, port);
|
|
1279
|
+
switchProfile(name, body.profile);
|
|
1280
|
+
logActivity("profile_switch", name, `Switched to profile: ${body.profile}`);
|
|
1281
|
+
return json({ success: true, profile: body.profile }, 200, port);
|
|
1282
|
+
} catch (e) {
|
|
1283
|
+
return json({ error: e instanceof Error ? e.message : "Failed to switch profile" }, 500, port);
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
const profileDeleteMatch = path.match(/^\/api\/connectors\/([^/]+)\/profiles\/([^/]+)$/);
|
|
1287
|
+
if (profileDeleteMatch && method === "DELETE") {
|
|
1288
|
+
const name = profileDeleteMatch[1];
|
|
1289
|
+
const profile = profileDeleteMatch[2];
|
|
1290
|
+
if (!isValidConnectorName(name))
|
|
1291
|
+
return json({ error: "Invalid connector name" }, 400, port);
|
|
1292
|
+
if (profile === "default")
|
|
1293
|
+
return json({ error: "Cannot delete the default profile" }, 400, port);
|
|
1294
|
+
try {
|
|
1295
|
+
const deleted = deleteProfile(name, profile);
|
|
1296
|
+
if (!deleted)
|
|
1297
|
+
return json({ error: `Profile '${profile}' not found` }, 404, port);
|
|
1298
|
+
logActivity("profile_delete", name, `Deleted profile: ${profile}`);
|
|
1299
|
+
return json({ success: true }, 200, port);
|
|
1300
|
+
} catch (e) {
|
|
1301
|
+
return json({ error: e instanceof Error ? e.message : "Failed to delete profile" }, 500, port);
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
if (path === "/api/export" && method === "GET") {
|
|
1305
|
+
try {
|
|
1306
|
+
const connectDir = join4(homedir2(), ".connectors");
|
|
1307
|
+
const result = {};
|
|
1308
|
+
if (existsSync4(connectDir)) {
|
|
1309
|
+
const entries = readdirSync3(connectDir, { withFileTypes: true });
|
|
1310
|
+
for (const entry of entries) {
|
|
1311
|
+
if (!entry.isDirectory() || !entry.name.startsWith("connect-"))
|
|
1312
|
+
continue;
|
|
1313
|
+
const connectorName = entry.name.replace(/^connect-/, "");
|
|
1314
|
+
const profilesDir = join4(connectDir, entry.name, "profiles");
|
|
1315
|
+
if (!existsSync4(profilesDir))
|
|
1316
|
+
continue;
|
|
1317
|
+
const profiles = {};
|
|
1318
|
+
const profileEntries = readdirSync3(profilesDir, { withFileTypes: true });
|
|
1319
|
+
for (const pEntry of profileEntries) {
|
|
1320
|
+
if (pEntry.isFile() && pEntry.name.endsWith(".json")) {
|
|
1321
|
+
const profileName = basename(pEntry.name, ".json");
|
|
1322
|
+
try {
|
|
1323
|
+
const config = JSON.parse(readFileSync4(join4(profilesDir, pEntry.name), "utf-8"));
|
|
1324
|
+
profiles[profileName] = config;
|
|
1325
|
+
} catch {}
|
|
1326
|
+
}
|
|
1327
|
+
if (pEntry.isDirectory()) {
|
|
1328
|
+
const configPath = join4(profilesDir, pEntry.name, "config.json");
|
|
1329
|
+
if (existsSync4(configPath)) {
|
|
1330
|
+
try {
|
|
1331
|
+
const config = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
1332
|
+
profiles[pEntry.name] = config;
|
|
1333
|
+
} catch {}
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
if (Object.keys(profiles).length > 0) {
|
|
1338
|
+
result[connectorName] = { profiles };
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
const exportData = { connectors: result, exportedAt: new Date().toISOString() };
|
|
1343
|
+
return new Response(JSON.stringify(exportData, null, 2), {
|
|
1344
|
+
status: 200,
|
|
1345
|
+
headers: {
|
|
1346
|
+
"Content-Type": "application/json",
|
|
1347
|
+
"Content-Disposition": `attachment; filename="connectors-backup-${new Date().toISOString().slice(0, 10)}.json"`,
|
|
1348
|
+
"Access-Control-Allow-Origin": port ? `http://localhost:${port}` : "*",
|
|
1349
|
+
...SECURITY_HEADERS
|
|
1350
|
+
}
|
|
1351
|
+
});
|
|
1352
|
+
} catch (e) {
|
|
1353
|
+
return json({ error: e instanceof Error ? e.message : "Failed to export credentials" }, 500, port);
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
if (path === "/api/import" && method === "POST") {
|
|
1357
|
+
try {
|
|
1358
|
+
const contentLength = parseInt(req.headers.get("content-length") || "0", 10);
|
|
1359
|
+
if (contentLength > MAX_BODY_SIZE)
|
|
1360
|
+
return json({ error: "Request body too large" }, 413, port);
|
|
1361
|
+
const body = await req.json();
|
|
1362
|
+
if (!body.connectors || typeof body.connectors !== "object") {
|
|
1363
|
+
return json({ error: "Invalid import format: missing 'connectors' object" }, 400, port);
|
|
1364
|
+
}
|
|
1365
|
+
let imported = 0;
|
|
1366
|
+
const connectDir = join4(homedir2(), ".connectors");
|
|
1367
|
+
for (const [connectorName, data] of Object.entries(body.connectors)) {
|
|
1368
|
+
if (!isValidConnectorName(connectorName))
|
|
1369
|
+
continue;
|
|
1370
|
+
if (!data.profiles || typeof data.profiles !== "object")
|
|
1371
|
+
continue;
|
|
1372
|
+
const connectorDir = join4(connectDir, `connect-${connectorName}`);
|
|
1373
|
+
const profilesDir = join4(connectorDir, "profiles");
|
|
1374
|
+
for (const [profileName, config] of Object.entries(data.profiles)) {
|
|
1375
|
+
if (!config || typeof config !== "object")
|
|
1376
|
+
continue;
|
|
1377
|
+
mkdirSync3(profilesDir, { recursive: true });
|
|
1378
|
+
const profileFile = join4(profilesDir, `${profileName}.json`);
|
|
1379
|
+
writeFileSync3(profileFile, JSON.stringify(config, null, 2));
|
|
1380
|
+
imported++;
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
logActivity("credentials_imported", "all", `Imported ${imported} profiles`);
|
|
1384
|
+
return json({ success: true, imported }, 200, port);
|
|
1385
|
+
} catch (e) {
|
|
1386
|
+
return json({ error: e instanceof Error ? e.message : "Failed to import credentials" }, 500, port);
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1020
1389
|
const oauthStartMatch = path.match(/^\/oauth\/([^/]+)\/start$/);
|
|
1021
1390
|
if (oauthStartMatch && method === "GET") {
|
|
1022
1391
|
const name = oauthStartMatch[1];
|
|
1023
1392
|
const redirectUri = `http://localhost:${port}/oauth/${name}/callback`;
|
|
1024
1393
|
const authUrl = getOAuthStartUrl(name, redirectUri);
|
|
1025
1394
|
if (!authUrl) {
|
|
1026
|
-
return htmlResponse(errorPage("OAuth Not Available", `No OAuth client credentials found for <strong>${name}</strong>.`, `Set up credentials at <code>~/.
|
|
1395
|
+
return htmlResponse(errorPage("OAuth Not Available", `No OAuth client credentials found for <strong>${name}</strong>.`, `Set up credentials at <code>~/.connectors/connect-${name}/credentials.json</code>`));
|
|
1027
1396
|
}
|
|
1028
1397
|
return Response.redirect(authUrl, 302);
|
|
1029
1398
|
}
|
|
@@ -1045,6 +1414,7 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
1045
1414
|
try {
|
|
1046
1415
|
const redirectUri = `http://localhost:${port}/oauth/${name}/callback`;
|
|
1047
1416
|
await exchangeOAuthCode(name, code, redirectUri);
|
|
1417
|
+
logActivity("oauth_connected", name);
|
|
1048
1418
|
return htmlResponse(`<!DOCTYPE html><html><head><meta charset="utf-8"></head><body style="font-family:system-ui,sans-serif;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#0a0a0a;color:#e5e5e5;">
|
|
1049
1419
|
<div style="text-align:center;">
|
|
1050
1420
|
<h2 style="color:#22c55e;">Connected!</h2>
|
|
@@ -1065,7 +1435,7 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
1065
1435
|
return new Response(null, {
|
|
1066
1436
|
headers: {
|
|
1067
1437
|
"Access-Control-Allow-Origin": `http://localhost:${port}`,
|
|
1068
|
-
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
|
|
1438
|
+
"Access-Control-Allow-Methods": "GET, POST, DELETE, OPTIONS",
|
|
1069
1439
|
"Access-Control-Allow-Headers": "Content-Type"
|
|
1070
1440
|
}
|
|
1071
1441
|
});
|
|
@@ -75,10 +75,10 @@ const client = new Anthropic({ apiKey: 'YOUR_API_KEY' });
|
|
|
75
75
|
|
|
76
76
|
## Data Storage
|
|
77
77
|
|
|
78
|
-
Configuration stored in `~/.
|
|
78
|
+
Configuration stored in `~/.connectors/connect-anthropic/`:
|
|
79
79
|
|
|
80
80
|
```
|
|
81
|
-
~/.
|
|
81
|
+
~/.connectors/connect-anthropic/
|
|
82
82
|
├── current_profile # Active profile name
|
|
83
83
|
└── profiles/
|
|
84
84
|
├── default.json # Default profile
|
|
@@ -13,8 +13,8 @@ export interface ProfileConfig {
|
|
|
13
13
|
// Store for --profile flag override (set by CLI before commands run)
|
|
14
14
|
let profileOverride: string | undefined;
|
|
15
15
|
|
|
16
|
-
// Config directory: ~/.
|
|
17
|
-
const CONFIG_DIR = join(homedir(), '.
|
|
16
|
+
// Config directory: ~/.connectors/{connector-name}/
|
|
17
|
+
const CONFIG_DIR = join(homedir(), '.connectors', CONNECTOR_NAME);
|
|
18
18
|
const PROFILES_DIR = join(CONFIG_DIR, 'profiles');
|
|
19
19
|
const CURRENT_PROFILE_FILE = join(CONFIG_DIR, 'current_profile');
|
|
20
20
|
|
|
@@ -58,7 +58,7 @@ API Key authentication. Credentials can be set via:
|
|
|
58
58
|
|
|
59
59
|
### Multi-Profile Configuration
|
|
60
60
|
|
|
61
|
-
Profiles stored in `~/.
|
|
61
|
+
Profiles stored in `~/.connectors/connect-aws/profiles/`:
|
|
62
62
|
- Each profile is a separate JSON file
|
|
63
63
|
- `current_profile` file tracks active profile
|
|
64
64
|
- `--profile` flag overrides for single command
|
|
@@ -132,7 +132,7 @@ connect-aws config show
|
|
|
132
132
|
## Data Storage
|
|
133
133
|
|
|
134
134
|
```
|
|
135
|
-
~/.
|
|
135
|
+
~/.connectors/connect-aws/
|
|
136
136
|
├── current_profile # Active profile name
|
|
137
137
|
└── profiles/
|
|
138
138
|
├── default.json # Default profile
|
|
@@ -58,7 +58,7 @@ API Key authentication. Credentials can be set via:
|
|
|
58
58
|
|
|
59
59
|
### Multi-Profile Configuration
|
|
60
60
|
|
|
61
|
-
Profiles stored in `~/.
|
|
61
|
+
Profiles stored in `~/.connectors/connect-aws/profiles/`:
|
|
62
62
|
- Each profile is a separate JSON file
|
|
63
63
|
- `current_profile` file tracks active profile
|
|
64
64
|
- `--profile` flag overrides for single command
|
|
@@ -132,7 +132,7 @@ connect-aws config show
|
|
|
132
132
|
## Data Storage
|
|
133
133
|
|
|
134
134
|
```
|
|
135
|
-
~/.
|
|
135
|
+
~/.connectors/connect-aws/
|
|
136
136
|
├── current_profile # Active profile name
|
|
137
137
|
└── profiles/
|
|
138
138
|
├── default.json # Default profile
|
|
@@ -58,7 +58,7 @@ API Key authentication. Credentials can be set via:
|
|
|
58
58
|
|
|
59
59
|
### Multi-Profile Configuration
|
|
60
60
|
|
|
61
|
-
Profiles stored in `~/.
|
|
61
|
+
Profiles stored in `~/.connectors/connect-aws/profiles/`:
|
|
62
62
|
- Each profile is a separate JSON file
|
|
63
63
|
- `current_profile` file tracks active profile
|
|
64
64
|
- `--profile` flag overrides for single command
|
|
@@ -132,7 +132,7 @@ connect-aws config show
|
|
|
132
132
|
## Data Storage
|
|
133
133
|
|
|
134
134
|
```
|
|
135
|
-
~/.
|
|
135
|
+
~/.connectors/connect-aws/
|
|
136
136
|
├── current_profile # Active profile name
|
|
137
137
|
└── profiles/
|
|
138
138
|
├── default.json # Default profile
|
|
@@ -100,10 +100,10 @@ const client = new Aws({ apiKey: 'YOUR_API_KEY' });
|
|
|
100
100
|
|
|
101
101
|
## Data Storage
|
|
102
102
|
|
|
103
|
-
Configuration stored in `~/.
|
|
103
|
+
Configuration stored in `~/.connectors/connect-aws/`:
|
|
104
104
|
|
|
105
105
|
```
|
|
106
|
-
~/.
|
|
106
|
+
~/.connectors/connect-aws/
|
|
107
107
|
├── current_profile # Active profile name
|
|
108
108
|
└── profiles/
|
|
109
109
|
├── default.json # Default profile
|
|
@@ -15,8 +15,8 @@ export interface ProfileConfig {
|
|
|
15
15
|
// Store for --profile flag override (set by CLI before commands run)
|
|
16
16
|
let profileOverride: string | undefined;
|
|
17
17
|
|
|
18
|
-
// Config directory: ~/.
|
|
19
|
-
const CONFIG_DIR = join(homedir(), '.
|
|
18
|
+
// Config directory: ~/.connectors/{connector-name}/
|
|
19
|
+
const CONFIG_DIR = join(homedir(), '.connectors', CONNECTOR_NAME);
|
|
20
20
|
const PROFILES_DIR = join(CONFIG_DIR, 'profiles');
|
|
21
21
|
const CURRENT_PROFILE_FILE = join(CONFIG_DIR, 'current_profile');
|
|
22
22
|
|
|
@@ -78,7 +78,7 @@ connect-brandsight config set-secret <api-secret>
|
|
|
78
78
|
connect-brandsight config set-customer-id <customer-id>
|
|
79
79
|
connect-brandsight config show
|
|
80
80
|
|
|
81
|
-
# Contact Management (stored in ~/.
|
|
81
|
+
# Contact Management (stored in ~/.connectors/connect-brandsight/contacts/)
|
|
82
82
|
connect-brandsight contacts add <name> \
|
|
83
83
|
--first-name "John" --last-name "Doe" \
|
|
84
84
|
--email "john@example.com" --phone "+1.5551234567" \
|
|
@@ -115,7 +115,7 @@ connect-brandsight dns add <domain> <type> <name> <data>
|
|
|
115
115
|
## Data Storage
|
|
116
116
|
|
|
117
117
|
```
|
|
118
|
-
~/.
|
|
118
|
+
~/.connectors/connect-brandsight/
|
|
119
119
|
├── current_profile # Active profile name
|
|
120
120
|
└── profiles/
|
|
121
121
|
├── default.json # Default profile
|
|
@@ -78,7 +78,7 @@ connect-brandsight config set-secret <api-secret>
|
|
|
78
78
|
connect-brandsight config set-customer-id <customer-id>
|
|
79
79
|
connect-brandsight config show
|
|
80
80
|
|
|
81
|
-
# Contact Management (stored in ~/.
|
|
81
|
+
# Contact Management (stored in ~/.connectors/connect-brandsight/contacts/)
|
|
82
82
|
connect-brandsight contacts add <name> \
|
|
83
83
|
--first-name "John" --last-name "Doe" \
|
|
84
84
|
--email "john@example.com" --phone "+1.5551234567" \
|
|
@@ -115,7 +115,7 @@ connect-brandsight dns add <domain> <type> <name> <data>
|
|
|
115
115
|
## Data Storage
|
|
116
116
|
|
|
117
117
|
```
|
|
118
|
-
~/.
|
|
118
|
+
~/.connectors/connect-brandsight/
|
|
119
119
|
├── current_profile # Active profile name
|
|
120
120
|
└── profiles/
|
|
121
121
|
├── default.json # Default profile
|