@hasna/connectors 1.3.25 → 1.3.26
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 +606 -170
- package/bin/mcp.js +633 -197
- package/bin/serve.js +654 -222
- package/dist/core/connectors/gmail.d.ts +5 -0
- package/dist/index.js +595 -163
- package/package.json +1 -1
package/bin/serve.js
CHANGED
|
@@ -10009,7 +10009,7 @@ var init_promotions = __esm(() => {
|
|
|
10009
10009
|
});
|
|
10010
10010
|
|
|
10011
10011
|
// src/server/serve.ts
|
|
10012
|
-
import { existsSync as
|
|
10012
|
+
import { existsSync as existsSync17, readdirSync as readdirSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync8, mkdirSync as mkdirSync12 } from "fs";
|
|
10013
10013
|
|
|
10014
10014
|
// src/db/agents.ts
|
|
10015
10015
|
init_database();
|
|
@@ -10240,12 +10240,12 @@ async function runWorkflow(workflow) {
|
|
|
10240
10240
|
|
|
10241
10241
|
// src/server/serve.ts
|
|
10242
10242
|
init_database();
|
|
10243
|
-
import { join as
|
|
10243
|
+
import { join as join18, dirname as dirname8, extname, basename as basename3 } from "path";
|
|
10244
10244
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
10245
10245
|
|
|
10246
10246
|
// src/lib/registry.ts
|
|
10247
|
-
import { existsSync as
|
|
10248
|
-
import { join as
|
|
10247
|
+
import { existsSync as existsSync12, readFileSync as readFileSync6 } from "fs";
|
|
10248
|
+
import { join as join13, dirname as dirname5 } from "path";
|
|
10249
10249
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
10250
10250
|
|
|
10251
10251
|
// src/core/errors.ts
|
|
@@ -10260,7 +10260,7 @@ class ConnectorDefinitionError extends Error {
|
|
|
10260
10260
|
|
|
10261
10261
|
// src/core/connector.ts
|
|
10262
10262
|
var CONNECTOR_NAME_RE = /^[a-z0-9-]+$/;
|
|
10263
|
-
var OPERATION_NAME_RE = /^[
|
|
10263
|
+
var OPERATION_NAME_RE = /^[A-Za-z0-9:._-]+$/;
|
|
10264
10264
|
function defineConnector(definition) {
|
|
10265
10265
|
const { meta, auth, operations } = definition;
|
|
10266
10266
|
if (!CONNECTOR_NAME_RE.test(meta.name)) {
|
|
@@ -15159,13 +15159,444 @@ var githubConnector = defineConnector({
|
|
|
15159
15159
|
}
|
|
15160
15160
|
});
|
|
15161
15161
|
|
|
15162
|
-
// src/core/connectors/
|
|
15162
|
+
// src/core/connectors/gmail.ts
|
|
15163
15163
|
import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync3, readdirSync as readdirSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
15164
15164
|
import { homedir as homedir8 } from "os";
|
|
15165
15165
|
import { basename, join as join9 } from "path";
|
|
15166
|
-
var
|
|
15166
|
+
var GMAIL_API_BASE = "https://gmail.googleapis.com/gmail/v1";
|
|
15167
15167
|
var TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
15168
15168
|
var REFRESH_BUFFER_MS = 5 * 60 * 1000;
|
|
15169
|
+
var listMessagesSchema = exports_external2.object({
|
|
15170
|
+
max: exports_external2.coerce.number().int().positive().max(500).optional(),
|
|
15171
|
+
maxResults: exports_external2.coerce.number().int().positive().max(500).optional(),
|
|
15172
|
+
pageToken: exports_external2.string().optional(),
|
|
15173
|
+
query: exports_external2.string().optional(),
|
|
15174
|
+
q: exports_external2.string().optional(),
|
|
15175
|
+
label: exports_external2.string().optional(),
|
|
15176
|
+
labelIds: exports_external2.union([exports_external2.string(), exports_external2.array(exports_external2.string())]).optional(),
|
|
15177
|
+
includeSpamTrash: exports_external2.boolean().optional()
|
|
15178
|
+
});
|
|
15179
|
+
var messageIdSchema = exports_external2.object({
|
|
15180
|
+
args: exports_external2.array(exports_external2.union([exports_external2.string(), exports_external2.number(), exports_external2.boolean()])).optional(),
|
|
15181
|
+
messageId: exports_external2.string().optional()
|
|
15182
|
+
});
|
|
15183
|
+
var readMessageSchema = messageIdSchema.extend({
|
|
15184
|
+
body: exports_external2.boolean().optional(),
|
|
15185
|
+
html: exports_external2.boolean().optional(),
|
|
15186
|
+
format: exports_external2.enum(["full", "metadata", "minimal", "raw"]).optional()
|
|
15187
|
+
});
|
|
15188
|
+
var attachmentListSchema = messageIdSchema;
|
|
15189
|
+
var attachmentDownloadSchema = messageIdSchema.extend({
|
|
15190
|
+
attachmentId: exports_external2.string().optional(),
|
|
15191
|
+
filename: exports_external2.string().optional(),
|
|
15192
|
+
mimeType: exports_external2.string().optional(),
|
|
15193
|
+
dir: exports_external2.string().optional(),
|
|
15194
|
+
outputDir: exports_external2.string().optional()
|
|
15195
|
+
});
|
|
15196
|
+
var historyListSchema = exports_external2.object({
|
|
15197
|
+
startHistoryId: exports_external2.string(),
|
|
15198
|
+
historyTypes: exports_external2.union([exports_external2.string(), exports_external2.array(exports_external2.string())]).optional(),
|
|
15199
|
+
labelId: exports_external2.string().optional(),
|
|
15200
|
+
maxResults: exports_external2.coerce.number().int().positive().max(500).optional(),
|
|
15201
|
+
pageToken: exports_external2.string().optional()
|
|
15202
|
+
});
|
|
15203
|
+
var replySchema = messageIdSchema.extend({
|
|
15204
|
+
body: exports_external2.string(),
|
|
15205
|
+
html: exports_external2.boolean().optional(),
|
|
15206
|
+
isHtml: exports_external2.boolean().optional(),
|
|
15207
|
+
cc: exports_external2.union([exports_external2.string(), exports_external2.array(exports_external2.string())]).optional(),
|
|
15208
|
+
bcc: exports_external2.union([exports_external2.string(), exports_external2.array(exports_external2.string())]).optional()
|
|
15209
|
+
});
|
|
15210
|
+
var gmailConnector = defineConnector({
|
|
15211
|
+
meta: {
|
|
15212
|
+
name: "gmail",
|
|
15213
|
+
displayName: "Gmail",
|
|
15214
|
+
description: "Profile-aware Gmail mailbox operations for sync, labels, attachments, history, and replies.",
|
|
15215
|
+
category: "communication",
|
|
15216
|
+
tags: ["google", "gmail", "email", "mailbox"]
|
|
15217
|
+
},
|
|
15218
|
+
auth: {
|
|
15219
|
+
type: "oauth2",
|
|
15220
|
+
supportsProfiles: true,
|
|
15221
|
+
fields: [
|
|
15222
|
+
{ key: "clientId", env: "GMAIL_CLIENT_ID", label: "OAuth client ID" },
|
|
15223
|
+
{ key: "clientSecret", env: "GMAIL_CLIENT_SECRET", label: "OAuth client secret", secret: true }
|
|
15224
|
+
]
|
|
15225
|
+
},
|
|
15226
|
+
createContext: ({ profile }) => ({ profile: profile || "default" }),
|
|
15227
|
+
operations: {
|
|
15228
|
+
"profiles.list": {
|
|
15229
|
+
summary: "List configured Gmail profiles.",
|
|
15230
|
+
execute: () => ({ profiles: listProfiles() })
|
|
15231
|
+
},
|
|
15232
|
+
"profile.get": {
|
|
15233
|
+
summary: "Get the authenticated Gmail profile.",
|
|
15234
|
+
execute: async ({ context }) => requestJson(context.profile, "/users/me/profile", {})
|
|
15235
|
+
},
|
|
15236
|
+
"messages.list": {
|
|
15237
|
+
summary: "List Gmail messages.",
|
|
15238
|
+
inputSchema: listMessagesSchema,
|
|
15239
|
+
execute: async ({ context }, input) => {
|
|
15240
|
+
const labelIds = normalizeStringArray(input.labelIds ?? input.label);
|
|
15241
|
+
return requestJson(context.profile, "/users/me/messages", {
|
|
15242
|
+
maxResults: input.maxResults ?? input.max ?? 50,
|
|
15243
|
+
pageToken: input.pageToken,
|
|
15244
|
+
q: input.q ?? input.query,
|
|
15245
|
+
labelIds: labelIds.length > 0 ? labelIds.join(",") : undefined,
|
|
15246
|
+
includeSpamTrash: input.includeSpamTrash
|
|
15247
|
+
});
|
|
15248
|
+
}
|
|
15249
|
+
},
|
|
15250
|
+
"messages.read": {
|
|
15251
|
+
summary: "Read a Gmail message with optional extracted body.",
|
|
15252
|
+
inputSchema: readMessageSchema,
|
|
15253
|
+
execute: async ({ context }, input) => {
|
|
15254
|
+
const messageId = getMessageId(input);
|
|
15255
|
+
const message = await requestJson(context.profile, `/users/me/messages/${encodeURIComponent(messageId)}`, { format: input.format ?? "full" });
|
|
15256
|
+
const headers = headersToObject(message.payload?.headers ?? []);
|
|
15257
|
+
return {
|
|
15258
|
+
...message,
|
|
15259
|
+
from: headers.From ?? headers.from ?? "",
|
|
15260
|
+
to: headers.To ?? headers.to ?? "",
|
|
15261
|
+
cc: headers.Cc ?? headers.cc ?? "",
|
|
15262
|
+
subject: headers.Subject ?? headers.subject ?? "",
|
|
15263
|
+
date: headers.Date ?? headers.date ?? "",
|
|
15264
|
+
body: input.body ? extractBody(message, Boolean(input.html)) : undefined,
|
|
15265
|
+
size: message.sizeEstimate
|
|
15266
|
+
};
|
|
15267
|
+
}
|
|
15268
|
+
},
|
|
15269
|
+
"messages.getRaw": {
|
|
15270
|
+
summary: "Read raw base64url Gmail message content.",
|
|
15271
|
+
inputSchema: messageIdSchema,
|
|
15272
|
+
execute: async ({ context }, input) => {
|
|
15273
|
+
const messageId = getMessageId(input);
|
|
15274
|
+
return requestJson(context.profile, `/users/me/messages/${encodeURIComponent(messageId)}`, { format: "raw" });
|
|
15275
|
+
}
|
|
15276
|
+
},
|
|
15277
|
+
"messages.mark-read": {
|
|
15278
|
+
summary: "Mark a message as read.",
|
|
15279
|
+
inputSchema: messageIdSchema,
|
|
15280
|
+
execute: async ({ context }, input) => modifyMessage(context.profile, getMessageId(input), undefined, ["UNREAD"])
|
|
15281
|
+
},
|
|
15282
|
+
"messages.mark-unread": {
|
|
15283
|
+
summary: "Mark a message as unread.",
|
|
15284
|
+
inputSchema: messageIdSchema,
|
|
15285
|
+
execute: async ({ context }, input) => modifyMessage(context.profile, getMessageId(input), ["UNREAD"], undefined)
|
|
15286
|
+
},
|
|
15287
|
+
"messages.archive": {
|
|
15288
|
+
summary: "Archive a message by removing the INBOX label.",
|
|
15289
|
+
inputSchema: messageIdSchema,
|
|
15290
|
+
execute: async ({ context }, input) => modifyMessage(context.profile, getMessageId(input), undefined, ["INBOX"])
|
|
15291
|
+
},
|
|
15292
|
+
"messages.star": {
|
|
15293
|
+
summary: "Star a message.",
|
|
15294
|
+
inputSchema: messageIdSchema,
|
|
15295
|
+
execute: async ({ context }, input) => modifyMessage(context.profile, getMessageId(input), ["STARRED"], undefined)
|
|
15296
|
+
},
|
|
15297
|
+
"messages.reply": {
|
|
15298
|
+
summary: "Reply to a Gmail message in the same thread.",
|
|
15299
|
+
inputSchema: replySchema,
|
|
15300
|
+
execute: async ({ context }, input) => replyToMessage(context.profile, getMessageId(input), input)
|
|
15301
|
+
},
|
|
15302
|
+
"attachments.list": {
|
|
15303
|
+
summary: "List Gmail message attachments.",
|
|
15304
|
+
inputSchema: attachmentListSchema,
|
|
15305
|
+
execute: async ({ context }, input) => {
|
|
15306
|
+
const message = await requestJson(context.profile, `/users/me/messages/${encodeURIComponent(getMessageId(input))}`, { format: "full" });
|
|
15307
|
+
return collectAttachments(message.payload);
|
|
15308
|
+
}
|
|
15309
|
+
},
|
|
15310
|
+
"attachments.download": {
|
|
15311
|
+
summary: "Download one or all Gmail message attachments to disk.",
|
|
15312
|
+
inputSchema: attachmentDownloadSchema,
|
|
15313
|
+
execute: async ({ context }, input) => downloadAttachments(context.profile, input)
|
|
15314
|
+
},
|
|
15315
|
+
"labels.list": {
|
|
15316
|
+
summary: "List Gmail labels.",
|
|
15317
|
+
execute: async ({ context }) => requestJson(context.profile, "/users/me/labels", {})
|
|
15318
|
+
},
|
|
15319
|
+
"history.list": {
|
|
15320
|
+
summary: "List Gmail mailbox history from a history id.",
|
|
15321
|
+
inputSchema: historyListSchema,
|
|
15322
|
+
execute: async ({ context }, input) => requestJson(context.profile, "/users/me/history", {
|
|
15323
|
+
startHistoryId: input.startHistoryId,
|
|
15324
|
+
historyTypes: normalizeStringArray(input.historyTypes).join(",") || undefined,
|
|
15325
|
+
labelId: input.labelId,
|
|
15326
|
+
maxResults: input.maxResults,
|
|
15327
|
+
pageToken: input.pageToken
|
|
15328
|
+
})
|
|
15329
|
+
}
|
|
15330
|
+
}
|
|
15331
|
+
});
|
|
15332
|
+
async function modifyMessage(profile, messageId, addLabelIds, removeLabelIds) {
|
|
15333
|
+
return requestJson(profile, `/users/me/messages/${encodeURIComponent(messageId)}/modify`, {}, {
|
|
15334
|
+
method: "POST",
|
|
15335
|
+
body: {
|
|
15336
|
+
addLabelIds: addLabelIds ?? [],
|
|
15337
|
+
removeLabelIds: removeLabelIds ?? []
|
|
15338
|
+
}
|
|
15339
|
+
});
|
|
15340
|
+
}
|
|
15341
|
+
async function replyToMessage(profile, messageId, input) {
|
|
15342
|
+
const original = await requestJson(profile, `/users/me/messages/${encodeURIComponent(messageId)}`, { format: "full" });
|
|
15343
|
+
const headers = headersToObject(original.payload?.headers ?? []);
|
|
15344
|
+
const subject = normalizeReplySubject(headers.Subject ?? headers.subject ?? "");
|
|
15345
|
+
const to = headers.From ?? headers.from ?? "";
|
|
15346
|
+
const messageIdHeader = headers["Message-ID"] ?? headers["Message-Id"] ?? headers["message-id"] ?? "";
|
|
15347
|
+
const references = [headers.References ?? headers.references, messageIdHeader].filter(Boolean).join(" ");
|
|
15348
|
+
const raw = buildRawEmail({
|
|
15349
|
+
to,
|
|
15350
|
+
cc: normalizeStringArray(input.cc),
|
|
15351
|
+
bcc: normalizeStringArray(input.bcc),
|
|
15352
|
+
subject,
|
|
15353
|
+
body: input.body,
|
|
15354
|
+
isHtml: Boolean(input.html ?? input.isHtml),
|
|
15355
|
+
inReplyTo: messageIdHeader,
|
|
15356
|
+
references
|
|
15357
|
+
});
|
|
15358
|
+
return requestJson(profile, "/users/me/messages/send", {}, {
|
|
15359
|
+
method: "POST",
|
|
15360
|
+
body: {
|
|
15361
|
+
raw: Buffer.from(raw).toString("base64url"),
|
|
15362
|
+
threadId: original.threadId
|
|
15363
|
+
}
|
|
15364
|
+
});
|
|
15365
|
+
}
|
|
15366
|
+
async function downloadAttachments(profile, input) {
|
|
15367
|
+
const messageId = getMessageId(input);
|
|
15368
|
+
const outputDir = input.dir ?? input.outputDir ?? join9(configDirs()[0], "attachments", messageId);
|
|
15369
|
+
mkdirSync6(outputDir, { recursive: true });
|
|
15370
|
+
const attachments = input.attachmentId && input.filename ? [{
|
|
15371
|
+
attachmentId: input.attachmentId,
|
|
15372
|
+
filename: input.filename,
|
|
15373
|
+
mimeType: input.mimeType ?? "application/octet-stream",
|
|
15374
|
+
size: 0
|
|
15375
|
+
}] : collectAttachments((await requestJson(profile, `/users/me/messages/${encodeURIComponent(messageId)}`, { format: "full" })).payload);
|
|
15376
|
+
const downloaded = [];
|
|
15377
|
+
for (const attachment of attachments) {
|
|
15378
|
+
const data = await requestJson(profile, `/users/me/messages/${encodeURIComponent(messageId)}/attachments/${encodeURIComponent(attachment.attachmentId)}`, {});
|
|
15379
|
+
const filename = safeFilename(attachment.filename);
|
|
15380
|
+
const path = join9(outputDir, filename);
|
|
15381
|
+
const buffer = Buffer.from(data.data, "base64url");
|
|
15382
|
+
writeFileSync3(path, buffer);
|
|
15383
|
+
downloaded.push({
|
|
15384
|
+
filename,
|
|
15385
|
+
path,
|
|
15386
|
+
size: buffer.length,
|
|
15387
|
+
mimeType: attachment.mimeType
|
|
15388
|
+
});
|
|
15389
|
+
}
|
|
15390
|
+
return downloaded;
|
|
15391
|
+
}
|
|
15392
|
+
async function requestJson(profile, path, params, options = {}) {
|
|
15393
|
+
const token = await getValidAccessToken(profile);
|
|
15394
|
+
const url = new URL(`${GMAIL_API_BASE}${path}`);
|
|
15395
|
+
for (const [key, value] of Object.entries(params)) {
|
|
15396
|
+
if (value !== undefined && value !== null && value !== "")
|
|
15397
|
+
url.searchParams.append(key, String(value));
|
|
15398
|
+
}
|
|
15399
|
+
const response = await fetch(url, {
|
|
15400
|
+
method: options.method ?? "GET",
|
|
15401
|
+
headers: {
|
|
15402
|
+
Authorization: `Bearer ${token}`,
|
|
15403
|
+
Accept: "application/json",
|
|
15404
|
+
...options.body ? { "Content-Type": "application/json" } : {}
|
|
15405
|
+
},
|
|
15406
|
+
body: options.body ? JSON.stringify(options.body) : undefined
|
|
15407
|
+
});
|
|
15408
|
+
const text = await response.text();
|
|
15409
|
+
const data = text ? JSON.parse(text) : {};
|
|
15410
|
+
if (!response.ok) {
|
|
15411
|
+
const error = data;
|
|
15412
|
+
throw new Error(`Gmail request failed (${response.status}): ${error.error?.message ?? response.statusText}`);
|
|
15413
|
+
}
|
|
15414
|
+
return data;
|
|
15415
|
+
}
|
|
15416
|
+
async function getValidAccessToken(profile) {
|
|
15417
|
+
if (process.env.GMAIL_ACCESS_TOKEN)
|
|
15418
|
+
return process.env.GMAIL_ACCESS_TOKEN;
|
|
15419
|
+
const tokens = loadTokens(profile);
|
|
15420
|
+
if (!tokens?.accessToken && !tokens?.refreshToken) {
|
|
15421
|
+
throw new Error(`Gmail profile "${profile}" is not authenticated. Run: connectors auth gmail`);
|
|
15422
|
+
}
|
|
15423
|
+
if (tokens.accessToken && (!tokens.expiresAt || Date.now() < tokens.expiresAt - REFRESH_BUFFER_MS))
|
|
15424
|
+
return tokens.accessToken;
|
|
15425
|
+
if (!tokens.refreshToken)
|
|
15426
|
+
return tokens.accessToken ?? "";
|
|
15427
|
+
return (await refreshAccessToken(profile, tokens)).accessToken ?? "";
|
|
15428
|
+
}
|
|
15429
|
+
async function refreshAccessToken(profile, currentTokens) {
|
|
15430
|
+
const credentials = loadCredentials(profile);
|
|
15431
|
+
if (!credentials.clientId || !credentials.clientSecret)
|
|
15432
|
+
throw new Error("Gmail OAuth credentials are not configured. Run: connectors auth gmail");
|
|
15433
|
+
if (!currentTokens.refreshToken)
|
|
15434
|
+
throw new Error(`Gmail profile "${profile}" has no refresh token. Run: connectors auth gmail`);
|
|
15435
|
+
const response = await fetch(TOKEN_URL, {
|
|
15436
|
+
method: "POST",
|
|
15437
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
15438
|
+
body: new URLSearchParams({
|
|
15439
|
+
client_id: credentials.clientId,
|
|
15440
|
+
client_secret: credentials.clientSecret,
|
|
15441
|
+
refresh_token: currentTokens.refreshToken,
|
|
15442
|
+
grant_type: "refresh_token"
|
|
15443
|
+
})
|
|
15444
|
+
});
|
|
15445
|
+
const data = await response.json().catch(() => ({}));
|
|
15446
|
+
if (!response.ok || !data.access_token)
|
|
15447
|
+
throw new Error(`Gmail token refresh failed: ${data.error_description || data.error || response.statusText}`);
|
|
15448
|
+
const tokens = {
|
|
15449
|
+
accessToken: data.access_token,
|
|
15450
|
+
refreshToken: currentTokens.refreshToken,
|
|
15451
|
+
expiresAt: Date.now() + (data.expires_in ?? 3600) * 1000,
|
|
15452
|
+
tokenType: data.token_type ?? currentTokens.tokenType,
|
|
15453
|
+
scope: data.scope ?? currentTokens.scope
|
|
15454
|
+
};
|
|
15455
|
+
saveTokens(profile, tokens);
|
|
15456
|
+
return tokens;
|
|
15457
|
+
}
|
|
15458
|
+
function listProfiles() {
|
|
15459
|
+
const profiles = new Set;
|
|
15460
|
+
for (const baseDir of configDirs()) {
|
|
15461
|
+
const profilesDir = join9(baseDir, "profiles");
|
|
15462
|
+
if (!existsSync8(profilesDir))
|
|
15463
|
+
continue;
|
|
15464
|
+
for (const entry of readdirSync5(profilesDir, { withFileTypes: true })) {
|
|
15465
|
+
if (entry.isDirectory())
|
|
15466
|
+
profiles.add(entry.name);
|
|
15467
|
+
if (entry.isFile() && entry.name.endsWith(".json"))
|
|
15468
|
+
profiles.add(basename(entry.name, ".json"));
|
|
15469
|
+
}
|
|
15470
|
+
}
|
|
15471
|
+
return Array.from(profiles).sort((a, b) => a.localeCompare(b));
|
|
15472
|
+
}
|
|
15473
|
+
function loadCredentials(profile) {
|
|
15474
|
+
const envClientId = process.env.GMAIL_CLIENT_ID ?? process.env.GOOGLE_CLIENT_ID;
|
|
15475
|
+
const envClientSecret = process.env.GMAIL_CLIENT_SECRET ?? process.env.GOOGLE_CLIENT_SECRET;
|
|
15476
|
+
if (envClientId && envClientSecret)
|
|
15477
|
+
return { clientId: envClientId, clientSecret: envClientSecret };
|
|
15478
|
+
for (const baseDir of configDirs()) {
|
|
15479
|
+
const credentials = {
|
|
15480
|
+
...readJson(join9(baseDir, "credentials.json")),
|
|
15481
|
+
...readJson(join9(baseDir, "profiles", profile, "config.json"))
|
|
15482
|
+
};
|
|
15483
|
+
if (credentials.clientId || credentials.clientSecret)
|
|
15484
|
+
return credentials;
|
|
15485
|
+
}
|
|
15486
|
+
return {};
|
|
15487
|
+
}
|
|
15488
|
+
function loadTokens(profile) {
|
|
15489
|
+
for (const baseDir of configDirs()) {
|
|
15490
|
+
const fromProfile = readJson(join9(baseDir, "profiles", profile, "tokens.json"));
|
|
15491
|
+
if (fromProfile)
|
|
15492
|
+
return fromProfile;
|
|
15493
|
+
const flat = readJson(join9(baseDir, "profiles", `${profile}.json`));
|
|
15494
|
+
if (flat)
|
|
15495
|
+
return flat.tokens ?? (flat.accessToken || flat.refreshToken ? flat : null);
|
|
15496
|
+
}
|
|
15497
|
+
return null;
|
|
15498
|
+
}
|
|
15499
|
+
function saveTokens(profile, tokens) {
|
|
15500
|
+
const baseDir = configDirs().find((dir) => existsSync8(dir)) ?? configDirs()[0];
|
|
15501
|
+
const profileDir = join9(baseDir, "profiles", profile);
|
|
15502
|
+
mkdirSync6(profileDir, { recursive: true });
|
|
15503
|
+
writeFileSync3(join9(profileDir, "tokens.json"), JSON.stringify(tokens, null, 2), { mode: 384 });
|
|
15504
|
+
}
|
|
15505
|
+
function configDirs() {
|
|
15506
|
+
const explicit = process.env.HASNA_GMAIL_CONNECTOR_DIR ?? process.env.GMAIL_CONNECTOR_DIR;
|
|
15507
|
+
if (explicit)
|
|
15508
|
+
return [explicit];
|
|
15509
|
+
const baseDir = process.env.HASNA_CONNECTORS_DIR ?? join9(homedir8(), ".hasna", "connectors");
|
|
15510
|
+
return [join9(baseDir, "connect-gmail"), join9(baseDir, "gmail")];
|
|
15511
|
+
}
|
|
15512
|
+
function readJson(path) {
|
|
15513
|
+
if (!existsSync8(path))
|
|
15514
|
+
return null;
|
|
15515
|
+
try {
|
|
15516
|
+
return JSON.parse(readFileSync3(path, "utf8"));
|
|
15517
|
+
} catch {
|
|
15518
|
+
return null;
|
|
15519
|
+
}
|
|
15520
|
+
}
|
|
15521
|
+
function getMessageId(input) {
|
|
15522
|
+
const id = input.messageId ?? (input.args?.[0] != null ? String(input.args[0]) : undefined);
|
|
15523
|
+
if (!id)
|
|
15524
|
+
throw new Error("Gmail messageId is required");
|
|
15525
|
+
return id;
|
|
15526
|
+
}
|
|
15527
|
+
function headersToObject(headers) {
|
|
15528
|
+
const out = {};
|
|
15529
|
+
for (const header of headers)
|
|
15530
|
+
out[header.name] = header.value;
|
|
15531
|
+
return out;
|
|
15532
|
+
}
|
|
15533
|
+
function extractBody(message, preferHtml = false) {
|
|
15534
|
+
if (!message.payload)
|
|
15535
|
+
return "";
|
|
15536
|
+
const targetType = preferHtml ? "text/html" : "text/plain";
|
|
15537
|
+
const parts = [];
|
|
15538
|
+
collectTextParts(message.payload, parts);
|
|
15539
|
+
return parts.find((part) => part.mimeType === targetType)?.data ?? parts.find((part) => part.mimeType.startsWith("text/"))?.data ?? "";
|
|
15540
|
+
}
|
|
15541
|
+
function collectTextParts(part, results) {
|
|
15542
|
+
const mimeType = (part.mimeType ?? "").split(";")[0].trim().toLowerCase();
|
|
15543
|
+
if (part.body?.data && mimeType.startsWith("text/")) {
|
|
15544
|
+
results.push({ mimeType, data: Buffer.from(part.body.data, "base64url").toString("utf8") });
|
|
15545
|
+
}
|
|
15546
|
+
for (const child of part.parts ?? [])
|
|
15547
|
+
collectTextParts(child, results);
|
|
15548
|
+
}
|
|
15549
|
+
function collectAttachments(part, attachments = []) {
|
|
15550
|
+
if (!part)
|
|
15551
|
+
return attachments;
|
|
15552
|
+
if (part.body?.attachmentId && part.filename) {
|
|
15553
|
+
attachments.push({
|
|
15554
|
+
attachmentId: part.body.attachmentId,
|
|
15555
|
+
filename: part.filename,
|
|
15556
|
+
mimeType: part.mimeType ?? "application/octet-stream",
|
|
15557
|
+
size: part.body.size ?? 0,
|
|
15558
|
+
partId: part.partId
|
|
15559
|
+
});
|
|
15560
|
+
}
|
|
15561
|
+
for (const child of part.parts ?? [])
|
|
15562
|
+
collectAttachments(child, attachments);
|
|
15563
|
+
return attachments;
|
|
15564
|
+
}
|
|
15565
|
+
function normalizeStringArray(value) {
|
|
15566
|
+
if (!value)
|
|
15567
|
+
return [];
|
|
15568
|
+
return Array.isArray(value) ? value : value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
15569
|
+
}
|
|
15570
|
+
function normalizeReplySubject(subject) {
|
|
15571
|
+
return subject.toLowerCase().startsWith("re:") ? subject : `Re: ${subject}`;
|
|
15572
|
+
}
|
|
15573
|
+
function buildRawEmail(input) {
|
|
15574
|
+
const headers = [
|
|
15575
|
+
`To: ${input.to}`,
|
|
15576
|
+
input.cc.length ? `Cc: ${input.cc.join(", ")}` : "",
|
|
15577
|
+
input.bcc.length ? `Bcc: ${input.bcc.join(", ")}` : "",
|
|
15578
|
+
`Subject: ${input.subject}`,
|
|
15579
|
+
input.inReplyTo ? `In-Reply-To: ${input.inReplyTo}` : "",
|
|
15580
|
+
input.references ? `References: ${input.references}` : "",
|
|
15581
|
+
"MIME-Version: 1.0",
|
|
15582
|
+
`Content-Type: ${input.isHtml ? "text/html" : "text/plain"}; charset=UTF-8`
|
|
15583
|
+
].filter(Boolean);
|
|
15584
|
+
return `${headers.join(`\r
|
|
15585
|
+
`)}\r
|
|
15586
|
+
\r
|
|
15587
|
+
${input.body}`;
|
|
15588
|
+
}
|
|
15589
|
+
function safeFilename(filename) {
|
|
15590
|
+
return basename(filename.replace(/[\u00A0\u2000-\u200B\u202F\u205F\u3000]/g, " ")).replace(/[\/\\]/g, "_");
|
|
15591
|
+
}
|
|
15592
|
+
|
|
15593
|
+
// src/core/connectors/googledrive.ts
|
|
15594
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync4, readdirSync as readdirSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
15595
|
+
import { homedir as homedir9 } from "os";
|
|
15596
|
+
import { basename as basename2, join as join10 } from "path";
|
|
15597
|
+
var DRIVE_API_BASE = "https://www.googleapis.com/drive/v3";
|
|
15598
|
+
var TOKEN_URL2 = "https://oauth2.googleapis.com/token";
|
|
15599
|
+
var REFRESH_BUFFER_MS2 = 5 * 60 * 1000;
|
|
15169
15600
|
var DEFAULT_FILE_FIELDS = [
|
|
15170
15601
|
"id",
|
|
15171
15602
|
"name",
|
|
@@ -15246,12 +15677,12 @@ var googleDriveConnector = defineConnector({
|
|
|
15246
15677
|
operations: {
|
|
15247
15678
|
"profiles.list": {
|
|
15248
15679
|
summary: "List configured Google Drive profiles.",
|
|
15249
|
-
execute: () => ({ profiles:
|
|
15680
|
+
execute: () => ({ profiles: listProfiles2() })
|
|
15250
15681
|
},
|
|
15251
15682
|
"files.list": {
|
|
15252
15683
|
summary: "List Google Drive files.",
|
|
15253
15684
|
inputSchema: listFilesSchema,
|
|
15254
|
-
execute: async ({ context }, input) =>
|
|
15685
|
+
execute: async ({ context }, input) => requestJson2(context.profile, "/files", {
|
|
15255
15686
|
pageSize: input.pageSize ?? 1000,
|
|
15256
15687
|
pageToken: input.pageToken,
|
|
15257
15688
|
q: input.q,
|
|
@@ -15266,7 +15697,7 @@ var googleDriveConnector = defineConnector({
|
|
|
15266
15697
|
"files.get": {
|
|
15267
15698
|
summary: "Get Google Drive file metadata.",
|
|
15268
15699
|
inputSchema: fileIdSchema,
|
|
15269
|
-
execute: async ({ context }, input) =>
|
|
15700
|
+
execute: async ({ context }, input) => requestJson2(context.profile, `/files/${encodeURIComponent(input.fileId)}`, {
|
|
15270
15701
|
fields: input.fields ?? DEFAULT_FILE_FIELDS,
|
|
15271
15702
|
supportsAllDrives: true
|
|
15272
15703
|
})
|
|
@@ -15275,7 +15706,7 @@ var googleDriveConnector = defineConnector({
|
|
|
15275
15706
|
summary: "Download or export a Google Drive file as base64 content.",
|
|
15276
15707
|
inputSchema: downloadSchema,
|
|
15277
15708
|
execute: async ({ context }, input) => {
|
|
15278
|
-
const file = input.file ?? await
|
|
15709
|
+
const file = input.file ?? await requestJson2(context.profile, `/files/${encodeURIComponent(input.fileId)}`, { fields: DEFAULT_FILE_FIELDS, supportsAllDrives: true });
|
|
15279
15710
|
const exportMimeType = file.mimeType.startsWith("application/vnd.google-apps.") ? input.exportMimeType ?? defaultExportMimeType(file.mimeType) : undefined;
|
|
15280
15711
|
const data = await requestBinary(context.profile, exportMimeType ? `/files/${encodeURIComponent(file.id)}/export` : `/files/${encodeURIComponent(file.id)}`, exportMimeType ? { mimeType: exportMimeType, supportsAllDrives: true } : { alt: "media", supportsAllDrives: true });
|
|
15281
15712
|
const mimeType = exportMimeType ?? file.mimeType ?? "application/octet-stream";
|
|
@@ -15289,7 +15720,7 @@ var googleDriveConnector = defineConnector({
|
|
|
15289
15720
|
"drives.list": {
|
|
15290
15721
|
summary: "List Google shared drives.",
|
|
15291
15722
|
inputSchema: listDrivesSchema,
|
|
15292
|
-
execute: async ({ context }, input) =>
|
|
15723
|
+
execute: async ({ context }, input) => requestJson2(context.profile, "/drives", {
|
|
15293
15724
|
pageSize: input.pageSize ?? 100,
|
|
15294
15725
|
pageToken: input.pageToken,
|
|
15295
15726
|
q: input.q
|
|
@@ -15297,7 +15728,7 @@ var googleDriveConnector = defineConnector({
|
|
|
15297
15728
|
}
|
|
15298
15729
|
}
|
|
15299
15730
|
});
|
|
15300
|
-
async function
|
|
15731
|
+
async function requestJson2(profile, path, params) {
|
|
15301
15732
|
const response = await request(profile, path, params);
|
|
15302
15733
|
const text = await response.text();
|
|
15303
15734
|
return text ? JSON.parse(text) : {};
|
|
@@ -15306,7 +15737,7 @@ async function requestBinary(profile, path, params) {
|
|
|
15306
15737
|
return (await request(profile, path, params)).arrayBuffer();
|
|
15307
15738
|
}
|
|
15308
15739
|
async function request(profile, path, params) {
|
|
15309
|
-
const token = await
|
|
15740
|
+
const token = await getValidAccessToken2(profile);
|
|
15310
15741
|
const url = new URL(`${DRIVE_API_BASE}${path}`);
|
|
15311
15742
|
for (const [key, value] of Object.entries(params)) {
|
|
15312
15743
|
if (value !== undefined && value !== null && value !== "")
|
|
@@ -15319,26 +15750,26 @@ async function request(profile, path, params) {
|
|
|
15319
15750
|
}
|
|
15320
15751
|
return response;
|
|
15321
15752
|
}
|
|
15322
|
-
async function
|
|
15753
|
+
async function getValidAccessToken2(profile) {
|
|
15323
15754
|
if (process.env.GOOGLE_ACCESS_TOKEN)
|
|
15324
15755
|
return process.env.GOOGLE_ACCESS_TOKEN;
|
|
15325
|
-
const tokens =
|
|
15756
|
+
const tokens = loadTokens2(profile);
|
|
15326
15757
|
if (!tokens?.accessToken && !tokens?.refreshToken) {
|
|
15327
15758
|
throw new Error(`Google Drive profile "${profile}" is not authenticated. Run: connectors auth googledrive`);
|
|
15328
15759
|
}
|
|
15329
|
-
if (tokens.accessToken && (!tokens.expiresAt || Date.now() < tokens.expiresAt -
|
|
15760
|
+
if (tokens.accessToken && (!tokens.expiresAt || Date.now() < tokens.expiresAt - REFRESH_BUFFER_MS2))
|
|
15330
15761
|
return tokens.accessToken;
|
|
15331
15762
|
if (!tokens.refreshToken)
|
|
15332
15763
|
return tokens.accessToken ?? "";
|
|
15333
|
-
return (await
|
|
15764
|
+
return (await refreshAccessToken2(profile, tokens)).accessToken ?? "";
|
|
15334
15765
|
}
|
|
15335
|
-
async function
|
|
15336
|
-
const credentials =
|
|
15766
|
+
async function refreshAccessToken2(profile, currentTokens) {
|
|
15767
|
+
const credentials = loadCredentials2(profile);
|
|
15337
15768
|
if (!credentials.clientId || !credentials.clientSecret)
|
|
15338
15769
|
throw new Error("Google Drive OAuth credentials are not configured. Run: connectors auth googledrive");
|
|
15339
15770
|
if (!currentTokens.refreshToken)
|
|
15340
15771
|
throw new Error(`Google Drive profile "${profile}" has no refresh token. Run: connectors auth googledrive`);
|
|
15341
|
-
const response = await fetch(
|
|
15772
|
+
const response = await fetch(TOKEN_URL2, {
|
|
15342
15773
|
method: "POST",
|
|
15343
15774
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
15344
15775
|
body: new URLSearchParams({
|
|
@@ -15358,68 +15789,68 @@ async function refreshAccessToken(profile, currentTokens) {
|
|
|
15358
15789
|
tokenType: data.token_type ?? currentTokens.tokenType,
|
|
15359
15790
|
scope: data.scope ?? currentTokens.scope
|
|
15360
15791
|
};
|
|
15361
|
-
|
|
15792
|
+
saveTokens2(profile, tokens);
|
|
15362
15793
|
return tokens;
|
|
15363
15794
|
}
|
|
15364
|
-
function
|
|
15795
|
+
function listProfiles2() {
|
|
15365
15796
|
const profiles = new Set;
|
|
15366
|
-
for (const baseDir of
|
|
15367
|
-
const profilesDir =
|
|
15368
|
-
if (!
|
|
15797
|
+
for (const baseDir of configDirs2()) {
|
|
15798
|
+
const profilesDir = join10(baseDir, "profiles");
|
|
15799
|
+
if (!existsSync9(profilesDir))
|
|
15369
15800
|
continue;
|
|
15370
|
-
for (const entry of
|
|
15801
|
+
for (const entry of readdirSync6(profilesDir, { withFileTypes: true })) {
|
|
15371
15802
|
if (entry.isDirectory())
|
|
15372
15803
|
profiles.add(entry.name);
|
|
15373
15804
|
if (entry.isFile() && entry.name.endsWith(".json"))
|
|
15374
|
-
profiles.add(
|
|
15805
|
+
profiles.add(basename2(entry.name, ".json"));
|
|
15375
15806
|
}
|
|
15376
15807
|
}
|
|
15377
15808
|
return Array.from(profiles).sort((a, b) => a.localeCompare(b));
|
|
15378
15809
|
}
|
|
15379
|
-
function
|
|
15810
|
+
function loadCredentials2(profile) {
|
|
15380
15811
|
const envClientId = process.env.GOOGLE_CLIENT_ID;
|
|
15381
15812
|
const envClientSecret = process.env.GOOGLE_CLIENT_SECRET;
|
|
15382
15813
|
if (envClientId && envClientSecret)
|
|
15383
15814
|
return { clientId: envClientId, clientSecret: envClientSecret };
|
|
15384
|
-
for (const baseDir of
|
|
15815
|
+
for (const baseDir of configDirs2()) {
|
|
15385
15816
|
const credentials = {
|
|
15386
|
-
...
|
|
15387
|
-
...
|
|
15817
|
+
...readJson2(join10(baseDir, "credentials.json")),
|
|
15818
|
+
...readJson2(join10(baseDir, "profiles", profile, "config.json"))
|
|
15388
15819
|
};
|
|
15389
15820
|
if (credentials.clientId || credentials.clientSecret)
|
|
15390
15821
|
return credentials;
|
|
15391
15822
|
}
|
|
15392
15823
|
return {};
|
|
15393
15824
|
}
|
|
15394
|
-
function
|
|
15395
|
-
for (const baseDir of
|
|
15396
|
-
const fromProfile =
|
|
15825
|
+
function loadTokens2(profile) {
|
|
15826
|
+
for (const baseDir of configDirs2()) {
|
|
15827
|
+
const fromProfile = readJson2(join10(baseDir, "profiles", profile, "tokens.json"));
|
|
15397
15828
|
if (fromProfile)
|
|
15398
15829
|
return fromProfile;
|
|
15399
|
-
const flat =
|
|
15830
|
+
const flat = readJson2(join10(baseDir, "profiles", `${profile}.json`));
|
|
15400
15831
|
if (flat)
|
|
15401
15832
|
return flat.tokens ?? (flat.accessToken || flat.refreshToken ? flat : null);
|
|
15402
15833
|
}
|
|
15403
15834
|
return null;
|
|
15404
15835
|
}
|
|
15405
|
-
function
|
|
15406
|
-
const baseDir =
|
|
15407
|
-
const profileDir =
|
|
15408
|
-
|
|
15409
|
-
|
|
15836
|
+
function saveTokens2(profile, tokens) {
|
|
15837
|
+
const baseDir = configDirs2().find((dir) => existsSync9(dir)) ?? configDirs2()[0];
|
|
15838
|
+
const profileDir = join10(baseDir, "profiles", profile);
|
|
15839
|
+
mkdirSync7(profileDir, { recursive: true });
|
|
15840
|
+
writeFileSync4(join10(profileDir, "tokens.json"), JSON.stringify(tokens, null, 2), { mode: 384 });
|
|
15410
15841
|
}
|
|
15411
|
-
function
|
|
15842
|
+
function configDirs2() {
|
|
15412
15843
|
const explicit = process.env.HASNA_GOOGLE_DRIVE_CONNECTOR_DIR ?? process.env.GOOGLE_DRIVE_CONNECTOR_DIR;
|
|
15413
15844
|
if (explicit)
|
|
15414
15845
|
return [explicit];
|
|
15415
|
-
const baseDir = process.env.HASNA_CONNECTORS_DIR ??
|
|
15416
|
-
return [
|
|
15846
|
+
const baseDir = process.env.HASNA_CONNECTORS_DIR ?? join10(homedir9(), ".hasna", "connectors");
|
|
15847
|
+
return [join10(baseDir, "connect-googledrive"), join10(baseDir, "googledrive")];
|
|
15417
15848
|
}
|
|
15418
|
-
function
|
|
15419
|
-
if (!
|
|
15849
|
+
function readJson2(path) {
|
|
15850
|
+
if (!existsSync9(path))
|
|
15420
15851
|
return null;
|
|
15421
15852
|
try {
|
|
15422
|
-
return JSON.parse(
|
|
15853
|
+
return JSON.parse(readFileSync4(path, "utf8"));
|
|
15423
15854
|
} catch {
|
|
15424
15855
|
return null;
|
|
15425
15856
|
}
|
|
@@ -15451,7 +15882,7 @@ function extractGoogleError(body) {
|
|
|
15451
15882
|
// package.json
|
|
15452
15883
|
var package_default = {
|
|
15453
15884
|
name: "@hasna/connectors",
|
|
15454
|
-
version: "1.3.
|
|
15885
|
+
version: "1.3.26",
|
|
15455
15886
|
description: "Open source connector library - Install API connectors with a single command",
|
|
15456
15887
|
type: "module",
|
|
15457
15888
|
bin: {
|
|
@@ -15539,15 +15970,15 @@ var package_default = {
|
|
|
15539
15970
|
|
|
15540
15971
|
// src/core/connectors/imessage.ts
|
|
15541
15972
|
import {
|
|
15542
|
-
existsSync as
|
|
15543
|
-
mkdirSync as
|
|
15544
|
-
readFileSync as
|
|
15545
|
-
readdirSync as
|
|
15973
|
+
existsSync as existsSync10,
|
|
15974
|
+
mkdirSync as mkdirSync8,
|
|
15975
|
+
readFileSync as readFileSync5,
|
|
15976
|
+
readdirSync as readdirSync7,
|
|
15546
15977
|
rmSync,
|
|
15547
15978
|
statSync as statSync2,
|
|
15548
|
-
writeFileSync as
|
|
15979
|
+
writeFileSync as writeFileSync5
|
|
15549
15980
|
} from "fs";
|
|
15550
|
-
import { join as
|
|
15981
|
+
import { join as join11 } from "path";
|
|
15551
15982
|
init_database();
|
|
15552
15983
|
var CONNECTOR_DIRNAME = "connect-imessage";
|
|
15553
15984
|
var COMMAND_SPECS = [
|
|
@@ -15709,36 +16140,36 @@ var messageReplyInputSchema = exports_external2.object({
|
|
|
15709
16140
|
deviceId: exports_external2.string().optional()
|
|
15710
16141
|
});
|
|
15711
16142
|
function getConfigDir2() {
|
|
15712
|
-
return
|
|
16143
|
+
return join11(getConnectorsHome(), CONNECTOR_DIRNAME);
|
|
15713
16144
|
}
|
|
15714
16145
|
function getProfilesDir() {
|
|
15715
|
-
return
|
|
16146
|
+
return join11(getConfigDir2(), "profiles");
|
|
15716
16147
|
}
|
|
15717
16148
|
function getCurrentProfile() {
|
|
15718
|
-
const currentProfileFile =
|
|
15719
|
-
if (!
|
|
16149
|
+
const currentProfileFile = join11(getConfigDir2(), "current_profile");
|
|
16150
|
+
if (!existsSync10(currentProfileFile)) {
|
|
15720
16151
|
return "default";
|
|
15721
16152
|
}
|
|
15722
16153
|
try {
|
|
15723
|
-
return
|
|
16154
|
+
return readFileSync5(currentProfileFile, "utf-8").trim() || "default";
|
|
15724
16155
|
} catch {
|
|
15725
16156
|
return "default";
|
|
15726
16157
|
}
|
|
15727
16158
|
}
|
|
15728
16159
|
function setCurrentProfile(profile) {
|
|
15729
16160
|
const configDir = getConfigDir2();
|
|
15730
|
-
|
|
15731
|
-
|
|
16161
|
+
mkdirSync8(configDir, { recursive: true });
|
|
16162
|
+
writeFileSync5(join11(configDir, "current_profile"), profile);
|
|
15732
16163
|
}
|
|
15733
16164
|
function getFlatProfilePath(profile) {
|
|
15734
|
-
return
|
|
16165
|
+
return join11(getProfilesDir(), `${profile}.json`);
|
|
15735
16166
|
}
|
|
15736
16167
|
function getDirectoryProfilePath(profile) {
|
|
15737
|
-
return
|
|
16168
|
+
return join11(getProfilesDir(), profile, "config.json");
|
|
15738
16169
|
}
|
|
15739
16170
|
function loadJsonFile(path) {
|
|
15740
16171
|
try {
|
|
15741
|
-
return JSON.parse(
|
|
16172
|
+
return JSON.parse(readFileSync5(path, "utf-8"));
|
|
15742
16173
|
} catch {
|
|
15743
16174
|
return {};
|
|
15744
16175
|
}
|
|
@@ -15754,8 +16185,8 @@ function sanitizeProfileConfig(config) {
|
|
|
15754
16185
|
};
|
|
15755
16186
|
}
|
|
15756
16187
|
function loadProfile(profile = getCurrentProfile()) {
|
|
15757
|
-
const flatConfig =
|
|
15758
|
-
const directoryConfig =
|
|
16188
|
+
const flatConfig = existsSync10(getFlatProfilePath(profile)) ? loadJsonFile(getFlatProfilePath(profile)) : {};
|
|
16189
|
+
const directoryConfig = existsSync10(getDirectoryProfilePath(profile)) ? loadJsonFile(getDirectoryProfilePath(profile)) : {};
|
|
15759
16190
|
return sanitizeProfileConfig({
|
|
15760
16191
|
...flatConfig,
|
|
15761
16192
|
...directoryConfig
|
|
@@ -15763,25 +16194,25 @@ function loadProfile(profile = getCurrentProfile()) {
|
|
|
15763
16194
|
}
|
|
15764
16195
|
function writeProfile(profile, config) {
|
|
15765
16196
|
const profilesDir = getProfilesDir();
|
|
15766
|
-
|
|
15767
|
-
|
|
16197
|
+
mkdirSync8(profilesDir, { recursive: true });
|
|
16198
|
+
writeFileSync5(getFlatProfilePath(profile), JSON.stringify(config, null, 2) + `
|
|
15768
16199
|
`);
|
|
15769
16200
|
}
|
|
15770
16201
|
function profileExists(profile) {
|
|
15771
16202
|
if (profile === "default") {
|
|
15772
16203
|
return true;
|
|
15773
16204
|
}
|
|
15774
|
-
return
|
|
16205
|
+
return existsSync10(getFlatProfilePath(profile)) || existsSync10(join11(getProfilesDir(), profile));
|
|
15775
16206
|
}
|
|
15776
|
-
function
|
|
16207
|
+
function listProfiles3() {
|
|
15777
16208
|
const profilesDir = getProfilesDir();
|
|
15778
16209
|
const seen = new Set(["default"]);
|
|
15779
|
-
if (!
|
|
16210
|
+
if (!existsSync10(profilesDir)) {
|
|
15780
16211
|
return [...seen];
|
|
15781
16212
|
}
|
|
15782
16213
|
try {
|
|
15783
|
-
for (const entry of
|
|
15784
|
-
const fullPath =
|
|
16214
|
+
for (const entry of readdirSync7(profilesDir)) {
|
|
16215
|
+
const fullPath = join11(profilesDir, entry);
|
|
15785
16216
|
const stat = statSync2(fullPath);
|
|
15786
16217
|
if (stat.isDirectory()) {
|
|
15787
16218
|
seen.add(entry);
|
|
@@ -15802,11 +16233,11 @@ function createProfile(profile, config = {}) {
|
|
|
15802
16233
|
}
|
|
15803
16234
|
function clearProfile(profile = getCurrentProfile()) {
|
|
15804
16235
|
const flatPath = getFlatProfilePath(profile);
|
|
15805
|
-
const directoryPath =
|
|
15806
|
-
if (
|
|
16236
|
+
const directoryPath = join11(getProfilesDir(), profile);
|
|
16237
|
+
if (existsSync10(flatPath)) {
|
|
15807
16238
|
rmSync(flatPath);
|
|
15808
16239
|
}
|
|
15809
|
-
if (
|
|
16240
|
+
if (existsSync10(directoryPath)) {
|
|
15810
16241
|
rmSync(directoryPath, { recursive: true, force: true });
|
|
15811
16242
|
}
|
|
15812
16243
|
}
|
|
@@ -16102,7 +16533,7 @@ async function sendMessage(context, input) {
|
|
|
16102
16533
|
direction: "outbound"
|
|
16103
16534
|
});
|
|
16104
16535
|
}
|
|
16105
|
-
async function
|
|
16536
|
+
async function replyToMessage2(context, input) {
|
|
16106
16537
|
const payload = await bridgeRequest(context, "/messages/reply", {
|
|
16107
16538
|
method: "POST",
|
|
16108
16539
|
body: {
|
|
@@ -16216,7 +16647,7 @@ async function runProfileCommand2(args, context) {
|
|
|
16216
16647
|
switch (subcommand) {
|
|
16217
16648
|
case "list": {
|
|
16218
16649
|
const current = getCurrentProfile();
|
|
16219
|
-
const profiles =
|
|
16650
|
+
const profiles = listProfiles3();
|
|
16220
16651
|
return successOutput({ current, profiles }, context.format, () => profiles.map((profile) => `${profile}${profile === current ? " (active)" : ""}`).join(`
|
|
16221
16652
|
`));
|
|
16222
16653
|
}
|
|
@@ -16390,7 +16821,7 @@ async function runMessageCommand(args, context) {
|
|
|
16390
16821
|
if (!conversationId || !text) {
|
|
16391
16822
|
return failure2("Usage: connect-imessage message reply --conversation <id> --text <text>");
|
|
16392
16823
|
}
|
|
16393
|
-
return successOutput(await
|
|
16824
|
+
return successOutput(await replyToMessage2(resolved, {
|
|
16394
16825
|
conversationId,
|
|
16395
16826
|
text,
|
|
16396
16827
|
replyToMessageId: asString2(options.replyTo),
|
|
@@ -16548,7 +16979,7 @@ var imessageConnector = defineConnector({
|
|
|
16548
16979
|
summary: "Reply to an existing conversation through the bridge",
|
|
16549
16980
|
inputSchema: messageReplyInputSchema,
|
|
16550
16981
|
async execute({ context }, input) {
|
|
16551
|
-
return
|
|
16982
|
+
return replyToMessage2(context, input);
|
|
16552
16983
|
}
|
|
16553
16984
|
}
|
|
16554
16985
|
},
|
|
@@ -16611,19 +17042,19 @@ var imessageConnector = defineConnector({
|
|
|
16611
17042
|
});
|
|
16612
17043
|
|
|
16613
17044
|
// src/core/connectors/stripe.ts
|
|
16614
|
-
import { existsSync as
|
|
16615
|
-
import { dirname as dirname4, join as
|
|
17045
|
+
import { existsSync as existsSync11 } from "fs";
|
|
17046
|
+
import { dirname as dirname4, join as join12 } from "path";
|
|
16616
17047
|
import { fileURLToPath as fileURLToPath2, pathToFileURL as pathToFileURL2 } from "url";
|
|
16617
17048
|
var __dirname3 = dirname4(fileURLToPath2(import.meta.url));
|
|
16618
17049
|
function resolveStripeConnectorDir() {
|
|
16619
17050
|
const candidates = [
|
|
16620
|
-
|
|
16621
|
-
|
|
16622
|
-
|
|
16623
|
-
|
|
17051
|
+
join12(__dirname3, "..", "..", "..", "connectors", "connect-stripe"),
|
|
17052
|
+
join12(__dirname3, "..", "..", "connectors", "connect-stripe"),
|
|
17053
|
+
join12(__dirname3, "..", "connectors", "connect-stripe"),
|
|
17054
|
+
join12(process.cwd(), "connectors", "connect-stripe")
|
|
16624
17055
|
];
|
|
16625
17056
|
for (const candidate of candidates) {
|
|
16626
|
-
if (
|
|
17057
|
+
if (existsSync11(candidate)) {
|
|
16627
17058
|
return candidate;
|
|
16628
17059
|
}
|
|
16629
17060
|
}
|
|
@@ -16862,10 +17293,10 @@ function buildCommandHelp2(spec) {
|
|
|
16862
17293
|
var ROOT_HELP3 = buildRootHelp2(COMMAND_SPECS2);
|
|
16863
17294
|
var COMMAND_HELP3 = Object.fromEntries(COMMAND_SPECS2.map((spec) => [spec.name, buildCommandHelp2(spec)]));
|
|
16864
17295
|
async function loadStripeApiModule() {
|
|
16865
|
-
return await import(pathToFileURL2(
|
|
17296
|
+
return await import(pathToFileURL2(join12(CONNECTOR_DIR2, "src", "api", "index.ts")).href);
|
|
16866
17297
|
}
|
|
16867
17298
|
async function loadStripeConfigModule() {
|
|
16868
|
-
return await import(pathToFileURL2(
|
|
17299
|
+
return await import(pathToFileURL2(join12(CONNECTOR_DIR2, "src", "utils", "config.ts")).href);
|
|
16869
17300
|
}
|
|
16870
17301
|
function extractGlobalArgs3(args) {
|
|
16871
17302
|
const remaining = [];
|
|
@@ -17477,6 +17908,7 @@ var stripeConnector = defineConnector({
|
|
|
17477
17908
|
|
|
17478
17909
|
// src/core/builtins.ts
|
|
17479
17910
|
var INTERNAL_CONNECTOR_DEFINITIONS = [
|
|
17911
|
+
gmailConnector,
|
|
17480
17912
|
githubConnector,
|
|
17481
17913
|
googleDriveConnector,
|
|
17482
17914
|
imessageConnector,
|
|
@@ -23503,17 +23935,17 @@ function loadConnectorVersions() {
|
|
|
23503
23935
|
versionsLoaded = true;
|
|
23504
23936
|
const thisDir = dirname5(fileURLToPath3(import.meta.url));
|
|
23505
23937
|
const candidates = [
|
|
23506
|
-
|
|
23507
|
-
|
|
23938
|
+
join13(thisDir, "..", "connectors"),
|
|
23939
|
+
join13(thisDir, "..", "..", "connectors")
|
|
23508
23940
|
];
|
|
23509
|
-
const connectorsDir = candidates.find((d) =>
|
|
23941
|
+
const connectorsDir = candidates.find((d) => existsSync12(d));
|
|
23510
23942
|
if (!connectorsDir)
|
|
23511
23943
|
return;
|
|
23512
23944
|
for (const connector of CONNECTORS) {
|
|
23513
23945
|
try {
|
|
23514
|
-
const pkgPath =
|
|
23515
|
-
if (
|
|
23516
|
-
const pkg = JSON.parse(
|
|
23946
|
+
const pkgPath = join13(connectorsDir, `connect-${connector.name}`, "package.json");
|
|
23947
|
+
if (existsSync12(pkgPath)) {
|
|
23948
|
+
const pkg = JSON.parse(readFileSync6(pkgPath, "utf-8"));
|
|
23517
23949
|
connector.version = pkg.version || "0.0.0";
|
|
23518
23950
|
continue;
|
|
23519
23951
|
}
|
|
@@ -23526,16 +23958,16 @@ function loadConnectorVersions() {
|
|
|
23526
23958
|
}
|
|
23527
23959
|
|
|
23528
23960
|
// src/lib/installer.ts
|
|
23529
|
-
import { existsSync as
|
|
23530
|
-
import { join as
|
|
23961
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync9, readFileSync as readFileSync7, writeFileSync as writeFileSync6, readdirSync as readdirSync8, statSync as statSync3, rmSync as rmSync2 } from "fs";
|
|
23962
|
+
import { join as join14, dirname as dirname6 } from "path";
|
|
23531
23963
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
23532
23964
|
var __dirname4 = dirname6(fileURLToPath4(import.meta.url));
|
|
23533
23965
|
function resolveConnectorsDir() {
|
|
23534
|
-
const fromBin =
|
|
23535
|
-
if (
|
|
23966
|
+
const fromBin = join14(__dirname4, "..", "connectors");
|
|
23967
|
+
if (existsSync13(fromBin))
|
|
23536
23968
|
return fromBin;
|
|
23537
|
-
const fromSrc =
|
|
23538
|
-
if (
|
|
23969
|
+
const fromSrc = join14(__dirname4, "..", "..", "connectors");
|
|
23970
|
+
if (existsSync13(fromSrc))
|
|
23539
23971
|
return fromSrc;
|
|
23540
23972
|
return fromBin;
|
|
23541
23973
|
}
|
|
@@ -23547,21 +23979,21 @@ function normalizeConnectorName(name) {
|
|
|
23547
23979
|
return name.startsWith("connect-") ? name.slice("connect-".length) : name;
|
|
23548
23980
|
}
|
|
23549
23981
|
function getProjectConnectorsDir(targetDir) {
|
|
23550
|
-
return
|
|
23982
|
+
return join14(targetDir, PROJECT_CONNECTORS_DIRNAME);
|
|
23551
23983
|
}
|
|
23552
23984
|
function getEnablementManifestPath(targetDir) {
|
|
23553
|
-
return
|
|
23985
|
+
return join14(getProjectConnectorsDir(targetDir), ENABLEMENT_MANIFEST_FILENAME);
|
|
23554
23986
|
}
|
|
23555
23987
|
function getLegacyInstallPath(targetDir, name) {
|
|
23556
|
-
return
|
|
23988
|
+
return join14(getProjectConnectorsDir(targetDir), `connect-${normalizeConnectorName(name)}`);
|
|
23557
23989
|
}
|
|
23558
23990
|
function loadEnablementManifest(targetDir) {
|
|
23559
23991
|
const manifestPath = getEnablementManifestPath(targetDir);
|
|
23560
|
-
if (!
|
|
23992
|
+
if (!existsSync13(manifestPath)) {
|
|
23561
23993
|
return null;
|
|
23562
23994
|
}
|
|
23563
23995
|
try {
|
|
23564
|
-
const raw = JSON.parse(
|
|
23996
|
+
const raw = JSON.parse(readFileSync7(manifestPath, "utf-8"));
|
|
23565
23997
|
if (!Array.isArray(raw.connectors)) {
|
|
23566
23998
|
return null;
|
|
23567
23999
|
}
|
|
@@ -23577,11 +24009,11 @@ function loadEnablementManifest(targetDir) {
|
|
|
23577
24009
|
}
|
|
23578
24010
|
function getLegacyInstalledConnectors(targetDir) {
|
|
23579
24011
|
const connectorsDir = getProjectConnectorsDir(targetDir);
|
|
23580
|
-
if (!
|
|
24012
|
+
if (!existsSync13(connectorsDir)) {
|
|
23581
24013
|
return [];
|
|
23582
24014
|
}
|
|
23583
|
-
return
|
|
23584
|
-
const fullPath =
|
|
24015
|
+
return readdirSync8(connectorsDir).filter((entry) => {
|
|
24016
|
+
const fullPath = join14(connectorsDir, entry);
|
|
23585
24017
|
return entry.startsWith("connect-") && statSync3(fullPath).isDirectory();
|
|
23586
24018
|
}).map((entry) => entry.replace("connect-", "")).sort();
|
|
23587
24019
|
}
|
|
@@ -23590,7 +24022,7 @@ function getEnabledConnectors(targetDir) {
|
|
|
23590
24022
|
return [...new Set([...manifestConnectors, ...getLegacyInstalledConnectors(targetDir)])].sort();
|
|
23591
24023
|
}
|
|
23592
24024
|
function updateConnectorsIndex(connectorsDir, connectors18) {
|
|
23593
|
-
const indexPath =
|
|
24025
|
+
const indexPath = join14(connectorsDir, ENABLEMENT_INDEX_FILENAME);
|
|
23594
24026
|
const connectorList = connectors18.map((connector) => ` "${connector}",`).join(`
|
|
23595
24027
|
`);
|
|
23596
24028
|
const content = `/**
|
|
@@ -23606,28 +24038,28 @@ ${connectorList}
|
|
|
23606
24038
|
|
|
23607
24039
|
export type EnabledConnectorName = typeof enabledConnectors[number];
|
|
23608
24040
|
`;
|
|
23609
|
-
|
|
24041
|
+
writeFileSync6(indexPath, content);
|
|
23610
24042
|
}
|
|
23611
24043
|
function writeEnablementManifest(targetDir, connectors18) {
|
|
23612
24044
|
const connectorsDir = getProjectConnectorsDir(targetDir);
|
|
23613
|
-
|
|
24045
|
+
mkdirSync9(connectorsDir, { recursive: true });
|
|
23614
24046
|
const manifest = {
|
|
23615
24047
|
version: 1,
|
|
23616
24048
|
mode: "internal",
|
|
23617
24049
|
updatedAt: new Date().toISOString(),
|
|
23618
24050
|
connectors: [...new Set(connectors18.map((value) => normalizeConnectorName(value)))].sort()
|
|
23619
24051
|
};
|
|
23620
|
-
|
|
24052
|
+
writeFileSync6(getEnablementManifestPath(targetDir), JSON.stringify(manifest, null, 2) + `
|
|
23621
24053
|
`);
|
|
23622
24054
|
updateConnectorsIndex(connectorsDir, manifest.connectors);
|
|
23623
24055
|
}
|
|
23624
24056
|
function getConnectorPath(name) {
|
|
23625
24057
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
23626
|
-
return
|
|
24058
|
+
return join14(CONNECTORS_DIR, connectorName);
|
|
23627
24059
|
}
|
|
23628
24060
|
function connectorExists(name) {
|
|
23629
24061
|
const normalizedName = normalizeConnectorName(name);
|
|
23630
|
-
return hasInternalConnectorDefinition(normalizedName) ||
|
|
24062
|
+
return hasInternalConnectorDefinition(normalizedName) || existsSync13(getConnectorPath(normalizedName));
|
|
23631
24063
|
}
|
|
23632
24064
|
function installConnector(name, options = {}) {
|
|
23633
24065
|
const { targetDir = process.cwd(), overwrite = false } = options;
|
|
@@ -23660,7 +24092,7 @@ function installConnector(name, options = {}) {
|
|
|
23660
24092
|
try {
|
|
23661
24093
|
const nextEnabled = [...new Set([...installed, normalizedName])].sort();
|
|
23662
24094
|
writeEnablementManifest(targetDir, nextEnabled);
|
|
23663
|
-
if (overwrite &&
|
|
24095
|
+
if (overwrite && existsSync13(legacyInstallPath)) {
|
|
23664
24096
|
rmSync2(legacyInstallPath, { recursive: true });
|
|
23665
24097
|
}
|
|
23666
24098
|
return {
|
|
@@ -23692,9 +24124,9 @@ function parseConnectorDocs(raw) {
|
|
|
23692
24124
|
function getConnectorDocs(name) {
|
|
23693
24125
|
const normalizedName = normalizeConnectorName(name);
|
|
23694
24126
|
const connectorPath = getConnectorPath(normalizedName);
|
|
23695
|
-
const claudeMdPath =
|
|
23696
|
-
if (
|
|
23697
|
-
return parseConnectorDocs(
|
|
24127
|
+
const claudeMdPath = join14(connectorPath, "CLAUDE.md");
|
|
24128
|
+
if (existsSync13(claudeMdPath)) {
|
|
24129
|
+
return parseConnectorDocs(readFileSync7(claudeMdPath, "utf-8"));
|
|
23698
24130
|
}
|
|
23699
24131
|
const internalDocs = getInternalConnectorDefinition(normalizedName)?.docsMarkdown;
|
|
23700
24132
|
if (internalDocs) {
|
|
@@ -23738,29 +24170,29 @@ function removeConnector(name, targetDir = process.cwd()) {
|
|
|
23738
24170
|
const nextEnabled = installed.filter((connector) => connector !== normalizedName);
|
|
23739
24171
|
writeEnablementManifest(targetDir, nextEnabled);
|
|
23740
24172
|
const legacyInstallPath = getLegacyInstallPath(targetDir, normalizedName);
|
|
23741
|
-
if (
|
|
24173
|
+
if (existsSync13(legacyInstallPath)) {
|
|
23742
24174
|
rmSync2(legacyInstallPath, { recursive: true });
|
|
23743
24175
|
}
|
|
23744
24176
|
return true;
|
|
23745
24177
|
}
|
|
23746
24178
|
|
|
23747
24179
|
// src/lib/runner.ts
|
|
23748
|
-
import { existsSync as
|
|
23749
|
-
import { join as
|
|
24180
|
+
import { existsSync as existsSync16, readdirSync as readdirSync10 } from "fs";
|
|
24181
|
+
import { join as join17, dirname as dirname7 } from "path";
|
|
23750
24182
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
23751
24183
|
import { spawn as spawn2 } from "child_process";
|
|
23752
24184
|
init_database();
|
|
23753
24185
|
|
|
23754
24186
|
// src/server/auth.ts
|
|
23755
|
-
import { existsSync as
|
|
24187
|
+
import { existsSync as existsSync15, readFileSync as readFileSync8, writeFileSync as writeFileSync7, mkdirSync as mkdirSync11, readdirSync as readdirSync9, rmSync as rmSync3, statSync as statSync5 } from "fs";
|
|
23756
24188
|
import { randomBytes } from "crypto";
|
|
23757
|
-
import { join as
|
|
24189
|
+
import { join as join16 } from "path";
|
|
23758
24190
|
|
|
23759
24191
|
// src/lib/lock.ts
|
|
23760
24192
|
init_database();
|
|
23761
|
-
import { openSync, closeSync, unlinkSync, existsSync as
|
|
23762
|
-
import { join as
|
|
23763
|
-
import { mkdirSync as
|
|
24193
|
+
import { openSync, closeSync, unlinkSync, existsSync as existsSync14, statSync as statSync4 } from "fs";
|
|
24194
|
+
import { join as join15 } from "path";
|
|
24195
|
+
import { mkdirSync as mkdirSync10 } from "fs";
|
|
23764
24196
|
var LOCK_TIMEOUT_MS = 5000;
|
|
23765
24197
|
var LOCK_RETRY_MS = 100;
|
|
23766
24198
|
var STALE_LOCK_MS = 30000;
|
|
@@ -23774,9 +24206,9 @@ class LockTimeoutError extends Error {
|
|
|
23774
24206
|
}
|
|
23775
24207
|
}
|
|
23776
24208
|
function lockPath(connector) {
|
|
23777
|
-
const dir =
|
|
23778
|
-
|
|
23779
|
-
return
|
|
24209
|
+
const dir = join15(getConnectorsHome(), `connect-${connector}`);
|
|
24210
|
+
mkdirSync10(dir, { recursive: true });
|
|
24211
|
+
return join15(dir, ".write.lock");
|
|
23780
24212
|
}
|
|
23781
24213
|
function isStale(path) {
|
|
23782
24214
|
try {
|
|
@@ -23787,7 +24219,7 @@ function isStale(path) {
|
|
|
23787
24219
|
}
|
|
23788
24220
|
}
|
|
23789
24221
|
function tryAcquire(path) {
|
|
23790
|
-
if (
|
|
24222
|
+
if (existsSync14(path) && isStale(path)) {
|
|
23791
24223
|
try {
|
|
23792
24224
|
unlinkSync(path);
|
|
23793
24225
|
} catch {}
|
|
@@ -23880,14 +24312,14 @@ function getAuthType(name) {
|
|
|
23880
24312
|
}
|
|
23881
24313
|
function getConnectorConfigDir(name) {
|
|
23882
24314
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
23883
|
-
return
|
|
24315
|
+
return join16(getConnectorsHome(), connectorName);
|
|
23884
24316
|
}
|
|
23885
24317
|
function getCurrentProfile2(name) {
|
|
23886
24318
|
const configDir = getConnectorConfigDir(name);
|
|
23887
|
-
const currentProfileFile =
|
|
23888
|
-
if (
|
|
24319
|
+
const currentProfileFile = join16(configDir, "current_profile");
|
|
24320
|
+
if (existsSync15(currentProfileFile)) {
|
|
23889
24321
|
try {
|
|
23890
|
-
return
|
|
24322
|
+
return readFileSync8(currentProfileFile, "utf-8").trim() || "default";
|
|
23891
24323
|
} catch {
|
|
23892
24324
|
return "default";
|
|
23893
24325
|
}
|
|
@@ -23899,16 +24331,16 @@ function loadProfileConfig(name) {
|
|
|
23899
24331
|
const profile = getCurrentProfile2(name);
|
|
23900
24332
|
let flatConfig = {};
|
|
23901
24333
|
let dirConfig = {};
|
|
23902
|
-
const profileFile =
|
|
23903
|
-
if (
|
|
24334
|
+
const profileFile = join16(configDir, "profiles", `${profile}.json`);
|
|
24335
|
+
if (existsSync15(profileFile)) {
|
|
23904
24336
|
try {
|
|
23905
|
-
flatConfig = JSON.parse(
|
|
24337
|
+
flatConfig = JSON.parse(readFileSync8(profileFile, "utf-8"));
|
|
23906
24338
|
} catch {}
|
|
23907
24339
|
}
|
|
23908
|
-
const profileDirConfig =
|
|
23909
|
-
if (
|
|
24340
|
+
const profileDirConfig = join16(configDir, "profiles", profile, "config.json");
|
|
24341
|
+
if (existsSync15(profileDirConfig)) {
|
|
23910
24342
|
try {
|
|
23911
|
-
dirConfig = JSON.parse(
|
|
24343
|
+
dirConfig = JSON.parse(readFileSync8(profileDirConfig, "utf-8"));
|
|
23912
24344
|
} catch {}
|
|
23913
24345
|
}
|
|
23914
24346
|
if (Object.keys(flatConfig).length === 0 && Object.keys(dirConfig).length === 0) {
|
|
@@ -23916,13 +24348,13 @@ function loadProfileConfig(name) {
|
|
|
23916
24348
|
}
|
|
23917
24349
|
return { ...flatConfig, ...dirConfig };
|
|
23918
24350
|
}
|
|
23919
|
-
function
|
|
24351
|
+
function loadTokens3(name) {
|
|
23920
24352
|
const configDir = getConnectorConfigDir(name);
|
|
23921
24353
|
const profile = getCurrentProfile2(name);
|
|
23922
|
-
const tokensFile =
|
|
23923
|
-
if (
|
|
24354
|
+
const tokensFile = join16(configDir, "profiles", profile, "tokens.json");
|
|
24355
|
+
if (existsSync15(tokensFile)) {
|
|
23924
24356
|
try {
|
|
23925
|
-
return JSON.parse(
|
|
24357
|
+
return JSON.parse(readFileSync8(tokensFile, "utf-8"));
|
|
23926
24358
|
} catch {
|
|
23927
24359
|
return null;
|
|
23928
24360
|
}
|
|
@@ -23961,7 +24393,7 @@ function getAuthStatus(name) {
|
|
|
23961
24393
|
const authType = getAuthType(name);
|
|
23962
24394
|
const docs = getConnectorDocs(name);
|
|
23963
24395
|
const oauthConfig = authType === "oauth" ? getOAuthConfig(name) : {};
|
|
23964
|
-
const tokens = authType === "oauth" ?
|
|
24396
|
+
const tokens = authType === "oauth" ? loadTokens3(name) : null;
|
|
23965
24397
|
const profileConfig = authType === "oauth" ? loadProfileConfig(name) : {};
|
|
23966
24398
|
const envVars = (docs?.envVars || []).map((v) => ({
|
|
23967
24399
|
variable: v.variable,
|
|
@@ -24010,43 +24442,43 @@ function _saveApiKey(name, key, field) {
|
|
|
24010
24442
|
const profile = getCurrentProfile2(name);
|
|
24011
24443
|
const keyField = field || guessKeyField(name);
|
|
24012
24444
|
if (keyField === "clientId" || keyField === "clientSecret") {
|
|
24013
|
-
const credentialsFile =
|
|
24014
|
-
|
|
24445
|
+
const credentialsFile = join16(configDir, "credentials.json");
|
|
24446
|
+
mkdirSync11(configDir, { recursive: true });
|
|
24015
24447
|
let creds = {};
|
|
24016
|
-
if (
|
|
24448
|
+
if (existsSync15(credentialsFile)) {
|
|
24017
24449
|
try {
|
|
24018
|
-
creds = JSON.parse(
|
|
24450
|
+
creds = JSON.parse(readFileSync8(credentialsFile, "utf-8"));
|
|
24019
24451
|
} catch {}
|
|
24020
24452
|
}
|
|
24021
24453
|
creds[keyField] = key;
|
|
24022
|
-
|
|
24454
|
+
writeFileSync7(credentialsFile, JSON.stringify(creds, null, 2));
|
|
24023
24455
|
return;
|
|
24024
24456
|
}
|
|
24025
|
-
const profileFile =
|
|
24026
|
-
const profileDir =
|
|
24027
|
-
if (
|
|
24457
|
+
const profileFile = join16(configDir, "profiles", `${profile}.json`);
|
|
24458
|
+
const profileDir = join16(configDir, "profiles", profile);
|
|
24459
|
+
if (existsSync15(profileFile)) {
|
|
24028
24460
|
let config = {};
|
|
24029
24461
|
try {
|
|
24030
|
-
config = JSON.parse(
|
|
24462
|
+
config = JSON.parse(readFileSync8(profileFile, "utf-8"));
|
|
24031
24463
|
} catch {}
|
|
24032
24464
|
config[keyField] = key;
|
|
24033
|
-
|
|
24465
|
+
writeFileSync7(profileFile, JSON.stringify(config, null, 2));
|
|
24034
24466
|
return;
|
|
24035
24467
|
}
|
|
24036
|
-
if (
|
|
24037
|
-
const configFile =
|
|
24468
|
+
if (existsSync15(profileDir)) {
|
|
24469
|
+
const configFile = join16(profileDir, "config.json");
|
|
24038
24470
|
let config = {};
|
|
24039
|
-
if (
|
|
24471
|
+
if (existsSync15(configFile)) {
|
|
24040
24472
|
try {
|
|
24041
|
-
config = JSON.parse(
|
|
24473
|
+
config = JSON.parse(readFileSync8(configFile, "utf-8"));
|
|
24042
24474
|
} catch {}
|
|
24043
24475
|
}
|
|
24044
24476
|
config[keyField] = key;
|
|
24045
|
-
|
|
24477
|
+
writeFileSync7(configFile, JSON.stringify(config, null, 2));
|
|
24046
24478
|
return;
|
|
24047
24479
|
}
|
|
24048
|
-
|
|
24049
|
-
|
|
24480
|
+
mkdirSync11(profileDir, { recursive: true });
|
|
24481
|
+
writeFileSync7(join16(profileDir, "config.json"), JSON.stringify({ [keyField]: key }, null, 2));
|
|
24050
24482
|
}
|
|
24051
24483
|
function guessKeyField(name) {
|
|
24052
24484
|
const docs = getConnectorDocs(name);
|
|
@@ -24064,10 +24496,10 @@ function guessKeyField(name) {
|
|
|
24064
24496
|
}
|
|
24065
24497
|
function getOAuthConfig(name) {
|
|
24066
24498
|
const configDir = getConnectorConfigDir(name);
|
|
24067
|
-
const credentialsFile =
|
|
24068
|
-
if (
|
|
24499
|
+
const credentialsFile = join16(configDir, "credentials.json");
|
|
24500
|
+
if (existsSync15(credentialsFile)) {
|
|
24069
24501
|
try {
|
|
24070
|
-
const creds = JSON.parse(
|
|
24502
|
+
const creds = JSON.parse(readFileSync8(credentialsFile, "utf-8"));
|
|
24071
24503
|
return { clientId: creds.clientId, clientSecret: creds.clientSecret };
|
|
24072
24504
|
} catch {}
|
|
24073
24505
|
}
|
|
@@ -24146,17 +24578,17 @@ async function exchangeOAuthCode(name, code, redirectUri) {
|
|
|
24146
24578
|
function saveOAuthTokens(name, tokens) {
|
|
24147
24579
|
const configDir = getConnectorConfigDir(name);
|
|
24148
24580
|
const profile = getCurrentProfile2(name);
|
|
24149
|
-
const profileDir =
|
|
24150
|
-
|
|
24151
|
-
const tokensFile =
|
|
24152
|
-
|
|
24581
|
+
const profileDir = join16(configDir, "profiles", profile);
|
|
24582
|
+
mkdirSync11(profileDir, { recursive: true });
|
|
24583
|
+
const tokensFile = join16(profileDir, "tokens.json");
|
|
24584
|
+
writeFileSync7(tokensFile, JSON.stringify(tokens, null, 2), { mode: 384 });
|
|
24153
24585
|
}
|
|
24154
24586
|
async function refreshOAuthToken(name) {
|
|
24155
24587
|
return withWriteLock(name, () => _refreshOAuthToken(name));
|
|
24156
24588
|
}
|
|
24157
24589
|
async function _refreshOAuthToken(name) {
|
|
24158
24590
|
const oauthConfig = getOAuthConfig(name);
|
|
24159
|
-
const currentTokens =
|
|
24591
|
+
const currentTokens = loadTokens3(name);
|
|
24160
24592
|
if (!oauthConfig.clientId || !oauthConfig.clientSecret) {
|
|
24161
24593
|
throw new Error("OAuth credentials not configured for " + name);
|
|
24162
24594
|
}
|
|
@@ -24189,16 +24621,16 @@ async function _refreshOAuthToken(name) {
|
|
|
24189
24621
|
saveOAuthTokens(name, tokens);
|
|
24190
24622
|
return tokens;
|
|
24191
24623
|
}
|
|
24192
|
-
function
|
|
24624
|
+
function listProfiles4(name) {
|
|
24193
24625
|
const configDir = getConnectorConfigDir(name);
|
|
24194
|
-
const profilesDir =
|
|
24195
|
-
if (!
|
|
24626
|
+
const profilesDir = join16(configDir, "profiles");
|
|
24627
|
+
if (!existsSync15(profilesDir))
|
|
24196
24628
|
return ["default"];
|
|
24197
24629
|
const seen = new Set;
|
|
24198
24630
|
try {
|
|
24199
|
-
const entries =
|
|
24631
|
+
const entries = readdirSync9(profilesDir);
|
|
24200
24632
|
for (const entry of entries) {
|
|
24201
|
-
const fullPath =
|
|
24633
|
+
const fullPath = join16(profilesDir, entry);
|
|
24202
24634
|
const stat = statSync5(fullPath);
|
|
24203
24635
|
if (stat.isDirectory()) {
|
|
24204
24636
|
seen.add(entry);
|
|
@@ -24212,24 +24644,24 @@ function listProfiles3(name) {
|
|
|
24212
24644
|
}
|
|
24213
24645
|
function switchProfile(name, profile) {
|
|
24214
24646
|
const configDir = getConnectorConfigDir(name);
|
|
24215
|
-
|
|
24216
|
-
|
|
24647
|
+
mkdirSync11(configDir, { recursive: true });
|
|
24648
|
+
writeFileSync7(join16(configDir, "current_profile"), profile);
|
|
24217
24649
|
}
|
|
24218
24650
|
function deleteProfile2(name, profile) {
|
|
24219
24651
|
if (profile === "default")
|
|
24220
24652
|
return false;
|
|
24221
24653
|
const configDir = getConnectorConfigDir(name);
|
|
24222
|
-
const profilesDir =
|
|
24223
|
-
const profileFile =
|
|
24224
|
-
if (
|
|
24654
|
+
const profilesDir = join16(configDir, "profiles");
|
|
24655
|
+
const profileFile = join16(profilesDir, `${profile}.json`);
|
|
24656
|
+
if (existsSync15(profileFile)) {
|
|
24225
24657
|
rmSync3(profileFile);
|
|
24226
24658
|
if (getCurrentProfile2(name) === profile) {
|
|
24227
24659
|
switchProfile(name, "default");
|
|
24228
24660
|
}
|
|
24229
24661
|
return true;
|
|
24230
24662
|
}
|
|
24231
|
-
const profileDir =
|
|
24232
|
-
if (
|
|
24663
|
+
const profileDir = join16(profilesDir, profile);
|
|
24664
|
+
if (existsSync15(profileDir)) {
|
|
24233
24665
|
rmSync3(profileDir, { recursive: true });
|
|
24234
24666
|
if (getCurrentProfile2(name) === profile) {
|
|
24235
24667
|
switchProfile(name, "default");
|
|
@@ -24242,11 +24674,11 @@ function deleteProfile2(name, profile) {
|
|
|
24242
24674
|
// src/lib/runner.ts
|
|
24243
24675
|
var __dirname5 = dirname7(fileURLToPath5(import.meta.url));
|
|
24244
24676
|
function resolveConnectorsDir2() {
|
|
24245
|
-
const fromBin =
|
|
24246
|
-
if (
|
|
24677
|
+
const fromBin = join17(__dirname5, "..", "connectors");
|
|
24678
|
+
if (existsSync16(fromBin))
|
|
24247
24679
|
return fromBin;
|
|
24248
|
-
const fromSrc =
|
|
24249
|
-
if (
|
|
24680
|
+
const fromSrc = join17(__dirname5, "..", "..", "connectors");
|
|
24681
|
+
if (existsSync16(fromSrc))
|
|
24250
24682
|
return fromSrc;
|
|
24251
24683
|
return fromBin;
|
|
24252
24684
|
}
|
|
@@ -24299,7 +24731,7 @@ function buildEnvWithCredentials(connectorName, baseEnv) {
|
|
|
24299
24731
|
}
|
|
24300
24732
|
if (getAuthType(connectorName) === "oauth") {
|
|
24301
24733
|
const oauthConfig = getOAuthConfig(connectorName);
|
|
24302
|
-
const tokens =
|
|
24734
|
+
const tokens = loadTokens3(connectorName);
|
|
24303
24735
|
for (const { variable } of getEnvVars(connectorName)) {
|
|
24304
24736
|
if (env[variable])
|
|
24305
24737
|
continue;
|
|
@@ -24320,9 +24752,9 @@ function buildEnvWithCredentials(connectorName, baseEnv) {
|
|
|
24320
24752
|
}
|
|
24321
24753
|
function getConnectorCliPath(name) {
|
|
24322
24754
|
const safeName = name.replace(/[^a-z0-9-]/g, "");
|
|
24323
|
-
const connectorDir =
|
|
24324
|
-
const cliPath =
|
|
24325
|
-
if (
|
|
24755
|
+
const connectorDir = join17(CONNECTORS_DIR2, `connect-${safeName}`);
|
|
24756
|
+
const cliPath = join17(connectorDir, "src", "cli", "index.ts");
|
|
24757
|
+
if (existsSync16(cliPath))
|
|
24326
24758
|
return cliPath;
|
|
24327
24759
|
return null;
|
|
24328
24760
|
}
|
|
@@ -24499,20 +24931,20 @@ function resolveDashboardDir() {
|
|
|
24499
24931
|
const candidates = [];
|
|
24500
24932
|
try {
|
|
24501
24933
|
const scriptDir = dirname8(fileURLToPath6(import.meta.url));
|
|
24502
|
-
candidates.push(
|
|
24503
|
-
candidates.push(
|
|
24934
|
+
candidates.push(join18(scriptDir, "..", "dashboard", "dist"));
|
|
24935
|
+
candidates.push(join18(scriptDir, "..", "..", "dashboard", "dist"));
|
|
24504
24936
|
} catch {}
|
|
24505
24937
|
if (process.argv[1]) {
|
|
24506
24938
|
const mainDir = dirname8(process.argv[1]);
|
|
24507
|
-
candidates.push(
|
|
24508
|
-
candidates.push(
|
|
24939
|
+
candidates.push(join18(mainDir, "..", "dashboard", "dist"));
|
|
24940
|
+
candidates.push(join18(mainDir, "..", "..", "dashboard", "dist"));
|
|
24509
24941
|
}
|
|
24510
|
-
candidates.push(
|
|
24942
|
+
candidates.push(join18(process.cwd(), "dashboard", "dist"));
|
|
24511
24943
|
for (const candidate of candidates) {
|
|
24512
|
-
if (
|
|
24944
|
+
if (existsSync17(candidate))
|
|
24513
24945
|
return candidate;
|
|
24514
24946
|
}
|
|
24515
|
-
return
|
|
24947
|
+
return join18(process.cwd(), "dashboard", "dist");
|
|
24516
24948
|
}
|
|
24517
24949
|
var MIME_TYPES = {
|
|
24518
24950
|
".html": "text/html; charset=utf-8",
|
|
@@ -24614,7 +25046,7 @@ function oauthPage(type, title, message, hint, extra) {
|
|
|
24614
25046
|
</body></html>`;
|
|
24615
25047
|
}
|
|
24616
25048
|
function serveStaticFile(filePath) {
|
|
24617
|
-
if (!
|
|
25049
|
+
if (!existsSync17(filePath))
|
|
24618
25050
|
return null;
|
|
24619
25051
|
const ext = extname(filePath);
|
|
24620
25052
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
@@ -24651,7 +25083,7 @@ async function startServer(requestedPort, options) {
|
|
|
24651
25083
|
const strict = options?.strict ?? false;
|
|
24652
25084
|
loadConnectorVersions();
|
|
24653
25085
|
const dashboardDir = resolveDashboardDir();
|
|
24654
|
-
const dashboardExists =
|
|
25086
|
+
const dashboardExists = existsSync17(dashboardDir);
|
|
24655
25087
|
if (!dashboardExists) {
|
|
24656
25088
|
console.error(`
|
|
24657
25089
|
Dashboard not found at: ${dashboardDir}`);
|
|
@@ -25053,13 +25485,13 @@ ${result.stderr}`;
|
|
|
25053
25485
|
if (!isValidConnectorName(name))
|
|
25054
25486
|
return json({ error: "Invalid connector name" }, 400, port);
|
|
25055
25487
|
try {
|
|
25056
|
-
const profiles =
|
|
25057
|
-
const configDir =
|
|
25058
|
-
const currentProfileFile =
|
|
25488
|
+
const profiles = listProfiles4(name);
|
|
25489
|
+
const configDir = join18(getConnectorsHome(), name.startsWith("connect-") ? name : `connect-${name}`);
|
|
25490
|
+
const currentProfileFile = join18(configDir, "current_profile");
|
|
25059
25491
|
let current = "default";
|
|
25060
|
-
if (
|
|
25492
|
+
if (existsSync17(currentProfileFile)) {
|
|
25061
25493
|
try {
|
|
25062
|
-
current =
|
|
25494
|
+
current = readFileSync9(currentProfileFile, "utf-8").trim() || "default";
|
|
25063
25495
|
} catch {}
|
|
25064
25496
|
}
|
|
25065
25497
|
return json({ current, profiles }, 200, port);
|
|
@@ -25108,30 +25540,30 @@ ${result.stderr}`;
|
|
|
25108
25540
|
try {
|
|
25109
25541
|
const connectDir = getConnectorsHome();
|
|
25110
25542
|
const result = {};
|
|
25111
|
-
if (
|
|
25112
|
-
const entries =
|
|
25543
|
+
if (existsSync17(connectDir)) {
|
|
25544
|
+
const entries = readdirSync11(connectDir, { withFileTypes: true });
|
|
25113
25545
|
for (const entry of entries) {
|
|
25114
25546
|
if (!entry.isDirectory() || !entry.name.startsWith("connect-"))
|
|
25115
25547
|
continue;
|
|
25116
25548
|
const connectorName = entry.name.replace(/^connect-/, "");
|
|
25117
|
-
const profilesDir =
|
|
25118
|
-
if (!
|
|
25549
|
+
const profilesDir = join18(connectDir, entry.name, "profiles");
|
|
25550
|
+
if (!existsSync17(profilesDir))
|
|
25119
25551
|
continue;
|
|
25120
25552
|
const profiles = {};
|
|
25121
|
-
const profileEntries =
|
|
25553
|
+
const profileEntries = readdirSync11(profilesDir, { withFileTypes: true });
|
|
25122
25554
|
for (const pEntry of profileEntries) {
|
|
25123
25555
|
if (pEntry.isFile() && pEntry.name.endsWith(".json")) {
|
|
25124
|
-
const profileName =
|
|
25556
|
+
const profileName = basename3(pEntry.name, ".json");
|
|
25125
25557
|
try {
|
|
25126
|
-
const config = JSON.parse(
|
|
25558
|
+
const config = JSON.parse(readFileSync9(join18(profilesDir, pEntry.name), "utf-8"));
|
|
25127
25559
|
profiles[profileName] = config;
|
|
25128
25560
|
} catch {}
|
|
25129
25561
|
}
|
|
25130
25562
|
if (pEntry.isDirectory()) {
|
|
25131
|
-
const configPath =
|
|
25132
|
-
if (
|
|
25563
|
+
const configPath = join18(profilesDir, pEntry.name, "config.json");
|
|
25564
|
+
if (existsSync17(configPath)) {
|
|
25133
25565
|
try {
|
|
25134
|
-
const config = JSON.parse(
|
|
25566
|
+
const config = JSON.parse(readFileSync9(configPath, "utf-8"));
|
|
25135
25567
|
profiles[pEntry.name] = config;
|
|
25136
25568
|
} catch {}
|
|
25137
25569
|
}
|
|
@@ -25172,14 +25604,14 @@ ${result.stderr}`;
|
|
|
25172
25604
|
continue;
|
|
25173
25605
|
if (!data.profiles || typeof data.profiles !== "object")
|
|
25174
25606
|
continue;
|
|
25175
|
-
const connectorDir =
|
|
25176
|
-
const profilesDir =
|
|
25607
|
+
const connectorDir = join18(connectDir, `connect-${connectorName}`);
|
|
25608
|
+
const profilesDir = join18(connectorDir, "profiles");
|
|
25177
25609
|
for (const [profileName, config] of Object.entries(data.profiles)) {
|
|
25178
25610
|
if (!config || typeof config !== "object")
|
|
25179
25611
|
continue;
|
|
25180
|
-
|
|
25181
|
-
const profileFile =
|
|
25182
|
-
|
|
25612
|
+
mkdirSync12(profilesDir, { recursive: true });
|
|
25613
|
+
const profileFile = join18(profilesDir, `${profileName}.json`);
|
|
25614
|
+
writeFileSync8(profileFile, JSON.stringify(config, null, 2));
|
|
25183
25615
|
imported++;
|
|
25184
25616
|
}
|
|
25185
25617
|
}
|
|
@@ -25234,12 +25666,12 @@ ${result.stderr}`;
|
|
|
25234
25666
|
}
|
|
25235
25667
|
if (dashboardExists && (method === "GET" || method === "HEAD")) {
|
|
25236
25668
|
if (path !== "/") {
|
|
25237
|
-
const filePath =
|
|
25669
|
+
const filePath = join18(dashboardDir, path);
|
|
25238
25670
|
const res2 = serveStaticFile(filePath);
|
|
25239
25671
|
if (res2)
|
|
25240
25672
|
return res2;
|
|
25241
25673
|
}
|
|
25242
|
-
const indexPath =
|
|
25674
|
+
const indexPath = join18(dashboardDir, "index.html");
|
|
25243
25675
|
const res = serveStaticFile(indexPath);
|
|
25244
25676
|
if (res)
|
|
25245
25677
|
return res;
|