@hasna/connectors 1.1.12 → 1.1.14
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/bin/index.js +230 -156
- package/bin/mcp.js +115 -41
- package/bin/serve.js +144 -68
- package/dist/lib/lock.d.ts +22 -0
- package/dist/lib/lock.test.d.ts +1 -0
- package/dist/server/auth.d.ts +4 -2
- package/package.json +1 -2
package/bin/index.js
CHANGED
|
@@ -9631,11 +9631,78 @@ var init_installer = __esm(() => {
|
|
|
9631
9631
|
CONNECTORS_DIR = resolveConnectorsDir();
|
|
9632
9632
|
});
|
|
9633
9633
|
|
|
9634
|
+
// src/lib/lock.ts
|
|
9635
|
+
import { openSync, closeSync, unlinkSync, existsSync as existsSync3 } from "fs";
|
|
9636
|
+
import { join as join3 } from "path";
|
|
9637
|
+
import { homedir as homedir2 } from "os";
|
|
9638
|
+
import { mkdirSync as mkdirSync2 } from "fs";
|
|
9639
|
+
function lockPath(connector) {
|
|
9640
|
+
const dir = join3(homedir2(), ".connectors", `connect-${connector}`);
|
|
9641
|
+
mkdirSync2(dir, { recursive: true });
|
|
9642
|
+
return join3(dir, ".write.lock");
|
|
9643
|
+
}
|
|
9644
|
+
function isStale(path) {
|
|
9645
|
+
try {
|
|
9646
|
+
const { statSync: statSync2 } = __require("fs");
|
|
9647
|
+
const stat = statSync2(path);
|
|
9648
|
+
return Date.now() - stat.mtimeMs > STALE_LOCK_MS;
|
|
9649
|
+
} catch {
|
|
9650
|
+
return false;
|
|
9651
|
+
}
|
|
9652
|
+
}
|
|
9653
|
+
function tryAcquire(path) {
|
|
9654
|
+
if (existsSync3(path) && isStale(path)) {
|
|
9655
|
+
try {
|
|
9656
|
+
unlinkSync(path);
|
|
9657
|
+
} catch {}
|
|
9658
|
+
}
|
|
9659
|
+
try {
|
|
9660
|
+
const fd = openSync(path, "wx");
|
|
9661
|
+
closeSync(fd);
|
|
9662
|
+
return true;
|
|
9663
|
+
} catch (e) {
|
|
9664
|
+
if (e.code === "EEXIST")
|
|
9665
|
+
return false;
|
|
9666
|
+
throw e;
|
|
9667
|
+
}
|
|
9668
|
+
}
|
|
9669
|
+
function release(path) {
|
|
9670
|
+
try {
|
|
9671
|
+
unlinkSync(path);
|
|
9672
|
+
} catch {}
|
|
9673
|
+
}
|
|
9674
|
+
async function withWriteLock(connector, fn) {
|
|
9675
|
+
const path = lockPath(connector);
|
|
9676
|
+
const deadline = Date.now() + LOCK_TIMEOUT_MS;
|
|
9677
|
+
while (Date.now() < deadline) {
|
|
9678
|
+
if (tryAcquire(path)) {
|
|
9679
|
+
try {
|
|
9680
|
+
return await fn();
|
|
9681
|
+
} finally {
|
|
9682
|
+
release(path);
|
|
9683
|
+
}
|
|
9684
|
+
}
|
|
9685
|
+
await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_MS));
|
|
9686
|
+
}
|
|
9687
|
+
throw new LockTimeoutError(connector);
|
|
9688
|
+
}
|
|
9689
|
+
var LOCK_TIMEOUT_MS = 5000, LOCK_RETRY_MS = 100, STALE_LOCK_MS = 30000, LockTimeoutError;
|
|
9690
|
+
var init_lock = __esm(() => {
|
|
9691
|
+
LockTimeoutError = class LockTimeoutError extends Error {
|
|
9692
|
+
connector;
|
|
9693
|
+
constructor(connector) {
|
|
9694
|
+
super(`Could not acquire write lock for connector "${connector}" within ${LOCK_TIMEOUT_MS}ms. Another agent may be writing. Try again shortly.`);
|
|
9695
|
+
this.connector = connector;
|
|
9696
|
+
this.name = "LockTimeoutError";
|
|
9697
|
+
}
|
|
9698
|
+
};
|
|
9699
|
+
});
|
|
9700
|
+
|
|
9634
9701
|
// src/server/auth.ts
|
|
9635
|
-
import { existsSync as
|
|
9702
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, readdirSync as readdirSync2, rmSync as rmSync2, statSync as statSync2 } from "fs";
|
|
9636
9703
|
import { randomBytes } from "crypto";
|
|
9637
|
-
import { homedir as
|
|
9638
|
-
import { join as
|
|
9704
|
+
import { homedir as homedir3 } from "os";
|
|
9705
|
+
import { join as join4 } from "path";
|
|
9639
9706
|
function getAuthType(name) {
|
|
9640
9707
|
const docs = getConnectorDocs(name);
|
|
9641
9708
|
if (!docs?.auth)
|
|
@@ -9649,12 +9716,12 @@ function getAuthType(name) {
|
|
|
9649
9716
|
}
|
|
9650
9717
|
function getConnectorConfigDir(name) {
|
|
9651
9718
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
9652
|
-
return
|
|
9719
|
+
return join4(homedir3(), ".connectors", connectorName);
|
|
9653
9720
|
}
|
|
9654
9721
|
function getCurrentProfile(name) {
|
|
9655
9722
|
const configDir = getConnectorConfigDir(name);
|
|
9656
|
-
const currentProfileFile =
|
|
9657
|
-
if (
|
|
9723
|
+
const currentProfileFile = join4(configDir, "current_profile");
|
|
9724
|
+
if (existsSync4(currentProfileFile)) {
|
|
9658
9725
|
try {
|
|
9659
9726
|
return readFileSync3(currentProfileFile, "utf-8").trim() || "default";
|
|
9660
9727
|
} catch {
|
|
@@ -9668,14 +9735,14 @@ function loadProfileConfig(name) {
|
|
|
9668
9735
|
const profile = getCurrentProfile(name);
|
|
9669
9736
|
let flatConfig = {};
|
|
9670
9737
|
let dirConfig = {};
|
|
9671
|
-
const profileFile =
|
|
9672
|
-
if (
|
|
9738
|
+
const profileFile = join4(configDir, "profiles", `${profile}.json`);
|
|
9739
|
+
if (existsSync4(profileFile)) {
|
|
9673
9740
|
try {
|
|
9674
9741
|
flatConfig = JSON.parse(readFileSync3(profileFile, "utf-8"));
|
|
9675
9742
|
} catch {}
|
|
9676
9743
|
}
|
|
9677
|
-
const profileDirConfig =
|
|
9678
|
-
if (
|
|
9744
|
+
const profileDirConfig = join4(configDir, "profiles", profile, "config.json");
|
|
9745
|
+
if (existsSync4(profileDirConfig)) {
|
|
9679
9746
|
try {
|
|
9680
9747
|
dirConfig = JSON.parse(readFileSync3(profileDirConfig, "utf-8"));
|
|
9681
9748
|
} catch {}
|
|
@@ -9688,8 +9755,8 @@ function loadProfileConfig(name) {
|
|
|
9688
9755
|
function loadTokens(name) {
|
|
9689
9756
|
const configDir = getConnectorConfigDir(name);
|
|
9690
9757
|
const profile = getCurrentProfile(name);
|
|
9691
|
-
const tokensFile =
|
|
9692
|
-
if (
|
|
9758
|
+
const tokensFile = join4(configDir, "profiles", profile, "tokens.json");
|
|
9759
|
+
if (existsSync4(tokensFile)) {
|
|
9693
9760
|
try {
|
|
9694
9761
|
return JSON.parse(readFileSync3(tokensFile, "utf-8"));
|
|
9695
9762
|
} catch {
|
|
@@ -9740,15 +9807,18 @@ function getEnvVars(name) {
|
|
|
9740
9807
|
const docs = getConnectorDocs(name);
|
|
9741
9808
|
return docs?.envVars || [];
|
|
9742
9809
|
}
|
|
9743
|
-
function saveApiKey(name, key, field) {
|
|
9810
|
+
async function saveApiKey(name, key, field) {
|
|
9811
|
+
return withWriteLock(name, () => _saveApiKey(name, key, field));
|
|
9812
|
+
}
|
|
9813
|
+
function _saveApiKey(name, key, field) {
|
|
9744
9814
|
const configDir = getConnectorConfigDir(name);
|
|
9745
9815
|
const profile = getCurrentProfile(name);
|
|
9746
9816
|
const keyField = field || guessKeyField(name);
|
|
9747
9817
|
if (keyField === "clientId" || keyField === "clientSecret") {
|
|
9748
|
-
const credentialsFile =
|
|
9749
|
-
|
|
9818
|
+
const credentialsFile = join4(configDir, "credentials.json");
|
|
9819
|
+
mkdirSync3(configDir, { recursive: true });
|
|
9750
9820
|
let creds = {};
|
|
9751
|
-
if (
|
|
9821
|
+
if (existsSync4(credentialsFile)) {
|
|
9752
9822
|
try {
|
|
9753
9823
|
creds = JSON.parse(readFileSync3(credentialsFile, "utf-8"));
|
|
9754
9824
|
} catch {}
|
|
@@ -9757,9 +9827,9 @@ function saveApiKey(name, key, field) {
|
|
|
9757
9827
|
writeFileSync2(credentialsFile, JSON.stringify(creds, null, 2));
|
|
9758
9828
|
return;
|
|
9759
9829
|
}
|
|
9760
|
-
const profileFile =
|
|
9761
|
-
const profileDir =
|
|
9762
|
-
if (
|
|
9830
|
+
const profileFile = join4(configDir, "profiles", `${profile}.json`);
|
|
9831
|
+
const profileDir = join4(configDir, "profiles", profile);
|
|
9832
|
+
if (existsSync4(profileFile)) {
|
|
9763
9833
|
let config = {};
|
|
9764
9834
|
try {
|
|
9765
9835
|
config = JSON.parse(readFileSync3(profileFile, "utf-8"));
|
|
@@ -9768,10 +9838,10 @@ function saveApiKey(name, key, field) {
|
|
|
9768
9838
|
writeFileSync2(profileFile, JSON.stringify(config, null, 2));
|
|
9769
9839
|
return;
|
|
9770
9840
|
}
|
|
9771
|
-
if (
|
|
9772
|
-
const configFile =
|
|
9841
|
+
if (existsSync4(profileDir)) {
|
|
9842
|
+
const configFile = join4(profileDir, "config.json");
|
|
9773
9843
|
let config = {};
|
|
9774
|
-
if (
|
|
9844
|
+
if (existsSync4(configFile)) {
|
|
9775
9845
|
try {
|
|
9776
9846
|
config = JSON.parse(readFileSync3(configFile, "utf-8"));
|
|
9777
9847
|
} catch {}
|
|
@@ -9780,8 +9850,8 @@ function saveApiKey(name, key, field) {
|
|
|
9780
9850
|
writeFileSync2(configFile, JSON.stringify(config, null, 2));
|
|
9781
9851
|
return;
|
|
9782
9852
|
}
|
|
9783
|
-
|
|
9784
|
-
writeFileSync2(
|
|
9853
|
+
mkdirSync3(profileDir, { recursive: true });
|
|
9854
|
+
writeFileSync2(join4(profileDir, "config.json"), JSON.stringify({ [keyField]: key }, null, 2));
|
|
9785
9855
|
}
|
|
9786
9856
|
function guessKeyField(name) {
|
|
9787
9857
|
const docs = getConnectorDocs(name);
|
|
@@ -9799,8 +9869,8 @@ function guessKeyField(name) {
|
|
|
9799
9869
|
}
|
|
9800
9870
|
function getOAuthConfig(name) {
|
|
9801
9871
|
const configDir = getConnectorConfigDir(name);
|
|
9802
|
-
const credentialsFile =
|
|
9803
|
-
if (
|
|
9872
|
+
const credentialsFile = join4(configDir, "credentials.json");
|
|
9873
|
+
if (existsSync4(credentialsFile)) {
|
|
9804
9874
|
try {
|
|
9805
9875
|
const creds = JSON.parse(readFileSync3(credentialsFile, "utf-8"));
|
|
9806
9876
|
return { clientId: creds.clientId, clientSecret: creds.clientSecret };
|
|
@@ -9881,12 +9951,15 @@ async function exchangeOAuthCode(name, code, redirectUri) {
|
|
|
9881
9951
|
function saveOAuthTokens(name, tokens) {
|
|
9882
9952
|
const configDir = getConnectorConfigDir(name);
|
|
9883
9953
|
const profile = getCurrentProfile(name);
|
|
9884
|
-
const profileDir =
|
|
9885
|
-
|
|
9886
|
-
const tokensFile =
|
|
9954
|
+
const profileDir = join4(configDir, "profiles", profile);
|
|
9955
|
+
mkdirSync3(profileDir, { recursive: true });
|
|
9956
|
+
const tokensFile = join4(profileDir, "tokens.json");
|
|
9887
9957
|
writeFileSync2(tokensFile, JSON.stringify(tokens, null, 2), { mode: 384 });
|
|
9888
9958
|
}
|
|
9889
9959
|
async function refreshOAuthToken(name) {
|
|
9960
|
+
return withWriteLock(name, () => _refreshOAuthToken(name));
|
|
9961
|
+
}
|
|
9962
|
+
async function _refreshOAuthToken(name) {
|
|
9890
9963
|
const oauthConfig = getOAuthConfig(name);
|
|
9891
9964
|
const currentTokens = loadTokens(name);
|
|
9892
9965
|
if (!oauthConfig.clientId || !oauthConfig.clientSecret) {
|
|
@@ -9923,14 +9996,14 @@ async function refreshOAuthToken(name) {
|
|
|
9923
9996
|
}
|
|
9924
9997
|
function listProfiles(name) {
|
|
9925
9998
|
const configDir = getConnectorConfigDir(name);
|
|
9926
|
-
const profilesDir =
|
|
9927
|
-
if (!
|
|
9999
|
+
const profilesDir = join4(configDir, "profiles");
|
|
10000
|
+
if (!existsSync4(profilesDir))
|
|
9928
10001
|
return ["default"];
|
|
9929
10002
|
const seen = new Set;
|
|
9930
10003
|
try {
|
|
9931
10004
|
const entries = readdirSync2(profilesDir);
|
|
9932
10005
|
for (const entry of entries) {
|
|
9933
|
-
const fullPath =
|
|
10006
|
+
const fullPath = join4(profilesDir, entry);
|
|
9934
10007
|
const stat = statSync2(fullPath);
|
|
9935
10008
|
if (stat.isDirectory()) {
|
|
9936
10009
|
seen.add(entry);
|
|
@@ -9944,24 +10017,24 @@ function listProfiles(name) {
|
|
|
9944
10017
|
}
|
|
9945
10018
|
function switchProfile(name, profile) {
|
|
9946
10019
|
const configDir = getConnectorConfigDir(name);
|
|
9947
|
-
|
|
9948
|
-
writeFileSync2(
|
|
10020
|
+
mkdirSync3(configDir, { recursive: true });
|
|
10021
|
+
writeFileSync2(join4(configDir, "current_profile"), profile);
|
|
9949
10022
|
}
|
|
9950
10023
|
function deleteProfile(name, profile) {
|
|
9951
10024
|
if (profile === "default")
|
|
9952
10025
|
return false;
|
|
9953
10026
|
const configDir = getConnectorConfigDir(name);
|
|
9954
|
-
const profilesDir =
|
|
9955
|
-
const profileFile =
|
|
9956
|
-
if (
|
|
10027
|
+
const profilesDir = join4(configDir, "profiles");
|
|
10028
|
+
const profileFile = join4(profilesDir, `${profile}.json`);
|
|
10029
|
+
if (existsSync4(profileFile)) {
|
|
9957
10030
|
rmSync2(profileFile);
|
|
9958
10031
|
if (getCurrentProfile(name) === profile) {
|
|
9959
10032
|
switchProfile(name, "default");
|
|
9960
10033
|
}
|
|
9961
10034
|
return true;
|
|
9962
10035
|
}
|
|
9963
|
-
const profileDir =
|
|
9964
|
-
if (
|
|
10036
|
+
const profileDir = join4(profilesDir, profile);
|
|
10037
|
+
if (existsSync4(profileDir)) {
|
|
9965
10038
|
rmSync2(profileDir, { recursive: true });
|
|
9966
10039
|
if (getCurrentProfile(name) === profile) {
|
|
9967
10040
|
switchProfile(name, "default");
|
|
@@ -9973,6 +10046,7 @@ function deleteProfile(name, profile) {
|
|
|
9973
10046
|
var FETCH_TIMEOUT = 1e4, oauthStateStore, GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth", GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token", GOOGLE_SCOPES;
|
|
9974
10047
|
var init_auth = __esm(() => {
|
|
9975
10048
|
init_installer();
|
|
10049
|
+
init_lock();
|
|
9976
10050
|
oauthStateStore = new Map;
|
|
9977
10051
|
GOOGLE_SCOPES = {
|
|
9978
10052
|
gmail: [
|
|
@@ -10016,14 +10090,14 @@ var init_auth = __esm(() => {
|
|
|
10016
10090
|
|
|
10017
10091
|
// src/db/database.ts
|
|
10018
10092
|
import { Database } from "bun:sqlite";
|
|
10019
|
-
import { join as
|
|
10020
|
-
import { homedir as
|
|
10021
|
-
import { mkdirSync as
|
|
10093
|
+
import { join as join6 } from "path";
|
|
10094
|
+
import { homedir as homedir4 } from "os";
|
|
10095
|
+
import { mkdirSync as mkdirSync4 } from "fs";
|
|
10022
10096
|
function getDatabase(path) {
|
|
10023
10097
|
if (_db)
|
|
10024
10098
|
return _db;
|
|
10025
10099
|
const dbPath = path ?? DB_PATH;
|
|
10026
|
-
|
|
10100
|
+
mkdirSync4(join6(dbPath, ".."), { recursive: true });
|
|
10027
10101
|
_db = new Database(dbPath);
|
|
10028
10102
|
_db.run("PRAGMA journal_mode = WAL");
|
|
10029
10103
|
migrate(_db);
|
|
@@ -10046,8 +10120,8 @@ function migrate(db) {
|
|
|
10046
10120
|
}
|
|
10047
10121
|
var DB_DIR, DB_PATH, _db = null;
|
|
10048
10122
|
var init_database = __esm(() => {
|
|
10049
|
-
DB_DIR =
|
|
10050
|
-
DB_PATH =
|
|
10123
|
+
DB_DIR = join6(homedir4(), ".connectors");
|
|
10124
|
+
DB_PATH = join6(DB_DIR, "connectors.db");
|
|
10051
10125
|
});
|
|
10052
10126
|
|
|
10053
10127
|
// src/db/agents.ts
|
|
@@ -10121,10 +10195,10 @@ var exports_serve = {};
|
|
|
10121
10195
|
__export(exports_serve, {
|
|
10122
10196
|
startServer: () => startServer
|
|
10123
10197
|
});
|
|
10124
|
-
import { existsSync as
|
|
10125
|
-
import { join as
|
|
10198
|
+
import { existsSync as existsSync6, readdirSync as readdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync5 } from "fs";
|
|
10199
|
+
import { join as join7, dirname as dirname4, extname, basename } from "path";
|
|
10126
10200
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
10127
|
-
import { homedir as
|
|
10201
|
+
import { homedir as homedir5 } from "os";
|
|
10128
10202
|
function logActivity(action, connector, detail) {
|
|
10129
10203
|
activityLog.unshift({ action, connector, timestamp: Date.now(), detail });
|
|
10130
10204
|
if (activityLog.length > MAX_ACTIVITY_LOG) {
|
|
@@ -10135,20 +10209,20 @@ function resolveDashboardDir() {
|
|
|
10135
10209
|
const candidates = [];
|
|
10136
10210
|
try {
|
|
10137
10211
|
const scriptDir = dirname4(fileURLToPath4(import.meta.url));
|
|
10138
|
-
candidates.push(
|
|
10139
|
-
candidates.push(
|
|
10212
|
+
candidates.push(join7(scriptDir, "..", "dashboard", "dist"));
|
|
10213
|
+
candidates.push(join7(scriptDir, "..", "..", "dashboard", "dist"));
|
|
10140
10214
|
} catch {}
|
|
10141
10215
|
if (process.argv[1]) {
|
|
10142
10216
|
const mainDir = dirname4(process.argv[1]);
|
|
10143
|
-
candidates.push(
|
|
10144
|
-
candidates.push(
|
|
10217
|
+
candidates.push(join7(mainDir, "..", "dashboard", "dist"));
|
|
10218
|
+
candidates.push(join7(mainDir, "..", "..", "dashboard", "dist"));
|
|
10145
10219
|
}
|
|
10146
|
-
candidates.push(
|
|
10220
|
+
candidates.push(join7(process.cwd(), "dashboard", "dist"));
|
|
10147
10221
|
for (const candidate of candidates) {
|
|
10148
|
-
if (
|
|
10222
|
+
if (existsSync6(candidate))
|
|
10149
10223
|
return candidate;
|
|
10150
10224
|
}
|
|
10151
|
-
return
|
|
10225
|
+
return join7(process.cwd(), "dashboard", "dist");
|
|
10152
10226
|
}
|
|
10153
10227
|
function json(data, status = 200, port) {
|
|
10154
10228
|
return new Response(JSON.stringify(data), {
|
|
@@ -10221,7 +10295,7 @@ function oauthPage(type, title, message, hint, extra) {
|
|
|
10221
10295
|
</body></html>`;
|
|
10222
10296
|
}
|
|
10223
10297
|
function serveStaticFile(filePath) {
|
|
10224
|
-
if (!
|
|
10298
|
+
if (!existsSync6(filePath))
|
|
10225
10299
|
return null;
|
|
10226
10300
|
const ext = extname(filePath);
|
|
10227
10301
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
@@ -10245,7 +10319,7 @@ async function startServer(requestedPort, options) {
|
|
|
10245
10319
|
const shouldOpen = options?.open ?? true;
|
|
10246
10320
|
loadConnectorVersions();
|
|
10247
10321
|
const dashboardDir = resolveDashboardDir();
|
|
10248
|
-
const dashboardExists =
|
|
10322
|
+
const dashboardExists = existsSync6(dashboardDir);
|
|
10249
10323
|
if (!dashboardExists) {
|
|
10250
10324
|
console.error(`
|
|
10251
10325
|
Dashboard not found at: ${dashboardDir}`);
|
|
@@ -10320,7 +10394,7 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
10320
10394
|
const body = await req.json();
|
|
10321
10395
|
if (!body.key)
|
|
10322
10396
|
return json({ error: "Missing 'key' in request body" }, 400, port);
|
|
10323
|
-
saveApiKey(name, body.key, body.field);
|
|
10397
|
+
await saveApiKey(name, body.key, body.field);
|
|
10324
10398
|
logActivity("key_saved", name, body.field ? `Field: ${body.field}` : undefined);
|
|
10325
10399
|
return json({ success: true }, 200, port);
|
|
10326
10400
|
} catch (e) {
|
|
@@ -10426,10 +10500,10 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
10426
10500
|
return json({ error: "Invalid connector name" }, 400, port);
|
|
10427
10501
|
try {
|
|
10428
10502
|
const profiles = listProfiles(name);
|
|
10429
|
-
const configDir =
|
|
10430
|
-
const currentProfileFile =
|
|
10503
|
+
const configDir = join7(homedir5(), ".connectors", name.startsWith("connect-") ? name : `connect-${name}`);
|
|
10504
|
+
const currentProfileFile = join7(configDir, "current_profile");
|
|
10431
10505
|
let current = "default";
|
|
10432
|
-
if (
|
|
10506
|
+
if (existsSync6(currentProfileFile)) {
|
|
10433
10507
|
try {
|
|
10434
10508
|
current = readFileSync4(currentProfileFile, "utf-8").trim() || "default";
|
|
10435
10509
|
} catch {}
|
|
@@ -10478,16 +10552,16 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
10478
10552
|
}
|
|
10479
10553
|
if (path === "/api/export" && method === "GET") {
|
|
10480
10554
|
try {
|
|
10481
|
-
const connectDir =
|
|
10555
|
+
const connectDir = join7(homedir5(), ".connectors");
|
|
10482
10556
|
const result = {};
|
|
10483
|
-
if (
|
|
10557
|
+
if (existsSync6(connectDir)) {
|
|
10484
10558
|
const entries = readdirSync3(connectDir, { withFileTypes: true });
|
|
10485
10559
|
for (const entry of entries) {
|
|
10486
10560
|
if (!entry.isDirectory() || !entry.name.startsWith("connect-"))
|
|
10487
10561
|
continue;
|
|
10488
10562
|
const connectorName = entry.name.replace(/^connect-/, "");
|
|
10489
|
-
const profilesDir =
|
|
10490
|
-
if (!
|
|
10563
|
+
const profilesDir = join7(connectDir, entry.name, "profiles");
|
|
10564
|
+
if (!existsSync6(profilesDir))
|
|
10491
10565
|
continue;
|
|
10492
10566
|
const profiles = {};
|
|
10493
10567
|
const profileEntries = readdirSync3(profilesDir, { withFileTypes: true });
|
|
@@ -10495,13 +10569,13 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
10495
10569
|
if (pEntry.isFile() && pEntry.name.endsWith(".json")) {
|
|
10496
10570
|
const profileName = basename(pEntry.name, ".json");
|
|
10497
10571
|
try {
|
|
10498
|
-
const config = JSON.parse(readFileSync4(
|
|
10572
|
+
const config = JSON.parse(readFileSync4(join7(profilesDir, pEntry.name), "utf-8"));
|
|
10499
10573
|
profiles[profileName] = config;
|
|
10500
10574
|
} catch {}
|
|
10501
10575
|
}
|
|
10502
10576
|
if (pEntry.isDirectory()) {
|
|
10503
|
-
const configPath =
|
|
10504
|
-
if (
|
|
10577
|
+
const configPath = join7(profilesDir, pEntry.name, "config.json");
|
|
10578
|
+
if (existsSync6(configPath)) {
|
|
10505
10579
|
try {
|
|
10506
10580
|
const config = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
10507
10581
|
profiles[pEntry.name] = config;
|
|
@@ -10538,19 +10612,19 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
10538
10612
|
return json({ error: "Invalid import format: missing 'connectors' object" }, 400, port);
|
|
10539
10613
|
}
|
|
10540
10614
|
let imported = 0;
|
|
10541
|
-
const connectDir =
|
|
10615
|
+
const connectDir = join7(homedir5(), ".connectors");
|
|
10542
10616
|
for (const [connectorName, data] of Object.entries(body.connectors)) {
|
|
10543
10617
|
if (!isValidConnectorName(connectorName))
|
|
10544
10618
|
continue;
|
|
10545
10619
|
if (!data.profiles || typeof data.profiles !== "object")
|
|
10546
10620
|
continue;
|
|
10547
|
-
const connectorDir =
|
|
10548
|
-
const profilesDir =
|
|
10621
|
+
const connectorDir = join7(connectDir, `connect-${connectorName}`);
|
|
10622
|
+
const profilesDir = join7(connectorDir, "profiles");
|
|
10549
10623
|
for (const [profileName, config] of Object.entries(data.profiles)) {
|
|
10550
10624
|
if (!config || typeof config !== "object")
|
|
10551
10625
|
continue;
|
|
10552
|
-
|
|
10553
|
-
const profileFile =
|
|
10626
|
+
mkdirSync5(profilesDir, { recursive: true });
|
|
10627
|
+
const profileFile = join7(profilesDir, `${profileName}.json`);
|
|
10554
10628
|
writeFileSync3(profileFile, JSON.stringify(config, null, 2));
|
|
10555
10629
|
imported++;
|
|
10556
10630
|
}
|
|
@@ -10606,12 +10680,12 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
10606
10680
|
}
|
|
10607
10681
|
if (dashboardExists && (method === "GET" || method === "HEAD")) {
|
|
10608
10682
|
if (path !== "/") {
|
|
10609
|
-
const filePath =
|
|
10683
|
+
const filePath = join7(dashboardDir, path);
|
|
10610
10684
|
const res2 = serveStaticFile(filePath);
|
|
10611
10685
|
if (res2)
|
|
10612
10686
|
return res2;
|
|
10613
10687
|
}
|
|
10614
|
-
const indexPath =
|
|
10688
|
+
const indexPath = join7(dashboardDir, "index.html");
|
|
10615
10689
|
const res = serveStaticFile(indexPath);
|
|
10616
10690
|
if (res)
|
|
10617
10691
|
return res;
|
|
@@ -12155,9 +12229,9 @@ function App({ initialConnectors, overwrite = false }) {
|
|
|
12155
12229
|
init_registry();
|
|
12156
12230
|
init_installer();
|
|
12157
12231
|
init_auth();
|
|
12158
|
-
import { readdirSync as readdirSync4, existsSync as
|
|
12159
|
-
import { homedir as
|
|
12160
|
-
import { join as
|
|
12232
|
+
import { readdirSync as readdirSync4, existsSync as existsSync7, statSync as statSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync6 } from "fs";
|
|
12233
|
+
import { homedir as homedir6 } from "os";
|
|
12234
|
+
import { join as join8, relative } from "path";
|
|
12161
12235
|
|
|
12162
12236
|
// src/lib/test-endpoints.ts
|
|
12163
12237
|
var TEST_ENDPOINTS = {
|
|
@@ -12358,17 +12432,17 @@ var TEST_ENDPOINTS = {
|
|
|
12358
12432
|
import { createInterface } from "readline";
|
|
12359
12433
|
|
|
12360
12434
|
// src/lib/runner.ts
|
|
12361
|
-
import { existsSync as
|
|
12362
|
-
import { join as
|
|
12435
|
+
import { existsSync as existsSync5 } from "fs";
|
|
12436
|
+
import { join as join5, dirname as dirname3 } from "path";
|
|
12363
12437
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
12364
12438
|
import { spawn } from "child_process";
|
|
12365
12439
|
var __dirname3 = dirname3(fileURLToPath3(import.meta.url));
|
|
12366
12440
|
function resolveConnectorsDir2() {
|
|
12367
|
-
const fromBin =
|
|
12368
|
-
if (
|
|
12441
|
+
const fromBin = join5(__dirname3, "..", "connectors");
|
|
12442
|
+
if (existsSync5(fromBin))
|
|
12369
12443
|
return fromBin;
|
|
12370
|
-
const fromSrc =
|
|
12371
|
-
if (
|
|
12444
|
+
const fromSrc = join5(__dirname3, "..", "..", "connectors");
|
|
12445
|
+
if (existsSync5(fromSrc))
|
|
12372
12446
|
return fromSrc;
|
|
12373
12447
|
return fromBin;
|
|
12374
12448
|
}
|
|
@@ -12408,9 +12482,9 @@ function buildEnvWithCredentials(connectorName, baseEnv) {
|
|
|
12408
12482
|
}
|
|
12409
12483
|
function getConnectorCliPath(name) {
|
|
12410
12484
|
const safeName = name.replace(/[^a-z0-9-]/g, "");
|
|
12411
|
-
const connectorDir =
|
|
12412
|
-
const cliPath =
|
|
12413
|
-
if (
|
|
12485
|
+
const connectorDir = join5(CONNECTORS_DIR2, `connect-${safeName}`);
|
|
12486
|
+
const cliPath = join5(connectorDir, "src", "cli", "index.ts");
|
|
12487
|
+
if (existsSync5(cliPath))
|
|
12414
12488
|
return cliPath;
|
|
12415
12489
|
return null;
|
|
12416
12490
|
}
|
|
@@ -12523,7 +12597,7 @@ Run 'connectors --help' for full usage.`);
|
|
|
12523
12597
|
function listFilesRecursive(dir, base = dir) {
|
|
12524
12598
|
const files = [];
|
|
12525
12599
|
for (const entry of readdirSync4(dir)) {
|
|
12526
|
-
const fullPath =
|
|
12600
|
+
const fullPath = join8(dir, entry);
|
|
12527
12601
|
if (statSync3(fullPath).isDirectory()) {
|
|
12528
12602
|
files.push(...listFilesRecursive(fullPath, base));
|
|
12529
12603
|
} else {
|
|
@@ -12572,7 +12646,7 @@ program2.command("install").alias("add").argument("[connectors...]", "Connectors
|
|
|
12572
12646
|
}
|
|
12573
12647
|
if (options.dryRun) {
|
|
12574
12648
|
const installed = getInstalledConnectors();
|
|
12575
|
-
const destDir =
|
|
12649
|
+
const destDir = join8(process.cwd(), ".connectors");
|
|
12576
12650
|
const actions = [];
|
|
12577
12651
|
for (const name of connectors) {
|
|
12578
12652
|
if (!/^[a-z0-9-]+$/.test(name)) {
|
|
@@ -12590,7 +12664,7 @@ program2.command("install").alias("add").argument("[connectors...]", "Connectors
|
|
|
12590
12664
|
}
|
|
12591
12665
|
const connectorDirName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
12592
12666
|
const sourcePath = getConnectorPath(name);
|
|
12593
|
-
const destPath =
|
|
12667
|
+
const destPath = join8(destDir, connectorDirName);
|
|
12594
12668
|
const alreadyInstalled = installed.includes(name);
|
|
12595
12669
|
const files = listFilesRecursive(sourcePath);
|
|
12596
12670
|
const importLine = `export * as ${name} from './${connectorDirName}/src/index.js';`;
|
|
@@ -13094,15 +13168,15 @@ Updating ${toUpdate.length} connector(s)...
|
|
|
13094
13168
|
});
|
|
13095
13169
|
program2.command("status").option("--json", "Output as JSON", false).description("Show auth status of all configured connectors (project + global)").action((options) => {
|
|
13096
13170
|
const installed = getInstalledConnectors();
|
|
13097
|
-
const configDir =
|
|
13171
|
+
const configDir = join8(homedir6(), ".connectors");
|
|
13098
13172
|
const seen = new Set;
|
|
13099
13173
|
const allStatuses = [];
|
|
13100
13174
|
function buildStatusEntry(name, source) {
|
|
13101
13175
|
const auth = getAuthStatus(name);
|
|
13102
13176
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
13103
|
-
const currentProfileFile =
|
|
13177
|
+
const currentProfileFile = join8(configDir, connectorName, "current_profile");
|
|
13104
13178
|
let profile = "default";
|
|
13105
|
-
if (
|
|
13179
|
+
if (existsSync7(currentProfileFile)) {
|
|
13106
13180
|
try {
|
|
13107
13181
|
profile = readFileSync5(currentProfileFile, "utf-8").trim() || "default";
|
|
13108
13182
|
} catch {}
|
|
@@ -13140,13 +13214,13 @@ program2.command("status").option("--json", "Output as JSON", false).description
|
|
|
13140
13214
|
seen.add(name);
|
|
13141
13215
|
allStatuses.push(buildStatusEntry(name, "project"));
|
|
13142
13216
|
}
|
|
13143
|
-
if (
|
|
13217
|
+
if (existsSync7(configDir)) {
|
|
13144
13218
|
try {
|
|
13145
13219
|
const globalDirs = readdirSync4(configDir).filter((f) => {
|
|
13146
13220
|
if (!f.startsWith("connect-"))
|
|
13147
13221
|
return false;
|
|
13148
13222
|
try {
|
|
13149
|
-
return statSync3(
|
|
13223
|
+
return statSync3(join8(configDir, f)).isDirectory();
|
|
13150
13224
|
} catch {
|
|
13151
13225
|
return false;
|
|
13152
13226
|
}
|
|
@@ -13420,7 +13494,7 @@ Open this URL to authenticate:
|
|
|
13420
13494
|
return;
|
|
13421
13495
|
}
|
|
13422
13496
|
if (options.key) {
|
|
13423
|
-
saveApiKey(connector, options.key, options.field || undefined);
|
|
13497
|
+
await saveApiKey(connector, options.key, options.field || undefined);
|
|
13424
13498
|
const statusAfter2 = getAuthStatus(connector);
|
|
13425
13499
|
if (options.json) {
|
|
13426
13500
|
console.log(JSON.stringify({
|
|
@@ -13494,7 +13568,7 @@ Open this URL to authenticate:
|
|
|
13494
13568
|
process.exit(1);
|
|
13495
13569
|
return;
|
|
13496
13570
|
}
|
|
13497
|
-
saveApiKey(connector, key.trim(), options.field || undefined);
|
|
13571
|
+
await saveApiKey(connector, key.trim(), options.field || undefined);
|
|
13498
13572
|
const statusAfter = getAuthStatus(connector);
|
|
13499
13573
|
console.log(chalk2.green(`
|
|
13500
13574
|
\u2713 API key saved for ${meta.displayName}`));
|
|
@@ -13511,15 +13585,15 @@ program2.command("init").option("--json", "Output presets and suggestions as JSO
|
|
|
13511
13585
|
{ key: "commerce", emoji: "\uD83D\uDCB3", label: "Commerce", connectors: ["stripe", "shopify", "paypal", "revolut", "mercury"], description: "Commerce and finance" },
|
|
13512
13586
|
{ key: "google", emoji: "\uD83D\uDCC1", label: "Google Workspace", connectors: ["gmail", "googledrive", "googlecalendar", "googledocs", "googlesheets"], description: "Google Workspace suite" }
|
|
13513
13587
|
];
|
|
13514
|
-
const connectorsHome =
|
|
13588
|
+
const connectorsHome = join8(homedir6(), ".connectors");
|
|
13515
13589
|
let configuredCount = 0;
|
|
13516
13590
|
const configuredNames = [];
|
|
13517
13591
|
try {
|
|
13518
|
-
if (
|
|
13519
|
-
const entries = readdirSync4(connectorsHome).filter((e) => e.startsWith("connect-") && statSync3(
|
|
13592
|
+
if (existsSync7(connectorsHome)) {
|
|
13593
|
+
const entries = readdirSync4(connectorsHome).filter((e) => e.startsWith("connect-") && statSync3(join8(connectorsHome, e)).isDirectory());
|
|
13520
13594
|
for (const entry of entries) {
|
|
13521
|
-
const profilesDir =
|
|
13522
|
-
if (
|
|
13595
|
+
const profilesDir = join8(connectorsHome, entry, "profiles");
|
|
13596
|
+
if (existsSync7(profilesDir)) {
|
|
13523
13597
|
configuredCount++;
|
|
13524
13598
|
configuredNames.push(entry.replace(/^connect-/, ""));
|
|
13525
13599
|
}
|
|
@@ -13617,42 +13691,42 @@ function redactSecrets(obj) {
|
|
|
13617
13691
|
return obj;
|
|
13618
13692
|
}
|
|
13619
13693
|
program2.command("export").option("-o, --output <file>", "Write to file instead of stdout").option("--include-secrets", "Include secrets in plaintext (dangerous \u2014 use only for backup/restore)").description("Export all connector credentials as JSON backup").action((options) => {
|
|
13620
|
-
const connectDir =
|
|
13694
|
+
const connectDir = join8(homedir6(), ".connectors");
|
|
13621
13695
|
const result = {};
|
|
13622
|
-
if (
|
|
13696
|
+
if (existsSync7(connectDir)) {
|
|
13623
13697
|
for (const entry of readdirSync4(connectDir)) {
|
|
13624
|
-
const entryPath =
|
|
13698
|
+
const entryPath = join8(connectDir, entry);
|
|
13625
13699
|
if (!statSync3(entryPath).isDirectory() || !entry.startsWith("connect-"))
|
|
13626
13700
|
continue;
|
|
13627
13701
|
const connectorName = entry.replace(/^connect-/, "");
|
|
13628
13702
|
let credentials = undefined;
|
|
13629
|
-
const credentialsPath =
|
|
13630
|
-
if (
|
|
13703
|
+
const credentialsPath = join8(entryPath, "credentials.json");
|
|
13704
|
+
if (existsSync7(credentialsPath)) {
|
|
13631
13705
|
try {
|
|
13632
13706
|
credentials = JSON.parse(readFileSync5(credentialsPath, "utf-8"));
|
|
13633
13707
|
} catch {}
|
|
13634
13708
|
}
|
|
13635
|
-
const profilesDir =
|
|
13636
|
-
if (!
|
|
13709
|
+
const profilesDir = join8(entryPath, "profiles");
|
|
13710
|
+
if (!existsSync7(profilesDir) && !credentials)
|
|
13637
13711
|
continue;
|
|
13638
13712
|
const profiles = {};
|
|
13639
|
-
if (
|
|
13713
|
+
if (existsSync7(profilesDir)) {
|
|
13640
13714
|
for (const pEntry of readdirSync4(profilesDir)) {
|
|
13641
|
-
const pPath =
|
|
13715
|
+
const pPath = join8(profilesDir, pEntry);
|
|
13642
13716
|
if (statSync3(pPath).isFile() && pEntry.endsWith(".json")) {
|
|
13643
13717
|
try {
|
|
13644
13718
|
profiles[pEntry.replace(/\.json$/, "")] = JSON.parse(readFileSync5(pPath, "utf-8"));
|
|
13645
13719
|
} catch {}
|
|
13646
13720
|
} else if (statSync3(pPath).isDirectory()) {
|
|
13647
|
-
const configPath =
|
|
13648
|
-
const tokensPath =
|
|
13721
|
+
const configPath = join8(pPath, "config.json");
|
|
13722
|
+
const tokensPath = join8(pPath, "tokens.json");
|
|
13649
13723
|
let merged = {};
|
|
13650
|
-
if (
|
|
13724
|
+
if (existsSync7(configPath)) {
|
|
13651
13725
|
try {
|
|
13652
13726
|
merged = { ...merged, ...JSON.parse(readFileSync5(configPath, "utf-8")) };
|
|
13653
13727
|
} catch {}
|
|
13654
13728
|
}
|
|
13655
|
-
if (
|
|
13729
|
+
if (existsSync7(tokensPath)) {
|
|
13656
13730
|
try {
|
|
13657
13731
|
merged = { ...merged, ...JSON.parse(readFileSync5(tokensPath, "utf-8")) };
|
|
13658
13732
|
} catch {}
|
|
@@ -13689,7 +13763,7 @@ program2.command("import").argument("<file>", "JSON backup file to import (use -
|
|
|
13689
13763
|
chunks.push(chunk.toString());
|
|
13690
13764
|
raw = chunks.join("");
|
|
13691
13765
|
} else {
|
|
13692
|
-
if (!
|
|
13766
|
+
if (!existsSync7(file)) {
|
|
13693
13767
|
if (options.json) {
|
|
13694
13768
|
console.log(JSON.stringify({ error: `File not found: ${file}` }));
|
|
13695
13769
|
} else {
|
|
@@ -13721,25 +13795,25 @@ program2.command("import").argument("<file>", "JSON backup file to import (use -
|
|
|
13721
13795
|
process.exit(1);
|
|
13722
13796
|
return;
|
|
13723
13797
|
}
|
|
13724
|
-
const connectDir =
|
|
13798
|
+
const connectDir = join8(homedir6(), ".connectors");
|
|
13725
13799
|
let imported = 0;
|
|
13726
13800
|
for (const [connectorName, connData] of Object.entries(data.connectors)) {
|
|
13727
13801
|
if (!/^[a-z0-9-]+$/.test(connectorName))
|
|
13728
13802
|
continue;
|
|
13729
|
-
const connectorDir =
|
|
13803
|
+
const connectorDir = join8(connectDir, `connect-${connectorName}`);
|
|
13730
13804
|
if (connData.credentials && typeof connData.credentials === "object") {
|
|
13731
|
-
|
|
13732
|
-
writeFileSync4(
|
|
13805
|
+
mkdirSync6(connectorDir, { recursive: true });
|
|
13806
|
+
writeFileSync4(join8(connectorDir, "credentials.json"), JSON.stringify(connData.credentials, null, 2));
|
|
13733
13807
|
imported++;
|
|
13734
13808
|
}
|
|
13735
13809
|
if (!connData.profiles || typeof connData.profiles !== "object")
|
|
13736
13810
|
continue;
|
|
13737
|
-
const profilesDir =
|
|
13811
|
+
const profilesDir = join8(connectorDir, "profiles");
|
|
13738
13812
|
for (const [profileName, config] of Object.entries(connData.profiles)) {
|
|
13739
13813
|
if (!config || typeof config !== "object")
|
|
13740
13814
|
continue;
|
|
13741
|
-
|
|
13742
|
-
writeFileSync4(
|
|
13815
|
+
mkdirSync6(profilesDir, { recursive: true });
|
|
13816
|
+
writeFileSync4(join8(profilesDir, `${profileName}.json`), JSON.stringify(config, null, 2));
|
|
13743
13817
|
imported++;
|
|
13744
13818
|
}
|
|
13745
13819
|
}
|
|
@@ -13750,9 +13824,9 @@ program2.command("import").argument("<file>", "JSON backup file to import (use -
|
|
|
13750
13824
|
}
|
|
13751
13825
|
});
|
|
13752
13826
|
program2.command("auth-import").option("--json", "Output as JSON", false).option("-d, --dry-run", "Preview what would be imported without copying", false).option("--force", "Overwrite existing files in ~/.connectors/", false).description("Migrate auth tokens from ~/.connect/ to ~/.connectors/").action((options) => {
|
|
13753
|
-
const oldBase =
|
|
13754
|
-
const newBase =
|
|
13755
|
-
if (!
|
|
13827
|
+
const oldBase = join8(homedir6(), ".connect");
|
|
13828
|
+
const newBase = join8(homedir6(), ".connectors");
|
|
13829
|
+
if (!existsSync7(oldBase)) {
|
|
13756
13830
|
if (options.json) {
|
|
13757
13831
|
console.log(JSON.stringify({ imported: [], skipped: [], error: null, message: "No ~/.connect/ directory found" }));
|
|
13758
13832
|
} else {
|
|
@@ -13764,7 +13838,7 @@ program2.command("auth-import").option("--json", "Output as JSON", false).option
|
|
|
13764
13838
|
if (!name.startsWith("connect-"))
|
|
13765
13839
|
return false;
|
|
13766
13840
|
try {
|
|
13767
|
-
return statSync3(
|
|
13841
|
+
return statSync3(join8(oldBase, name)).isDirectory();
|
|
13768
13842
|
} catch {
|
|
13769
13843
|
return false;
|
|
13770
13844
|
}
|
|
@@ -13780,8 +13854,8 @@ program2.command("auth-import").option("--json", "Output as JSON", false).option
|
|
|
13780
13854
|
const imported = [];
|
|
13781
13855
|
const skipped = [];
|
|
13782
13856
|
for (const dirName of entries) {
|
|
13783
|
-
const oldDir =
|
|
13784
|
-
const newDir =
|
|
13857
|
+
const oldDir = join8(oldBase, dirName);
|
|
13858
|
+
const newDir = join8(newBase, dirName);
|
|
13785
13859
|
const connectorName = dirName.replace(/^connect-/, "");
|
|
13786
13860
|
const allFiles = listFilesRecursive(oldDir);
|
|
13787
13861
|
const authFiles = allFiles.filter((f) => {
|
|
@@ -13792,15 +13866,15 @@ program2.command("auth-import").option("--json", "Output as JSON", false).option
|
|
|
13792
13866
|
const copiedFiles = [];
|
|
13793
13867
|
const skippedFiles = [];
|
|
13794
13868
|
for (const relFile of authFiles) {
|
|
13795
|
-
const srcPath =
|
|
13796
|
-
const destPath =
|
|
13797
|
-
if (
|
|
13869
|
+
const srcPath = join8(oldDir, relFile);
|
|
13870
|
+
const destPath = join8(newDir, relFile);
|
|
13871
|
+
if (existsSync7(destPath) && !options.force) {
|
|
13798
13872
|
skippedFiles.push(relFile);
|
|
13799
13873
|
continue;
|
|
13800
13874
|
}
|
|
13801
13875
|
if (!options.dryRun) {
|
|
13802
|
-
const parentDir =
|
|
13803
|
-
|
|
13876
|
+
const parentDir = join8(destPath, "..");
|
|
13877
|
+
mkdirSync6(parentDir, { recursive: true });
|
|
13804
13878
|
const content = readFileSync5(srcPath);
|
|
13805
13879
|
writeFileSync4(destPath, content);
|
|
13806
13880
|
}
|
|
@@ -14075,7 +14149,7 @@ Available presets:
|
|
|
14075
14149
|
`));
|
|
14076
14150
|
});
|
|
14077
14151
|
program2.command("whoami").option("--json", "Output as JSON", false).description("Show current setup: config dir, installed connectors, auth status").action((options) => {
|
|
14078
|
-
const configDir =
|
|
14152
|
+
const configDir = join8(homedir6(), ".connectors");
|
|
14079
14153
|
const installed = getInstalledConnectors();
|
|
14080
14154
|
const version = "0.3.1";
|
|
14081
14155
|
let configured = 0;
|
|
@@ -14089,23 +14163,23 @@ program2.command("whoami").option("--json", "Output as JSON", false).description
|
|
|
14089
14163
|
configured++;
|
|
14090
14164
|
else
|
|
14091
14165
|
unconfigured++;
|
|
14092
|
-
const connectorConfigDir =
|
|
14093
|
-
const currentProfileFile =
|
|
14166
|
+
const connectorConfigDir = join8(configDir, name.startsWith("connect-") ? name : `connect-${name}`);
|
|
14167
|
+
const currentProfileFile = join8(connectorConfigDir, "current_profile");
|
|
14094
14168
|
let profile = "default";
|
|
14095
|
-
if (
|
|
14169
|
+
if (existsSync7(currentProfileFile)) {
|
|
14096
14170
|
try {
|
|
14097
14171
|
profile = readFileSync5(currentProfileFile, "utf-8").trim() || "default";
|
|
14098
14172
|
} catch {}
|
|
14099
14173
|
}
|
|
14100
14174
|
connectorDetails.push({ name, configured: auth.configured, authType: auth.type, profile, source: "project" });
|
|
14101
14175
|
}
|
|
14102
|
-
if (
|
|
14176
|
+
if (existsSync7(configDir)) {
|
|
14103
14177
|
try {
|
|
14104
14178
|
const globalDirs = readdirSync4(configDir).filter((f) => {
|
|
14105
14179
|
if (!f.startsWith("connect-"))
|
|
14106
14180
|
return false;
|
|
14107
14181
|
try {
|
|
14108
|
-
return statSync3(
|
|
14182
|
+
return statSync3(join8(configDir, f)).isDirectory();
|
|
14109
14183
|
} catch {
|
|
14110
14184
|
return false;
|
|
14111
14185
|
}
|
|
@@ -14119,9 +14193,9 @@ program2.command("whoami").option("--json", "Output as JSON", false).description
|
|
|
14119
14193
|
continue;
|
|
14120
14194
|
seen.add(name);
|
|
14121
14195
|
configured++;
|
|
14122
|
-
const currentProfileFile =
|
|
14196
|
+
const currentProfileFile = join8(configDir, dir, "current_profile");
|
|
14123
14197
|
let profile = "default";
|
|
14124
|
-
if (
|
|
14198
|
+
if (existsSync7(currentProfileFile)) {
|
|
14125
14199
|
try {
|
|
14126
14200
|
profile = readFileSync5(currentProfileFile, "utf-8").trim() || "default";
|
|
14127
14201
|
} catch {}
|
|
@@ -14134,7 +14208,7 @@ program2.command("whoami").option("--json", "Output as JSON", false).description
|
|
|
14134
14208
|
console.log(JSON.stringify({
|
|
14135
14209
|
version,
|
|
14136
14210
|
configDir,
|
|
14137
|
-
configDirExists:
|
|
14211
|
+
configDirExists: existsSync7(configDir),
|
|
14138
14212
|
installed: installed.length,
|
|
14139
14213
|
configured,
|
|
14140
14214
|
unconfigured,
|
|
@@ -14146,7 +14220,7 @@ program2.command("whoami").option("--json", "Output as JSON", false).description
|
|
|
14146
14220
|
Connectors Setup
|
|
14147
14221
|
`));
|
|
14148
14222
|
console.log(` Version: ${chalk2.cyan(version)}`);
|
|
14149
|
-
console.log(` Config: ${configDir}${
|
|
14223
|
+
console.log(` Config: ${configDir}${existsSync7(configDir) ? "" : chalk2.dim(" (not created yet)")}`);
|
|
14150
14224
|
console.log(` Installed: ${installed.length} connector${installed.length !== 1 ? "s" : ""}`);
|
|
14151
14225
|
console.log(` Configured: ${chalk2.green(String(configured))} ready, ${unconfigured > 0 ? chalk2.red(String(unconfigured)) : chalk2.dim("0")} need auth`);
|
|
14152
14226
|
const projectConnectors = connectorDetails.filter((c) => c.source === "project");
|
|
@@ -14236,16 +14310,16 @@ Testing connector credentials...
|
|
|
14236
14310
|
}
|
|
14237
14311
|
}
|
|
14238
14312
|
if (!apiKey) {
|
|
14239
|
-
const connectorConfigDir =
|
|
14313
|
+
const connectorConfigDir = join8(homedir6(), ".connectors", name.startsWith("connect-") ? name : `connect-${name}`);
|
|
14240
14314
|
let currentProfile = "default";
|
|
14241
|
-
const currentProfileFile =
|
|
14242
|
-
if (
|
|
14315
|
+
const currentProfileFile = join8(connectorConfigDir, "current_profile");
|
|
14316
|
+
if (existsSync7(currentProfileFile)) {
|
|
14243
14317
|
try {
|
|
14244
14318
|
currentProfile = readFileSync5(currentProfileFile, "utf-8").trim() || "default";
|
|
14245
14319
|
} catch {}
|
|
14246
14320
|
}
|
|
14247
|
-
const tokensFile =
|
|
14248
|
-
if (
|
|
14321
|
+
const tokensFile = join8(connectorConfigDir, "profiles", currentProfile, "tokens.json");
|
|
14322
|
+
if (existsSync7(tokensFile)) {
|
|
14249
14323
|
try {
|
|
14250
14324
|
const tokens = JSON.parse(readFileSync5(tokensFile, "utf-8"));
|
|
14251
14325
|
const isExpired = tokens.expiresAt && Date.now() >= tokens.expiresAt - 60000;
|
|
@@ -14265,8 +14339,8 @@ Testing connector credentials...
|
|
|
14265
14339
|
} catch {}
|
|
14266
14340
|
}
|
|
14267
14341
|
if (!apiKey) {
|
|
14268
|
-
const profileFile =
|
|
14269
|
-
if (
|
|
14342
|
+
const profileFile = join8(connectorConfigDir, "profiles", `${currentProfile}.json`);
|
|
14343
|
+
if (existsSync7(profileFile)) {
|
|
14270
14344
|
try {
|
|
14271
14345
|
const config = JSON.parse(readFileSync5(profileFile, "utf-8"));
|
|
14272
14346
|
apiKey = Object.values(config).find((v) => typeof v === "string" && v.length > 0);
|
|
@@ -14274,8 +14348,8 @@ Testing connector credentials...
|
|
|
14274
14348
|
}
|
|
14275
14349
|
}
|
|
14276
14350
|
if (!apiKey) {
|
|
14277
|
-
const profileDirConfig =
|
|
14278
|
-
if (
|
|
14351
|
+
const profileDirConfig = join8(connectorConfigDir, "profiles", currentProfile, "config.json");
|
|
14352
|
+
if (existsSync7(profileDirConfig)) {
|
|
14279
14353
|
try {
|
|
14280
14354
|
const config = JSON.parse(readFileSync5(profileDirConfig, "utf-8"));
|
|
14281
14355
|
apiKey = Object.values(config).find((v) => typeof v === "string" && v.length > 0);
|
|
@@ -14444,7 +14518,7 @@ Setting up ${meta.displayName}...
|
|
|
14444
14518
|
const alreadyInstalled = installed.includes(meta.name);
|
|
14445
14519
|
let installResult;
|
|
14446
14520
|
if (alreadyInstalled && !options.overwrite) {
|
|
14447
|
-
installResult = { success: true, path:
|
|
14521
|
+
installResult = { success: true, path: join8(process.cwd(), ".connectors", `connect-${meta.name}`) };
|
|
14448
14522
|
if (!options.json) {
|
|
14449
14523
|
console.log(` ${chalk2.green("\u2713")} Already installed`);
|
|
14450
14524
|
}
|
|
@@ -14469,7 +14543,7 @@ Setting up ${meta.displayName}...
|
|
|
14469
14543
|
let authConfigured = false;
|
|
14470
14544
|
if (authType === "oauth") {
|
|
14471
14545
|
if (options.key) {
|
|
14472
|
-
saveApiKey(name, options.key, options.field || undefined);
|
|
14546
|
+
await saveApiKey(name, options.key, options.field || undefined);
|
|
14473
14547
|
authConfigured = true;
|
|
14474
14548
|
if (!options.json) {
|
|
14475
14549
|
console.log(` ${chalk2.green("\u2713")} Token saved`);
|
|
@@ -14527,7 +14601,7 @@ Setting up ${meta.displayName}...
|
|
|
14527
14601
|
}
|
|
14528
14602
|
} else {
|
|
14529
14603
|
if (options.key) {
|
|
14530
|
-
saveApiKey(name, options.key, options.field || undefined);
|
|
14604
|
+
await saveApiKey(name, options.key, options.field || undefined);
|
|
14531
14605
|
authConfigured = true;
|
|
14532
14606
|
if (!options.json) {
|
|
14533
14607
|
console.log(` ${chalk2.green("\u2713")} ${authType === "bearer" ? "Bearer token" : "API key"} saved`);
|