@hasna/connectors 1.3.7 → 1.3.8
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 +283 -253
- package/bin/mcp.js +241 -238
- package/bin/serve.js +106 -77
- package/dist/db/database.d.ts +6 -0
- package/dist/index.js +82 -46
- package/dist/lib/llm.d.ts +1 -1
- package/dist/lib/lock.d.ts +1 -1
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -1904,147 +1904,45 @@ var require_commander = __commonJS((exports) => {
|
|
|
1904
1904
|
exports.InvalidOptionArgumentError = InvalidArgumentError;
|
|
1905
1905
|
});
|
|
1906
1906
|
|
|
1907
|
-
// src/lib/llm.ts
|
|
1908
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
1909
|
-
import { join } from "path";
|
|
1910
|
-
import { homedir } from "os";
|
|
1911
|
-
function getLlmConfigPath() {
|
|
1912
|
-
return join(homedir(), ".connectors", "llm.json");
|
|
1913
|
-
}
|
|
1914
|
-
function getLlmConfig() {
|
|
1915
|
-
const path = getLlmConfigPath();
|
|
1916
|
-
if (!existsSync(path))
|
|
1917
|
-
return null;
|
|
1918
|
-
try {
|
|
1919
|
-
return JSON.parse(readFileSync(path, "utf-8"));
|
|
1920
|
-
} catch {
|
|
1921
|
-
return null;
|
|
1922
|
-
}
|
|
1923
|
-
}
|
|
1924
|
-
function saveLlmConfig(config) {
|
|
1925
|
-
const dir = join(homedir(), ".connectors");
|
|
1926
|
-
mkdirSync(dir, { recursive: true });
|
|
1927
|
-
writeFileSync(getLlmConfigPath(), JSON.stringify(config, null, 2));
|
|
1928
|
-
}
|
|
1929
|
-
function setLlmStrip(enabled) {
|
|
1930
|
-
const config = getLlmConfig();
|
|
1931
|
-
if (!config)
|
|
1932
|
-
throw new Error("No LLM config found. Run: connectors llm set --provider <provider> --key <key>");
|
|
1933
|
-
saveLlmConfig({ ...config, strip: enabled });
|
|
1934
|
-
}
|
|
1935
|
-
function maskKey(key) {
|
|
1936
|
-
if (key.length <= 8)
|
|
1937
|
-
return "***";
|
|
1938
|
-
return key.slice(0, 8) + "***";
|
|
1939
|
-
}
|
|
1940
|
-
|
|
1941
|
-
class LLMClient {
|
|
1942
|
-
config;
|
|
1943
|
-
constructor(config) {
|
|
1944
|
-
this.config = config;
|
|
1945
|
-
}
|
|
1946
|
-
static fromConfig() {
|
|
1947
|
-
const config = getLlmConfig();
|
|
1948
|
-
if (!config)
|
|
1949
|
-
return null;
|
|
1950
|
-
return new LLMClient(config);
|
|
1951
|
-
}
|
|
1952
|
-
async complete(prompt, content) {
|
|
1953
|
-
const start = Date.now();
|
|
1954
|
-
const { provider, model, api_key } = this.config;
|
|
1955
|
-
if (provider === "anthropic") {
|
|
1956
|
-
return this._anthropicComplete(prompt, content, start);
|
|
1957
|
-
}
|
|
1958
|
-
const baseUrl = PROVIDER_BASE_URLS[provider];
|
|
1959
|
-
const response = await fetch(`${baseUrl}/chat/completions`, {
|
|
1960
|
-
method: "POST",
|
|
1961
|
-
headers: {
|
|
1962
|
-
"Content-Type": "application/json",
|
|
1963
|
-
Authorization: `Bearer ${api_key}`
|
|
1964
|
-
},
|
|
1965
|
-
body: JSON.stringify({
|
|
1966
|
-
model,
|
|
1967
|
-
messages: [
|
|
1968
|
-
{ role: "system", content: prompt },
|
|
1969
|
-
{ role: "user", content }
|
|
1970
|
-
],
|
|
1971
|
-
temperature: 0,
|
|
1972
|
-
max_tokens: 4096
|
|
1973
|
-
})
|
|
1974
|
-
});
|
|
1975
|
-
if (!response.ok) {
|
|
1976
|
-
const error = await response.text();
|
|
1977
|
-
throw new Error(`LLM request failed (${provider} ${response.status}): ${error}`);
|
|
1978
|
-
}
|
|
1979
|
-
const data = await response.json();
|
|
1980
|
-
return {
|
|
1981
|
-
content: data.choices[0].message.content,
|
|
1982
|
-
provider,
|
|
1983
|
-
model,
|
|
1984
|
-
latency_ms: Date.now() - start
|
|
1985
|
-
};
|
|
1986
|
-
}
|
|
1987
|
-
async _anthropicComplete(prompt, content, start) {
|
|
1988
|
-
const { model, api_key } = this.config;
|
|
1989
|
-
const response = await fetch("https://api.anthropic.com/v1/messages", {
|
|
1990
|
-
method: "POST",
|
|
1991
|
-
headers: {
|
|
1992
|
-
"Content-Type": "application/json",
|
|
1993
|
-
"x-api-key": api_key,
|
|
1994
|
-
"anthropic-version": "2023-06-01"
|
|
1995
|
-
},
|
|
1996
|
-
body: JSON.stringify({
|
|
1997
|
-
model,
|
|
1998
|
-
system: prompt,
|
|
1999
|
-
messages: [{ role: "user", content }],
|
|
2000
|
-
max_tokens: 4096
|
|
2001
|
-
})
|
|
2002
|
-
});
|
|
2003
|
-
if (!response.ok) {
|
|
2004
|
-
const error = await response.text();
|
|
2005
|
-
throw new Error(`LLM request failed (anthropic ${response.status}): ${error}`);
|
|
2006
|
-
}
|
|
2007
|
-
const data = await response.json();
|
|
2008
|
-
return {
|
|
2009
|
-
content: data.content[0].text,
|
|
2010
|
-
provider: "anthropic",
|
|
2011
|
-
model,
|
|
2012
|
-
latency_ms: Date.now() - start
|
|
2013
|
-
};
|
|
2014
|
-
}
|
|
2015
|
-
}
|
|
2016
|
-
var PROVIDER_BASE_URLS, PROVIDER_DEFAULTS;
|
|
2017
|
-
var init_llm = __esm(() => {
|
|
2018
|
-
PROVIDER_BASE_URLS = {
|
|
2019
|
-
cerebras: "https://api.cerebras.ai/v1",
|
|
2020
|
-
groq: "https://api.groq.com/openai/v1",
|
|
2021
|
-
openai: "https://api.openai.com/v1"
|
|
2022
|
-
};
|
|
2023
|
-
PROVIDER_DEFAULTS = {
|
|
2024
|
-
cerebras: { model: "qwen-3-32b" },
|
|
2025
|
-
groq: { model: "llama-3.3-70b-versatile" },
|
|
2026
|
-
openai: { model: "gpt-4o-mini" },
|
|
2027
|
-
anthropic: { model: "claude-haiku-4-5-20251001" }
|
|
2028
|
-
};
|
|
2029
|
-
});
|
|
2030
|
-
|
|
2031
1907
|
// src/db/database.ts
|
|
2032
1908
|
var exports_database = {};
|
|
2033
1909
|
__export(exports_database, {
|
|
2034
1910
|
shortUuid: () => shortUuid,
|
|
2035
1911
|
now: () => now,
|
|
2036
1912
|
getDatabase: () => getDatabase,
|
|
1913
|
+
getConnectorsHome: () => getConnectorsHome,
|
|
2037
1914
|
closeDatabase: () => closeDatabase
|
|
2038
1915
|
});
|
|
2039
1916
|
import { Database } from "bun:sqlite";
|
|
2040
|
-
import { join
|
|
2041
|
-
import { homedir
|
|
2042
|
-
import { mkdirSync
|
|
1917
|
+
import { join } from "path";
|
|
1918
|
+
import { homedir } from "os";
|
|
1919
|
+
import { mkdirSync, existsSync, readdirSync, copyFileSync, statSync } from "fs";
|
|
1920
|
+
function getConnectorsHome() {
|
|
1921
|
+
const home = process.env["HOME"] || process.env["USERPROFILE"] || homedir();
|
|
1922
|
+
const newDir = join(home, ".hasna", "connectors");
|
|
1923
|
+
const oldDir = join(home, ".connectors");
|
|
1924
|
+
if (existsSync(oldDir) && !existsSync(newDir)) {
|
|
1925
|
+
mkdirSync(newDir, { recursive: true });
|
|
1926
|
+
try {
|
|
1927
|
+
for (const file of readdirSync(oldDir)) {
|
|
1928
|
+
const oldPath = join(oldDir, file);
|
|
1929
|
+
const newPath = join(newDir, file);
|
|
1930
|
+
try {
|
|
1931
|
+
if (statSync(oldPath).isFile()) {
|
|
1932
|
+
copyFileSync(oldPath, newPath);
|
|
1933
|
+
}
|
|
1934
|
+
} catch {}
|
|
1935
|
+
}
|
|
1936
|
+
} catch {}
|
|
1937
|
+
}
|
|
1938
|
+
mkdirSync(newDir, { recursive: true });
|
|
1939
|
+
return newDir;
|
|
1940
|
+
}
|
|
2043
1941
|
function getDatabase(path) {
|
|
2044
1942
|
if (_db)
|
|
2045
1943
|
return _db;
|
|
2046
1944
|
const dbPath = path ?? DB_PATH;
|
|
2047
|
-
|
|
1945
|
+
mkdirSync(join(dbPath, ".."), { recursive: true });
|
|
2048
1946
|
_db = new Database(dbPath);
|
|
2049
1947
|
_db.run("PRAGMA journal_mode = WAL");
|
|
2050
1948
|
migrate(_db);
|
|
@@ -2154,8 +2052,132 @@ function migrate(db) {
|
|
|
2154
2052
|
}
|
|
2155
2053
|
var DB_DIR, DB_PATH, _db = null;
|
|
2156
2054
|
var init_database = __esm(() => {
|
|
2157
|
-
DB_DIR =
|
|
2158
|
-
DB_PATH =
|
|
2055
|
+
DB_DIR = getConnectorsHome();
|
|
2056
|
+
DB_PATH = join(DB_DIR, "connectors.db");
|
|
2057
|
+
});
|
|
2058
|
+
|
|
2059
|
+
// src/lib/llm.ts
|
|
2060
|
+
import { existsSync as existsSync2, readFileSync, writeFileSync, mkdirSync as mkdirSync2 } from "fs";
|
|
2061
|
+
import { join as join2 } from "path";
|
|
2062
|
+
function getLlmConfigPath() {
|
|
2063
|
+
return join2(getConnectorsHome(), "llm.json");
|
|
2064
|
+
}
|
|
2065
|
+
function getLlmConfig() {
|
|
2066
|
+
const path = getLlmConfigPath();
|
|
2067
|
+
if (!existsSync2(path))
|
|
2068
|
+
return null;
|
|
2069
|
+
try {
|
|
2070
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
2071
|
+
} catch {
|
|
2072
|
+
return null;
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
function saveLlmConfig(config) {
|
|
2076
|
+
const dir = getConnectorsHome();
|
|
2077
|
+
mkdirSync2(dir, { recursive: true });
|
|
2078
|
+
writeFileSync(getLlmConfigPath(), JSON.stringify(config, null, 2));
|
|
2079
|
+
}
|
|
2080
|
+
function setLlmStrip(enabled) {
|
|
2081
|
+
const config = getLlmConfig();
|
|
2082
|
+
if (!config)
|
|
2083
|
+
throw new Error("No LLM config found. Run: connectors llm set --provider <provider> --key <key>");
|
|
2084
|
+
saveLlmConfig({ ...config, strip: enabled });
|
|
2085
|
+
}
|
|
2086
|
+
function maskKey(key) {
|
|
2087
|
+
if (key.length <= 8)
|
|
2088
|
+
return "***";
|
|
2089
|
+
return key.slice(0, 8) + "***";
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
class LLMClient {
|
|
2093
|
+
config;
|
|
2094
|
+
constructor(config) {
|
|
2095
|
+
this.config = config;
|
|
2096
|
+
}
|
|
2097
|
+
static fromConfig() {
|
|
2098
|
+
const config = getLlmConfig();
|
|
2099
|
+
if (!config)
|
|
2100
|
+
return null;
|
|
2101
|
+
return new LLMClient(config);
|
|
2102
|
+
}
|
|
2103
|
+
async complete(prompt, content) {
|
|
2104
|
+
const start = Date.now();
|
|
2105
|
+
const { provider, model, api_key } = this.config;
|
|
2106
|
+
if (provider === "anthropic") {
|
|
2107
|
+
return this._anthropicComplete(prompt, content, start);
|
|
2108
|
+
}
|
|
2109
|
+
const baseUrl = PROVIDER_BASE_URLS[provider];
|
|
2110
|
+
const response = await fetch(`${baseUrl}/chat/completions`, {
|
|
2111
|
+
method: "POST",
|
|
2112
|
+
headers: {
|
|
2113
|
+
"Content-Type": "application/json",
|
|
2114
|
+
Authorization: `Bearer ${api_key}`
|
|
2115
|
+
},
|
|
2116
|
+
body: JSON.stringify({
|
|
2117
|
+
model,
|
|
2118
|
+
messages: [
|
|
2119
|
+
{ role: "system", content: prompt },
|
|
2120
|
+
{ role: "user", content }
|
|
2121
|
+
],
|
|
2122
|
+
temperature: 0,
|
|
2123
|
+
max_tokens: 4096
|
|
2124
|
+
})
|
|
2125
|
+
});
|
|
2126
|
+
if (!response.ok) {
|
|
2127
|
+
const error = await response.text();
|
|
2128
|
+
throw new Error(`LLM request failed (${provider} ${response.status}): ${error}`);
|
|
2129
|
+
}
|
|
2130
|
+
const data = await response.json();
|
|
2131
|
+
return {
|
|
2132
|
+
content: data.choices[0].message.content,
|
|
2133
|
+
provider,
|
|
2134
|
+
model,
|
|
2135
|
+
latency_ms: Date.now() - start
|
|
2136
|
+
};
|
|
2137
|
+
}
|
|
2138
|
+
async _anthropicComplete(prompt, content, start) {
|
|
2139
|
+
const { model, api_key } = this.config;
|
|
2140
|
+
const response = await fetch("https://api.anthropic.com/v1/messages", {
|
|
2141
|
+
method: "POST",
|
|
2142
|
+
headers: {
|
|
2143
|
+
"Content-Type": "application/json",
|
|
2144
|
+
"x-api-key": api_key,
|
|
2145
|
+
"anthropic-version": "2023-06-01"
|
|
2146
|
+
},
|
|
2147
|
+
body: JSON.stringify({
|
|
2148
|
+
model,
|
|
2149
|
+
system: prompt,
|
|
2150
|
+
messages: [{ role: "user", content }],
|
|
2151
|
+
max_tokens: 4096
|
|
2152
|
+
})
|
|
2153
|
+
});
|
|
2154
|
+
if (!response.ok) {
|
|
2155
|
+
const error = await response.text();
|
|
2156
|
+
throw new Error(`LLM request failed (anthropic ${response.status}): ${error}`);
|
|
2157
|
+
}
|
|
2158
|
+
const data = await response.json();
|
|
2159
|
+
return {
|
|
2160
|
+
content: data.content[0].text,
|
|
2161
|
+
provider: "anthropic",
|
|
2162
|
+
model,
|
|
2163
|
+
latency_ms: Date.now() - start
|
|
2164
|
+
};
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
var PROVIDER_BASE_URLS, PROVIDER_DEFAULTS;
|
|
2168
|
+
var init_llm = __esm(() => {
|
|
2169
|
+
init_database();
|
|
2170
|
+
PROVIDER_BASE_URLS = {
|
|
2171
|
+
cerebras: "https://api.cerebras.ai/v1",
|
|
2172
|
+
groq: "https://api.groq.com/openai/v1",
|
|
2173
|
+
openai: "https://api.openai.com/v1"
|
|
2174
|
+
};
|
|
2175
|
+
PROVIDER_DEFAULTS = {
|
|
2176
|
+
cerebras: { model: "qwen-3-32b" },
|
|
2177
|
+
groq: { model: "llama-3.3-70b-versatile" },
|
|
2178
|
+
openai: { model: "gpt-4o-mini" },
|
|
2179
|
+
anthropic: { model: "claude-haiku-4-5-20251001" }
|
|
2180
|
+
};
|
|
2159
2181
|
});
|
|
2160
2182
|
|
|
2161
2183
|
// src/db/jobs.ts
|
|
@@ -2566,7 +2588,7 @@ var init_synonyms = __esm(() => {
|
|
|
2566
2588
|
});
|
|
2567
2589
|
|
|
2568
2590
|
// src/lib/registry.ts
|
|
2569
|
-
import { existsSync as
|
|
2591
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
2570
2592
|
import { join as join3, dirname } from "path";
|
|
2571
2593
|
import { fileURLToPath } from "url";
|
|
2572
2594
|
function getConnectorsByCategory(category) {
|
|
@@ -2731,13 +2753,13 @@ function loadConnectorVersions() {
|
|
|
2731
2753
|
join3(thisDir, "..", "connectors"),
|
|
2732
2754
|
join3(thisDir, "..", "..", "connectors")
|
|
2733
2755
|
];
|
|
2734
|
-
const connectorsDir = candidates.find((d) =>
|
|
2756
|
+
const connectorsDir = candidates.find((d) => existsSync3(d));
|
|
2735
2757
|
if (!connectorsDir)
|
|
2736
2758
|
return;
|
|
2737
2759
|
for (const connector of CONNECTORS) {
|
|
2738
2760
|
try {
|
|
2739
2761
|
const pkgPath = join3(connectorsDir, `connect-${connector.name}`, "package.json");
|
|
2740
|
-
if (
|
|
2762
|
+
if (existsSync3(pkgPath)) {
|
|
2741
2763
|
const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
|
|
2742
2764
|
connector.version = pkg.version || "0.0.0";
|
|
2743
2765
|
}
|
|
@@ -3152,6 +3174,13 @@ var init_registry = __esm(() => {
|
|
|
3152
3174
|
category: "Data & Analytics",
|
|
3153
3175
|
tags: ["weather", "data"]
|
|
3154
3176
|
},
|
|
3177
|
+
{
|
|
3178
|
+
name: "arxiv",
|
|
3179
|
+
displayName: "arXiv",
|
|
3180
|
+
description: "Research paper search and retrieval",
|
|
3181
|
+
category: "Data & Analytics",
|
|
3182
|
+
tags: ["research", "papers", "academic"]
|
|
3183
|
+
},
|
|
3155
3184
|
{
|
|
3156
3185
|
name: "brandsight",
|
|
3157
3186
|
displayName: "Brandsight",
|
|
@@ -10305,16 +10334,15 @@ var require_cli_spinners = __commonJS((exports, module) => {
|
|
|
10305
10334
|
});
|
|
10306
10335
|
|
|
10307
10336
|
// src/lib/installer.ts
|
|
10308
|
-
import { existsSync as
|
|
10309
|
-
import { homedir as homedir3 } from "os";
|
|
10337
|
+
import { existsSync as existsSync4, cpSync, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2, readdirSync as readdirSync2, statSync as statSync2, rmSync } from "fs";
|
|
10310
10338
|
import { join as join4, dirname as dirname2 } from "path";
|
|
10311
10339
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
10312
10340
|
function resolveConnectorsDir() {
|
|
10313
10341
|
const fromBin = join4(__dirname2, "..", "connectors");
|
|
10314
|
-
if (
|
|
10342
|
+
if (existsSync4(fromBin))
|
|
10315
10343
|
return fromBin;
|
|
10316
10344
|
const fromSrc = join4(__dirname2, "..", "..", "connectors");
|
|
10317
|
-
if (
|
|
10345
|
+
if (existsSync4(fromSrc))
|
|
10318
10346
|
return fromSrc;
|
|
10319
10347
|
return fromBin;
|
|
10320
10348
|
}
|
|
@@ -10323,7 +10351,7 @@ function getConnectorPath(name) {
|
|
|
10323
10351
|
return join4(CONNECTORS_DIR, connectorName);
|
|
10324
10352
|
}
|
|
10325
10353
|
function connectorExists(name) {
|
|
10326
|
-
return
|
|
10354
|
+
return existsSync4(getConnectorPath(name));
|
|
10327
10355
|
}
|
|
10328
10356
|
function installConnector(name, options = {}) {
|
|
10329
10357
|
const { targetDir = process.cwd(), overwrite = false } = options;
|
|
@@ -10338,14 +10366,14 @@ function installConnector(name, options = {}) {
|
|
|
10338
10366
|
const sourcePath = getConnectorPath(name);
|
|
10339
10367
|
const destDir = join4(targetDir, ".connectors");
|
|
10340
10368
|
const destPath = join4(destDir, connectorName);
|
|
10341
|
-
if (!
|
|
10369
|
+
if (!existsSync4(sourcePath)) {
|
|
10342
10370
|
return {
|
|
10343
10371
|
connector: name,
|
|
10344
10372
|
success: false,
|
|
10345
10373
|
error: `Connector '${name}' not found`
|
|
10346
10374
|
};
|
|
10347
10375
|
}
|
|
10348
|
-
if (
|
|
10376
|
+
if (existsSync4(destPath) && !overwrite) {
|
|
10349
10377
|
return {
|
|
10350
10378
|
connector: name,
|
|
10351
10379
|
success: false,
|
|
@@ -10354,21 +10382,21 @@ function installConnector(name, options = {}) {
|
|
|
10354
10382
|
};
|
|
10355
10383
|
}
|
|
10356
10384
|
try {
|
|
10357
|
-
if (!
|
|
10385
|
+
if (!existsSync4(destDir)) {
|
|
10358
10386
|
mkdirSync3(destDir, { recursive: true });
|
|
10359
10387
|
}
|
|
10360
10388
|
cpSync(sourcePath, destPath, { recursive: true });
|
|
10361
|
-
const homeCredDir = join4(
|
|
10362
|
-
if (
|
|
10389
|
+
const homeCredDir = join4(getConnectorsHome(), connectorName);
|
|
10390
|
+
if (existsSync4(homeCredDir)) {
|
|
10363
10391
|
const filesToCopy = ["credentials.json", "current_profile"];
|
|
10364
10392
|
for (const file of filesToCopy) {
|
|
10365
10393
|
const src = join4(homeCredDir, file);
|
|
10366
|
-
if (
|
|
10394
|
+
if (existsSync4(src)) {
|
|
10367
10395
|
cpSync(src, join4(destPath, file));
|
|
10368
10396
|
}
|
|
10369
10397
|
}
|
|
10370
10398
|
const profilesDir = join4(homeCredDir, "profiles");
|
|
10371
|
-
if (
|
|
10399
|
+
if (existsSync4(profilesDir)) {
|
|
10372
10400
|
cpSync(profilesDir, join4(destPath, "profiles"), { recursive: true });
|
|
10373
10401
|
}
|
|
10374
10402
|
}
|
|
@@ -10388,7 +10416,7 @@ function installConnector(name, options = {}) {
|
|
|
10388
10416
|
}
|
|
10389
10417
|
function updateConnectorsIndex(connectorsDir) {
|
|
10390
10418
|
const indexPath = join4(connectorsDir, "index.ts");
|
|
10391
|
-
const connectors =
|
|
10419
|
+
const connectors = readdirSync2(connectorsDir).filter((f) => f.startsWith("connect-") && !f.includes("."));
|
|
10392
10420
|
const exports = connectors.map((c) => {
|
|
10393
10421
|
const name = c.replace("connect-", "");
|
|
10394
10422
|
return `export * as ${name} from './${c}/src/index.js';`;
|
|
@@ -10405,18 +10433,18 @@ ${exports}
|
|
|
10405
10433
|
}
|
|
10406
10434
|
function getInstalledConnectors(targetDir = process.cwd()) {
|
|
10407
10435
|
const connectorsDir = join4(targetDir, ".connectors");
|
|
10408
|
-
if (!
|
|
10436
|
+
if (!existsSync4(connectorsDir)) {
|
|
10409
10437
|
return [];
|
|
10410
10438
|
}
|
|
10411
|
-
return
|
|
10439
|
+
return readdirSync2(connectorsDir).filter((f) => {
|
|
10412
10440
|
const fullPath = join4(connectorsDir, f);
|
|
10413
|
-
return f.startsWith("connect-") &&
|
|
10441
|
+
return f.startsWith("connect-") && statSync2(fullPath).isDirectory();
|
|
10414
10442
|
}).map((f) => f.replace("connect-", ""));
|
|
10415
10443
|
}
|
|
10416
10444
|
function getConnectorDocs(name) {
|
|
10417
10445
|
const connectorPath = getConnectorPath(name);
|
|
10418
10446
|
const claudeMdPath = join4(connectorPath, "CLAUDE.md");
|
|
10419
|
-
if (!
|
|
10447
|
+
if (!existsSync4(claudeMdPath))
|
|
10420
10448
|
return null;
|
|
10421
10449
|
const raw = readFileSync3(claudeMdPath, "utf-8");
|
|
10422
10450
|
return {
|
|
@@ -10459,7 +10487,7 @@ function removeConnector(name, targetDir = process.cwd()) {
|
|
|
10459
10487
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
10460
10488
|
const connectorsDir = join4(targetDir, ".connectors");
|
|
10461
10489
|
const connectorPath = join4(connectorsDir, connectorName);
|
|
10462
|
-
if (!
|
|
10490
|
+
if (!existsSync4(connectorPath)) {
|
|
10463
10491
|
return false;
|
|
10464
10492
|
}
|
|
10465
10493
|
rmSync(connectorPath, { recursive: true });
|
|
@@ -10468,30 +10496,30 @@ function removeConnector(name, targetDir = process.cwd()) {
|
|
|
10468
10496
|
}
|
|
10469
10497
|
var __dirname2, CONNECTORS_DIR;
|
|
10470
10498
|
var init_installer = __esm(() => {
|
|
10499
|
+
init_database();
|
|
10471
10500
|
__dirname2 = dirname2(fileURLToPath2(import.meta.url));
|
|
10472
10501
|
CONNECTORS_DIR = resolveConnectorsDir();
|
|
10473
10502
|
});
|
|
10474
10503
|
|
|
10475
10504
|
// src/lib/lock.ts
|
|
10476
|
-
import { openSync, closeSync, unlinkSync, existsSync as
|
|
10505
|
+
import { openSync, closeSync, unlinkSync, existsSync as existsSync5, statSync as statSync3 } from "fs";
|
|
10477
10506
|
import { join as join5 } from "path";
|
|
10478
|
-
import { homedir as homedir4 } from "os";
|
|
10479
10507
|
import { mkdirSync as mkdirSync4 } from "fs";
|
|
10480
10508
|
function lockPath(connector) {
|
|
10481
|
-
const dir = join5(
|
|
10509
|
+
const dir = join5(getConnectorsHome(), `connect-${connector}`);
|
|
10482
10510
|
mkdirSync4(dir, { recursive: true });
|
|
10483
10511
|
return join5(dir, ".write.lock");
|
|
10484
10512
|
}
|
|
10485
10513
|
function isStale(path) {
|
|
10486
10514
|
try {
|
|
10487
|
-
const stat =
|
|
10515
|
+
const stat = statSync3(path);
|
|
10488
10516
|
return Date.now() - stat.mtimeMs > STALE_LOCK_MS;
|
|
10489
10517
|
} catch {
|
|
10490
10518
|
return false;
|
|
10491
10519
|
}
|
|
10492
10520
|
}
|
|
10493
10521
|
function tryAcquire(path) {
|
|
10494
|
-
if (
|
|
10522
|
+
if (existsSync5(path) && isStale(path)) {
|
|
10495
10523
|
try {
|
|
10496
10524
|
unlinkSync(path);
|
|
10497
10525
|
} catch {}
|
|
@@ -10528,6 +10556,7 @@ async function withWriteLock(connector, fn) {
|
|
|
10528
10556
|
}
|
|
10529
10557
|
var LOCK_TIMEOUT_MS = 5000, LOCK_RETRY_MS = 100, STALE_LOCK_MS = 30000, LockTimeoutError;
|
|
10530
10558
|
var init_lock = __esm(() => {
|
|
10559
|
+
init_database();
|
|
10531
10560
|
LockTimeoutError = class LockTimeoutError extends Error {
|
|
10532
10561
|
connector;
|
|
10533
10562
|
constructor(connector) {
|
|
@@ -10539,9 +10568,8 @@ var init_lock = __esm(() => {
|
|
|
10539
10568
|
});
|
|
10540
10569
|
|
|
10541
10570
|
// src/server/auth.ts
|
|
10542
|
-
import { existsSync as
|
|
10571
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync5, readdirSync as readdirSync3, rmSync as rmSync2, statSync as statSync4 } from "fs";
|
|
10543
10572
|
import { randomBytes } from "crypto";
|
|
10544
|
-
import { homedir as homedir5 } from "os";
|
|
10545
10573
|
import { join as join6 } from "path";
|
|
10546
10574
|
function getAuthType(name) {
|
|
10547
10575
|
const docs = getConnectorDocs(name);
|
|
@@ -10556,12 +10584,12 @@ function getAuthType(name) {
|
|
|
10556
10584
|
}
|
|
10557
10585
|
function getConnectorConfigDir(name) {
|
|
10558
10586
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
10559
|
-
return join6(
|
|
10587
|
+
return join6(getConnectorsHome(), connectorName);
|
|
10560
10588
|
}
|
|
10561
10589
|
function getCurrentProfile(name) {
|
|
10562
10590
|
const configDir = getConnectorConfigDir(name);
|
|
10563
10591
|
const currentProfileFile = join6(configDir, "current_profile");
|
|
10564
|
-
if (
|
|
10592
|
+
if (existsSync6(currentProfileFile)) {
|
|
10565
10593
|
try {
|
|
10566
10594
|
return readFileSync4(currentProfileFile, "utf-8").trim() || "default";
|
|
10567
10595
|
} catch {
|
|
@@ -10576,13 +10604,13 @@ function loadProfileConfig(name) {
|
|
|
10576
10604
|
let flatConfig = {};
|
|
10577
10605
|
let dirConfig = {};
|
|
10578
10606
|
const profileFile = join6(configDir, "profiles", `${profile}.json`);
|
|
10579
|
-
if (
|
|
10607
|
+
if (existsSync6(profileFile)) {
|
|
10580
10608
|
try {
|
|
10581
10609
|
flatConfig = JSON.parse(readFileSync4(profileFile, "utf-8"));
|
|
10582
10610
|
} catch {}
|
|
10583
10611
|
}
|
|
10584
10612
|
const profileDirConfig = join6(configDir, "profiles", profile, "config.json");
|
|
10585
|
-
if (
|
|
10613
|
+
if (existsSync6(profileDirConfig)) {
|
|
10586
10614
|
try {
|
|
10587
10615
|
dirConfig = JSON.parse(readFileSync4(profileDirConfig, "utf-8"));
|
|
10588
10616
|
} catch {}
|
|
@@ -10596,7 +10624,7 @@ function loadTokens(name) {
|
|
|
10596
10624
|
const configDir = getConnectorConfigDir(name);
|
|
10597
10625
|
const profile = getCurrentProfile(name);
|
|
10598
10626
|
const tokensFile = join6(configDir, "profiles", profile, "tokens.json");
|
|
10599
|
-
if (
|
|
10627
|
+
if (existsSync6(tokensFile)) {
|
|
10600
10628
|
try {
|
|
10601
10629
|
return JSON.parse(readFileSync4(tokensFile, "utf-8"));
|
|
10602
10630
|
} catch {
|
|
@@ -10668,7 +10696,7 @@ function _saveApiKey(name, key, field) {
|
|
|
10668
10696
|
const credentialsFile = join6(configDir, "credentials.json");
|
|
10669
10697
|
mkdirSync5(configDir, { recursive: true });
|
|
10670
10698
|
let creds = {};
|
|
10671
|
-
if (
|
|
10699
|
+
if (existsSync6(credentialsFile)) {
|
|
10672
10700
|
try {
|
|
10673
10701
|
creds = JSON.parse(readFileSync4(credentialsFile, "utf-8"));
|
|
10674
10702
|
} catch {}
|
|
@@ -10679,7 +10707,7 @@ function _saveApiKey(name, key, field) {
|
|
|
10679
10707
|
}
|
|
10680
10708
|
const profileFile = join6(configDir, "profiles", `${profile}.json`);
|
|
10681
10709
|
const profileDir = join6(configDir, "profiles", profile);
|
|
10682
|
-
if (
|
|
10710
|
+
if (existsSync6(profileFile)) {
|
|
10683
10711
|
let config = {};
|
|
10684
10712
|
try {
|
|
10685
10713
|
config = JSON.parse(readFileSync4(profileFile, "utf-8"));
|
|
@@ -10688,10 +10716,10 @@ function _saveApiKey(name, key, field) {
|
|
|
10688
10716
|
writeFileSync3(profileFile, JSON.stringify(config, null, 2));
|
|
10689
10717
|
return;
|
|
10690
10718
|
}
|
|
10691
|
-
if (
|
|
10719
|
+
if (existsSync6(profileDir)) {
|
|
10692
10720
|
const configFile = join6(profileDir, "config.json");
|
|
10693
10721
|
let config = {};
|
|
10694
|
-
if (
|
|
10722
|
+
if (existsSync6(configFile)) {
|
|
10695
10723
|
try {
|
|
10696
10724
|
config = JSON.parse(readFileSync4(configFile, "utf-8"));
|
|
10697
10725
|
} catch {}
|
|
@@ -10720,7 +10748,7 @@ function guessKeyField(name) {
|
|
|
10720
10748
|
function getOAuthConfig(name) {
|
|
10721
10749
|
const configDir = getConnectorConfigDir(name);
|
|
10722
10750
|
const credentialsFile = join6(configDir, "credentials.json");
|
|
10723
|
-
if (
|
|
10751
|
+
if (existsSync6(credentialsFile)) {
|
|
10724
10752
|
try {
|
|
10725
10753
|
const creds = JSON.parse(readFileSync4(credentialsFile, "utf-8"));
|
|
10726
10754
|
return { clientId: creds.clientId, clientSecret: creds.clientSecret };
|
|
@@ -10847,14 +10875,14 @@ async function _refreshOAuthToken(name) {
|
|
|
10847
10875
|
function listProfiles(name) {
|
|
10848
10876
|
const configDir = getConnectorConfigDir(name);
|
|
10849
10877
|
const profilesDir = join6(configDir, "profiles");
|
|
10850
|
-
if (!
|
|
10878
|
+
if (!existsSync6(profilesDir))
|
|
10851
10879
|
return ["default"];
|
|
10852
10880
|
const seen = new Set;
|
|
10853
10881
|
try {
|
|
10854
|
-
const entries =
|
|
10882
|
+
const entries = readdirSync3(profilesDir);
|
|
10855
10883
|
for (const entry of entries) {
|
|
10856
10884
|
const fullPath = join6(profilesDir, entry);
|
|
10857
|
-
const stat =
|
|
10885
|
+
const stat = statSync4(fullPath);
|
|
10858
10886
|
if (stat.isDirectory()) {
|
|
10859
10887
|
seen.add(entry);
|
|
10860
10888
|
} else if (entry.endsWith(".json")) {
|
|
@@ -10876,7 +10904,7 @@ function deleteProfile(name, profile) {
|
|
|
10876
10904
|
const configDir = getConnectorConfigDir(name);
|
|
10877
10905
|
const profilesDir = join6(configDir, "profiles");
|
|
10878
10906
|
const profileFile = join6(profilesDir, `${profile}.json`);
|
|
10879
|
-
if (
|
|
10907
|
+
if (existsSync6(profileFile)) {
|
|
10880
10908
|
rmSync2(profileFile);
|
|
10881
10909
|
if (getCurrentProfile(name) === profile) {
|
|
10882
10910
|
switchProfile(name, "default");
|
|
@@ -10884,7 +10912,7 @@ function deleteProfile(name, profile) {
|
|
|
10884
10912
|
return true;
|
|
10885
10913
|
}
|
|
10886
10914
|
const profileDir = join6(profilesDir, profile);
|
|
10887
|
-
if (
|
|
10915
|
+
if (existsSync6(profileDir)) {
|
|
10888
10916
|
rmSync2(profileDir, { recursive: true });
|
|
10889
10917
|
if (getCurrentProfile(name) === profile) {
|
|
10890
10918
|
switchProfile(name, "default");
|
|
@@ -10897,6 +10925,7 @@ var FETCH_TIMEOUT = 1e4, oauthStateStore, GOOGLE_AUTH_URL = "https://accounts.go
|
|
|
10897
10925
|
var init_auth = __esm(() => {
|
|
10898
10926
|
init_installer();
|
|
10899
10927
|
init_lock();
|
|
10928
|
+
init_database();
|
|
10900
10929
|
oauthStateStore = new Map;
|
|
10901
10930
|
GOOGLE_SCOPES = {
|
|
10902
10931
|
gmail: [
|
|
@@ -11150,10 +11179,9 @@ var exports_serve = {};
|
|
|
11150
11179
|
__export(exports_serve, {
|
|
11151
11180
|
startServer: () => startServer
|
|
11152
11181
|
});
|
|
11153
|
-
import { existsSync as
|
|
11182
|
+
import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync6 } from "fs";
|
|
11154
11183
|
import { join as join8, dirname as dirname4, extname, basename } from "path";
|
|
11155
11184
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
11156
|
-
import { homedir as homedir6 } from "os";
|
|
11157
11185
|
function logActivity(action, connector, detail) {
|
|
11158
11186
|
activityLog.unshift({ action, connector, timestamp: Date.now(), detail });
|
|
11159
11187
|
if (activityLog.length > MAX_ACTIVITY_LOG) {
|
|
@@ -11174,7 +11202,7 @@ function resolveDashboardDir() {
|
|
|
11174
11202
|
}
|
|
11175
11203
|
candidates.push(join8(process.cwd(), "dashboard", "dist"));
|
|
11176
11204
|
for (const candidate of candidates) {
|
|
11177
|
-
if (
|
|
11205
|
+
if (existsSync8(candidate))
|
|
11178
11206
|
return candidate;
|
|
11179
11207
|
}
|
|
11180
11208
|
return join8(process.cwd(), "dashboard", "dist");
|
|
@@ -11262,7 +11290,7 @@ function oauthPage(type, title, message, hint, extra) {
|
|
|
11262
11290
|
</body></html>`;
|
|
11263
11291
|
}
|
|
11264
11292
|
function serveStaticFile(filePath) {
|
|
11265
|
-
if (!
|
|
11293
|
+
if (!existsSync8(filePath))
|
|
11266
11294
|
return null;
|
|
11267
11295
|
const ext = extname(filePath);
|
|
11268
11296
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
@@ -11286,7 +11314,7 @@ async function startServer(requestedPort, options) {
|
|
|
11286
11314
|
const shouldOpen = options?.open ?? true;
|
|
11287
11315
|
loadConnectorVersions();
|
|
11288
11316
|
const dashboardDir = resolveDashboardDir();
|
|
11289
|
-
const dashboardExists =
|
|
11317
|
+
const dashboardExists = existsSync8(dashboardDir);
|
|
11290
11318
|
if (!dashboardExists) {
|
|
11291
11319
|
console.error(`
|
|
11292
11320
|
Dashboard not found at: ${dashboardDir}`);
|
|
@@ -11440,7 +11468,7 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
11440
11468
|
const { getPromotedConnectors: getPromotedConnectors2 } = await Promise.resolve().then(() => (init_promotions(), exports_promotions));
|
|
11441
11469
|
const limit = parseInt(url2.searchParams.get("limit") || "10", 10);
|
|
11442
11470
|
const days = parseInt(url2.searchParams.get("days") || "7", 10);
|
|
11443
|
-
const db =
|
|
11471
|
+
const db = getDatabase3();
|
|
11444
11472
|
const top = getTopConnectors2(limit, days, db);
|
|
11445
11473
|
const promoted = new Set(getPromotedConnectors2(db));
|
|
11446
11474
|
return json(top.map((t) => ({ ...t, promoted: promoted.has(t.connector) })), 200, port);
|
|
@@ -11451,12 +11479,12 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
11451
11479
|
if (!getConnector(name))
|
|
11452
11480
|
return json({ error: "Connector not found" }, 404, port);
|
|
11453
11481
|
const { promoteConnector: promoteConnector2 } = await Promise.resolve().then(() => (init_promotions(), exports_promotions));
|
|
11454
|
-
promoteConnector2(name,
|
|
11482
|
+
promoteConnector2(name, getDatabase3());
|
|
11455
11483
|
return json({ success: true, connector: name }, 200, port);
|
|
11456
11484
|
}
|
|
11457
11485
|
if (promoteMatch && method === "DELETE") {
|
|
11458
11486
|
const { demoteConnector: demoteConnector2 } = await Promise.resolve().then(() => (init_promotions(), exports_promotions));
|
|
11459
|
-
const removed = demoteConnector2(promoteMatch[1],
|
|
11487
|
+
const removed = demoteConnector2(promoteMatch[1], getDatabase3());
|
|
11460
11488
|
return json({ success: removed, connector: promoteMatch[1] }, 200, port);
|
|
11461
11489
|
}
|
|
11462
11490
|
if (path === "/api/llm" && method === "GET") {
|
|
@@ -11492,19 +11520,19 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
11492
11520
|
}
|
|
11493
11521
|
}
|
|
11494
11522
|
if (path === "/api/jobs" && method === "GET") {
|
|
11495
|
-
return json(listJobs(
|
|
11523
|
+
return json(listJobs(getDatabase3()), 200, port);
|
|
11496
11524
|
}
|
|
11497
11525
|
if (path === "/api/jobs" && method === "POST") {
|
|
11498
11526
|
const body = await req.json().catch(() => ({}));
|
|
11499
11527
|
if (!body.name || !body.connector || !body.command || !body.cron)
|
|
11500
11528
|
return json({ error: "name, connector, command, cron required" }, 400, port);
|
|
11501
|
-
const job = createJob({ name: body.name, connector: body.connector, command: body.command, args: body.args ?? [], cron: body.cron, strip: !!body.strip },
|
|
11529
|
+
const job = createJob({ name: body.name, connector: body.connector, command: body.command, args: body.args ?? [], cron: body.cron, strip: !!body.strip }, getDatabase3());
|
|
11502
11530
|
return json(job, 201, port);
|
|
11503
11531
|
}
|
|
11504
11532
|
const jobMatch = path.match(/^\/api\/jobs\/([^/]+)$/);
|
|
11505
11533
|
if (jobMatch) {
|
|
11506
|
-
const db =
|
|
11507
|
-
const job = getJobByName(jobMatch[1]) ??
|
|
11534
|
+
const db = getDatabase3();
|
|
11535
|
+
const job = getJobByName(jobMatch[1]) ?? getDatabase3().query("SELECT * FROM connector_jobs WHERE id = ?").get(jobMatch[1]);
|
|
11508
11536
|
if (!job && method !== "DELETE")
|
|
11509
11537
|
return json({ error: "Job not found" }, 404, port);
|
|
11510
11538
|
if (method === "GET")
|
|
@@ -11525,7 +11553,7 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
11525
11553
|
}
|
|
11526
11554
|
const jobRunMatch = path.match(/^\/api\/jobs\/([^/]+)\/run$/);
|
|
11527
11555
|
if (jobRunMatch && method === "POST") {
|
|
11528
|
-
const db =
|
|
11556
|
+
const db = getDatabase3();
|
|
11529
11557
|
const job = getJobByName(jobRunMatch[1], db);
|
|
11530
11558
|
if (!job)
|
|
11531
11559
|
return json({ error: "Job not found" }, 404, port);
|
|
@@ -11533,18 +11561,18 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
11533
11561
|
return json(result, 200, port);
|
|
11534
11562
|
}
|
|
11535
11563
|
if (path === "/api/workflows" && method === "GET") {
|
|
11536
|
-
return json(listWorkflows(
|
|
11564
|
+
return json(listWorkflows(getDatabase3()), 200, port);
|
|
11537
11565
|
}
|
|
11538
11566
|
if (path === "/api/workflows" && method === "POST") {
|
|
11539
11567
|
const body = await req.json().catch(() => ({}));
|
|
11540
11568
|
if (!body.name || !body.steps)
|
|
11541
11569
|
return json({ error: "name and steps required" }, 400, port);
|
|
11542
|
-
const wf = createWorkflow({ name: body.name, steps: body.steps },
|
|
11570
|
+
const wf = createWorkflow({ name: body.name, steps: body.steps }, getDatabase3());
|
|
11543
11571
|
return json(wf, 201, port);
|
|
11544
11572
|
}
|
|
11545
11573
|
const wfMatch = path.match(/^\/api\/workflows\/([^/]+)$/);
|
|
11546
11574
|
if (wfMatch) {
|
|
11547
|
-
const db =
|
|
11575
|
+
const db = getDatabase3();
|
|
11548
11576
|
const wf = getWorkflowByName(wfMatch[1], db);
|
|
11549
11577
|
if (!wf)
|
|
11550
11578
|
return json({ error: "Workflow not found" }, 404, port);
|
|
@@ -11557,7 +11585,7 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
11557
11585
|
}
|
|
11558
11586
|
const wfRunMatch = path.match(/^\/api\/workflows\/([^/]+)\/run$/);
|
|
11559
11587
|
if (wfRunMatch && method === "POST") {
|
|
11560
|
-
const wf = getWorkflowByName(wfRunMatch[1],
|
|
11588
|
+
const wf = getWorkflowByName(wfRunMatch[1], getDatabase3());
|
|
11561
11589
|
if (!wf)
|
|
11562
11590
|
return json({ error: "Workflow not found" }, 404, port);
|
|
11563
11591
|
const result = await runWorkflow(wf);
|
|
@@ -11603,10 +11631,10 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
11603
11631
|
return json({ error: "Invalid connector name" }, 400, port);
|
|
11604
11632
|
try {
|
|
11605
11633
|
const profiles = listProfiles(name);
|
|
11606
|
-
const configDir = join8(
|
|
11634
|
+
const configDir = join8(getConnectorsHome(), name.startsWith("connect-") ? name : `connect-${name}`);
|
|
11607
11635
|
const currentProfileFile = join8(configDir, "current_profile");
|
|
11608
11636
|
let current = "default";
|
|
11609
|
-
if (
|
|
11637
|
+
if (existsSync8(currentProfileFile)) {
|
|
11610
11638
|
try {
|
|
11611
11639
|
current = readFileSync5(currentProfileFile, "utf-8").trim() || "default";
|
|
11612
11640
|
} catch {}
|
|
@@ -11655,19 +11683,19 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
11655
11683
|
}
|
|
11656
11684
|
if (path === "/api/export" && method === "GET") {
|
|
11657
11685
|
try {
|
|
11658
|
-
const connectDir =
|
|
11686
|
+
const connectDir = getConnectorsHome();
|
|
11659
11687
|
const result = {};
|
|
11660
|
-
if (
|
|
11661
|
-
const entries =
|
|
11688
|
+
if (existsSync8(connectDir)) {
|
|
11689
|
+
const entries = readdirSync4(connectDir, { withFileTypes: true });
|
|
11662
11690
|
for (const entry of entries) {
|
|
11663
11691
|
if (!entry.isDirectory() || !entry.name.startsWith("connect-"))
|
|
11664
11692
|
continue;
|
|
11665
11693
|
const connectorName = entry.name.replace(/^connect-/, "");
|
|
11666
11694
|
const profilesDir = join8(connectDir, entry.name, "profiles");
|
|
11667
|
-
if (!
|
|
11695
|
+
if (!existsSync8(profilesDir))
|
|
11668
11696
|
continue;
|
|
11669
11697
|
const profiles = {};
|
|
11670
|
-
const profileEntries =
|
|
11698
|
+
const profileEntries = readdirSync4(profilesDir, { withFileTypes: true });
|
|
11671
11699
|
for (const pEntry of profileEntries) {
|
|
11672
11700
|
if (pEntry.isFile() && pEntry.name.endsWith(".json")) {
|
|
11673
11701
|
const profileName = basename(pEntry.name, ".json");
|
|
@@ -11678,7 +11706,7 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
11678
11706
|
}
|
|
11679
11707
|
if (pEntry.isDirectory()) {
|
|
11680
11708
|
const configPath = join8(profilesDir, pEntry.name, "config.json");
|
|
11681
|
-
if (
|
|
11709
|
+
if (existsSync8(configPath)) {
|
|
11682
11710
|
try {
|
|
11683
11711
|
const config = JSON.parse(readFileSync5(configPath, "utf-8"));
|
|
11684
11712
|
profiles[pEntry.name] = config;
|
|
@@ -11715,7 +11743,7 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
11715
11743
|
return json({ error: "Invalid import format: missing 'connectors' object" }, 400, port);
|
|
11716
11744
|
}
|
|
11717
11745
|
let imported = 0;
|
|
11718
|
-
const connectDir =
|
|
11746
|
+
const connectDir = getConnectorsHome();
|
|
11719
11747
|
for (const [connectorName, data] of Object.entries(body.connectors)) {
|
|
11720
11748
|
if (!isValidConnectorName(connectorName))
|
|
11721
11749
|
continue;
|
|
@@ -11803,8 +11831,8 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
11803
11831
|
process.on("SIGINT", shutdown);
|
|
11804
11832
|
process.on("SIGTERM", shutdown);
|
|
11805
11833
|
const { startScheduler: startScheduler2 } = await Promise.resolve().then(() => (init_scheduler(), exports_scheduler));
|
|
11806
|
-
const { getDatabase:
|
|
11807
|
-
startScheduler2(
|
|
11834
|
+
const { getDatabase: getDatabase3 } = await Promise.resolve().then(() => (init_database(), exports_database));
|
|
11835
|
+
startScheduler2(getDatabase3());
|
|
11808
11836
|
const url = `http://localhost:${port}`;
|
|
11809
11837
|
console.log(`Connectors Dashboard running at ${url}`);
|
|
11810
11838
|
if (shouldOpen) {
|
|
@@ -11825,6 +11853,7 @@ var init_serve = __esm(() => {
|
|
|
11825
11853
|
init_workflows();
|
|
11826
11854
|
init_scheduler();
|
|
11827
11855
|
init_workflow_runner();
|
|
11856
|
+
init_database();
|
|
11828
11857
|
init_registry();
|
|
11829
11858
|
init_installer();
|
|
11830
11859
|
init_auth();
|
|
@@ -11872,7 +11901,7 @@ import chalk2 from "chalk";
|
|
|
11872
11901
|
// package.json
|
|
11873
11902
|
var package_default = {
|
|
11874
11903
|
name: "@hasna/connectors",
|
|
11875
|
-
version: "1.3.
|
|
11904
|
+
version: "1.3.8",
|
|
11876
11905
|
description: "Open source connector library - Install API connectors with a single command",
|
|
11877
11906
|
type: "module",
|
|
11878
11907
|
bin: {
|
|
@@ -13437,8 +13466,9 @@ function App({ initialConnectors, overwrite = false }) {
|
|
|
13437
13466
|
init_registry();
|
|
13438
13467
|
init_installer();
|
|
13439
13468
|
init_auth();
|
|
13440
|
-
|
|
13441
|
-
import {
|
|
13469
|
+
init_database();
|
|
13470
|
+
import { readdirSync as readdirSync5, existsSync as existsSync9, statSync as statSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync5, mkdirSync as mkdirSync7 } from "fs";
|
|
13471
|
+
import { homedir as homedir2 } from "os";
|
|
13442
13472
|
import { join as join9, relative } from "path";
|
|
13443
13473
|
|
|
13444
13474
|
// src/lib/test-endpoints.ts
|
|
@@ -13640,17 +13670,17 @@ var TEST_ENDPOINTS = {
|
|
|
13640
13670
|
import { createInterface } from "readline";
|
|
13641
13671
|
|
|
13642
13672
|
// src/lib/runner.ts
|
|
13643
|
-
import { existsSync as
|
|
13673
|
+
import { existsSync as existsSync7 } from "fs";
|
|
13644
13674
|
import { join as join7, dirname as dirname3 } from "path";
|
|
13645
13675
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
13646
13676
|
import { spawn as spawn3 } from "child_process";
|
|
13647
13677
|
var __dirname3 = dirname3(fileURLToPath3(import.meta.url));
|
|
13648
13678
|
function resolveConnectorsDir2() {
|
|
13649
13679
|
const fromBin = join7(__dirname3, "..", "connectors");
|
|
13650
|
-
if (
|
|
13680
|
+
if (existsSync7(fromBin))
|
|
13651
13681
|
return fromBin;
|
|
13652
13682
|
const fromSrc = join7(__dirname3, "..", "..", "connectors");
|
|
13653
|
-
if (
|
|
13683
|
+
if (existsSync7(fromSrc))
|
|
13654
13684
|
return fromSrc;
|
|
13655
13685
|
return fromBin;
|
|
13656
13686
|
}
|
|
@@ -13692,7 +13722,7 @@ function getConnectorCliPath(name) {
|
|
|
13692
13722
|
const safeName = name.replace(/[^a-z0-9-]/g, "");
|
|
13693
13723
|
const connectorDir = join7(CONNECTORS_DIR2, `connect-${safeName}`);
|
|
13694
13724
|
const cliPath = join7(connectorDir, "src", "cli", "index.ts");
|
|
13695
|
-
if (
|
|
13725
|
+
if (existsSync7(cliPath))
|
|
13696
13726
|
return cliPath;
|
|
13697
13727
|
return null;
|
|
13698
13728
|
}
|
|
@@ -13804,9 +13834,9 @@ Run 'connectors --help' for full usage.`);
|
|
|
13804
13834
|
});
|
|
13805
13835
|
function listFilesRecursive(dir, base = dir) {
|
|
13806
13836
|
const files = [];
|
|
13807
|
-
for (const entry of
|
|
13837
|
+
for (const entry of readdirSync5(dir)) {
|
|
13808
13838
|
const fullPath = join9(dir, entry);
|
|
13809
|
-
if (
|
|
13839
|
+
if (statSync5(fullPath).isDirectory()) {
|
|
13810
13840
|
files.push(...listFilesRecursive(fullPath, base));
|
|
13811
13841
|
} else {
|
|
13812
13842
|
files.push(relative(base, fullPath));
|
|
@@ -14386,7 +14416,7 @@ Updating ${toUpdate.length} connector(s)...
|
|
|
14386
14416
|
});
|
|
14387
14417
|
program2.command("status").option("--json", "Output as JSON", false).description("Show auth status of all configured connectors (project + global)").action((options) => {
|
|
14388
14418
|
const installed = getInstalledConnectors();
|
|
14389
|
-
const configDir =
|
|
14419
|
+
const configDir = getConnectorsHome();
|
|
14390
14420
|
const seen = new Set;
|
|
14391
14421
|
const allStatuses = [];
|
|
14392
14422
|
function buildStatusEntry(name, source) {
|
|
@@ -14394,7 +14424,7 @@ program2.command("status").option("--json", "Output as JSON", false).description
|
|
|
14394
14424
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
14395
14425
|
const currentProfileFile = join9(configDir, connectorName, "current_profile");
|
|
14396
14426
|
let profile = "default";
|
|
14397
|
-
if (
|
|
14427
|
+
if (existsSync9(currentProfileFile)) {
|
|
14398
14428
|
try {
|
|
14399
14429
|
profile = readFileSync6(currentProfileFile, "utf-8").trim() || "default";
|
|
14400
14430
|
} catch {}
|
|
@@ -14432,13 +14462,13 @@ program2.command("status").option("--json", "Output as JSON", false).description
|
|
|
14432
14462
|
seen.add(name);
|
|
14433
14463
|
allStatuses.push(buildStatusEntry(name, "project"));
|
|
14434
14464
|
}
|
|
14435
|
-
if (
|
|
14465
|
+
if (existsSync9(configDir)) {
|
|
14436
14466
|
try {
|
|
14437
|
-
const globalDirs =
|
|
14467
|
+
const globalDirs = readdirSync5(configDir).filter((f) => {
|
|
14438
14468
|
if (!f.startsWith("connect-"))
|
|
14439
14469
|
return false;
|
|
14440
14470
|
try {
|
|
14441
|
-
return
|
|
14471
|
+
return statSync5(join9(configDir, f)).isDirectory();
|
|
14442
14472
|
} catch {
|
|
14443
14473
|
return false;
|
|
14444
14474
|
}
|
|
@@ -14803,15 +14833,15 @@ program2.command("init").option("--json", "Output presets and suggestions as JSO
|
|
|
14803
14833
|
{ key: "commerce", emoji: "\uD83D\uDCB3", label: "Commerce", connectors: ["stripe", "shopify", "paypal", "revolut", "mercury"], description: "Commerce and finance" },
|
|
14804
14834
|
{ key: "google", emoji: "\uD83D\uDCC1", label: "Google Workspace", connectors: ["gmail", "googledrive", "googlecalendar", "googledocs", "googlesheets"], description: "Google Workspace suite" }
|
|
14805
14835
|
];
|
|
14806
|
-
const connectorsHome =
|
|
14836
|
+
const connectorsHome = getConnectorsHome();
|
|
14807
14837
|
let configuredCount = 0;
|
|
14808
14838
|
const configuredNames = [];
|
|
14809
14839
|
try {
|
|
14810
|
-
if (
|
|
14811
|
-
const entries =
|
|
14840
|
+
if (existsSync9(connectorsHome)) {
|
|
14841
|
+
const entries = readdirSync5(connectorsHome).filter((e) => e.startsWith("connect-") && statSync5(join9(connectorsHome, e)).isDirectory());
|
|
14812
14842
|
for (const entry of entries) {
|
|
14813
14843
|
const profilesDir = join9(connectorsHome, entry, "profiles");
|
|
14814
|
-
if (
|
|
14844
|
+
if (existsSync9(profilesDir)) {
|
|
14815
14845
|
configuredCount++;
|
|
14816
14846
|
configuredNames.push(entry.replace(/^connect-/, ""));
|
|
14817
14847
|
}
|
|
@@ -14909,42 +14939,42 @@ function redactSecrets(obj) {
|
|
|
14909
14939
|
return obj;
|
|
14910
14940
|
}
|
|
14911
14941
|
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) => {
|
|
14912
|
-
const connectDir =
|
|
14942
|
+
const connectDir = getConnectorsHome();
|
|
14913
14943
|
const result = {};
|
|
14914
|
-
if (
|
|
14915
|
-
for (const entry of
|
|
14944
|
+
if (existsSync9(connectDir)) {
|
|
14945
|
+
for (const entry of readdirSync5(connectDir)) {
|
|
14916
14946
|
const entryPath = join9(connectDir, entry);
|
|
14917
|
-
if (!
|
|
14947
|
+
if (!statSync5(entryPath).isDirectory() || !entry.startsWith("connect-"))
|
|
14918
14948
|
continue;
|
|
14919
14949
|
const connectorName = entry.replace(/^connect-/, "");
|
|
14920
14950
|
let credentials = undefined;
|
|
14921
14951
|
const credentialsPath = join9(entryPath, "credentials.json");
|
|
14922
|
-
if (
|
|
14952
|
+
if (existsSync9(credentialsPath)) {
|
|
14923
14953
|
try {
|
|
14924
14954
|
credentials = JSON.parse(readFileSync6(credentialsPath, "utf-8"));
|
|
14925
14955
|
} catch {}
|
|
14926
14956
|
}
|
|
14927
14957
|
const profilesDir = join9(entryPath, "profiles");
|
|
14928
|
-
if (!
|
|
14958
|
+
if (!existsSync9(profilesDir) && !credentials)
|
|
14929
14959
|
continue;
|
|
14930
14960
|
const profiles = {};
|
|
14931
|
-
if (
|
|
14932
|
-
for (const pEntry of
|
|
14961
|
+
if (existsSync9(profilesDir)) {
|
|
14962
|
+
for (const pEntry of readdirSync5(profilesDir)) {
|
|
14933
14963
|
const pPath = join9(profilesDir, pEntry);
|
|
14934
|
-
if (
|
|
14964
|
+
if (statSync5(pPath).isFile() && pEntry.endsWith(".json")) {
|
|
14935
14965
|
try {
|
|
14936
14966
|
profiles[pEntry.replace(/\.json$/, "")] = JSON.parse(readFileSync6(pPath, "utf-8"));
|
|
14937
14967
|
} catch {}
|
|
14938
|
-
} else if (
|
|
14968
|
+
} else if (statSync5(pPath).isDirectory()) {
|
|
14939
14969
|
const configPath = join9(pPath, "config.json");
|
|
14940
14970
|
const tokensPath = join9(pPath, "tokens.json");
|
|
14941
14971
|
let merged = {};
|
|
14942
|
-
if (
|
|
14972
|
+
if (existsSync9(configPath)) {
|
|
14943
14973
|
try {
|
|
14944
14974
|
merged = { ...merged, ...JSON.parse(readFileSync6(configPath, "utf-8")) };
|
|
14945
14975
|
} catch {}
|
|
14946
14976
|
}
|
|
14947
|
-
if (
|
|
14977
|
+
if (existsSync9(tokensPath)) {
|
|
14948
14978
|
try {
|
|
14949
14979
|
merged = { ...merged, ...JSON.parse(readFileSync6(tokensPath, "utf-8")) };
|
|
14950
14980
|
} catch {}
|
|
@@ -14981,7 +15011,7 @@ program2.command("import").argument("<file>", "JSON backup file to import (use -
|
|
|
14981
15011
|
chunks.push(chunk.toString());
|
|
14982
15012
|
raw = chunks.join("");
|
|
14983
15013
|
} else {
|
|
14984
|
-
if (!
|
|
15014
|
+
if (!existsSync9(file)) {
|
|
14985
15015
|
if (options.json) {
|
|
14986
15016
|
console.log(JSON.stringify({ error: `File not found: ${file}` }));
|
|
14987
15017
|
} else {
|
|
@@ -15013,7 +15043,7 @@ program2.command("import").argument("<file>", "JSON backup file to import (use -
|
|
|
15013
15043
|
process.exit(1);
|
|
15014
15044
|
return;
|
|
15015
15045
|
}
|
|
15016
|
-
const connectDir =
|
|
15046
|
+
const connectDir = getConnectorsHome();
|
|
15017
15047
|
let imported = 0;
|
|
15018
15048
|
for (const [connectorName, connData] of Object.entries(data.connectors)) {
|
|
15019
15049
|
if (!/^[a-z0-9-]+$/.test(connectorName))
|
|
@@ -15041,10 +15071,10 @@ program2.command("import").argument("<file>", "JSON backup file to import (use -
|
|
|
15041
15071
|
console.log(chalk2.green(`\u2713 Imported ${imported} profile(s)`));
|
|
15042
15072
|
}
|
|
15043
15073
|
});
|
|
15044
|
-
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) => {
|
|
15045
|
-
const oldBase = join9(
|
|
15046
|
-
const newBase =
|
|
15047
|
-
if (!
|
|
15074
|
+
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 ~/.hasna/connectors/", false).description("Migrate auth tokens from ~/.connect/ to ~/.hasna/connectors/").action((options) => {
|
|
15075
|
+
const oldBase = join9(homedir2(), ".connect");
|
|
15076
|
+
const newBase = getConnectorsHome();
|
|
15077
|
+
if (!existsSync9(oldBase)) {
|
|
15048
15078
|
if (options.json) {
|
|
15049
15079
|
console.log(JSON.stringify({ imported: [], skipped: [], error: null, message: "No ~/.connect/ directory found" }));
|
|
15050
15080
|
} else {
|
|
@@ -15052,11 +15082,11 @@ program2.command("auth-import").option("--json", "Output as JSON", false).option
|
|
|
15052
15082
|
}
|
|
15053
15083
|
return;
|
|
15054
15084
|
}
|
|
15055
|
-
const entries =
|
|
15085
|
+
const entries = readdirSync5(oldBase).filter((name) => {
|
|
15056
15086
|
if (!name.startsWith("connect-"))
|
|
15057
15087
|
return false;
|
|
15058
15088
|
try {
|
|
15059
|
-
return
|
|
15089
|
+
return statSync5(join9(oldBase, name)).isDirectory();
|
|
15060
15090
|
} catch {
|
|
15061
15091
|
return false;
|
|
15062
15092
|
}
|
|
@@ -15086,7 +15116,7 @@ program2.command("auth-import").option("--json", "Output as JSON", false).option
|
|
|
15086
15116
|
for (const relFile of authFiles) {
|
|
15087
15117
|
const srcPath = join9(oldDir, relFile);
|
|
15088
15118
|
const destPath = join9(newDir, relFile);
|
|
15089
|
-
if (
|
|
15119
|
+
if (existsSync9(destPath) && !options.force) {
|
|
15090
15120
|
skippedFiles.push(relFile);
|
|
15091
15121
|
continue;
|
|
15092
15122
|
}
|
|
@@ -15367,7 +15397,7 @@ Available presets:
|
|
|
15367
15397
|
`));
|
|
15368
15398
|
});
|
|
15369
15399
|
program2.command("whoami").option("--json", "Output as JSON", false).description("Show current setup: config dir, installed connectors, auth status").action((options) => {
|
|
15370
|
-
const configDir =
|
|
15400
|
+
const configDir = getConnectorsHome();
|
|
15371
15401
|
const installed = getInstalledConnectors();
|
|
15372
15402
|
const version = "0.3.1";
|
|
15373
15403
|
let configured = 0;
|
|
@@ -15384,20 +15414,20 @@ program2.command("whoami").option("--json", "Output as JSON", false).description
|
|
|
15384
15414
|
const connectorConfigDir = join9(configDir, name.startsWith("connect-") ? name : `connect-${name}`);
|
|
15385
15415
|
const currentProfileFile = join9(connectorConfigDir, "current_profile");
|
|
15386
15416
|
let profile = "default";
|
|
15387
|
-
if (
|
|
15417
|
+
if (existsSync9(currentProfileFile)) {
|
|
15388
15418
|
try {
|
|
15389
15419
|
profile = readFileSync6(currentProfileFile, "utf-8").trim() || "default";
|
|
15390
15420
|
} catch {}
|
|
15391
15421
|
}
|
|
15392
15422
|
connectorDetails.push({ name, configured: auth.configured, authType: auth.type, profile, source: "project" });
|
|
15393
15423
|
}
|
|
15394
|
-
if (
|
|
15424
|
+
if (existsSync9(configDir)) {
|
|
15395
15425
|
try {
|
|
15396
|
-
const globalDirs =
|
|
15426
|
+
const globalDirs = readdirSync5(configDir).filter((f) => {
|
|
15397
15427
|
if (!f.startsWith("connect-"))
|
|
15398
15428
|
return false;
|
|
15399
15429
|
try {
|
|
15400
|
-
return
|
|
15430
|
+
return statSync5(join9(configDir, f)).isDirectory();
|
|
15401
15431
|
} catch {
|
|
15402
15432
|
return false;
|
|
15403
15433
|
}
|
|
@@ -15413,7 +15443,7 @@ program2.command("whoami").option("--json", "Output as JSON", false).description
|
|
|
15413
15443
|
configured++;
|
|
15414
15444
|
const currentProfileFile = join9(configDir, dir, "current_profile");
|
|
15415
15445
|
let profile = "default";
|
|
15416
|
-
if (
|
|
15446
|
+
if (existsSync9(currentProfileFile)) {
|
|
15417
15447
|
try {
|
|
15418
15448
|
profile = readFileSync6(currentProfileFile, "utf-8").trim() || "default";
|
|
15419
15449
|
} catch {}
|
|
@@ -15426,7 +15456,7 @@ program2.command("whoami").option("--json", "Output as JSON", false).description
|
|
|
15426
15456
|
console.log(JSON.stringify({
|
|
15427
15457
|
version,
|
|
15428
15458
|
configDir,
|
|
15429
|
-
configDirExists:
|
|
15459
|
+
configDirExists: existsSync9(configDir),
|
|
15430
15460
|
installed: installed.length,
|
|
15431
15461
|
configured,
|
|
15432
15462
|
unconfigured,
|
|
@@ -15438,7 +15468,7 @@ program2.command("whoami").option("--json", "Output as JSON", false).description
|
|
|
15438
15468
|
Connectors Setup
|
|
15439
15469
|
`));
|
|
15440
15470
|
console.log(` Version: ${chalk2.cyan(version)}`);
|
|
15441
|
-
console.log(` Config: ${configDir}${
|
|
15471
|
+
console.log(` Config: ${configDir}${existsSync9(configDir) ? "" : chalk2.dim(" (not created yet)")}`);
|
|
15442
15472
|
console.log(` Installed: ${installed.length} connector${installed.length !== 1 ? "s" : ""}`);
|
|
15443
15473
|
console.log(` Configured: ${chalk2.green(String(configured))} ready, ${unconfigured > 0 ? chalk2.red(String(unconfigured)) : chalk2.dim("0")} need auth`);
|
|
15444
15474
|
const projectConnectors = connectorDetails.filter((c) => c.source === "project");
|
|
@@ -15528,16 +15558,16 @@ Testing connector credentials...
|
|
|
15528
15558
|
}
|
|
15529
15559
|
}
|
|
15530
15560
|
if (!apiKey) {
|
|
15531
|
-
const connectorConfigDir = join9(
|
|
15561
|
+
const connectorConfigDir = join9(getConnectorsHome(), name.startsWith("connect-") ? name : `connect-${name}`);
|
|
15532
15562
|
let currentProfile = "default";
|
|
15533
15563
|
const currentProfileFile = join9(connectorConfigDir, "current_profile");
|
|
15534
|
-
if (
|
|
15564
|
+
if (existsSync9(currentProfileFile)) {
|
|
15535
15565
|
try {
|
|
15536
15566
|
currentProfile = readFileSync6(currentProfileFile, "utf-8").trim() || "default";
|
|
15537
15567
|
} catch {}
|
|
15538
15568
|
}
|
|
15539
15569
|
const tokensFile = join9(connectorConfigDir, "profiles", currentProfile, "tokens.json");
|
|
15540
|
-
if (
|
|
15570
|
+
if (existsSync9(tokensFile)) {
|
|
15541
15571
|
try {
|
|
15542
15572
|
const tokens = JSON.parse(readFileSync6(tokensFile, "utf-8"));
|
|
15543
15573
|
const isExpired = tokens.expiresAt && Date.now() >= tokens.expiresAt - 60000;
|
|
@@ -15558,7 +15588,7 @@ Testing connector credentials...
|
|
|
15558
15588
|
}
|
|
15559
15589
|
if (!apiKey) {
|
|
15560
15590
|
const profileFile = join9(connectorConfigDir, "profiles", `${currentProfile}.json`);
|
|
15561
|
-
if (
|
|
15591
|
+
if (existsSync9(profileFile)) {
|
|
15562
15592
|
try {
|
|
15563
15593
|
const config = JSON.parse(readFileSync6(profileFile, "utf-8"));
|
|
15564
15594
|
apiKey = Object.values(config).find((v) => typeof v === "string" && v.length > 0);
|
|
@@ -15567,7 +15597,7 @@ Testing connector credentials...
|
|
|
15567
15597
|
}
|
|
15568
15598
|
if (!apiKey) {
|
|
15569
15599
|
const profileDirConfig = join9(connectorConfigDir, "profiles", currentProfile, "config.json");
|
|
15570
|
-
if (
|
|
15600
|
+
if (existsSync9(profileDirConfig)) {
|
|
15571
15601
|
try {
|
|
15572
15602
|
const config = JSON.parse(readFileSync6(profileDirConfig, "utf-8"));
|
|
15573
15603
|
apiKey = Object.values(config).find((v) => typeof v === "string" && v.length > 0);
|