@hasna/connectors 1.4.0 → 1.4.1
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 +293 -967
- package/bin/mcp.js +11 -3
- package/bin/serve.js +11 -3
- package/connectors/googlephotos/src/cli/index.ts +1 -1
- package/connectors/yousearch/README.md +1 -1
- package/connectors/zendesk/CLAUDE.md +1 -1
- package/connectors/zendesk/Makefile +3 -1
- package/connectors/zendesk/README.md +3 -2
- package/connectors/zendesk/SCAFFOLD.md +2 -2
- package/connectors/zendesk/nginx-connector.conf +8 -8
- package/connectors/zendesk/nginx.conf +8 -8
- package/connectors/zendesk/src/cli/index.ts +19 -8
- package/connectors/zendesk/src/server/index.ts +1 -1
- package/connectors/zendesk/src/utils/config.test.ts +70 -0
- package/connectors/zendesk/src/utils/config.ts +12 -2
- package/connectors/zendesk/src/utils/remote-url.test.ts +72 -0
- package/dashboard/dist/assets/index-DlEljRrW.js +285 -0
- package/dashboard/dist/index.html +1 -1
- package/dist/index.js +11 -3
- package/package.json +11 -3
- package/connectors/tiktok-events-api/.test-home/.bun/install/cache/@t@/b0fec00ef4c1a326.pile +0 -0
- package/dashboard/dist/assets/index-XPlN-9Xy.js +0 -280
- package/dist/cli/commands/sync.d.ts +0 -2
- package/dist/db/pg-migrations.d.ts +0 -6
package/bin/index.js
CHANGED
|
@@ -1909,7 +1909,7 @@ var package_default;
|
|
|
1909
1909
|
var init_package = __esm(() => {
|
|
1910
1910
|
package_default = {
|
|
1911
1911
|
name: "@hasna/connectors",
|
|
1912
|
-
version: "1.4.
|
|
1912
|
+
version: "1.4.1",
|
|
1913
1913
|
description: "Open source connector library - Install API connectors with a single command",
|
|
1914
1914
|
type: "module",
|
|
1915
1915
|
bin: {
|
|
@@ -1922,7 +1922,15 @@ var init_package = __esm(() => {
|
|
|
1922
1922
|
"dist/",
|
|
1923
1923
|
"dashboard/dist/",
|
|
1924
1924
|
"connectors/",
|
|
1925
|
-
"README.md"
|
|
1925
|
+
"README.md",
|
|
1926
|
+
"!connectors/**/.test-home/**",
|
|
1927
|
+
"!connectors/**/node_modules/**",
|
|
1928
|
+
"!connectors/**/bun.lock",
|
|
1929
|
+
"!connectors/**/package-lock.json",
|
|
1930
|
+
"!connectors/**/yarn.lock",
|
|
1931
|
+
"!connectors/**/pnpm-lock.yaml",
|
|
1932
|
+
"!connectors/**/.env",
|
|
1933
|
+
"!connectors/**/.env.local"
|
|
1926
1934
|
],
|
|
1927
1935
|
exports: {
|
|
1928
1936
|
".": {
|
|
@@ -1937,7 +1945,7 @@ var init_package = __esm(() => {
|
|
|
1937
1945
|
main: "./dist/index.js",
|
|
1938
1946
|
types: "./dist/index.d.ts",
|
|
1939
1947
|
scripts: {
|
|
1940
|
-
build: "cd dashboard && bun run build && cd .. && bun build ./src/cli/index.tsx --outdir ./bin --target bun --external ink --external react --external chalk --external conf && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/server/index.ts --outfile ./bin/serve.js --target bun && bun build ./src/index.ts --outdir ./dist --target bun && bun build ./src/social/index.ts --outfile ./dist/social/index.js --target bun && tsc --emitDeclarationOnly --outDir ./dist && tsc -p tsconfig.social.json",
|
|
1948
|
+
build: "cd dashboard && bun run build && cd .. && bun build ./src/cli/index.tsx --outdir ./bin --target bun --external ink --external react --external chalk --external conf --external @hasna/events && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/server/index.ts --outfile ./bin/serve.js --target bun && bun build ./src/index.ts --outdir ./dist --target bun && bun build ./src/social/index.ts --outfile ./dist/social/index.js --target bun && tsc --emitDeclarationOnly --outDir ./dist && tsc -p tsconfig.social.json",
|
|
1941
1949
|
"build:dashboard": "cd dashboard && bun run build",
|
|
1942
1950
|
postinstall: 'mkdir -p $HOME/.hasna/connectors 2>/dev/null || true; [ "$SKIP_DASHBOARD" = "1" ] || [ ! -f dashboard/package.json ] || [ -d dashboard/node_modules ] || (cd dashboard && bun install)',
|
|
1943
1951
|
dev: "bun run ./src/cli/index.tsx",
|
|
@@ -6091,28 +6099,28 @@ var init_zod = __esm(() => {
|
|
|
6091
6099
|
|
|
6092
6100
|
// src/core/connectors/github.ts
|
|
6093
6101
|
import { Buffer as Buffer2 } from "buffer";
|
|
6094
|
-
import { existsSync
|
|
6095
|
-
import { dirname, join
|
|
6102
|
+
import { existsSync } from "fs";
|
|
6103
|
+
import { dirname, join } from "path";
|
|
6096
6104
|
import { fileURLToPath, pathToFileURL } from "url";
|
|
6097
6105
|
function resolveGithubConnectorDir() {
|
|
6098
6106
|
const candidates = [
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6107
|
+
join(__dirname2, "..", "..", "..", "connectors", "github"),
|
|
6108
|
+
join(__dirname2, "..", "..", "connectors", "github"),
|
|
6109
|
+
join(__dirname2, "..", "connectors", "github"),
|
|
6110
|
+
join(process.cwd(), "connectors", "github")
|
|
6103
6111
|
];
|
|
6104
6112
|
for (const candidate of candidates) {
|
|
6105
|
-
if (
|
|
6113
|
+
if (existsSync(candidate)) {
|
|
6106
6114
|
return candidate;
|
|
6107
6115
|
}
|
|
6108
6116
|
}
|
|
6109
6117
|
return candidates[0];
|
|
6110
6118
|
}
|
|
6111
6119
|
async function loadGitHubApiModule() {
|
|
6112
|
-
return await import(pathToFileURL(
|
|
6120
|
+
return await import(pathToFileURL(join(CONNECTOR_DIR, "src", "api", "index.ts")).href);
|
|
6113
6121
|
}
|
|
6114
6122
|
async function loadGitHubConfigModule() {
|
|
6115
|
-
return await import(pathToFileURL(
|
|
6123
|
+
return await import(pathToFileURL(join(CONNECTOR_DIR, "src", "utils", "config.ts")).href);
|
|
6116
6124
|
}
|
|
6117
6125
|
function extractGlobalArgs(args) {
|
|
6118
6126
|
const remaining = [];
|
|
@@ -6956,9 +6964,9 @@ Commands:
|
|
|
6956
6964
|
});
|
|
6957
6965
|
|
|
6958
6966
|
// src/core/connectors/gmail.ts
|
|
6959
|
-
import { existsSync as
|
|
6960
|
-
import { homedir
|
|
6961
|
-
import { basename, join as
|
|
6967
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, writeFileSync } from "fs";
|
|
6968
|
+
import { homedir } from "os";
|
|
6969
|
+
import { basename, join as join2 } from "path";
|
|
6962
6970
|
async function modifyMessage(profile, messageId, addLabelIds, removeLabelIds) {
|
|
6963
6971
|
return requestJson(profile, `/users/me/messages/${encodeURIComponent(messageId)}/modify`, {}, {
|
|
6964
6972
|
method: "POST",
|
|
@@ -6995,7 +7003,7 @@ async function replyToMessage(profile, messageId, input) {
|
|
|
6995
7003
|
}
|
|
6996
7004
|
async function downloadAttachments(profile, input) {
|
|
6997
7005
|
const messageId = getMessageId(input);
|
|
6998
|
-
const outputDir = input.dir ?? input.outputDir ??
|
|
7006
|
+
const outputDir = input.dir ?? input.outputDir ?? join2(configDirs()[0], "attachments", messageId);
|
|
6999
7007
|
mkdirSync(outputDir, { recursive: true });
|
|
7000
7008
|
const attachments = input.attachmentId && input.filename ? [{
|
|
7001
7009
|
attachmentId: input.attachmentId,
|
|
@@ -7007,7 +7015,7 @@ async function downloadAttachments(profile, input) {
|
|
|
7007
7015
|
for (const attachment of attachments) {
|
|
7008
7016
|
const data = await requestJson(profile, `/users/me/messages/${encodeURIComponent(messageId)}/attachments/${encodeURIComponent(attachment.attachmentId)}`, {});
|
|
7009
7017
|
const filename = safeFilename(attachment.filename);
|
|
7010
|
-
const path =
|
|
7018
|
+
const path = join2(outputDir, filename);
|
|
7011
7019
|
const buffer = Buffer.from(data.data, "base64url");
|
|
7012
7020
|
writeFileSync(path, buffer);
|
|
7013
7021
|
downloaded.push({
|
|
@@ -7124,8 +7132,8 @@ async function refreshAccessToken(profile, currentTokens) {
|
|
|
7124
7132
|
function listProfiles() {
|
|
7125
7133
|
const profiles = new Set;
|
|
7126
7134
|
for (const baseDir of configDirs()) {
|
|
7127
|
-
const profilesDir =
|
|
7128
|
-
if (!
|
|
7135
|
+
const profilesDir = join2(baseDir, "profiles");
|
|
7136
|
+
if (!existsSync2(profilesDir))
|
|
7129
7137
|
continue;
|
|
7130
7138
|
for (const entry of readdirSync(profilesDir, { withFileTypes: true })) {
|
|
7131
7139
|
if (entry.isDirectory())
|
|
@@ -7143,8 +7151,8 @@ function loadCredentials(profile) {
|
|
|
7143
7151
|
return { clientId: envClientId, clientSecret: envClientSecret };
|
|
7144
7152
|
for (const baseDir of configDirs()) {
|
|
7145
7153
|
const credentials = {
|
|
7146
|
-
...readJson(
|
|
7147
|
-
...readJson(
|
|
7154
|
+
...readJson(join2(baseDir, "credentials.json")),
|
|
7155
|
+
...readJson(join2(baseDir, "profiles", profile, "config.json"))
|
|
7148
7156
|
};
|
|
7149
7157
|
if (credentials.clientId || credentials.clientSecret)
|
|
7150
7158
|
return credentials;
|
|
@@ -7153,30 +7161,30 @@ function loadCredentials(profile) {
|
|
|
7153
7161
|
}
|
|
7154
7162
|
function loadTokens(profile) {
|
|
7155
7163
|
for (const baseDir of configDirs()) {
|
|
7156
|
-
const fromProfile = readJson(
|
|
7164
|
+
const fromProfile = readJson(join2(baseDir, "profiles", profile, "tokens.json"));
|
|
7157
7165
|
if (fromProfile)
|
|
7158
7166
|
return fromProfile;
|
|
7159
|
-
const flat = readJson(
|
|
7167
|
+
const flat = readJson(join2(baseDir, "profiles", `${profile}.json`));
|
|
7160
7168
|
if (flat)
|
|
7161
7169
|
return flat.tokens ?? (flat.accessToken || flat.refreshToken ? flat : null);
|
|
7162
7170
|
}
|
|
7163
7171
|
return null;
|
|
7164
7172
|
}
|
|
7165
7173
|
function saveTokens(profile, tokens) {
|
|
7166
|
-
const baseDir = configDirs().find((dir) =>
|
|
7167
|
-
const profileDir =
|
|
7174
|
+
const baseDir = configDirs().find((dir) => existsSync2(dir)) ?? configDirs()[0];
|
|
7175
|
+
const profileDir = join2(baseDir, "profiles", profile);
|
|
7168
7176
|
mkdirSync(profileDir, { recursive: true });
|
|
7169
|
-
writeFileSync(
|
|
7177
|
+
writeFileSync(join2(profileDir, "tokens.json"), JSON.stringify(tokens, null, 2), { mode: 384 });
|
|
7170
7178
|
}
|
|
7171
7179
|
function configDirs() {
|
|
7172
7180
|
const explicit = process.env.HASNA_GMAIL_CONNECTOR_DIR ?? process.env.GMAIL_CONNECTOR_DIR;
|
|
7173
7181
|
if (explicit)
|
|
7174
7182
|
return [explicit];
|
|
7175
|
-
const baseDir = process.env.HASNA_CONNECTORS_DIR ??
|
|
7176
|
-
return [
|
|
7183
|
+
const baseDir = process.env.HASNA_CONNECTORS_DIR ?? join2(homedir(), ".hasna", "connectors");
|
|
7184
|
+
return [join2(baseDir, "gmail"), join2(baseDir, "connect-gmail")];
|
|
7177
7185
|
}
|
|
7178
7186
|
function readJson(path) {
|
|
7179
|
-
if (!
|
|
7187
|
+
if (!existsSync2(path))
|
|
7180
7188
|
return null;
|
|
7181
7189
|
try {
|
|
7182
7190
|
return JSON.parse(readFileSync(path, "utf8"));
|
|
@@ -7426,9 +7434,9 @@ var init_gmail = __esm(() => {
|
|
|
7426
7434
|
});
|
|
7427
7435
|
|
|
7428
7436
|
// src/core/connectors/googledrive.ts
|
|
7429
|
-
import { existsSync as
|
|
7430
|
-
import { homedir as
|
|
7431
|
-
import { basename as basename2, join as
|
|
7437
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, readdirSync as readdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
7438
|
+
import { homedir as homedir2 } from "os";
|
|
7439
|
+
import { basename as basename2, join as join3 } from "path";
|
|
7432
7440
|
async function requestJson2(profile, path, params) {
|
|
7433
7441
|
const response = await request(profile, path, params);
|
|
7434
7442
|
const text = await response.text();
|
|
@@ -7496,8 +7504,8 @@ async function refreshAccessToken2(profile, currentTokens) {
|
|
|
7496
7504
|
function listProfiles2() {
|
|
7497
7505
|
const profiles = new Set;
|
|
7498
7506
|
for (const baseDir of configDirs2()) {
|
|
7499
|
-
const profilesDir =
|
|
7500
|
-
if (!
|
|
7507
|
+
const profilesDir = join3(baseDir, "profiles");
|
|
7508
|
+
if (!existsSync3(profilesDir))
|
|
7501
7509
|
continue;
|
|
7502
7510
|
for (const entry of readdirSync2(profilesDir, { withFileTypes: true })) {
|
|
7503
7511
|
if (entry.isDirectory())
|
|
@@ -7511,7 +7519,7 @@ function listProfiles2() {
|
|
|
7511
7519
|
function listProfileStatuses(profile) {
|
|
7512
7520
|
const profiles = profile ? [profile] : listProfiles2();
|
|
7513
7521
|
const uniqueProfiles = profiles.length ? profiles : ["default"];
|
|
7514
|
-
const
|
|
7522
|
+
const now = Date.now();
|
|
7515
7523
|
return uniqueProfiles.map((name) => {
|
|
7516
7524
|
const tokens = loadTokens2(name);
|
|
7517
7525
|
const credentials = loadCredentials2(name);
|
|
@@ -7519,7 +7527,7 @@ function listProfileStatuses(profile) {
|
|
|
7519
7527
|
const hasRefreshToken = Boolean(tokens?.refreshToken);
|
|
7520
7528
|
const hasOAuthCredentials = Boolean(credentials.clientId && credentials.clientSecret);
|
|
7521
7529
|
const expiresAt = tokens?.expiresAt ?? null;
|
|
7522
|
-
const expired = Boolean(expiresAt &&
|
|
7530
|
+
const expired = Boolean(expiresAt && now >= expiresAt - REFRESH_BUFFER_MS2);
|
|
7523
7531
|
const authenticated = Boolean(process.env.GOOGLE_ACCESS_TOKEN || hasRefreshToken || hasAccessToken && !expired);
|
|
7524
7532
|
const configured = authenticated || hasOAuthCredentials;
|
|
7525
7533
|
const authRequired = !authenticated || expired && !hasRefreshToken;
|
|
@@ -7544,8 +7552,8 @@ function loadCredentials2(profile) {
|
|
|
7544
7552
|
return { clientId: envClientId, clientSecret: envClientSecret };
|
|
7545
7553
|
for (const baseDir of configDirs2()) {
|
|
7546
7554
|
const credentials = {
|
|
7547
|
-
...readJson2(
|
|
7548
|
-
...readJson2(
|
|
7555
|
+
...readJson2(join3(baseDir, "credentials.json")),
|
|
7556
|
+
...readJson2(join3(baseDir, "profiles", profile, "config.json"))
|
|
7549
7557
|
};
|
|
7550
7558
|
if (credentials.clientId || credentials.clientSecret)
|
|
7551
7559
|
return credentials;
|
|
@@ -7554,30 +7562,30 @@ function loadCredentials2(profile) {
|
|
|
7554
7562
|
}
|
|
7555
7563
|
function loadTokens2(profile) {
|
|
7556
7564
|
for (const baseDir of configDirs2()) {
|
|
7557
|
-
const fromProfile = readJson2(
|
|
7565
|
+
const fromProfile = readJson2(join3(baseDir, "profiles", profile, "tokens.json"));
|
|
7558
7566
|
if (fromProfile)
|
|
7559
7567
|
return fromProfile;
|
|
7560
|
-
const flat = readJson2(
|
|
7568
|
+
const flat = readJson2(join3(baseDir, "profiles", `${profile}.json`));
|
|
7561
7569
|
if (flat)
|
|
7562
7570
|
return flat.tokens ?? (flat.accessToken || flat.refreshToken ? flat : null);
|
|
7563
7571
|
}
|
|
7564
7572
|
return null;
|
|
7565
7573
|
}
|
|
7566
7574
|
function saveTokens2(profile, tokens) {
|
|
7567
|
-
const baseDir = configDirs2().find((dir) =>
|
|
7568
|
-
const profileDir =
|
|
7575
|
+
const baseDir = configDirs2().find((dir) => existsSync3(dir)) ?? configDirs2()[0];
|
|
7576
|
+
const profileDir = join3(baseDir, "profiles", profile);
|
|
7569
7577
|
mkdirSync2(profileDir, { recursive: true });
|
|
7570
|
-
writeFileSync2(
|
|
7578
|
+
writeFileSync2(join3(profileDir, "tokens.json"), JSON.stringify(tokens, null, 2), { mode: 384 });
|
|
7571
7579
|
}
|
|
7572
7580
|
function configDirs2() {
|
|
7573
7581
|
const explicit = process.env.HASNA_GOOGLE_DRIVE_CONNECTOR_DIR ?? process.env.GOOGLE_DRIVE_CONNECTOR_DIR;
|
|
7574
7582
|
if (explicit)
|
|
7575
7583
|
return [explicit];
|
|
7576
|
-
const baseDir = process.env.HASNA_CONNECTORS_DIR ??
|
|
7577
|
-
return [
|
|
7584
|
+
const baseDir = process.env.HASNA_CONNECTORS_DIR ?? join3(homedir2(), ".hasna", "connectors");
|
|
7585
|
+
return [join3(baseDir, "googledrive"), join3(baseDir, "connect-googledrive")];
|
|
7578
7586
|
}
|
|
7579
7587
|
function readJson2(path) {
|
|
7580
|
-
if (!
|
|
7588
|
+
if (!existsSync3(path))
|
|
7581
7589
|
return null;
|
|
7582
7590
|
try {
|
|
7583
7591
|
return JSON.parse(readFileSync2(path, "utf8"));
|
|
@@ -7818,39 +7826,39 @@ var init_sqlite_adapter = () => {};
|
|
|
7818
7826
|
var exports_database = {};
|
|
7819
7827
|
__export(exports_database, {
|
|
7820
7828
|
shortUuid: () => shortUuid,
|
|
7821
|
-
now: () =>
|
|
7829
|
+
now: () => now,
|
|
7822
7830
|
getDatabase: () => getDatabase,
|
|
7823
7831
|
getConnectorsHome: () => getConnectorsHome,
|
|
7824
7832
|
closeDatabase: () => closeDatabase,
|
|
7825
7833
|
SqliteAdapter: () => SqliteAdapter
|
|
7826
7834
|
});
|
|
7827
|
-
import { dirname as dirname2, join as
|
|
7828
|
-
import { homedir as
|
|
7829
|
-
import { mkdirSync as mkdirSync3, existsSync as
|
|
7835
|
+
import { dirname as dirname2, join as join4 } from "path";
|
|
7836
|
+
import { homedir as homedir3 } from "os";
|
|
7837
|
+
import { mkdirSync as mkdirSync3, existsSync as existsSync4, readdirSync as readdirSync3, copyFileSync, statSync } from "fs";
|
|
7830
7838
|
function mergeDirectoryContents(sourceDir, targetDir) {
|
|
7831
|
-
if (!
|
|
7839
|
+
if (!existsSync4(sourceDir)) {
|
|
7832
7840
|
return;
|
|
7833
7841
|
}
|
|
7834
7842
|
mkdirSync3(targetDir, { recursive: true });
|
|
7835
7843
|
for (const entry of readdirSync3(sourceDir)) {
|
|
7836
|
-
const sourcePath =
|
|
7837
|
-
const targetPath =
|
|
7844
|
+
const sourcePath = join4(sourceDir, entry);
|
|
7845
|
+
const targetPath = join4(targetDir, entry);
|
|
7838
7846
|
try {
|
|
7839
7847
|
const sourceStat = statSync(sourcePath);
|
|
7840
7848
|
if (sourceStat.isDirectory()) {
|
|
7841
7849
|
mergeDirectoryContents(sourcePath, targetPath);
|
|
7842
7850
|
continue;
|
|
7843
7851
|
}
|
|
7844
|
-
if (!
|
|
7852
|
+
if (!existsSync4(targetPath)) {
|
|
7845
7853
|
copyFileSync(sourcePath, targetPath);
|
|
7846
7854
|
}
|
|
7847
7855
|
} catch {}
|
|
7848
7856
|
}
|
|
7849
7857
|
}
|
|
7850
7858
|
function getConnectorsHome() {
|
|
7851
|
-
const home = process.env["HOME"] || process.env["USERPROFILE"] ||
|
|
7852
|
-
const newDir =
|
|
7853
|
-
const legacyDirs = [
|
|
7859
|
+
const home = process.env["HOME"] || process.env["USERPROFILE"] || homedir3();
|
|
7860
|
+
const newDir = join4(home, ".hasna", "connectors");
|
|
7861
|
+
const legacyDirs = [join4(home, ".connectors"), join4(home, ".connect")];
|
|
7854
7862
|
mkdirSync3(newDir, { recursive: true });
|
|
7855
7863
|
for (const legacyDir of legacyDirs) {
|
|
7856
7864
|
try {
|
|
@@ -7882,7 +7890,7 @@ function closeDatabase() {
|
|
|
7882
7890
|
_db = null;
|
|
7883
7891
|
_dbPath = null;
|
|
7884
7892
|
}
|
|
7885
|
-
function
|
|
7893
|
+
function now() {
|
|
7886
7894
|
return new Date().toISOString();
|
|
7887
7895
|
}
|
|
7888
7896
|
function shortUuid() {
|
|
@@ -7999,12 +8007,12 @@ var init_database = __esm(() => {
|
|
|
7999
8007
|
init_sqlite_adapter();
|
|
8000
8008
|
init_sqlite_adapter();
|
|
8001
8009
|
DB_DIR = getConnectorsHome();
|
|
8002
|
-
DB_PATH =
|
|
8010
|
+
DB_PATH = join4(DB_DIR, "connectors.db");
|
|
8003
8011
|
});
|
|
8004
8012
|
|
|
8005
8013
|
// src/lib/connector-resolver.ts
|
|
8006
|
-
import { existsSync as
|
|
8007
|
-
import { join as
|
|
8014
|
+
import { existsSync as existsSync5, readdirSync as readdirSync4, statSync as statSync2 } from "fs";
|
|
8015
|
+
import { join as join5 } from "path";
|
|
8008
8016
|
function stripLegacyPrefix(name) {
|
|
8009
8017
|
return name.startsWith(LEGACY_CONNECTOR_PREFIX) ? name.slice(LEGACY_CONNECTOR_PREFIX.length) : name;
|
|
8010
8018
|
}
|
|
@@ -8047,8 +8055,8 @@ function connectorPackageDirNames(name) {
|
|
|
8047
8055
|
function resolveConnectorPackagePath(connectorsDir, name) {
|
|
8048
8056
|
const resolution = resolveConnectorName(name);
|
|
8049
8057
|
const dirNames = connectorPackageDirNames(name);
|
|
8050
|
-
const checkedPaths = dirNames.map((dirName) =>
|
|
8051
|
-
const existingPath = checkedPaths.find((path) =>
|
|
8058
|
+
const checkedPaths = dirNames.map((dirName) => join5(connectorsDir, dirName));
|
|
8059
|
+
const existingPath = checkedPaths.find((path) => existsSync5(path)) ?? null;
|
|
8052
8060
|
const existingDirName = existingPath ? dirNames[checkedPaths.indexOf(existingPath)] : null;
|
|
8053
8061
|
return {
|
|
8054
8062
|
...resolution,
|
|
@@ -8067,10 +8075,10 @@ function getConnectorPackagePath(connectorsDir, name) {
|
|
|
8067
8075
|
function resolveConnectorConfigPaths(name, connectorsHome = getConnectorsHome()) {
|
|
8068
8076
|
const resolution = resolveConnectorName(name);
|
|
8069
8077
|
const preferredDirName = resolution.canonicalName || resolution.legacyName;
|
|
8070
|
-
const preferredPath =
|
|
8071
|
-
const legacyPath =
|
|
8078
|
+
const preferredPath = join5(connectorsHome, preferredDirName);
|
|
8079
|
+
const legacyPath = join5(connectorsHome, resolution.legacyName);
|
|
8072
8080
|
const paths = preferredPath === legacyPath ? [preferredPath] : [preferredPath, legacyPath];
|
|
8073
|
-
const existingPaths = paths.filter((path) =>
|
|
8081
|
+
const existingPaths = paths.filter((path) => existsSync5(path));
|
|
8074
8082
|
return {
|
|
8075
8083
|
...resolution,
|
|
8076
8084
|
connectorsHome,
|
|
@@ -8088,11 +8096,11 @@ function getConnectorConfigReadDirs(name, connectorsHome = getConnectorsHome())
|
|
|
8088
8096
|
return resolveConnectorConfigPaths(name, connectorsHome).readPaths;
|
|
8089
8097
|
}
|
|
8090
8098
|
function listConfiguredConnectorNames(connectorsHome = getConnectorsHome()) {
|
|
8091
|
-
if (!
|
|
8099
|
+
if (!existsSync5(connectorsHome))
|
|
8092
8100
|
return [];
|
|
8093
8101
|
const names = new Set;
|
|
8094
8102
|
for (const entry of readdirSync4(connectorsHome)) {
|
|
8095
|
-
const fullPath =
|
|
8103
|
+
const fullPath = join5(connectorsHome, entry);
|
|
8096
8104
|
try {
|
|
8097
8105
|
if (!statSync2(fullPath).isDirectory())
|
|
8098
8106
|
continue;
|
|
@@ -8115,7 +8123,7 @@ var init_connector_resolver = __esm(() => {
|
|
|
8115
8123
|
|
|
8116
8124
|
// src/core/connectors/imessage.ts
|
|
8117
8125
|
import {
|
|
8118
|
-
existsSync as
|
|
8126
|
+
existsSync as existsSync6,
|
|
8119
8127
|
mkdirSync as mkdirSync4,
|
|
8120
8128
|
readFileSync as readFileSync3,
|
|
8121
8129
|
readdirSync as readdirSync5,
|
|
@@ -8123,7 +8131,7 @@ import {
|
|
|
8123
8131
|
statSync as statSync3,
|
|
8124
8132
|
writeFileSync as writeFileSync3
|
|
8125
8133
|
} from "fs";
|
|
8126
|
-
import { join as
|
|
8134
|
+
import { join as join6 } from "path";
|
|
8127
8135
|
function buildRootHelp(specs) {
|
|
8128
8136
|
const lines = [
|
|
8129
8137
|
"Usage: connect-imessage [options] [command]",
|
|
@@ -8174,12 +8182,12 @@ function getConfigReadDirs() {
|
|
|
8174
8182
|
return getConnectorConfigReadDirs(CONNECTOR_NAME);
|
|
8175
8183
|
}
|
|
8176
8184
|
function getProfilesDir() {
|
|
8177
|
-
return
|
|
8185
|
+
return join6(getConfigDir(), "profiles");
|
|
8178
8186
|
}
|
|
8179
8187
|
function getCurrentProfile() {
|
|
8180
8188
|
for (const configDir of getConfigReadDirs()) {
|
|
8181
|
-
const currentProfileFile =
|
|
8182
|
-
if (!
|
|
8189
|
+
const currentProfileFile = join6(configDir, "current_profile");
|
|
8190
|
+
if (!existsSync6(currentProfileFile))
|
|
8183
8191
|
continue;
|
|
8184
8192
|
try {
|
|
8185
8193
|
return readFileSync3(currentProfileFile, "utf-8").trim() || "default";
|
|
@@ -8192,16 +8200,16 @@ function getCurrentProfile() {
|
|
|
8192
8200
|
function setCurrentProfile(profile) {
|
|
8193
8201
|
const configDir = getConfigDir();
|
|
8194
8202
|
mkdirSync4(configDir, { recursive: true });
|
|
8195
|
-
writeFileSync3(
|
|
8203
|
+
writeFileSync3(join6(configDir, "current_profile"), profile);
|
|
8196
8204
|
}
|
|
8197
8205
|
function getFlatProfilePath(profile) {
|
|
8198
|
-
return
|
|
8206
|
+
return join6(getProfilesDir(), `${profile}.json`);
|
|
8199
8207
|
}
|
|
8200
8208
|
function getFlatProfileReadPaths(profile) {
|
|
8201
|
-
return getConfigReadDirs().map((dir) =>
|
|
8209
|
+
return getConfigReadDirs().map((dir) => join6(dir, "profiles", `${profile}.json`));
|
|
8202
8210
|
}
|
|
8203
8211
|
function getDirectoryProfileReadPaths(profile) {
|
|
8204
|
-
return getConfigReadDirs().map((dir) =>
|
|
8212
|
+
return getConfigReadDirs().map((dir) => join6(dir, "profiles", profile, "config.json"));
|
|
8205
8213
|
}
|
|
8206
8214
|
function loadJsonFile(path) {
|
|
8207
8215
|
try {
|
|
@@ -8221,8 +8229,8 @@ function sanitizeProfileConfig(config) {
|
|
|
8221
8229
|
};
|
|
8222
8230
|
}
|
|
8223
8231
|
function loadProfile(profile = getCurrentProfile()) {
|
|
8224
|
-
const flatConfig = getFlatProfileReadPaths(profile).reverse().reduce((config, path) => ({ ...config, ...
|
|
8225
|
-
const directoryConfig = getDirectoryProfileReadPaths(profile).reverse().reduce((config, path) => ({ ...config, ...
|
|
8232
|
+
const flatConfig = getFlatProfileReadPaths(profile).reverse().reduce((config, path) => ({ ...config, ...existsSync6(path) ? loadJsonFile(path) : {} }), {});
|
|
8233
|
+
const directoryConfig = getDirectoryProfileReadPaths(profile).reverse().reduce((config, path) => ({ ...config, ...existsSync6(path) ? loadJsonFile(path) : {} }), {});
|
|
8226
8234
|
return sanitizeProfileConfig({
|
|
8227
8235
|
...flatConfig,
|
|
8228
8236
|
...directoryConfig
|
|
@@ -8238,17 +8246,17 @@ function profileExists(profile) {
|
|
|
8238
8246
|
if (profile === "default") {
|
|
8239
8247
|
return true;
|
|
8240
8248
|
}
|
|
8241
|
-
return getFlatProfileReadPaths(profile).some((path) =>
|
|
8249
|
+
return getFlatProfileReadPaths(profile).some((path) => existsSync6(path)) || getConfigReadDirs().some((dir) => existsSync6(join6(dir, "profiles", profile)));
|
|
8242
8250
|
}
|
|
8243
8251
|
function listProfiles3() {
|
|
8244
8252
|
const seen = new Set(["default"]);
|
|
8245
8253
|
for (const configDir of getConfigReadDirs()) {
|
|
8246
|
-
const profilesDir =
|
|
8247
|
-
if (!
|
|
8254
|
+
const profilesDir = join6(configDir, "profiles");
|
|
8255
|
+
if (!existsSync6(profilesDir))
|
|
8248
8256
|
continue;
|
|
8249
8257
|
try {
|
|
8250
8258
|
for (const entry of readdirSync5(profilesDir)) {
|
|
8251
|
-
const fullPath =
|
|
8259
|
+
const fullPath = join6(profilesDir, entry);
|
|
8252
8260
|
const stat = statSync3(fullPath);
|
|
8253
8261
|
if (stat.isDirectory()) {
|
|
8254
8262
|
seen.add(entry);
|
|
@@ -8270,11 +8278,11 @@ function createProfile(profile, config = {}) {
|
|
|
8270
8278
|
}
|
|
8271
8279
|
function clearProfile(profile = getCurrentProfile()) {
|
|
8272
8280
|
const flatPath = getFlatProfilePath(profile);
|
|
8273
|
-
const directoryPath =
|
|
8274
|
-
if (
|
|
8281
|
+
const directoryPath = join6(getProfilesDir(), profile);
|
|
8282
|
+
if (existsSync6(flatPath)) {
|
|
8275
8283
|
rmSync(flatPath);
|
|
8276
8284
|
}
|
|
8277
|
-
if (
|
|
8285
|
+
if (existsSync6(directoryPath)) {
|
|
8278
8286
|
rmSync(directoryPath, { recursive: true, force: true });
|
|
8279
8287
|
}
|
|
8280
8288
|
}
|
|
@@ -9200,18 +9208,18 @@ var init_imessage = __esm(() => {
|
|
|
9200
9208
|
});
|
|
9201
9209
|
|
|
9202
9210
|
// src/core/connectors/stripe.ts
|
|
9203
|
-
import { existsSync as
|
|
9204
|
-
import { dirname as dirname3, join as
|
|
9211
|
+
import { existsSync as existsSync7 } from "fs";
|
|
9212
|
+
import { dirname as dirname3, join as join7 } from "path";
|
|
9205
9213
|
import { fileURLToPath as fileURLToPath2, pathToFileURL as pathToFileURL2 } from "url";
|
|
9206
9214
|
function resolveStripeConnectorDir() {
|
|
9207
9215
|
const candidates = [
|
|
9208
|
-
|
|
9209
|
-
|
|
9210
|
-
|
|
9211
|
-
|
|
9216
|
+
join7(__dirname3, "..", "..", "..", "connectors", "stripe"),
|
|
9217
|
+
join7(__dirname3, "..", "..", "connectors", "stripe"),
|
|
9218
|
+
join7(__dirname3, "..", "connectors", "stripe"),
|
|
9219
|
+
join7(process.cwd(), "connectors", "stripe")
|
|
9212
9220
|
];
|
|
9213
9221
|
for (const candidate of candidates) {
|
|
9214
|
-
if (
|
|
9222
|
+
if (existsSync7(candidate)) {
|
|
9215
9223
|
return candidate;
|
|
9216
9224
|
}
|
|
9217
9225
|
}
|
|
@@ -9259,10 +9267,10 @@ function buildCommandHelp2(spec) {
|
|
|
9259
9267
|
`);
|
|
9260
9268
|
}
|
|
9261
9269
|
async function loadStripeApiModule() {
|
|
9262
|
-
return await import(pathToFileURL2(
|
|
9270
|
+
return await import(pathToFileURL2(join7(CONNECTOR_DIR2, "src", "api", "index.ts")).href);
|
|
9263
9271
|
}
|
|
9264
9272
|
async function loadStripeConfigModule() {
|
|
9265
|
-
return await import(pathToFileURL2(
|
|
9273
|
+
return await import(pathToFileURL2(join7(CONNECTOR_DIR2, "src", "utils", "config.ts")).href);
|
|
9266
9274
|
}
|
|
9267
9275
|
function extractGlobalArgs3(args) {
|
|
9268
9276
|
const remaining = [];
|
|
@@ -18386,8 +18394,8 @@ __export(exports_registry, {
|
|
|
18386
18394
|
CONNECTORS: () => CONNECTORS,
|
|
18387
18395
|
CATEGORIES: () => CATEGORIES
|
|
18388
18396
|
});
|
|
18389
|
-
import { existsSync as
|
|
18390
|
-
import { join as
|
|
18397
|
+
import { existsSync as existsSync8, readFileSync as readFileSync4 } from "fs";
|
|
18398
|
+
import { join as join8, dirname as dirname4 } from "path";
|
|
18391
18399
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
18392
18400
|
function getConnectorsByCategory(category) {
|
|
18393
18401
|
return CONNECTORS.filter((c) => c.category === category);
|
|
@@ -18551,16 +18559,16 @@ function loadConnectorVersions() {
|
|
|
18551
18559
|
versionsLoaded = true;
|
|
18552
18560
|
const thisDir = dirname4(fileURLToPath3(import.meta.url));
|
|
18553
18561
|
const candidates = [
|
|
18554
|
-
|
|
18555
|
-
|
|
18562
|
+
join8(thisDir, "..", "connectors"),
|
|
18563
|
+
join8(thisDir, "..", "..", "connectors")
|
|
18556
18564
|
];
|
|
18557
|
-
const connectorsDir = candidates.find((d) =>
|
|
18565
|
+
const connectorsDir = candidates.find((d) => existsSync8(d));
|
|
18558
18566
|
if (!connectorsDir)
|
|
18559
18567
|
return;
|
|
18560
18568
|
for (const connector of CONNECTORS) {
|
|
18561
18569
|
try {
|
|
18562
|
-
const pkgPath =
|
|
18563
|
-
if (
|
|
18570
|
+
const pkgPath = join8(getConnectorPackagePath(connectorsDir, connector.name), "package.json");
|
|
18571
|
+
if (existsSync8(pkgPath)) {
|
|
18564
18572
|
const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
|
|
18565
18573
|
connector.version = pkg.version || "0.0.0";
|
|
18566
18574
|
continue;
|
|
@@ -20285,30 +20293,30 @@ __export(exports_installer, {
|
|
|
20285
20293
|
getConnectorDocs: () => getConnectorDocs,
|
|
20286
20294
|
connectorExists: () => connectorExists
|
|
20287
20295
|
});
|
|
20288
|
-
import { existsSync as
|
|
20289
|
-
import { join as
|
|
20296
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4, readdirSync as readdirSync6, statSync as statSync4, rmSync as rmSync2 } from "fs";
|
|
20297
|
+
import { join as join9, dirname as dirname5 } from "path";
|
|
20290
20298
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
20291
20299
|
function resolveConnectorsDir() {
|
|
20292
|
-
const fromBin =
|
|
20293
|
-
if (
|
|
20300
|
+
const fromBin = join9(__dirname4, "..", "connectors");
|
|
20301
|
+
if (existsSync9(fromBin))
|
|
20294
20302
|
return fromBin;
|
|
20295
|
-
const fromSrc =
|
|
20296
|
-
if (
|
|
20303
|
+
const fromSrc = join9(__dirname4, "..", "..", "connectors");
|
|
20304
|
+
if (existsSync9(fromSrc))
|
|
20297
20305
|
return fromSrc;
|
|
20298
20306
|
return fromBin;
|
|
20299
20307
|
}
|
|
20300
20308
|
function getProjectConnectorsDir(targetDir) {
|
|
20301
|
-
return
|
|
20309
|
+
return join9(targetDir, PROJECT_CONNECTORS_DIRNAME);
|
|
20302
20310
|
}
|
|
20303
20311
|
function getEnablementManifestPath(targetDir) {
|
|
20304
|
-
return
|
|
20312
|
+
return join9(getProjectConnectorsDir(targetDir), ENABLEMENT_MANIFEST_FILENAME);
|
|
20305
20313
|
}
|
|
20306
20314
|
function getLegacyInstallPath(targetDir, name) {
|
|
20307
|
-
return
|
|
20315
|
+
return join9(getProjectConnectorsDir(targetDir), legacyConnectorName(name));
|
|
20308
20316
|
}
|
|
20309
20317
|
function loadEnablementManifest(targetDir) {
|
|
20310
20318
|
const manifestPath = getEnablementManifestPath(targetDir);
|
|
20311
|
-
if (!
|
|
20319
|
+
if (!existsSync9(manifestPath)) {
|
|
20312
20320
|
return null;
|
|
20313
20321
|
}
|
|
20314
20322
|
try {
|
|
@@ -20328,11 +20336,11 @@ function loadEnablementManifest(targetDir) {
|
|
|
20328
20336
|
}
|
|
20329
20337
|
function getLegacyInstalledConnectors(targetDir) {
|
|
20330
20338
|
const connectorsDir = getProjectConnectorsDir(targetDir);
|
|
20331
|
-
if (!
|
|
20339
|
+
if (!existsSync9(connectorsDir)) {
|
|
20332
20340
|
return [];
|
|
20333
20341
|
}
|
|
20334
20342
|
return readdirSync6(connectorsDir).filter((entry) => {
|
|
20335
|
-
const fullPath =
|
|
20343
|
+
const fullPath = join9(connectorsDir, entry);
|
|
20336
20344
|
return entry.startsWith("connect-") && statSync4(fullPath).isDirectory();
|
|
20337
20345
|
}).map((entry) => entry.replace("connect-", "")).sort();
|
|
20338
20346
|
}
|
|
@@ -20341,7 +20349,7 @@ function getEnabledConnectors(targetDir) {
|
|
|
20341
20349
|
return [...new Set([...manifestConnectors, ...getLegacyInstalledConnectors(targetDir)])].sort();
|
|
20342
20350
|
}
|
|
20343
20351
|
function updateConnectorsIndex(connectorsDir, connectors18) {
|
|
20344
|
-
const indexPath =
|
|
20352
|
+
const indexPath = join9(connectorsDir, ENABLEMENT_INDEX_FILENAME);
|
|
20345
20353
|
const connectorList = connectors18.map((connector) => ` "${connector}",`).join(`
|
|
20346
20354
|
`);
|
|
20347
20355
|
const content = `/**
|
|
@@ -20377,7 +20385,7 @@ function getConnectorPath(name) {
|
|
|
20377
20385
|
}
|
|
20378
20386
|
function connectorExists(name) {
|
|
20379
20387
|
const normalizedName = normalizeConnectorName(name);
|
|
20380
|
-
return hasInternalConnectorDefinition(normalizedName) ||
|
|
20388
|
+
return hasInternalConnectorDefinition(normalizedName) || existsSync9(getConnectorPath(normalizedName));
|
|
20381
20389
|
}
|
|
20382
20390
|
function installConnector(name, options = {}) {
|
|
20383
20391
|
const { targetDir = process.cwd(), overwrite = false } = options;
|
|
@@ -20410,7 +20418,7 @@ function installConnector(name, options = {}) {
|
|
|
20410
20418
|
try {
|
|
20411
20419
|
const nextEnabled = [...new Set([...installed, normalizedName])].sort();
|
|
20412
20420
|
writeEnablementManifest(targetDir, nextEnabled);
|
|
20413
|
-
if (overwrite &&
|
|
20421
|
+
if (overwrite && existsSync9(legacyInstallPath)) {
|
|
20414
20422
|
rmSync2(legacyInstallPath, { recursive: true });
|
|
20415
20423
|
}
|
|
20416
20424
|
return {
|
|
@@ -20445,8 +20453,8 @@ function parseConnectorDocs(raw) {
|
|
|
20445
20453
|
function getConnectorDocs(name) {
|
|
20446
20454
|
const normalizedName = normalizeConnectorName(name);
|
|
20447
20455
|
const connectorPath = getConnectorPath(normalizedName);
|
|
20448
|
-
const claudeMdPath =
|
|
20449
|
-
if (
|
|
20456
|
+
const claudeMdPath = join9(connectorPath, "CLAUDE.md");
|
|
20457
|
+
if (existsSync9(claudeMdPath)) {
|
|
20450
20458
|
return parseConnectorDocs(readFileSync5(claudeMdPath, "utf-8"));
|
|
20451
20459
|
}
|
|
20452
20460
|
const internalDocs = getInternalConnectorDefinition(normalizedName)?.docsMarkdown;
|
|
@@ -20491,7 +20499,7 @@ function removeConnector(name, targetDir = process.cwd()) {
|
|
|
20491
20499
|
const nextEnabled = installed.filter((connector) => connector !== normalizedName);
|
|
20492
20500
|
writeEnablementManifest(targetDir, nextEnabled);
|
|
20493
20501
|
const legacyInstallPath = getLegacyInstallPath(targetDir, normalizedName);
|
|
20494
|
-
if (
|
|
20502
|
+
if (existsSync9(legacyInstallPath)) {
|
|
20495
20503
|
rmSync2(legacyInstallPath, { recursive: true });
|
|
20496
20504
|
}
|
|
20497
20505
|
return true;
|
|
@@ -20578,7 +20586,7 @@ function maybeTruncateOutput(text, options = {}) {
|
|
|
20578
20586
|
var DEFAULT_COMPACT_LIMIT = 20, DEFAULT_MCP_LIMIT = 20, MAX_COMPACT_LIMIT = 100, DEFAULT_TEXT_WIDTH = 96, DEFAULT_OUTPUT_CHARS = 6000;
|
|
20579
20587
|
|
|
20580
20588
|
// src/lib/lock.ts
|
|
20581
|
-
import { openSync, closeSync, unlinkSync, existsSync as
|
|
20589
|
+
import { openSync, closeSync, unlinkSync, existsSync as existsSync10, statSync as statSync6 } from "fs";
|
|
20582
20590
|
import { mkdirSync as mkdirSync6 } from "fs";
|
|
20583
20591
|
function lockPath(connector) {
|
|
20584
20592
|
const dir = getConnectorConfigDir(connector);
|
|
@@ -20594,7 +20602,7 @@ function isStale(path) {
|
|
|
20594
20602
|
}
|
|
20595
20603
|
}
|
|
20596
20604
|
function tryAcquire(path) {
|
|
20597
|
-
if (
|
|
20605
|
+
if (existsSync10(path) && isStale(path)) {
|
|
20598
20606
|
try {
|
|
20599
20607
|
unlinkSync(path);
|
|
20600
20608
|
} catch {}
|
|
@@ -20644,9 +20652,9 @@ var init_lock = __esm(() => {
|
|
|
20644
20652
|
});
|
|
20645
20653
|
|
|
20646
20654
|
// src/server/auth.ts
|
|
20647
|
-
import { chmodSync, existsSync as
|
|
20655
|
+
import { chmodSync, existsSync as existsSync11, readFileSync as readFileSync6, writeFileSync as writeFileSync5, mkdirSync as mkdirSync7, readdirSync as readdirSync8, rmSync as rmSync3, statSync as statSync7 } from "fs";
|
|
20648
20656
|
import { randomBytes } from "crypto";
|
|
20649
|
-
import { join as
|
|
20657
|
+
import { join as join11 } from "path";
|
|
20650
20658
|
function getAuthType(name) {
|
|
20651
20659
|
name = normalizeConnectorName(name);
|
|
20652
20660
|
const docs = getConnectorDocs(name);
|
|
@@ -20687,8 +20695,8 @@ function writePrivateText(path, data) {
|
|
|
20687
20695
|
function getCurrentProfile2(name) {
|
|
20688
20696
|
name = normalizeConnectorName(name);
|
|
20689
20697
|
for (const configDir of getConnectorConfigReadDirs2(name)) {
|
|
20690
|
-
const currentProfileFile =
|
|
20691
|
-
if (
|
|
20698
|
+
const currentProfileFile = join11(configDir, "current_profile");
|
|
20699
|
+
if (existsSync11(currentProfileFile)) {
|
|
20692
20700
|
try {
|
|
20693
20701
|
return readFileSync6(currentProfileFile, "utf-8").trim() || "default";
|
|
20694
20702
|
} catch {
|
|
@@ -20701,14 +20709,14 @@ function getCurrentProfile2(name) {
|
|
|
20701
20709
|
function loadProfileConfigFromDir(configDir, profile) {
|
|
20702
20710
|
let flatConfig = {};
|
|
20703
20711
|
let dirConfig = {};
|
|
20704
|
-
const profileFile =
|
|
20705
|
-
if (
|
|
20712
|
+
const profileFile = join11(configDir, "profiles", `${profile}.json`);
|
|
20713
|
+
if (existsSync11(profileFile)) {
|
|
20706
20714
|
try {
|
|
20707
20715
|
flatConfig = JSON.parse(readFileSync6(profileFile, "utf-8"));
|
|
20708
20716
|
} catch {}
|
|
20709
20717
|
}
|
|
20710
|
-
const profileDirConfig =
|
|
20711
|
-
if (
|
|
20718
|
+
const profileDirConfig = join11(configDir, "profiles", profile, "config.json");
|
|
20719
|
+
if (existsSync11(profileDirConfig)) {
|
|
20712
20720
|
try {
|
|
20713
20721
|
dirConfig = JSON.parse(readFileSync6(profileDirConfig, "utf-8"));
|
|
20714
20722
|
} catch {}
|
|
@@ -20728,8 +20736,8 @@ function loadTokens3(name) {
|
|
|
20728
20736
|
name = normalizeConnectorName(name);
|
|
20729
20737
|
const profile = getCurrentProfile2(name);
|
|
20730
20738
|
for (const configDir of getConnectorConfigReadDirs2(name)) {
|
|
20731
|
-
const tokensFile =
|
|
20732
|
-
if (
|
|
20739
|
+
const tokensFile = join11(configDir, "profiles", profile, "tokens.json");
|
|
20740
|
+
if (existsSync11(tokensFile)) {
|
|
20733
20741
|
try {
|
|
20734
20742
|
return JSON.parse(readFileSync6(tokensFile, "utf-8"));
|
|
20735
20743
|
} catch {
|
|
@@ -20862,10 +20870,10 @@ function _saveApiKey(name, key, field) {
|
|
|
20862
20870
|
const profile = getCurrentProfile2(name);
|
|
20863
20871
|
const keyField = field || guessKeyField(name);
|
|
20864
20872
|
if (keyField === "clientId" || keyField === "clientSecret") {
|
|
20865
|
-
const credentialsFile =
|
|
20873
|
+
const credentialsFile = join11(configDir, "credentials.json");
|
|
20866
20874
|
ensurePrivateDir(configDir);
|
|
20867
20875
|
let creds = {};
|
|
20868
|
-
if (
|
|
20876
|
+
if (existsSync11(credentialsFile)) {
|
|
20869
20877
|
try {
|
|
20870
20878
|
creds = JSON.parse(readFileSync6(credentialsFile, "utf-8"));
|
|
20871
20879
|
} catch {}
|
|
@@ -20874,10 +20882,10 @@ function _saveApiKey(name, key, field) {
|
|
|
20874
20882
|
writePrivateJson(credentialsFile, creds);
|
|
20875
20883
|
return;
|
|
20876
20884
|
}
|
|
20877
|
-
const profilesDir =
|
|
20878
|
-
const profileFile =
|
|
20879
|
-
const profileDir =
|
|
20880
|
-
if (
|
|
20885
|
+
const profilesDir = join11(configDir, "profiles");
|
|
20886
|
+
const profileFile = join11(profilesDir, `${profile}.json`);
|
|
20887
|
+
const profileDir = join11(profilesDir, profile);
|
|
20888
|
+
if (existsSync11(profileFile)) {
|
|
20881
20889
|
let config = {};
|
|
20882
20890
|
try {
|
|
20883
20891
|
config = JSON.parse(readFileSync6(profileFile, "utf-8"));
|
|
@@ -20888,10 +20896,10 @@ function _saveApiKey(name, key, field) {
|
|
|
20888
20896
|
writePrivateJson(profileFile, config);
|
|
20889
20897
|
return;
|
|
20890
20898
|
}
|
|
20891
|
-
if (
|
|
20892
|
-
const configFile =
|
|
20899
|
+
if (existsSync11(profileDir)) {
|
|
20900
|
+
const configFile = join11(profileDir, "config.json");
|
|
20893
20901
|
let config = {};
|
|
20894
|
-
if (
|
|
20902
|
+
if (existsSync11(configFile)) {
|
|
20895
20903
|
try {
|
|
20896
20904
|
config = JSON.parse(readFileSync6(configFile, "utf-8"));
|
|
20897
20905
|
} catch {}
|
|
@@ -20906,7 +20914,7 @@ function _saveApiKey(name, key, field) {
|
|
|
20906
20914
|
ensurePrivateDir(configDir);
|
|
20907
20915
|
ensurePrivateDir(profilesDir);
|
|
20908
20916
|
ensurePrivateDir(profileDir);
|
|
20909
|
-
writePrivateJson(
|
|
20917
|
+
writePrivateJson(join11(profileDir, "config.json"), { [keyField]: key });
|
|
20910
20918
|
}
|
|
20911
20919
|
function guessKeyField(name) {
|
|
20912
20920
|
name = normalizeConnectorName(name);
|
|
@@ -20926,8 +20934,8 @@ function guessKeyField(name) {
|
|
|
20926
20934
|
function getOAuthConfig(name) {
|
|
20927
20935
|
name = normalizeConnectorName(name);
|
|
20928
20936
|
for (const configDir of getConnectorConfigReadDirs2(name)) {
|
|
20929
|
-
const credentialsFile =
|
|
20930
|
-
if (
|
|
20937
|
+
const credentialsFile = join11(configDir, "credentials.json");
|
|
20938
|
+
if (existsSync11(credentialsFile)) {
|
|
20931
20939
|
try {
|
|
20932
20940
|
const creds = JSON.parse(readFileSync6(credentialsFile, "utf-8"));
|
|
20933
20941
|
return { clientId: creds.clientId, clientSecret: creds.clientSecret };
|
|
@@ -21013,12 +21021,12 @@ function saveOAuthTokens(name, tokens) {
|
|
|
21013
21021
|
name = normalizeConnectorName(name);
|
|
21014
21022
|
const configDir = getConnectorConfigDir2(name);
|
|
21015
21023
|
const profile = getCurrentProfile2(name);
|
|
21016
|
-
const profilesDir =
|
|
21017
|
-
const profileDir =
|
|
21024
|
+
const profilesDir = join11(configDir, "profiles");
|
|
21025
|
+
const profileDir = join11(profilesDir, profile);
|
|
21018
21026
|
ensurePrivateDir(configDir);
|
|
21019
21027
|
ensurePrivateDir(profilesDir);
|
|
21020
21028
|
ensurePrivateDir(profileDir);
|
|
21021
|
-
const tokensFile =
|
|
21029
|
+
const tokensFile = join11(profileDir, "tokens.json");
|
|
21022
21030
|
writePrivateJson(tokensFile, tokens);
|
|
21023
21031
|
}
|
|
21024
21032
|
async function refreshOAuthToken(name) {
|
|
@@ -21065,13 +21073,13 @@ function listProfiles4(name) {
|
|
|
21065
21073
|
name = normalizeConnectorName(name);
|
|
21066
21074
|
const seen = new Set;
|
|
21067
21075
|
for (const configDir of getConnectorConfigReadDirs2(name)) {
|
|
21068
|
-
const profilesDir =
|
|
21069
|
-
if (!
|
|
21076
|
+
const profilesDir = join11(configDir, "profiles");
|
|
21077
|
+
if (!existsSync11(profilesDir))
|
|
21070
21078
|
continue;
|
|
21071
21079
|
try {
|
|
21072
21080
|
const entries = readdirSync8(profilesDir);
|
|
21073
21081
|
for (const entry of entries) {
|
|
21074
|
-
const fullPath =
|
|
21082
|
+
const fullPath = join11(profilesDir, entry);
|
|
21075
21083
|
const stat = statSync7(fullPath);
|
|
21076
21084
|
if (stat.isDirectory()) {
|
|
21077
21085
|
seen.add(entry);
|
|
@@ -21088,24 +21096,24 @@ function switchProfile(name, profile) {
|
|
|
21088
21096
|
name = normalizeConnectorName(name);
|
|
21089
21097
|
const configDir = getConnectorConfigDir2(name);
|
|
21090
21098
|
ensurePrivateDir(configDir);
|
|
21091
|
-
writePrivateText(
|
|
21099
|
+
writePrivateText(join11(configDir, "current_profile"), profile);
|
|
21092
21100
|
}
|
|
21093
21101
|
function deleteProfile2(name, profile) {
|
|
21094
21102
|
name = normalizeConnectorName(name);
|
|
21095
21103
|
if (profile === "default")
|
|
21096
21104
|
return false;
|
|
21097
21105
|
const configDir = getConnectorConfigDir2(name);
|
|
21098
|
-
const profilesDir =
|
|
21099
|
-
const profileFile =
|
|
21100
|
-
if (
|
|
21106
|
+
const profilesDir = join11(configDir, "profiles");
|
|
21107
|
+
const profileFile = join11(profilesDir, `${profile}.json`);
|
|
21108
|
+
if (existsSync11(profileFile)) {
|
|
21101
21109
|
rmSync3(profileFile);
|
|
21102
21110
|
if (getCurrentProfile2(name) === profile) {
|
|
21103
21111
|
switchProfile(name, "default");
|
|
21104
21112
|
}
|
|
21105
21113
|
return true;
|
|
21106
21114
|
}
|
|
21107
|
-
const profileDir =
|
|
21108
|
-
if (
|
|
21115
|
+
const profileDir = join11(profilesDir, profile);
|
|
21116
|
+
if (existsSync11(profileDir)) {
|
|
21109
21117
|
rmSync3(profileDir, { recursive: true });
|
|
21110
21118
|
if (getCurrentProfile2(name) === profile) {
|
|
21111
21119
|
switchProfile(name, "default");
|
|
@@ -21175,7 +21183,7 @@ __export(exports_promotions, {
|
|
|
21175
21183
|
});
|
|
21176
21184
|
function promoteConnector(name, db) {
|
|
21177
21185
|
const d = db ?? getDatabase();
|
|
21178
|
-
d.run("INSERT OR REPLACE INTO connector_promotions (connector, promoted_at) VALUES (?, ?)", [name,
|
|
21186
|
+
d.run("INSERT OR REPLACE INTO connector_promotions (connector, promoted_at) VALUES (?, ?)", [name, now()]);
|
|
21179
21187
|
}
|
|
21180
21188
|
function demoteConnector(name, db) {
|
|
21181
21189
|
const d = db ?? getDatabase();
|
|
@@ -21205,7 +21213,7 @@ __export(exports_usage, {
|
|
|
21205
21213
|
});
|
|
21206
21214
|
function logUsage(connector, action, agentId, db) {
|
|
21207
21215
|
const d = db ?? getDatabase();
|
|
21208
|
-
d.run("INSERT INTO connector_usage (id, connector, action, agent_id, timestamp) VALUES (?, ?, ?, ?, ?)", [shortUuid(), connector, action, agentId ?? null,
|
|
21216
|
+
d.run("INSERT INTO connector_usage (id, connector, action, agent_id, timestamp) VALUES (?, ?, ?, ?, ?)", [shortUuid(), connector, action, agentId ?? null, now()]);
|
|
21209
21217
|
}
|
|
21210
21218
|
function getUsageStats(connector, db) {
|
|
21211
21219
|
const d = db ?? getDatabase();
|
|
@@ -21263,7 +21271,7 @@ function registerAgent(input, db) {
|
|
|
21263
21271
|
};
|
|
21264
21272
|
}
|
|
21265
21273
|
const updates = ["last_seen_at = ?"];
|
|
21266
|
-
const params = [
|
|
21274
|
+
const params = [now()];
|
|
21267
21275
|
if (input.session_id && !sameSession) {
|
|
21268
21276
|
updates.push("session_id = ?");
|
|
21269
21277
|
params.push(input.session_id);
|
|
@@ -21273,7 +21281,7 @@ function registerAgent(input, db) {
|
|
|
21273
21281
|
return getAgent(existing.id, d);
|
|
21274
21282
|
}
|
|
21275
21283
|
const id = shortUuid2();
|
|
21276
|
-
const ts =
|
|
21284
|
+
const ts = now();
|
|
21277
21285
|
d.run(`INSERT INTO agents (id, name, session_id, role, last_seen_at, created_at)
|
|
21278
21286
|
VALUES (?, ?, ?, ?, ?, ?)`, [id, normalizedName, input.session_id ?? null, input.role ?? "agent", ts, ts]);
|
|
21279
21287
|
return getAgent(id, d);
|
|
@@ -21292,12 +21300,12 @@ function listAgents(db) {
|
|
|
21292
21300
|
}
|
|
21293
21301
|
function heartbeat(id, db) {
|
|
21294
21302
|
const d = db ?? getDatabase();
|
|
21295
|
-
d.run("UPDATE agents SET last_seen_at = ? WHERE id = ?", [
|
|
21303
|
+
d.run("UPDATE agents SET last_seen_at = ? WHERE id = ?", [now(), id]);
|
|
21296
21304
|
return getAgent(id, d);
|
|
21297
21305
|
}
|
|
21298
21306
|
function setFocus(id, projectId, db) {
|
|
21299
21307
|
const d = db ?? getDatabase();
|
|
21300
|
-
d.run("UPDATE agents SET project_id = ?, last_seen_at = ? WHERE id = ?", [projectId,
|
|
21308
|
+
d.run("UPDATE agents SET project_id = ?, last_seen_at = ? WHERE id = ?", [projectId, now(), id]);
|
|
21301
21309
|
return getAgent(id, d);
|
|
21302
21310
|
}
|
|
21303
21311
|
function deleteAgent(id, db) {
|
|
@@ -21329,9 +21337,9 @@ function countActiveAgents(db) {
|
|
|
21329
21337
|
return Math.max(1, row?.count ?? 1);
|
|
21330
21338
|
}
|
|
21331
21339
|
function currentWindowStart() {
|
|
21332
|
-
const
|
|
21340
|
+
const now3 = Date.now();
|
|
21333
21341
|
const windowMs = WINDOW_SECONDS * 1000;
|
|
21334
|
-
return new Date(Math.floor(
|
|
21342
|
+
return new Date(Math.floor(now3 / windowMs) * windowMs).toISOString();
|
|
21335
21343
|
}
|
|
21336
21344
|
function checkRateBudget(agentId, connector, connectorLimit, consume = true, db) {
|
|
21337
21345
|
const d = db ?? getDatabase();
|
|
@@ -21393,14 +21401,14 @@ __export(exports_llm, {
|
|
|
21393
21401
|
PROVIDER_DEFAULTS: () => PROVIDER_DEFAULTS,
|
|
21394
21402
|
LLMClient: () => LLMClient
|
|
21395
21403
|
});
|
|
21396
|
-
import { existsSync as
|
|
21397
|
-
import { join as
|
|
21404
|
+
import { existsSync as existsSync12, readFileSync as readFileSync7, writeFileSync as writeFileSync6, mkdirSync as mkdirSync8 } from "fs";
|
|
21405
|
+
import { join as join12 } from "path";
|
|
21398
21406
|
function getLlmConfigPath() {
|
|
21399
|
-
return
|
|
21407
|
+
return join12(getConnectorsHome(), "llm.json");
|
|
21400
21408
|
}
|
|
21401
21409
|
function getLlmConfig() {
|
|
21402
21410
|
const path = getLlmConfigPath();
|
|
21403
|
-
if (!
|
|
21411
|
+
if (!existsSync12(path))
|
|
21404
21412
|
return null;
|
|
21405
21413
|
try {
|
|
21406
21414
|
return JSON.parse(readFileSync7(path, "utf-8"));
|
|
@@ -21561,7 +21569,7 @@ function rowToJob(row) {
|
|
|
21561
21569
|
function createJob(input, db) {
|
|
21562
21570
|
const d = db ?? getDatabase();
|
|
21563
21571
|
const id = shortUuid();
|
|
21564
|
-
const ts =
|
|
21572
|
+
const ts = now();
|
|
21565
21573
|
d.run("INSERT INTO connector_jobs (id, name, connector, command, args, cron, enabled, strip, created_at) VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?)", [id, input.name, input.connector, input.command, JSON.stringify(input.args ?? []), input.cron, input.strip ? 1 : 0, ts]);
|
|
21566
21574
|
return getJob(id, d);
|
|
21567
21575
|
}
|
|
@@ -21627,18 +21635,18 @@ function deleteJob(id, db) {
|
|
|
21627
21635
|
}
|
|
21628
21636
|
function touchJobLastRun(id, db) {
|
|
21629
21637
|
const d = db ?? getDatabase();
|
|
21630
|
-
d.run("UPDATE connector_jobs SET last_run_at = ? WHERE id = ?", [
|
|
21638
|
+
d.run("UPDATE connector_jobs SET last_run_at = ? WHERE id = ?", [now(), id]);
|
|
21631
21639
|
}
|
|
21632
21640
|
function createJobRun(jobId, db) {
|
|
21633
21641
|
const d = db ?? getDatabase();
|
|
21634
21642
|
const id = shortUuid();
|
|
21635
|
-
const ts =
|
|
21643
|
+
const ts = now();
|
|
21636
21644
|
d.run("INSERT INTO connector_job_runs (id, job_id, started_at) VALUES (?, ?, ?)", [id, jobId, ts]);
|
|
21637
21645
|
return { id, job_id: jobId, started_at: ts, finished_at: null, exit_code: null, raw_output: null, stripped_output: null };
|
|
21638
21646
|
}
|
|
21639
21647
|
function finishJobRun(id, result, db) {
|
|
21640
21648
|
const d = db ?? getDatabase();
|
|
21641
|
-
d.run("UPDATE connector_job_runs SET finished_at = ?, exit_code = ?, raw_output = ?, stripped_output = ? WHERE id = ?", [
|
|
21649
|
+
d.run("UPDATE connector_job_runs SET finished_at = ?, exit_code = ?, raw_output = ?, stripped_output = ? WHERE id = ?", [now(), result.exit_code, result.raw_output, result.stripped_output ?? null, id]);
|
|
21642
21650
|
}
|
|
21643
21651
|
function getLatestRun(jobId, db) {
|
|
21644
21652
|
const d = db ?? getDatabase();
|
|
@@ -21663,7 +21671,7 @@ function rowToWorkflow(row) {
|
|
|
21663
21671
|
function createWorkflow(input, db) {
|
|
21664
21672
|
const d = db ?? getDatabase();
|
|
21665
21673
|
const id = shortUuid();
|
|
21666
|
-
d.run("INSERT INTO connector_workflows (id, name, steps, enabled, created_at) VALUES (?, ?, ?, 1, ?)", [id, input.name, JSON.stringify(input.steps),
|
|
21674
|
+
d.run("INSERT INTO connector_workflows (id, name, steps, enabled, created_at) VALUES (?, ?, ?, 1, ?)", [id, input.name, JSON.stringify(input.steps), now()]);
|
|
21667
21675
|
return getWorkflow(id, d);
|
|
21668
21676
|
}
|
|
21669
21677
|
function getWorkflow(id, db) {
|
|
@@ -21696,7 +21704,7 @@ __export(exports_scheduler, {
|
|
|
21696
21704
|
startScheduler: () => startScheduler,
|
|
21697
21705
|
cronMatches: () => cronMatches
|
|
21698
21706
|
});
|
|
21699
|
-
import { spawn
|
|
21707
|
+
import { spawn } from "child_process";
|
|
21700
21708
|
function cronMatches(cron, d) {
|
|
21701
21709
|
const parts = cron.trim().split(/\s+/);
|
|
21702
21710
|
if (parts.length !== 5)
|
|
@@ -21723,7 +21731,7 @@ function cronMatches(cron, d) {
|
|
|
21723
21731
|
async function runConnectorCommand(connector, command, args) {
|
|
21724
21732
|
return new Promise((resolve) => {
|
|
21725
21733
|
const cmdArgs = [connector, command, ...args, "--format", "json"];
|
|
21726
|
-
const proc =
|
|
21734
|
+
const proc = spawn("connectors", ["run", ...cmdArgs], { shell: false });
|
|
21727
21735
|
let output = "";
|
|
21728
21736
|
proc.stdout.on("data", (d) => {
|
|
21729
21737
|
output += d.toString();
|
|
@@ -21760,14 +21768,14 @@ function startScheduler(db) {
|
|
|
21760
21768
|
_interval = setInterval(() => {
|
|
21761
21769
|
(async () => {
|
|
21762
21770
|
try {
|
|
21763
|
-
const
|
|
21764
|
-
const currentMinute =
|
|
21771
|
+
const now3 = new Date;
|
|
21772
|
+
const currentMinute = now3.getMinutes() + now3.getHours() * 60;
|
|
21765
21773
|
if (currentMinute === _lastCheckedMinute)
|
|
21766
21774
|
return;
|
|
21767
21775
|
_lastCheckedMinute = currentMinute;
|
|
21768
21776
|
const jobs = listEnabledJobs(db);
|
|
21769
21777
|
for (const job of jobs) {
|
|
21770
|
-
if (cronMatches(job.cron,
|
|
21778
|
+
if (cronMatches(job.cron, now3)) {
|
|
21771
21779
|
executeJob(job, db).catch(() => {});
|
|
21772
21780
|
}
|
|
21773
21781
|
}
|
|
@@ -21869,16 +21877,16 @@ __export(exports_runner, {
|
|
|
21869
21877
|
buildEnvWithCredentials: () => buildEnvWithCredentials,
|
|
21870
21878
|
buildConnectorOperationArgs: () => buildConnectorOperationArgs
|
|
21871
21879
|
});
|
|
21872
|
-
import { existsSync as
|
|
21873
|
-
import { join as
|
|
21880
|
+
import { existsSync as existsSync13, readdirSync as readdirSync9 } from "fs";
|
|
21881
|
+
import { join as join13, dirname as dirname6 } from "path";
|
|
21874
21882
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
21875
|
-
import { spawn as
|
|
21883
|
+
import { spawn as spawn2 } from "child_process";
|
|
21876
21884
|
function resolveConnectorsDir2() {
|
|
21877
|
-
const fromBin =
|
|
21878
|
-
if (
|
|
21885
|
+
const fromBin = join13(__dirname5, "..", "connectors");
|
|
21886
|
+
if (existsSync13(fromBin))
|
|
21879
21887
|
return fromBin;
|
|
21880
|
-
const fromSrc =
|
|
21881
|
-
if (
|
|
21888
|
+
const fromSrc = join13(__dirname5, "..", "..", "connectors");
|
|
21889
|
+
if (existsSync13(fromSrc))
|
|
21882
21890
|
return fromSrc;
|
|
21883
21891
|
return fromBin;
|
|
21884
21892
|
}
|
|
@@ -21946,8 +21954,8 @@ function buildEnvWithCredentials(connectorName, baseEnv) {
|
|
|
21946
21954
|
function getConnectorCliPath(name) {
|
|
21947
21955
|
const safeName = normalizeConnectorName(name).replace(/[^a-z0-9-]/g, "");
|
|
21948
21956
|
const connectorDir = getConnectorPackagePath(CONNECTORS_DIR2, safeName);
|
|
21949
|
-
const cliPath =
|
|
21950
|
-
if (
|
|
21957
|
+
const cliPath = join13(connectorDir, "src", "cli", "index.ts");
|
|
21958
|
+
if (existsSync13(cliPath))
|
|
21951
21959
|
return cliPath;
|
|
21952
21960
|
return null;
|
|
21953
21961
|
}
|
|
@@ -22142,7 +22150,7 @@ function runLegacyConnectorCommand(name, args, timeoutMs = 30000) {
|
|
|
22142
22150
|
});
|
|
22143
22151
|
}
|
|
22144
22152
|
return new Promise((resolve) => {
|
|
22145
|
-
const proc =
|
|
22153
|
+
const proc = spawn2("bun", ["run", cliPath, ...args], {
|
|
22146
22154
|
timeout: timeoutMs,
|
|
22147
22155
|
env: buildEnvWithCredentials(connectorName, process.env),
|
|
22148
22156
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -39054,9 +39062,9 @@ var init_management = __esm(() => {
|
|
|
39054
39062
|
});
|
|
39055
39063
|
|
|
39056
39064
|
// src/mcp/tools/auth.ts
|
|
39057
|
-
import { existsSync as
|
|
39058
|
-
import { join as
|
|
39059
|
-
import { spawn as
|
|
39065
|
+
import { existsSync as existsSync14, readFileSync as readFileSync8 } from "fs";
|
|
39066
|
+
import { join as join14 } from "path";
|
|
39067
|
+
import { spawn as spawn3 } from "child_process";
|
|
39060
39068
|
function registerAuthTools(server, stripped) {
|
|
39061
39069
|
server.registerTool("connector_auth_status", {
|
|
39062
39070
|
title: "Connector Auth Status",
|
|
@@ -39191,7 +39199,7 @@ function registerAuthTools(server, stripped) {
|
|
|
39191
39199
|
const oauthUrl = `http://localhost:${serverPort}/oauth/${name}/start`;
|
|
39192
39200
|
if (noBrowser) {
|
|
39193
39201
|
const connectorsHome = getConnectorsHome();
|
|
39194
|
-
const tokenPaths = getConnectorConfigReadDirs(name, connectorsHome).map((dir) =>
|
|
39202
|
+
const tokenPaths = getConnectorConfigReadDirs(name, connectorsHome).map((dir) => join14(dir, "profiles", "default", "tokens.json"));
|
|
39195
39203
|
let serverRunning = false;
|
|
39196
39204
|
try {
|
|
39197
39205
|
await fetch(`http://localhost:${serverPort}/api/connectors`);
|
|
@@ -39199,7 +39207,7 @@ function registerAuthTools(server, stripped) {
|
|
|
39199
39207
|
} catch {}
|
|
39200
39208
|
if (!serverRunning) {
|
|
39201
39209
|
const scriptPath = process.argv[1];
|
|
39202
|
-
const serverProc =
|
|
39210
|
+
const serverProc = spawn3("node", [scriptPath, "serve", "--port", String(serverPort)], {
|
|
39203
39211
|
detached: true,
|
|
39204
39212
|
stdio: "ignore"
|
|
39205
39213
|
});
|
|
@@ -39210,7 +39218,7 @@ function registerAuthTools(server, stripped) {
|
|
|
39210
39218
|
const maxAttempts = 120;
|
|
39211
39219
|
while (attempts < maxAttempts) {
|
|
39212
39220
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
39213
|
-
if (tokenPaths.some((tokensPath) =>
|
|
39221
|
+
if (tokenPaths.some((tokensPath) => existsSync14(tokensPath))) {
|
|
39214
39222
|
break;
|
|
39215
39223
|
}
|
|
39216
39224
|
attempts++;
|
|
@@ -39229,7 +39237,7 @@ function registerAuthTools(server, stripped) {
|
|
|
39229
39237
|
};
|
|
39230
39238
|
}
|
|
39231
39239
|
try {
|
|
39232
|
-
const tokensPath = tokenPaths.find((path) =>
|
|
39240
|
+
const tokensPath = tokenPaths.find((path) => existsSync14(path)) ?? tokenPaths[0];
|
|
39233
39241
|
const tokenData = JSON.parse(readFileSync8(tokensPath, "utf-8"));
|
|
39234
39242
|
return {
|
|
39235
39243
|
content: [{
|
|
@@ -40021,8 +40029,8 @@ var exports_serve = {};
|
|
|
40021
40029
|
__export(exports_serve, {
|
|
40022
40030
|
startServer: () => startServer
|
|
40023
40031
|
});
|
|
40024
|
-
import { existsSync as
|
|
40025
|
-
import { join as
|
|
40032
|
+
import { existsSync as existsSync15, readdirSync as readdirSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync7, mkdirSync as mkdirSync9 } from "fs";
|
|
40033
|
+
import { join as join15, dirname as dirname7, extname, basename as basename3 } from "path";
|
|
40026
40034
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
40027
40035
|
function logActivity(action, connector, detail) {
|
|
40028
40036
|
activityLog.unshift({ action, connector, timestamp: Date.now(), detail });
|
|
@@ -40034,20 +40042,20 @@ function resolveDashboardDir() {
|
|
|
40034
40042
|
const candidates = [];
|
|
40035
40043
|
try {
|
|
40036
40044
|
const scriptDir = dirname7(fileURLToPath6(import.meta.url));
|
|
40037
|
-
candidates.push(
|
|
40038
|
-
candidates.push(
|
|
40045
|
+
candidates.push(join15(scriptDir, "..", "dashboard", "dist"));
|
|
40046
|
+
candidates.push(join15(scriptDir, "..", "..", "dashboard", "dist"));
|
|
40039
40047
|
} catch {}
|
|
40040
40048
|
if (process.argv[1]) {
|
|
40041
40049
|
const mainDir = dirname7(process.argv[1]);
|
|
40042
|
-
candidates.push(
|
|
40043
|
-
candidates.push(
|
|
40050
|
+
candidates.push(join15(mainDir, "..", "dashboard", "dist"));
|
|
40051
|
+
candidates.push(join15(mainDir, "..", "..", "dashboard", "dist"));
|
|
40044
40052
|
}
|
|
40045
|
-
candidates.push(
|
|
40053
|
+
candidates.push(join15(process.cwd(), "dashboard", "dist"));
|
|
40046
40054
|
for (const candidate of candidates) {
|
|
40047
|
-
if (
|
|
40055
|
+
if (existsSync15(candidate))
|
|
40048
40056
|
return candidate;
|
|
40049
40057
|
}
|
|
40050
|
-
return
|
|
40058
|
+
return join15(process.cwd(), "dashboard", "dist");
|
|
40051
40059
|
}
|
|
40052
40060
|
function json(data, status = 200, port) {
|
|
40053
40061
|
return new Response(JSON.stringify(data), {
|
|
@@ -40129,7 +40137,7 @@ function oauthPage(type, title, message, hint, extra) {
|
|
|
40129
40137
|
</body></html>`;
|
|
40130
40138
|
}
|
|
40131
40139
|
function serveStaticFile(filePath) {
|
|
40132
|
-
if (!
|
|
40140
|
+
if (!existsSync15(filePath))
|
|
40133
40141
|
return null;
|
|
40134
40142
|
const ext = extname(filePath);
|
|
40135
40143
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
@@ -40166,7 +40174,7 @@ async function startServer(requestedPort, options) {
|
|
|
40166
40174
|
const strict = options?.strict ?? false;
|
|
40167
40175
|
loadConnectorVersions();
|
|
40168
40176
|
const dashboardDir = resolveDashboardDir();
|
|
40169
|
-
const dashboardExists =
|
|
40177
|
+
const dashboardExists = existsSync15(dashboardDir);
|
|
40170
40178
|
if (!dashboardExists) {
|
|
40171
40179
|
console.error(`
|
|
40172
40180
|
Dashboard not found at: ${dashboardDir}`);
|
|
@@ -40597,8 +40605,8 @@ ${result.stderr}`;
|
|
|
40597
40605
|
const profiles = listProfiles4(name);
|
|
40598
40606
|
let current = "default";
|
|
40599
40607
|
for (const configDir of getConnectorConfigReadDirs(name)) {
|
|
40600
|
-
const currentProfileFile =
|
|
40601
|
-
if (
|
|
40608
|
+
const currentProfileFile = join15(configDir, "current_profile");
|
|
40609
|
+
if (existsSync15(currentProfileFile)) {
|
|
40602
40610
|
try {
|
|
40603
40611
|
current = readFileSync9(currentProfileFile, "utf-8").trim() || "default";
|
|
40604
40612
|
} catch {}
|
|
@@ -40651,25 +40659,25 @@ ${result.stderr}`;
|
|
|
40651
40659
|
try {
|
|
40652
40660
|
const connectDir = getConnectorsHome();
|
|
40653
40661
|
const result = {};
|
|
40654
|
-
if (
|
|
40662
|
+
if (existsSync15(connectDir)) {
|
|
40655
40663
|
for (const connectorName of listConfiguredConnectorNames(connectDir)) {
|
|
40656
40664
|
const profiles = {};
|
|
40657
40665
|
for (const configDir of [...getConnectorConfigReadDirs(connectorName, connectDir)].reverse()) {
|
|
40658
|
-
const profilesDir =
|
|
40659
|
-
if (!
|
|
40666
|
+
const profilesDir = join15(configDir, "profiles");
|
|
40667
|
+
if (!existsSync15(profilesDir))
|
|
40660
40668
|
continue;
|
|
40661
40669
|
const profileEntries = readdirSync10(profilesDir, { withFileTypes: true });
|
|
40662
40670
|
for (const pEntry of profileEntries) {
|
|
40663
40671
|
if (pEntry.isFile() && pEntry.name.endsWith(".json")) {
|
|
40664
40672
|
const profileName = basename3(pEntry.name, ".json");
|
|
40665
40673
|
try {
|
|
40666
|
-
const config2 = JSON.parse(readFileSync9(
|
|
40674
|
+
const config2 = JSON.parse(readFileSync9(join15(profilesDir, pEntry.name), "utf-8"));
|
|
40667
40675
|
profiles[profileName] = config2;
|
|
40668
40676
|
} catch {}
|
|
40669
40677
|
}
|
|
40670
40678
|
if (pEntry.isDirectory()) {
|
|
40671
|
-
const configPath =
|
|
40672
|
-
if (
|
|
40679
|
+
const configPath = join15(profilesDir, pEntry.name, "config.json");
|
|
40680
|
+
if (existsSync15(configPath)) {
|
|
40673
40681
|
try {
|
|
40674
40682
|
const config2 = JSON.parse(readFileSync9(configPath, "utf-8"));
|
|
40675
40683
|
profiles[pEntry.name] = config2;
|
|
@@ -40714,12 +40722,12 @@ ${result.stderr}`;
|
|
|
40714
40722
|
if (!data.profiles || typeof data.profiles !== "object")
|
|
40715
40723
|
continue;
|
|
40716
40724
|
const connectorDir = getConnectorConfigDir(connectorName, connectDir);
|
|
40717
|
-
const profilesDir =
|
|
40725
|
+
const profilesDir = join15(connectorDir, "profiles");
|
|
40718
40726
|
for (const [profileName, config2] of Object.entries(data.profiles)) {
|
|
40719
40727
|
if (!config2 || typeof config2 !== "object")
|
|
40720
40728
|
continue;
|
|
40721
40729
|
mkdirSync9(profilesDir, { recursive: true });
|
|
40722
|
-
const profileFile =
|
|
40730
|
+
const profileFile = join15(profilesDir, `${profileName}.json`);
|
|
40723
40731
|
writeFileSync7(profileFile, JSON.stringify(config2, null, 2));
|
|
40724
40732
|
imported++;
|
|
40725
40733
|
}
|
|
@@ -40775,12 +40783,12 @@ ${result.stderr}`;
|
|
|
40775
40783
|
}
|
|
40776
40784
|
if (dashboardExists && (method === "GET" || method === "HEAD")) {
|
|
40777
40785
|
if (path !== "/") {
|
|
40778
|
-
const filePath =
|
|
40786
|
+
const filePath = join15(dashboardDir, path);
|
|
40779
40787
|
const res2 = serveStaticFile(filePath);
|
|
40780
40788
|
if (res2)
|
|
40781
40789
|
return res2;
|
|
40782
40790
|
}
|
|
40783
|
-
const indexPath =
|
|
40791
|
+
const indexPath = join15(dashboardDir, "index.html");
|
|
40784
40792
|
const res = serveStaticFile(indexPath);
|
|
40785
40793
|
if (res)
|
|
40786
40794
|
return res;
|
|
@@ -40865,692 +40873,10 @@ var {
|
|
|
40865
40873
|
Help
|
|
40866
40874
|
} = import__.default;
|
|
40867
40875
|
|
|
40868
|
-
// node_modules/@hasna/events/dist/commander.js
|
|
40869
|
-
import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
|
|
40870
|
-
import { existsSync } from "fs";
|
|
40871
|
-
import { homedir } from "os";
|
|
40872
|
-
import { join } from "path";
|
|
40873
|
-
import { createHmac, timingSafeEqual } from "crypto";
|
|
40874
|
-
import { randomUUID } from "crypto";
|
|
40875
|
-
import { spawn } from "child_process";
|
|
40876
|
-
import { randomUUID as randomUUID2 } from "crypto";
|
|
40877
|
-
function getPathValue(input, path) {
|
|
40878
|
-
return path.split(".").reduce((value, part) => {
|
|
40879
|
-
if (value && typeof value === "object" && part in value) {
|
|
40880
|
-
return value[part];
|
|
40881
|
-
}
|
|
40882
|
-
return;
|
|
40883
|
-
}, input);
|
|
40884
|
-
}
|
|
40885
|
-
function wildcardToRegExp(pattern) {
|
|
40886
|
-
const escaped = pattern.replace(/[|\\{}()[\]^$+?.]/g, "\\$&").replace(/\*/g, ".*");
|
|
40887
|
-
return new RegExp(`^${escaped}$`);
|
|
40888
|
-
}
|
|
40889
|
-
function matchString(value, matcher) {
|
|
40890
|
-
if (matcher === undefined)
|
|
40891
|
-
return true;
|
|
40892
|
-
if (value === undefined)
|
|
40893
|
-
return false;
|
|
40894
|
-
const matchers = Array.isArray(matcher) ? matcher : [matcher];
|
|
40895
|
-
return matchers.some((item) => wildcardToRegExp(item).test(value));
|
|
40896
|
-
}
|
|
40897
|
-
function matchRecord(input, matcher) {
|
|
40898
|
-
if (!matcher)
|
|
40899
|
-
return true;
|
|
40900
|
-
return Object.entries(matcher).every(([path, expected]) => {
|
|
40901
|
-
const actual = getPathValue(input, path);
|
|
40902
|
-
if (typeof expected === "string" || Array.isArray(expected)) {
|
|
40903
|
-
return matchString(actual === undefined ? undefined : String(actual), expected);
|
|
40904
|
-
}
|
|
40905
|
-
return actual === expected;
|
|
40906
|
-
});
|
|
40907
|
-
}
|
|
40908
|
-
function eventMatchesFilter(event, filter) {
|
|
40909
|
-
return matchString(event.source, filter.source) && matchString(event.type, filter.type) && matchString(event.subject, filter.subject) && matchString(event.severity, filter.severity) && matchRecord(event.data, filter.data) && matchRecord(event.metadata, filter.metadata);
|
|
40910
|
-
}
|
|
40911
|
-
function channelMatchesEvent(channel, event) {
|
|
40912
|
-
if (!channel.enabled)
|
|
40913
|
-
return false;
|
|
40914
|
-
if (!channel.filters || channel.filters.length === 0)
|
|
40915
|
-
return true;
|
|
40916
|
-
return channel.filters.some((filter) => eventMatchesFilter(event, filter));
|
|
40917
|
-
}
|
|
40918
|
-
var HASNA_EVENTS_DIR_ENV = "HASNA_EVENTS_DIR";
|
|
40919
|
-
var HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME";
|
|
40920
|
-
function getEventsDataDir(override) {
|
|
40921
|
-
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join(homedir(), ".hasna", "events");
|
|
40922
|
-
}
|
|
40923
|
-
class JsonEventsStore {
|
|
40924
|
-
dataDir;
|
|
40925
|
-
channelsPath;
|
|
40926
|
-
eventsPath;
|
|
40927
|
-
deliveriesPath;
|
|
40928
|
-
constructor(dataDir = getEventsDataDir()) {
|
|
40929
|
-
this.dataDir = dataDir;
|
|
40930
|
-
this.channelsPath = join(dataDir, "channels.json");
|
|
40931
|
-
this.eventsPath = join(dataDir, "events.json");
|
|
40932
|
-
this.deliveriesPath = join(dataDir, "deliveries.json");
|
|
40933
|
-
}
|
|
40934
|
-
async init() {
|
|
40935
|
-
await mkdir(this.dataDir, { recursive: true, mode: 448 });
|
|
40936
|
-
await chmod(this.dataDir, 448).catch(() => {
|
|
40937
|
-
return;
|
|
40938
|
-
});
|
|
40939
|
-
await this.ensureArrayFile(this.channelsPath);
|
|
40940
|
-
await this.ensureArrayFile(this.eventsPath);
|
|
40941
|
-
await this.ensureArrayFile(this.deliveriesPath);
|
|
40942
|
-
}
|
|
40943
|
-
async addChannel(channel) {
|
|
40944
|
-
await this.init();
|
|
40945
|
-
const channels = await this.readJson(this.channelsPath, []);
|
|
40946
|
-
const index = channels.findIndex((item) => item.id === channel.id);
|
|
40947
|
-
if (index >= 0) {
|
|
40948
|
-
channels[index] = { ...channel, createdAt: channels[index].createdAt, updatedAt: new Date().toISOString() };
|
|
40949
|
-
} else {
|
|
40950
|
-
channels.push(channel);
|
|
40951
|
-
}
|
|
40952
|
-
await this.writeJson(this.channelsPath, channels);
|
|
40953
|
-
return index >= 0 ? channels[index] : channel;
|
|
40954
|
-
}
|
|
40955
|
-
async listChannels() {
|
|
40956
|
-
await this.init();
|
|
40957
|
-
return this.readJson(this.channelsPath, []);
|
|
40958
|
-
}
|
|
40959
|
-
async getChannel(id) {
|
|
40960
|
-
const channels = await this.listChannels();
|
|
40961
|
-
return channels.find((channel) => channel.id === id);
|
|
40962
|
-
}
|
|
40963
|
-
async removeChannel(id) {
|
|
40964
|
-
await this.init();
|
|
40965
|
-
const channels = await this.readJson(this.channelsPath, []);
|
|
40966
|
-
const next = channels.filter((channel) => channel.id !== id);
|
|
40967
|
-
await this.writeJson(this.channelsPath, next);
|
|
40968
|
-
return next.length !== channels.length;
|
|
40969
|
-
}
|
|
40970
|
-
async appendEvent(event) {
|
|
40971
|
-
await this.init();
|
|
40972
|
-
const events = await this.readJson(this.eventsPath, []);
|
|
40973
|
-
events.push(event);
|
|
40974
|
-
await this.writeJson(this.eventsPath, events);
|
|
40975
|
-
return event;
|
|
40976
|
-
}
|
|
40977
|
-
async listEvents() {
|
|
40978
|
-
await this.init();
|
|
40979
|
-
return this.readJson(this.eventsPath, []);
|
|
40980
|
-
}
|
|
40981
|
-
async findEventByIdentity(identity) {
|
|
40982
|
-
const events = await this.listEvents();
|
|
40983
|
-
return events.find((event) => identity.id !== undefined && event.id === identity.id || identity.dedupeKey !== undefined && event.dedupeKey === identity.dedupeKey);
|
|
40984
|
-
}
|
|
40985
|
-
async appendDelivery(result) {
|
|
40986
|
-
await this.init();
|
|
40987
|
-
const deliveries = await this.readJson(this.deliveriesPath, []);
|
|
40988
|
-
deliveries.push(result);
|
|
40989
|
-
await this.writeJson(this.deliveriesPath, deliveries);
|
|
40990
|
-
return result;
|
|
40991
|
-
}
|
|
40992
|
-
async listDeliveries() {
|
|
40993
|
-
await this.init();
|
|
40994
|
-
return this.readJson(this.deliveriesPath, []);
|
|
40995
|
-
}
|
|
40996
|
-
async exportData() {
|
|
40997
|
-
return {
|
|
40998
|
-
channels: await this.listChannels(),
|
|
40999
|
-
events: await this.listEvents(),
|
|
41000
|
-
deliveries: await this.listDeliveries()
|
|
41001
|
-
};
|
|
41002
|
-
}
|
|
41003
|
-
async ensureArrayFile(path) {
|
|
41004
|
-
if (!existsSync(path)) {
|
|
41005
|
-
await writeFile(path, `[]
|
|
41006
|
-
`, { encoding: "utf-8", mode: 384 });
|
|
41007
|
-
}
|
|
41008
|
-
await chmod(path, 384).catch(() => {
|
|
41009
|
-
return;
|
|
41010
|
-
});
|
|
41011
|
-
}
|
|
41012
|
-
async readJson(path, fallback) {
|
|
41013
|
-
try {
|
|
41014
|
-
const raw = await readFile(path, "utf-8");
|
|
41015
|
-
if (!raw.trim())
|
|
41016
|
-
return fallback;
|
|
41017
|
-
return JSON.parse(raw);
|
|
41018
|
-
} catch (error) {
|
|
41019
|
-
if (error.code === "ENOENT")
|
|
41020
|
-
return fallback;
|
|
41021
|
-
throw error;
|
|
41022
|
-
}
|
|
41023
|
-
}
|
|
41024
|
-
async writeJson(path, value) {
|
|
41025
|
-
const tempPath = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
41026
|
-
await writeFile(tempPath, `${JSON.stringify(value, null, 2)}
|
|
41027
|
-
`, { encoding: "utf-8", mode: 384 });
|
|
41028
|
-
await rename(tempPath, path);
|
|
41029
|
-
await chmod(path, 384).catch(() => {
|
|
41030
|
-
return;
|
|
41031
|
-
});
|
|
41032
|
-
}
|
|
41033
|
-
}
|
|
41034
|
-
var DEFAULT_SIGNATURE_TOLERANCE_MS = 5 * 60 * 1000;
|
|
41035
|
-
function buildSignatureBase(timestamp, body) {
|
|
41036
|
-
return `${timestamp}.${body}`;
|
|
41037
|
-
}
|
|
41038
|
-
function signPayload(secret, timestamp, body) {
|
|
41039
|
-
const digest = createHmac("sha256", secret).update(buildSignatureBase(timestamp, body)).digest("hex");
|
|
41040
|
-
return `sha256=${digest}`;
|
|
41041
|
-
}
|
|
41042
|
-
function now() {
|
|
41043
|
-
return new Date().toISOString();
|
|
41044
|
-
}
|
|
41045
|
-
function truncate(value, max = 4096) {
|
|
41046
|
-
return value.length > max ? `${value.slice(0, max)}...` : value;
|
|
41047
|
-
}
|
|
41048
|
-
function buildWebhookRequest(event, channel) {
|
|
41049
|
-
if (!channel.webhook)
|
|
41050
|
-
throw new Error(`Channel ${channel.id} has no webhook config`);
|
|
41051
|
-
const body = JSON.stringify(event);
|
|
41052
|
-
const timestamp = event.time;
|
|
41053
|
-
const headers = {
|
|
41054
|
-
"Content-Type": "application/json",
|
|
41055
|
-
"User-Agent": "@hasna/events",
|
|
41056
|
-
"X-Hasna-Event-Id": event.id,
|
|
41057
|
-
"X-Hasna-Event-Type": event.type,
|
|
41058
|
-
"X-Hasna-Timestamp": timestamp,
|
|
41059
|
-
...channel.webhook.headers
|
|
41060
|
-
};
|
|
41061
|
-
if (channel.webhook.secret) {
|
|
41062
|
-
headers["X-Hasna-Signature"] = signPayload(channel.webhook.secret, timestamp, body);
|
|
41063
|
-
}
|
|
41064
|
-
return { body, headers };
|
|
41065
|
-
}
|
|
41066
|
-
async function dispatchWebhook(event, channel, options = {}) {
|
|
41067
|
-
if (!channel.webhook)
|
|
41068
|
-
throw new Error(`Channel ${channel.id} has no webhook config`);
|
|
41069
|
-
const startedAt = now();
|
|
41070
|
-
const { body, headers } = buildWebhookRequest(event, channel);
|
|
41071
|
-
const controller = new AbortController;
|
|
41072
|
-
const timeout = setTimeout(() => controller.abort(), channel.webhook.timeoutMs ?? 15000);
|
|
41073
|
-
try {
|
|
41074
|
-
const response = await (options.fetchImpl ?? fetch)(channel.webhook.url, {
|
|
41075
|
-
method: "POST",
|
|
41076
|
-
headers,
|
|
41077
|
-
body,
|
|
41078
|
-
signal: controller.signal
|
|
41079
|
-
});
|
|
41080
|
-
const responseBody = truncate(await response.text());
|
|
41081
|
-
return {
|
|
41082
|
-
attempt: 1,
|
|
41083
|
-
status: response.ok ? "success" : "failed",
|
|
41084
|
-
startedAt,
|
|
41085
|
-
completedAt: now(),
|
|
41086
|
-
responseStatus: response.status,
|
|
41087
|
-
responseBody,
|
|
41088
|
-
error: response.ok ? undefined : `Webhook returned HTTP ${response.status}`
|
|
41089
|
-
};
|
|
41090
|
-
} catch (error) {
|
|
41091
|
-
return {
|
|
41092
|
-
attempt: 1,
|
|
41093
|
-
status: "failed",
|
|
41094
|
-
startedAt,
|
|
41095
|
-
completedAt: now(),
|
|
41096
|
-
error: error instanceof Error ? error.message : String(error)
|
|
41097
|
-
};
|
|
41098
|
-
} finally {
|
|
41099
|
-
clearTimeout(timeout);
|
|
41100
|
-
}
|
|
41101
|
-
}
|
|
41102
|
-
async function dispatchCommand(event, channel) {
|
|
41103
|
-
if (!channel.command)
|
|
41104
|
-
throw new Error(`Channel ${channel.id} has no command config`);
|
|
41105
|
-
const startedAt = now();
|
|
41106
|
-
const eventJson = JSON.stringify(event);
|
|
41107
|
-
const env = {
|
|
41108
|
-
...process.env,
|
|
41109
|
-
...channel.command.env,
|
|
41110
|
-
HASNA_CHANNEL_ID: channel.id,
|
|
41111
|
-
HASNA_EVENT_ID: event.id,
|
|
41112
|
-
HASNA_EVENT_TYPE: event.type,
|
|
41113
|
-
HASNA_EVENT_SOURCE: event.source,
|
|
41114
|
-
HASNA_EVENT_SUBJECT: event.subject ?? "",
|
|
41115
|
-
HASNA_EVENT_SEVERITY: event.severity,
|
|
41116
|
-
HASNA_EVENT_TIME: event.time,
|
|
41117
|
-
HASNA_EVENT_DEDUPE_KEY: event.dedupeKey ?? "",
|
|
41118
|
-
HASNA_EVENT_SCHEMA_VERSION: event.schemaVersion,
|
|
41119
|
-
HASNA_EVENT_JSON: eventJson
|
|
41120
|
-
};
|
|
41121
|
-
return new Promise((resolve) => {
|
|
41122
|
-
const child = spawn(channel.command.command, channel.command.args ?? [], {
|
|
41123
|
-
cwd: channel.command.cwd,
|
|
41124
|
-
env,
|
|
41125
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
41126
|
-
});
|
|
41127
|
-
let stdout = "";
|
|
41128
|
-
let stderr = "";
|
|
41129
|
-
const timeout = setTimeout(() => child.kill("SIGTERM"), channel.command.timeoutMs ?? 15000);
|
|
41130
|
-
child.stdin.end(eventJson);
|
|
41131
|
-
child.stdout.on("data", (chunk) => {
|
|
41132
|
-
stdout += chunk.toString();
|
|
41133
|
-
});
|
|
41134
|
-
child.stderr.on("data", (chunk) => {
|
|
41135
|
-
stderr += chunk.toString();
|
|
41136
|
-
});
|
|
41137
|
-
child.on("error", (error) => {
|
|
41138
|
-
clearTimeout(timeout);
|
|
41139
|
-
resolve({
|
|
41140
|
-
attempt: 1,
|
|
41141
|
-
status: "failed",
|
|
41142
|
-
startedAt,
|
|
41143
|
-
completedAt: now(),
|
|
41144
|
-
stdout: truncate(stdout),
|
|
41145
|
-
stderr: truncate(stderr),
|
|
41146
|
-
error: error.message
|
|
41147
|
-
});
|
|
41148
|
-
});
|
|
41149
|
-
child.on("close", (code, signal) => {
|
|
41150
|
-
clearTimeout(timeout);
|
|
41151
|
-
const success = code === 0;
|
|
41152
|
-
resolve({
|
|
41153
|
-
attempt: 1,
|
|
41154
|
-
status: success ? "success" : "failed",
|
|
41155
|
-
startedAt,
|
|
41156
|
-
completedAt: now(),
|
|
41157
|
-
stdout: truncate(stdout),
|
|
41158
|
-
stderr: truncate(stderr),
|
|
41159
|
-
error: success ? undefined : `Command exited with ${signal ? `signal ${signal}` : `code ${code}`}`
|
|
41160
|
-
});
|
|
41161
|
-
});
|
|
41162
|
-
});
|
|
41163
|
-
}
|
|
41164
|
-
async function dispatchChannel(event, channel, options = {}) {
|
|
41165
|
-
if (channel.transport === "webhook")
|
|
41166
|
-
return dispatchWebhook(event, channel, options);
|
|
41167
|
-
if (channel.transport === "command")
|
|
41168
|
-
return dispatchCommand(event, channel);
|
|
41169
|
-
return {
|
|
41170
|
-
attempt: 1,
|
|
41171
|
-
status: "skipped",
|
|
41172
|
-
startedAt: now(),
|
|
41173
|
-
completedAt: now(),
|
|
41174
|
-
error: `Unsupported transport: ${channel.transport}`
|
|
41175
|
-
};
|
|
41176
|
-
}
|
|
41177
|
-
function createDeliveryResult(event, channel, attempts) {
|
|
41178
|
-
const status = attempts.some((attempt) => attempt.status === "success") ? "success" : attempts.every((attempt) => attempt.status === "skipped") ? "skipped" : "failed";
|
|
41179
|
-
return {
|
|
41180
|
-
id: randomUUID(),
|
|
41181
|
-
eventId: event.id,
|
|
41182
|
-
channelId: channel.id,
|
|
41183
|
-
transport: channel.transport,
|
|
41184
|
-
status,
|
|
41185
|
-
attempts,
|
|
41186
|
-
createdAt: attempts[0]?.startedAt ?? now(),
|
|
41187
|
-
completedAt: attempts.at(-1)?.completedAt ?? now()
|
|
41188
|
-
};
|
|
41189
|
-
}
|
|
41190
|
-
function createEvent(input) {
|
|
41191
|
-
return {
|
|
41192
|
-
id: input.id ?? randomUUID2(),
|
|
41193
|
-
source: input.source,
|
|
41194
|
-
type: input.type,
|
|
41195
|
-
time: normalizeTime(input.time),
|
|
41196
|
-
subject: input.subject,
|
|
41197
|
-
severity: input.severity ?? "info",
|
|
41198
|
-
data: input.data ?? {},
|
|
41199
|
-
message: input.message,
|
|
41200
|
-
dedupeKey: input.dedupeKey,
|
|
41201
|
-
schemaVersion: input.schemaVersion ?? "1.0",
|
|
41202
|
-
metadata: input.metadata ?? {}
|
|
41203
|
-
};
|
|
41204
|
-
}
|
|
41205
|
-
|
|
41206
|
-
class EventsClient {
|
|
41207
|
-
store;
|
|
41208
|
-
redactors;
|
|
41209
|
-
transportOptions;
|
|
41210
|
-
constructor(options = {}) {
|
|
41211
|
-
this.store = options.store ?? new JsonEventsStore(options.dataDir);
|
|
41212
|
-
this.redactors = options.redactors ?? [];
|
|
41213
|
-
this.transportOptions = { fetchImpl: options.fetchImpl };
|
|
41214
|
-
}
|
|
41215
|
-
async addChannel(input) {
|
|
41216
|
-
const timestamp = new Date().toISOString();
|
|
41217
|
-
return this.store.addChannel({
|
|
41218
|
-
...input,
|
|
41219
|
-
createdAt: input.createdAt ?? timestamp,
|
|
41220
|
-
updatedAt: input.updatedAt ?? timestamp
|
|
41221
|
-
});
|
|
41222
|
-
}
|
|
41223
|
-
async listChannels() {
|
|
41224
|
-
return this.store.listChannels();
|
|
41225
|
-
}
|
|
41226
|
-
async removeChannel(id) {
|
|
41227
|
-
return this.store.removeChannel(id);
|
|
41228
|
-
}
|
|
41229
|
-
async emit(input, options = {}) {
|
|
41230
|
-
const event = options.redactSensitiveData === false ? createEvent(input) : redactSensitiveKeys(createEvent(input));
|
|
41231
|
-
if (options.dedupe !== false) {
|
|
41232
|
-
const existing = await this.store.findEventByIdentity({ id: input.id, dedupeKey: event.dedupeKey });
|
|
41233
|
-
if (existing) {
|
|
41234
|
-
return { event: existing, deliveries: [], deduped: true };
|
|
41235
|
-
}
|
|
41236
|
-
}
|
|
41237
|
-
await this.store.appendEvent(event);
|
|
41238
|
-
const deliveries = options.deliver === false ? [] : await this.deliver(event);
|
|
41239
|
-
return { event, deliveries, deduped: false };
|
|
41240
|
-
}
|
|
41241
|
-
async listEvents() {
|
|
41242
|
-
return this.store.listEvents();
|
|
41243
|
-
}
|
|
41244
|
-
async listDeliveries() {
|
|
41245
|
-
return this.store.listDeliveries();
|
|
41246
|
-
}
|
|
41247
|
-
async deliver(event) {
|
|
41248
|
-
const channels = await this.store.listChannels();
|
|
41249
|
-
const selected = channels.filter((channel) => channelMatchesEvent(channel, event));
|
|
41250
|
-
const deliveries = [];
|
|
41251
|
-
for (const channel of selected) {
|
|
41252
|
-
const eventForChannel = await this.applyRedaction(event, channel);
|
|
41253
|
-
const result = await this.deliverWithRetry(eventForChannel, channel);
|
|
41254
|
-
await this.store.appendDelivery(result);
|
|
41255
|
-
deliveries.push(result);
|
|
41256
|
-
}
|
|
41257
|
-
return deliveries;
|
|
41258
|
-
}
|
|
41259
|
-
async testChannel(id, input = {}) {
|
|
41260
|
-
const channel = await this.store.getChannel(id);
|
|
41261
|
-
if (!channel)
|
|
41262
|
-
throw new Error(`Channel not found: ${id}`);
|
|
41263
|
-
const event = createEvent({
|
|
41264
|
-
source: input.source ?? "hasna.events",
|
|
41265
|
-
type: input.type ?? "events.test",
|
|
41266
|
-
subject: input.subject ?? id,
|
|
41267
|
-
severity: input.severity ?? "info",
|
|
41268
|
-
data: input.data ?? { test: true },
|
|
41269
|
-
message: input.message ?? "Hasna events test delivery",
|
|
41270
|
-
dedupeKey: input.dedupeKey,
|
|
41271
|
-
schemaVersion: input.schemaVersion,
|
|
41272
|
-
metadata: input.metadata,
|
|
41273
|
-
time: input.time,
|
|
41274
|
-
id: input.id
|
|
41275
|
-
});
|
|
41276
|
-
const eventForChannel = await this.applyRedaction(event, channel);
|
|
41277
|
-
const result = await this.deliverWithRetry(eventForChannel, channel);
|
|
41278
|
-
await this.store.appendDelivery(result);
|
|
41279
|
-
return result;
|
|
41280
|
-
}
|
|
41281
|
-
async replay(options = {}) {
|
|
41282
|
-
const events = (await this.store.listEvents()).filter((event) => {
|
|
41283
|
-
if (options.eventId && event.id !== options.eventId)
|
|
41284
|
-
return false;
|
|
41285
|
-
if (options.source && event.source !== options.source)
|
|
41286
|
-
return false;
|
|
41287
|
-
if (options.type && event.type !== options.type)
|
|
41288
|
-
return false;
|
|
41289
|
-
return true;
|
|
41290
|
-
});
|
|
41291
|
-
if (options.dryRun)
|
|
41292
|
-
return { events, deliveries: [] };
|
|
41293
|
-
const deliveries = [];
|
|
41294
|
-
for (const event of events) {
|
|
41295
|
-
deliveries.push(...await this.deliver(event));
|
|
41296
|
-
}
|
|
41297
|
-
return { events, deliveries };
|
|
41298
|
-
}
|
|
41299
|
-
async applyRedaction(event, channel) {
|
|
41300
|
-
let next = redactPaths(event, channel.redact?.paths ?? [], channel.redact?.replacement ?? "[REDACTED]");
|
|
41301
|
-
for (const redactor of this.redactors) {
|
|
41302
|
-
next = await redactor(next, channel);
|
|
41303
|
-
}
|
|
41304
|
-
return next;
|
|
41305
|
-
}
|
|
41306
|
-
async deliverWithRetry(event, channel) {
|
|
41307
|
-
const policy = normalizeRetryPolicy(channel.retry);
|
|
41308
|
-
const attempts = [];
|
|
41309
|
-
for (let index = 0;index < policy.maxAttempts; index += 1) {
|
|
41310
|
-
const attempt = await dispatchChannel(event, channel, this.transportOptions);
|
|
41311
|
-
attempt.attempt = index + 1;
|
|
41312
|
-
if (attempt.status === "failed" && index + 1 < policy.maxAttempts) {
|
|
41313
|
-
attempt.nextBackoffMs = Math.round(policy.backoffMs * policy.multiplier ** index);
|
|
41314
|
-
}
|
|
41315
|
-
attempts.push(attempt);
|
|
41316
|
-
if (attempt.status !== "failed")
|
|
41317
|
-
break;
|
|
41318
|
-
if (attempt.nextBackoffMs)
|
|
41319
|
-
await Bun.sleep(attempt.nextBackoffMs);
|
|
41320
|
-
}
|
|
41321
|
-
return createDeliveryResult(event, channel, attempts);
|
|
41322
|
-
}
|
|
41323
|
-
}
|
|
41324
|
-
function redactPaths(event, paths, replacement = "[REDACTED]") {
|
|
41325
|
-
if (paths.length === 0)
|
|
41326
|
-
return event;
|
|
41327
|
-
const copy = structuredClone(event);
|
|
41328
|
-
for (const path of paths) {
|
|
41329
|
-
setPath(copy, path, replacement);
|
|
41330
|
-
}
|
|
41331
|
-
return copy;
|
|
41332
|
-
}
|
|
41333
|
-
function sanitizeChannelForOutput(channel) {
|
|
41334
|
-
const copy = structuredClone(channel);
|
|
41335
|
-
if (copy.webhook?.secret)
|
|
41336
|
-
copy.webhook.secret = "[REDACTED]";
|
|
41337
|
-
if (copy.command?.env) {
|
|
41338
|
-
copy.command.env = Object.fromEntries(Object.entries(copy.command.env).map(([key, value]) => [key, shouldRedactKey(key) ? "[REDACTED]" : value]));
|
|
41339
|
-
}
|
|
41340
|
-
return copy;
|
|
41341
|
-
}
|
|
41342
|
-
function sanitizeChannelsForOutput(channels) {
|
|
41343
|
-
return channels.map(sanitizeChannelForOutput);
|
|
41344
|
-
}
|
|
41345
|
-
function redactSensitiveKeys(event, replacement = "[REDACTED]") {
|
|
41346
|
-
return redactValue(event, replacement);
|
|
41347
|
-
}
|
|
41348
|
-
function shouldRedactKey(key) {
|
|
41349
|
-
return /secret|token|password|api[_-]?key|authorization/i.test(key);
|
|
41350
|
-
}
|
|
41351
|
-
function redactValue(value, replacement) {
|
|
41352
|
-
if (Array.isArray(value))
|
|
41353
|
-
return value.map((item) => redactValue(item, replacement));
|
|
41354
|
-
if (!value || typeof value !== "object")
|
|
41355
|
-
return value;
|
|
41356
|
-
return Object.fromEntries(Object.entries(value).map(([key, item]) => [
|
|
41357
|
-
key,
|
|
41358
|
-
shouldRedactKey(key) ? replacement : redactValue(item, replacement)
|
|
41359
|
-
]));
|
|
41360
|
-
}
|
|
41361
|
-
function setPath(input, path, replacement) {
|
|
41362
|
-
const parts = path.split(".");
|
|
41363
|
-
let cursor = input;
|
|
41364
|
-
for (const part of parts.slice(0, -1)) {
|
|
41365
|
-
const next = cursor[part];
|
|
41366
|
-
if (!next || typeof next !== "object")
|
|
41367
|
-
return;
|
|
41368
|
-
cursor = next;
|
|
41369
|
-
}
|
|
41370
|
-
const last = parts.at(-1);
|
|
41371
|
-
if (last && last in cursor)
|
|
41372
|
-
cursor[last] = replacement;
|
|
41373
|
-
}
|
|
41374
|
-
function normalizeTime(value) {
|
|
41375
|
-
if (!value)
|
|
41376
|
-
return new Date().toISOString();
|
|
41377
|
-
return value instanceof Date ? value.toISOString() : value;
|
|
41378
|
-
}
|
|
41379
|
-
function normalizeRetryPolicy(policy) {
|
|
41380
|
-
return {
|
|
41381
|
-
maxAttempts: Math.max(1, policy?.maxAttempts ?? 1),
|
|
41382
|
-
backoffMs: Math.max(0, policy?.backoffMs ?? 250),
|
|
41383
|
-
multiplier: Math.max(1, policy?.multiplier ?? 2)
|
|
41384
|
-
};
|
|
41385
|
-
}
|
|
41386
|
-
function parseJsonObject(value, fallback) {
|
|
41387
|
-
if (!value)
|
|
41388
|
-
return fallback;
|
|
41389
|
-
const parsed = JSON.parse(value);
|
|
41390
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
41391
|
-
throw new Error("Expected a JSON object");
|
|
41392
|
-
}
|
|
41393
|
-
return parsed;
|
|
41394
|
-
}
|
|
41395
|
-
function parseHeaders(values) {
|
|
41396
|
-
if (!values?.length)
|
|
41397
|
-
return;
|
|
41398
|
-
const headers = {};
|
|
41399
|
-
for (const value of values) {
|
|
41400
|
-
const separator = value.indexOf("=");
|
|
41401
|
-
if (separator === -1)
|
|
41402
|
-
throw new Error(`Invalid header, expected name=value: ${value}`);
|
|
41403
|
-
headers[value.slice(0, separator)] = value.slice(separator + 1);
|
|
41404
|
-
}
|
|
41405
|
-
return headers;
|
|
41406
|
-
}
|
|
41407
|
-
function parseFilter(options) {
|
|
41408
|
-
const filter2 = {};
|
|
41409
|
-
if (options.source)
|
|
41410
|
-
filter2.source = options.source;
|
|
41411
|
-
if (options.type)
|
|
41412
|
-
filter2.type = options.type;
|
|
41413
|
-
if (options.subject)
|
|
41414
|
-
filter2.subject = options.subject;
|
|
41415
|
-
if (options.severity)
|
|
41416
|
-
filter2.severity = options.severity;
|
|
41417
|
-
return Object.keys(filter2).length > 0 ? [filter2] : undefined;
|
|
41418
|
-
}
|
|
41419
|
-
function createClient(options) {
|
|
41420
|
-
if (options.createClient)
|
|
41421
|
-
return options.createClient();
|
|
41422
|
-
return new EventsClient({ store: new JsonEventsStore(options.dataDir) });
|
|
41423
|
-
}
|
|
41424
|
-
function print(value, json, text) {
|
|
41425
|
-
if (json)
|
|
41426
|
-
console.log(JSON.stringify(value, null, 2));
|
|
41427
|
-
else
|
|
41428
|
-
console.log(text);
|
|
41429
|
-
}
|
|
41430
|
-
function hasJsonOption(options) {
|
|
41431
|
-
return Boolean(options?.json || options?.opts?.().json || options?.optsWithGlobals?.().json || options?.parent?.opts?.().json || options?.parent?.optsWithGlobals?.().json);
|
|
41432
|
-
}
|
|
41433
|
-
function wantsJson(actionOptions, command) {
|
|
41434
|
-
return hasJsonOption(actionOptions) || hasJsonOption(command);
|
|
41435
|
-
}
|
|
41436
|
-
function registerWebhookCommands(program2, options) {
|
|
41437
|
-
const webhooks = program2.command(options.webhooksCommandName ?? "webhooks").description("Manage Hasna event webhook subscriptions");
|
|
41438
|
-
webhooks.command("add").description("Add or replace a webhook or command subscription").argument("<target>", "Webhook URL or command binary").requiredOption("--id <id>", "Subscription/channel identifier").option("--transport <kind>", "Transport kind: webhook or command", "webhook").option("--name <name>", "Display name").option("--type <pattern>", "Event type filter, e.g. todos.task.*").option("--source <pattern>", "Event source filter").option("--subject <pattern>", "Event subject filter").option("--severity <pattern>", "Event severity filter").option("--secret <secret>", "Webhook HMAC secret").option("--header <name=value...>", "Webhook header", collectValues, []).option("--arg <arg...>", "Command argument", collectValues, []).option("--timeout-ms <ms>", "Transport timeout in milliseconds", parseNumber).option("--retry-attempts <n>", "Maximum delivery attempts", parseNumber).option("--retry-backoff-ms <ms>", "Initial retry backoff in milliseconds", parseNumber).option("--redact <path...>", "Event field path to redact before delivery", collectValues, []).option("--disabled", "Create channel disabled", false).option("-j, --json", "Print JSON output", false).action(async (target, actionOptions, command) => {
|
|
41439
|
-
const timestamp = new Date().toISOString();
|
|
41440
|
-
const channel = {
|
|
41441
|
-
id: actionOptions.id,
|
|
41442
|
-
name: actionOptions.name,
|
|
41443
|
-
enabled: !actionOptions.disabled,
|
|
41444
|
-
transport: actionOptions.transport,
|
|
41445
|
-
filters: parseFilter(actionOptions),
|
|
41446
|
-
retry: actionOptions.retryAttempts || actionOptions.retryBackoffMs ? { maxAttempts: actionOptions.retryAttempts, backoffMs: actionOptions.retryBackoffMs } : undefined,
|
|
41447
|
-
redact: actionOptions.redact?.length ? { paths: actionOptions.redact } : undefined,
|
|
41448
|
-
createdAt: timestamp,
|
|
41449
|
-
updatedAt: timestamp
|
|
41450
|
-
};
|
|
41451
|
-
if (actionOptions.transport === "webhook") {
|
|
41452
|
-
channel.webhook = { url: target, secret: actionOptions.secret, headers: parseHeaders(actionOptions.header), timeoutMs: actionOptions.timeoutMs };
|
|
41453
|
-
} else if (actionOptions.transport === "command") {
|
|
41454
|
-
channel.command = { command: target, args: actionOptions.arg ?? [], timeoutMs: actionOptions.timeoutMs };
|
|
41455
|
-
} else {
|
|
41456
|
-
throw new Error(`Transport ${actionOptions.transport} is reserved for future use and cannot be added yet`);
|
|
41457
|
-
}
|
|
41458
|
-
const saved = await createClient(options).addChannel(channel);
|
|
41459
|
-
print(sanitizeChannelForOutput(saved), wantsJson(actionOptions, command), `Added ${saved.transport} channel ${saved.id}`);
|
|
41460
|
-
});
|
|
41461
|
-
webhooks.command("list").description("List configured subscriptions").option("-j, --json", "Print JSON output", false).action(async (actionOptions, command) => {
|
|
41462
|
-
const channels = await createClient(options).listChannels();
|
|
41463
|
-
if (wantsJson(actionOptions, command)) {
|
|
41464
|
-
console.log(JSON.stringify(sanitizeChannelsForOutput(channels), null, 2));
|
|
41465
|
-
return;
|
|
41466
|
-
}
|
|
41467
|
-
if (!channels.length) {
|
|
41468
|
-
console.log("No channels configured.");
|
|
41469
|
-
return;
|
|
41470
|
-
}
|
|
41471
|
-
for (const channel of channels) {
|
|
41472
|
-
console.log(`${channel.id} ${channel.enabled ? "enabled" : "disabled"} ${channel.transport} ${channel.webhook?.url ?? channel.command?.command ?? channel.transport}`);
|
|
41473
|
-
}
|
|
41474
|
-
});
|
|
41475
|
-
webhooks.command("remove").description("Remove a subscription").argument("<id>", "Subscription/channel identifier").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions, command) => {
|
|
41476
|
-
const removed = await createClient(options).removeChannel(id);
|
|
41477
|
-
print({ removed }, wantsJson(actionOptions, command), removed ? `Removed ${id}` : `Channel not found: ${id}`);
|
|
41478
|
-
});
|
|
41479
|
-
webhooks.command("test").description("Send a test event to one subscription").argument("<id>", "Subscription/channel identifier").option("--type <type>", "Event type", "events.test").option("--subject <subject>", "Event subject").option("--message <message>", "Event message", "Hasna events test delivery").option("--data <json>", "Event data JSON object").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions, command) => {
|
|
41480
|
-
const result = await createClient(options).testChannel(id, {
|
|
41481
|
-
source: options.source,
|
|
41482
|
-
type: actionOptions.type,
|
|
41483
|
-
subject: actionOptions.subject ?? id,
|
|
41484
|
-
message: actionOptions.message,
|
|
41485
|
-
data: parseJsonObject(actionOptions.data, { test: true })
|
|
41486
|
-
});
|
|
41487
|
-
print(result, wantsJson(actionOptions, command), `${result.status}: ${result.channelId}`);
|
|
41488
|
-
});
|
|
41489
|
-
return webhooks;
|
|
41490
|
-
}
|
|
41491
|
-
function registerEventCommands(program2, options) {
|
|
41492
|
-
const events = program2.command(options.eventsCommandName ?? "events").description("Emit, list, and replay Hasna events");
|
|
41493
|
-
events.command("emit").description("Emit an event from this app").argument("<type>", "Event type").option("--source <source>", "Event source override").option("--subject <subject>", "Event subject").option("--severity <severity>", "Event severity", "info").option("--message <message>", "Event message").option("--dedupe-key <key>", "Dedupe key").option("--data <json>", "Event data JSON object").option("--metadata <json>", "Event metadata JSON object").option("--no-deliver", "Record without delivering").option("--no-dedupe", "Allow duplicate id/dedupeKey events").option("-j, --json", "Print JSON output", false).action(async (type, actionOptions, command) => {
|
|
41494
|
-
const result = await createClient(options).emit({
|
|
41495
|
-
source: actionOptions.source ?? options.source,
|
|
41496
|
-
type,
|
|
41497
|
-
subject: actionOptions.subject,
|
|
41498
|
-
severity: actionOptions.severity,
|
|
41499
|
-
message: actionOptions.message,
|
|
41500
|
-
dedupeKey: actionOptions.dedupeKey,
|
|
41501
|
-
data: parseJsonObject(actionOptions.data, {}),
|
|
41502
|
-
metadata: parseJsonObject(actionOptions.metadata, {})
|
|
41503
|
-
}, { deliver: actionOptions.deliver, dedupe: actionOptions.dedupe });
|
|
41504
|
-
print(result, wantsJson(actionOptions, command), `${result.deduped ? "Deduped" : "Emitted"} ${result.event.id} to ${result.deliveries.length} channel(s)`);
|
|
41505
|
-
});
|
|
41506
|
-
events.command("list").description("List recorded events").option("--source <source>", "Filter by source").option("--type <type>", "Filter by type").option("--limit <n>", "Limit results", parseNumber).option("-j, --json", "Print JSON output", false).action(async (actionOptions, command) => {
|
|
41507
|
-
let rows = await createClient(options).listEvents();
|
|
41508
|
-
if (actionOptions.source)
|
|
41509
|
-
rows = rows.filter((event) => event.source === actionOptions.source);
|
|
41510
|
-
if (actionOptions.type)
|
|
41511
|
-
rows = rows.filter((event) => event.type === actionOptions.type);
|
|
41512
|
-
if (actionOptions.limit)
|
|
41513
|
-
rows = rows.slice(-actionOptions.limit);
|
|
41514
|
-
if (wantsJson(actionOptions, command)) {
|
|
41515
|
-
console.log(JSON.stringify(rows, null, 2));
|
|
41516
|
-
return;
|
|
41517
|
-
}
|
|
41518
|
-
if (!rows.length) {
|
|
41519
|
-
console.log("No events recorded.");
|
|
41520
|
-
return;
|
|
41521
|
-
}
|
|
41522
|
-
for (const event of rows)
|
|
41523
|
-
console.log(`${event.time} ${event.id} ${event.source} ${event.type} ${event.severity}`);
|
|
41524
|
-
});
|
|
41525
|
-
events.command("replay").description("Replay recorded events").option("--id <id>", "Replay one event id").option("--source <source>", "Filter by source").option("--type <type>", "Filter by type").option("--dry-run", "Preview without delivery", false).option("-j, --json", "Print JSON output", false).action(async (actionOptions, command) => {
|
|
41526
|
-
const result = await createClient(options).replay({
|
|
41527
|
-
eventId: actionOptions.id,
|
|
41528
|
-
source: actionOptions.source,
|
|
41529
|
-
type: actionOptions.type,
|
|
41530
|
-
dryRun: actionOptions.dryRun
|
|
41531
|
-
});
|
|
41532
|
-
print(result, wantsJson(actionOptions, command), `Replayed ${result.events.length} event(s), ${result.deliveries.length} delivery result(s)`);
|
|
41533
|
-
});
|
|
41534
|
-
return events;
|
|
41535
|
-
}
|
|
41536
|
-
function registerEventsCommands(program2, options) {
|
|
41537
|
-
registerWebhookCommands(program2, options);
|
|
41538
|
-
registerEventCommands(program2, options);
|
|
41539
|
-
}
|
|
41540
|
-
function parseNumber(value) {
|
|
41541
|
-
const parsed = Number(value);
|
|
41542
|
-
if (!Number.isFinite(parsed))
|
|
41543
|
-
throw new Error(`Expected a number, got ${value}`);
|
|
41544
|
-
return parsed;
|
|
41545
|
-
}
|
|
41546
|
-
function collectValues(value, previous) {
|
|
41547
|
-
previous.push(value);
|
|
41548
|
-
return previous;
|
|
41549
|
-
}
|
|
41550
|
-
|
|
41551
40876
|
// src/cli/index.tsx
|
|
41552
40877
|
init_package();
|
|
41553
40878
|
init_registry2();
|
|
40879
|
+
import { registerEventsCommands } from "@hasna/events/commander";
|
|
41554
40880
|
|
|
41555
40881
|
// src/cli/components/App.tsx
|
|
41556
40882
|
import { useState as useState7 } from "react";
|
|
@@ -43028,7 +42354,7 @@ init_installer();
|
|
|
43028
42354
|
import { render } from "ink";
|
|
43029
42355
|
import chalk2 from "chalk";
|
|
43030
42356
|
import { readdirSync as readdirSync7, statSync as statSync5 } from "fs";
|
|
43031
|
-
import { join as
|
|
42357
|
+
import { join as join10, relative } from "path";
|
|
43032
42358
|
import { createInterface } from "readline";
|
|
43033
42359
|
import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
|
|
43034
42360
|
var isTTY = process.stdout.isTTY ?? false;
|
|
@@ -43043,7 +42369,7 @@ var PRESETS = {
|
|
|
43043
42369
|
function listFilesRecursive(dir, base = dir) {
|
|
43044
42370
|
const files = [];
|
|
43045
42371
|
for (const entry of readdirSync7(dir)) {
|
|
43046
|
-
const fullPath =
|
|
42372
|
+
const fullPath = join10(dir, entry);
|
|
43047
42373
|
if (statSync5(fullPath).isDirectory()) {
|
|
43048
42374
|
files.push(...listFilesRecursive(fullPath, base));
|
|
43049
42375
|
} else {
|
|
@@ -43093,9 +42419,9 @@ function registerCommands(program2) {
|
|
|
43093
42419
|
}
|
|
43094
42420
|
if (options.dryRun) {
|
|
43095
42421
|
const installed = getInstalledConnectors();
|
|
43096
|
-
const connectorsDir =
|
|
43097
|
-
const manifestPath =
|
|
43098
|
-
const indexPath =
|
|
42422
|
+
const connectorsDir = join10(process.cwd(), ".connectors");
|
|
42423
|
+
const manifestPath = join10(connectorsDir, "manifest.json");
|
|
42424
|
+
const indexPath = join10(connectorsDir, "index.ts");
|
|
43099
42425
|
const actions = [];
|
|
43100
42426
|
for (const name of connectors18) {
|
|
43101
42427
|
if (!/^[a-z0-9-]+$/.test(name)) {
|
|
@@ -43805,8 +43131,8 @@ init_auth();
|
|
|
43805
43131
|
init_database();
|
|
43806
43132
|
init_connector_resolver();
|
|
43807
43133
|
import chalk4 from "chalk";
|
|
43808
|
-
import { existsSync as
|
|
43809
|
-
import { join as
|
|
43134
|
+
import { existsSync as existsSync16, readFileSync as readFileSync10 } from "fs";
|
|
43135
|
+
import { join as join16 } from "path";
|
|
43810
43136
|
function registerCommands3(program2) {
|
|
43811
43137
|
program2.command("status").option("--json", "Output as JSON", false).option("--limit <n>", "Limit rows per section in human output").option("--offset <n>", "Skip first N rows per section in human output").option("-v, --verbose", "Show all human rows", false).description("Show auth status of all configured connectors (project + global)").action((options) => {
|
|
43812
43138
|
const parsedLimit = parseNonNegativeInt(options.limit, "--limit");
|
|
@@ -43828,8 +43154,8 @@ function registerCommands3(program2) {
|
|
|
43828
43154
|
const auth = getAuthStatus(name);
|
|
43829
43155
|
let profile = "default";
|
|
43830
43156
|
for (const connectorConfigDir of getConnectorConfigReadDirs(name, configDir)) {
|
|
43831
|
-
const currentProfileFile =
|
|
43832
|
-
if (
|
|
43157
|
+
const currentProfileFile = join16(connectorConfigDir, "current_profile");
|
|
43158
|
+
if (existsSync16(currentProfileFile)) {
|
|
43833
43159
|
try {
|
|
43834
43160
|
profile = readFileSync10(currentProfileFile, "utf-8").trim() || "default";
|
|
43835
43161
|
} catch {}
|
|
@@ -43869,7 +43195,7 @@ function registerCommands3(program2) {
|
|
|
43869
43195
|
seen.add(name);
|
|
43870
43196
|
allStatuses.push(buildStatusEntry(name, "project"));
|
|
43871
43197
|
}
|
|
43872
|
-
if (
|
|
43198
|
+
if (existsSync16(configDir)) {
|
|
43873
43199
|
try {
|
|
43874
43200
|
for (const name of listConfiguredConnectorNames(configDir)) {
|
|
43875
43201
|
if (name.startsWith("zzztest"))
|
|
@@ -44116,9 +43442,9 @@ init_registry2();
|
|
|
44116
43442
|
init_auth();
|
|
44117
43443
|
init_database();
|
|
44118
43444
|
import chalk5 from "chalk";
|
|
44119
|
-
import { existsSync as
|
|
44120
|
-
import { join as
|
|
44121
|
-
import { homedir as
|
|
43445
|
+
import { existsSync as existsSync17, readdirSync as readdirSync11, statSync as statSync8, readFileSync as readFileSync11, writeFileSync as writeFileSync8, mkdirSync as mkdirSync10 } from "fs";
|
|
43446
|
+
import { join as join17 } from "path";
|
|
43447
|
+
import { homedir as homedir4 } from "os";
|
|
44122
43448
|
import { createInterface as createInterface2 } from "readline";
|
|
44123
43449
|
init_connector_resolver();
|
|
44124
43450
|
var SENSITIVE_FIELDS = new Set([
|
|
@@ -44143,7 +43469,7 @@ var SENSITIVE_FIELDS = new Set([
|
|
|
44143
43469
|
"private_key",
|
|
44144
43470
|
"privatekey"
|
|
44145
43471
|
]);
|
|
44146
|
-
function
|
|
43472
|
+
function redactValue(value) {
|
|
44147
43473
|
if (value.length <= 8)
|
|
44148
43474
|
return "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
|
|
44149
43475
|
return value.slice(0, 4) + "\u2022\u2022\u2022\u2022" + value.slice(-4);
|
|
@@ -44159,7 +43485,7 @@ function redactSecrets(obj) {
|
|
|
44159
43485
|
const result = {};
|
|
44160
43486
|
for (const [key, value] of Object.entries(obj)) {
|
|
44161
43487
|
if (SENSITIVE_FIELDS.has(key.toLowerCase()) && typeof value === "string") {
|
|
44162
|
-
result[key] =
|
|
43488
|
+
result[key] = redactValue(value);
|
|
44163
43489
|
} else if (typeof value === "object" && value !== null) {
|
|
44164
43490
|
result[key] = redactSecrets(value);
|
|
44165
43491
|
} else {
|
|
@@ -44178,10 +43504,10 @@ function getOAuthTokenState(name) {
|
|
|
44178
43504
|
if (!tokens.expiresAt) {
|
|
44179
43505
|
return { hasTokens: true, expired: false };
|
|
44180
43506
|
}
|
|
44181
|
-
const
|
|
44182
|
-
const isExpired =
|
|
43507
|
+
const now3 = Date.now();
|
|
43508
|
+
const isExpired = now3 >= tokens.expiresAt - 60000;
|
|
44183
43509
|
const expiresIn = isExpired ? undefined : (() => {
|
|
44184
|
-
const ms = tokens.expiresAt -
|
|
43510
|
+
const ms = tokens.expiresAt - now3;
|
|
44185
43511
|
const mins = Math.floor(ms / 60000);
|
|
44186
43512
|
if (mins < 1)
|
|
44187
43513
|
return "less than a minute";
|
|
@@ -44193,8 +43519,8 @@ function getOAuthTokenState(name) {
|
|
|
44193
43519
|
}
|
|
44194
43520
|
function getCurrentOAuthProfile(name, connectorsHome = getConnectorsHome()) {
|
|
44195
43521
|
for (const dir of getConnectorConfigReadDirs(name, connectorsHome)) {
|
|
44196
|
-
const currentProfilePath =
|
|
44197
|
-
if (!
|
|
43522
|
+
const currentProfilePath = join17(dir, "current_profile");
|
|
43523
|
+
if (!existsSync17(currentProfilePath))
|
|
44198
43524
|
continue;
|
|
44199
43525
|
const profile = readFileSync11(currentProfilePath, "utf8").trim();
|
|
44200
43526
|
if (profile)
|
|
@@ -44203,11 +43529,11 @@ function getCurrentOAuthProfile(name, connectorsHome = getConnectorsHome()) {
|
|
|
44203
43529
|
return "default";
|
|
44204
43530
|
}
|
|
44205
43531
|
function getOAuthTokenPathsForProfile(name, connectorsHome = getConnectorsHome(), profile = getCurrentOAuthProfile(name, connectorsHome)) {
|
|
44206
|
-
return getConnectorConfigReadDirs(name, connectorsHome).map((dir) =>
|
|
43532
|
+
return getConnectorConfigReadDirs(name, connectorsHome).map((dir) => join17(dir, "profiles", profile, "tokens.json"));
|
|
44207
43533
|
}
|
|
44208
43534
|
function hasOAuthTokenFileUpdatedSince(tokenPaths, sinceMs) {
|
|
44209
43535
|
return tokenPaths.some((tokensPath) => {
|
|
44210
|
-
if (!
|
|
43536
|
+
if (!existsSync17(tokensPath))
|
|
44211
43537
|
return false;
|
|
44212
43538
|
return statSync8(tokensPath).mtimeMs >= sinceMs;
|
|
44213
43539
|
});
|
|
@@ -44335,9 +43661,9 @@ ${meta.displayName} \u2014 Auth Configuration
|
|
|
44335
43661
|
try {
|
|
44336
43662
|
if (!options.browser) {
|
|
44337
43663
|
console.log(chalk5.dim(`Starting OAuth server on port ${port}...`));
|
|
44338
|
-
const { spawn:
|
|
43664
|
+
const { spawn: spawn4 } = await import("child_process");
|
|
44339
43665
|
const scriptPath = process.argv[1];
|
|
44340
|
-
const serverProc =
|
|
43666
|
+
const serverProc = spawn4(process.execPath, [scriptPath, "serve", "--port", String(port)], {
|
|
44341
43667
|
detached: true,
|
|
44342
43668
|
stdio: "ignore"
|
|
44343
43669
|
});
|
|
@@ -44511,9 +43837,9 @@ Open this URL to authenticate:
|
|
|
44511
43837
|
let configuredCount = 0;
|
|
44512
43838
|
const configuredNames = [];
|
|
44513
43839
|
try {
|
|
44514
|
-
if (
|
|
43840
|
+
if (existsSync17(connectorsHome)) {
|
|
44515
43841
|
for (const name of listConfiguredConnectorNames(connectorsHome)) {
|
|
44516
|
-
const hasProfiles = getConnectorConfigReadDirs(name, connectorsHome).some((dir) =>
|
|
43842
|
+
const hasProfiles = getConnectorConfigReadDirs(name, connectorsHome).some((dir) => existsSync17(join17(dir, "profiles")));
|
|
44517
43843
|
if (hasProfiles) {
|
|
44518
43844
|
configuredCount++;
|
|
44519
43845
|
configuredNames.push(name);
|
|
@@ -44565,13 +43891,13 @@ Open this URL to authenticate:
|
|
|
44565
43891
|
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) => {
|
|
44566
43892
|
const connectDir = getConnectorsHome();
|
|
44567
43893
|
const result = {};
|
|
44568
|
-
if (
|
|
43894
|
+
if (existsSync17(connectDir)) {
|
|
44569
43895
|
for (const connectorName of listConfiguredConnectorNames(connectDir)) {
|
|
44570
43896
|
const connectorDirs = [...getConnectorConfigReadDirs(connectorName, connectDir)].reverse();
|
|
44571
43897
|
let credentials = undefined;
|
|
44572
43898
|
for (const connectorDir of connectorDirs) {
|
|
44573
|
-
const credentialsPath =
|
|
44574
|
-
if (
|
|
43899
|
+
const credentialsPath = join17(connectorDir, "credentials.json");
|
|
43900
|
+
if (existsSync17(credentialsPath)) {
|
|
44575
43901
|
try {
|
|
44576
43902
|
credentials = JSON.parse(readFileSync11(credentialsPath, "utf-8"));
|
|
44577
43903
|
} catch {}
|
|
@@ -44579,24 +43905,24 @@ Open this URL to authenticate:
|
|
|
44579
43905
|
}
|
|
44580
43906
|
const profiles = {};
|
|
44581
43907
|
for (const connectorDir of connectorDirs) {
|
|
44582
|
-
const profilesDir =
|
|
44583
|
-
if (
|
|
43908
|
+
const profilesDir = join17(connectorDir, "profiles");
|
|
43909
|
+
if (existsSync17(profilesDir)) {
|
|
44584
43910
|
for (const pEntry of readdirSync11(profilesDir)) {
|
|
44585
|
-
const pPath =
|
|
43911
|
+
const pPath = join17(profilesDir, pEntry);
|
|
44586
43912
|
if (statSync8(pPath).isFile() && pEntry.endsWith(".json")) {
|
|
44587
43913
|
try {
|
|
44588
43914
|
profiles[pEntry.replace(/\.json$/, "")] = JSON.parse(readFileSync11(pPath, "utf-8"));
|
|
44589
43915
|
} catch {}
|
|
44590
43916
|
} else if (statSync8(pPath).isDirectory()) {
|
|
44591
|
-
const configPath =
|
|
44592
|
-
const tokensPath =
|
|
43917
|
+
const configPath = join17(pPath, "config.json");
|
|
43918
|
+
const tokensPath = join17(pPath, "tokens.json");
|
|
44593
43919
|
let merged = {};
|
|
44594
|
-
if (
|
|
43920
|
+
if (existsSync17(configPath)) {
|
|
44595
43921
|
try {
|
|
44596
43922
|
merged = { ...merged, ...JSON.parse(readFileSync11(configPath, "utf-8")) };
|
|
44597
43923
|
} catch {}
|
|
44598
43924
|
}
|
|
44599
|
-
if (
|
|
43925
|
+
if (existsSync17(tokensPath)) {
|
|
44600
43926
|
try {
|
|
44601
43927
|
merged = { ...merged, ...JSON.parse(readFileSync11(tokensPath, "utf-8")) };
|
|
44602
43928
|
} catch {}
|
|
@@ -44634,7 +43960,7 @@ Open this URL to authenticate:
|
|
|
44634
43960
|
chunks.push(chunk.toString());
|
|
44635
43961
|
raw = chunks.join("");
|
|
44636
43962
|
} else {
|
|
44637
|
-
if (!
|
|
43963
|
+
if (!existsSync17(file)) {
|
|
44638
43964
|
if (options.json) {
|
|
44639
43965
|
console.log(JSON.stringify({ error: `File not found: ${file}` }));
|
|
44640
43966
|
} else {
|
|
@@ -44674,17 +44000,17 @@ Open this URL to authenticate:
|
|
|
44674
44000
|
const connectorDir = getConnectorConfigDir(connectorName, connectDir);
|
|
44675
44001
|
if (connData.credentials && typeof connData.credentials === "object") {
|
|
44676
44002
|
mkdirSync10(connectorDir, { recursive: true });
|
|
44677
|
-
writeFileSync8(
|
|
44003
|
+
writeFileSync8(join17(connectorDir, "credentials.json"), JSON.stringify(connData.credentials, null, 2));
|
|
44678
44004
|
imported++;
|
|
44679
44005
|
}
|
|
44680
44006
|
if (!connData.profiles || typeof connData.profiles !== "object")
|
|
44681
44007
|
continue;
|
|
44682
|
-
const profilesDir =
|
|
44008
|
+
const profilesDir = join17(connectorDir, "profiles");
|
|
44683
44009
|
for (const [profileName, config2] of Object.entries(connData.profiles)) {
|
|
44684
44010
|
if (!config2 || typeof config2 !== "object")
|
|
44685
44011
|
continue;
|
|
44686
44012
|
mkdirSync10(profilesDir, { recursive: true });
|
|
44687
|
-
writeFileSync8(
|
|
44013
|
+
writeFileSync8(join17(profilesDir, `${profileName}.json`), JSON.stringify(config2, null, 2));
|
|
44688
44014
|
imported++;
|
|
44689
44015
|
}
|
|
44690
44016
|
}
|
|
@@ -44695,9 +44021,9 @@ Open this URL to authenticate:
|
|
|
44695
44021
|
}
|
|
44696
44022
|
});
|
|
44697
44023
|
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) => {
|
|
44698
|
-
const oldBase =
|
|
44024
|
+
const oldBase = join17(homedir4(), ".connect");
|
|
44699
44025
|
const newBase = getConnectorsHome();
|
|
44700
|
-
if (!
|
|
44026
|
+
if (!existsSync17(oldBase)) {
|
|
44701
44027
|
if (options.json) {
|
|
44702
44028
|
console.log(JSON.stringify({ imported: [], skipped: [], error: null, message: "No ~/.connect/ directory found" }));
|
|
44703
44029
|
} else {
|
|
@@ -44709,7 +44035,7 @@ Open this URL to authenticate:
|
|
|
44709
44035
|
if (!name.startsWith("connect-"))
|
|
44710
44036
|
return false;
|
|
44711
44037
|
try {
|
|
44712
|
-
return statSync8(
|
|
44038
|
+
return statSync8(join17(oldBase, name)).isDirectory();
|
|
44713
44039
|
} catch {
|
|
44714
44040
|
return false;
|
|
44715
44041
|
}
|
|
@@ -44725,7 +44051,7 @@ Open this URL to authenticate:
|
|
|
44725
44051
|
const imported = [];
|
|
44726
44052
|
const skipped = [];
|
|
44727
44053
|
for (const dirName of entries) {
|
|
44728
|
-
const oldDir =
|
|
44054
|
+
const oldDir = join17(oldBase, dirName);
|
|
44729
44055
|
const connectorName = dirName.replace(/^connect-/, "");
|
|
44730
44056
|
const newDir = getConnectorConfigDir(connectorName, newBase);
|
|
44731
44057
|
const allFiles = listFilesRecursive(oldDir);
|
|
@@ -44737,14 +44063,14 @@ Open this URL to authenticate:
|
|
|
44737
44063
|
const copiedFiles = [];
|
|
44738
44064
|
const skippedFiles = [];
|
|
44739
44065
|
for (const relFile of authFiles) {
|
|
44740
|
-
const srcPath =
|
|
44741
|
-
const destPath =
|
|
44742
|
-
if (
|
|
44066
|
+
const srcPath = join17(oldDir, relFile);
|
|
44067
|
+
const destPath = join17(newDir, relFile);
|
|
44068
|
+
if (existsSync17(destPath) && !options.force) {
|
|
44743
44069
|
skippedFiles.push(relFile);
|
|
44744
44070
|
continue;
|
|
44745
44071
|
}
|
|
44746
44072
|
if (!options.dryRun) {
|
|
44747
|
-
const parentDir =
|
|
44073
|
+
const parentDir = join17(destPath, "..");
|
|
44748
44074
|
mkdirSync10(parentDir, { recursive: true });
|
|
44749
44075
|
const content = readFileSync11(srcPath);
|
|
44750
44076
|
writeFileSync8(destPath, content);
|
|
@@ -44813,8 +44139,8 @@ init_installer();
|
|
|
44813
44139
|
init_auth();
|
|
44814
44140
|
init_database();
|
|
44815
44141
|
import chalk6 from "chalk";
|
|
44816
|
-
import { existsSync as
|
|
44817
|
-
import { join as
|
|
44142
|
+
import { existsSync as existsSync18, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "fs";
|
|
44143
|
+
import { join as join18 } from "path";
|
|
44818
44144
|
|
|
44819
44145
|
// src/lib/test-endpoints.ts
|
|
44820
44146
|
var TEST_ENDPOINTS = {
|
|
@@ -45299,8 +44625,8 @@ Available presets:
|
|
|
45299
44625
|
unconfigured++;
|
|
45300
44626
|
let profile = "default";
|
|
45301
44627
|
for (const connectorConfigDir of getConnectorConfigReadDirs(name, configDir)) {
|
|
45302
|
-
const currentProfileFile =
|
|
45303
|
-
if (
|
|
44628
|
+
const currentProfileFile = join18(connectorConfigDir, "current_profile");
|
|
44629
|
+
if (existsSync18(currentProfileFile)) {
|
|
45304
44630
|
try {
|
|
45305
44631
|
profile = readFileSync12(currentProfileFile, "utf-8").trim() || "default";
|
|
45306
44632
|
} catch {}
|
|
@@ -45309,7 +44635,7 @@ Available presets:
|
|
|
45309
44635
|
}
|
|
45310
44636
|
connectorDetails.push({ name, configured: auth.configured, authType: auth.type, profile, source: "project" });
|
|
45311
44637
|
}
|
|
45312
|
-
if (
|
|
44638
|
+
if (existsSync18(configDir)) {
|
|
45313
44639
|
try {
|
|
45314
44640
|
for (const name of listConfiguredConnectorNames(configDir)) {
|
|
45315
44641
|
if (seen.has(name))
|
|
@@ -45321,8 +44647,8 @@ Available presets:
|
|
|
45321
44647
|
configured++;
|
|
45322
44648
|
let profile = "default";
|
|
45323
44649
|
for (const connectorConfigDir of getConnectorConfigReadDirs(name, configDir)) {
|
|
45324
|
-
const currentProfileFile =
|
|
45325
|
-
if (
|
|
44650
|
+
const currentProfileFile = join18(connectorConfigDir, "current_profile");
|
|
44651
|
+
if (existsSync18(currentProfileFile)) {
|
|
45326
44652
|
try {
|
|
45327
44653
|
profile = readFileSync12(currentProfileFile, "utf-8").trim() || "default";
|
|
45328
44654
|
} catch {}
|
|
@@ -45337,7 +44663,7 @@ Available presets:
|
|
|
45337
44663
|
console.log(JSON.stringify({
|
|
45338
44664
|
version: version2,
|
|
45339
44665
|
configDir,
|
|
45340
|
-
configDirExists:
|
|
44666
|
+
configDirExists: existsSync18(configDir),
|
|
45341
44667
|
installed: installed.length,
|
|
45342
44668
|
configured,
|
|
45343
44669
|
unconfigured,
|
|
@@ -45349,7 +44675,7 @@ Available presets:
|
|
|
45349
44675
|
Connectors Setup
|
|
45350
44676
|
`));
|
|
45351
44677
|
console.log(` Version: ${chalk6.cyan(version2)}`);
|
|
45352
|
-
console.log(` Config: ${configDir}${
|
|
44678
|
+
console.log(` Config: ${configDir}${existsSync18(configDir) ? "" : chalk6.dim(" (not created yet)")}`);
|
|
45353
44679
|
console.log(` Installed: ${installed.length} connector${installed.length !== 1 ? "s" : ""}`);
|
|
45354
44680
|
console.log(` Configured: ${chalk6.green(String(configured))} ready, ${unconfigured > 0 ? chalk6.red(String(unconfigured)) : chalk6.dim("0")} need auth`);
|
|
45355
44681
|
const projectConnectors = connectorDetails.filter((c) => c.source === "project");
|
|
@@ -45457,15 +44783,15 @@ Testing connector credentials...
|
|
|
45457
44783
|
const connectorConfigDirs = getConnectorConfigReadDirs(name);
|
|
45458
44784
|
let currentProfile = "default";
|
|
45459
44785
|
for (const connectorConfigDir of connectorConfigDirs) {
|
|
45460
|
-
const currentProfileFile =
|
|
45461
|
-
if (
|
|
44786
|
+
const currentProfileFile = join18(connectorConfigDir, "current_profile");
|
|
44787
|
+
if (existsSync18(currentProfileFile)) {
|
|
45462
44788
|
try {
|
|
45463
44789
|
currentProfile = readFileSync12(currentProfileFile, "utf-8").trim() || "default";
|
|
45464
44790
|
} catch {}
|
|
45465
44791
|
break;
|
|
45466
44792
|
}
|
|
45467
44793
|
}
|
|
45468
|
-
const tokensFile = connectorConfigDirs.map((dir) =>
|
|
44794
|
+
const tokensFile = connectorConfigDirs.map((dir) => join18(dir, "profiles", currentProfile, "tokens.json")).find((path) => existsSync18(path));
|
|
45469
44795
|
if (tokensFile) {
|
|
45470
44796
|
try {
|
|
45471
44797
|
const tokens = JSON.parse(readFileSync12(tokensFile, "utf-8"));
|
|
@@ -45487,8 +44813,8 @@ Testing connector credentials...
|
|
|
45487
44813
|
}
|
|
45488
44814
|
if (!apiKey) {
|
|
45489
44815
|
for (const connectorConfigDir of connectorConfigDirs) {
|
|
45490
|
-
const profileFile =
|
|
45491
|
-
if (
|
|
44816
|
+
const profileFile = join18(connectorConfigDir, "profiles", `${currentProfile}.json`);
|
|
44817
|
+
if (existsSync18(profileFile)) {
|
|
45492
44818
|
try {
|
|
45493
44819
|
const config2 = JSON.parse(readFileSync12(profileFile, "utf-8"));
|
|
45494
44820
|
apiKey = Object.values(config2).find((v) => typeof v === "string" && v.length > 0);
|
|
@@ -45500,8 +44826,8 @@ Testing connector credentials...
|
|
|
45500
44826
|
}
|
|
45501
44827
|
if (!apiKey) {
|
|
45502
44828
|
for (const connectorConfigDir of connectorConfigDirs) {
|
|
45503
|
-
const profileDirConfig =
|
|
45504
|
-
if (
|
|
44829
|
+
const profileDirConfig = join18(connectorConfigDir, "profiles", currentProfile, "config.json");
|
|
44830
|
+
if (existsSync18(profileDirConfig)) {
|
|
45505
44831
|
try {
|
|
45506
44832
|
const config2 = JSON.parse(readFileSync12(profileDirConfig, "utf-8"));
|
|
45507
44833
|
apiKey = Object.values(config2).find((v) => typeof v === "string" && v.length > 0);
|
|
@@ -45764,10 +45090,10 @@ Setting up ${meta.displayName}...
|
|
|
45764
45090
|
${chalk7.bold("Open this URL to authenticate:")}`);
|
|
45765
45091
|
console.log(` ${chalk7.cyan(oauthUrl)}
|
|
45766
45092
|
`);
|
|
45767
|
-
const { spawn:
|
|
45093
|
+
const { spawn: spawn4 } = await import("child_process");
|
|
45768
45094
|
const { getConnectorsHome: getConnectorsHome2 } = await Promise.resolve().then(() => (init_database(), exports_database));
|
|
45769
45095
|
const scriptPath = process.argv[1];
|
|
45770
|
-
const serverProc =
|
|
45096
|
+
const serverProc = spawn4(process.execPath, [scriptPath, "serve", "--port", String(port)], {
|
|
45771
45097
|
detached: true,
|
|
45772
45098
|
stdio: "ignore"
|
|
45773
45099
|
});
|