@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/dist/index.js
CHANGED
|
@@ -15,8 +15,8 @@ var __export = (target, all) => {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
// src/lib/registry.ts
|
|
18
|
-
import { existsSync as
|
|
19
|
-
import { join as
|
|
18
|
+
import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
|
|
19
|
+
import { join as join10, dirname as dirname5 } from "path";
|
|
20
20
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
21
21
|
|
|
22
22
|
// src/core/errors.ts
|
|
@@ -42,7 +42,7 @@ class ConnectorOperationNotFoundError extends Error {
|
|
|
42
42
|
|
|
43
43
|
// src/core/connector.ts
|
|
44
44
|
var CONNECTOR_NAME_RE = /^[a-z0-9-]+$/;
|
|
45
|
-
var OPERATION_NAME_RE = /^[
|
|
45
|
+
var OPERATION_NAME_RE = /^[A-Za-z0-9:._-]+$/;
|
|
46
46
|
function defineConnector(definition) {
|
|
47
47
|
const { meta, auth, operations } = definition;
|
|
48
48
|
if (!CONNECTOR_NAME_RE.test(meta.name)) {
|
|
@@ -4967,13 +4967,444 @@ var githubConnector = defineConnector({
|
|
|
4967
4967
|
}
|
|
4968
4968
|
});
|
|
4969
4969
|
|
|
4970
|
-
// src/core/connectors/
|
|
4970
|
+
// src/core/connectors/gmail.ts
|
|
4971
4971
|
import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, writeFileSync } from "fs";
|
|
4972
4972
|
import { homedir } from "os";
|
|
4973
4973
|
import { basename, join as join2 } from "path";
|
|
4974
|
-
var
|
|
4974
|
+
var GMAIL_API_BASE = "https://gmail.googleapis.com/gmail/v1";
|
|
4975
4975
|
var TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
4976
4976
|
var REFRESH_BUFFER_MS = 5 * 60 * 1000;
|
|
4977
|
+
var listMessagesSchema = exports_external.object({
|
|
4978
|
+
max: exports_external.coerce.number().int().positive().max(500).optional(),
|
|
4979
|
+
maxResults: exports_external.coerce.number().int().positive().max(500).optional(),
|
|
4980
|
+
pageToken: exports_external.string().optional(),
|
|
4981
|
+
query: exports_external.string().optional(),
|
|
4982
|
+
q: exports_external.string().optional(),
|
|
4983
|
+
label: exports_external.string().optional(),
|
|
4984
|
+
labelIds: exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]).optional(),
|
|
4985
|
+
includeSpamTrash: exports_external.boolean().optional()
|
|
4986
|
+
});
|
|
4987
|
+
var messageIdSchema = exports_external.object({
|
|
4988
|
+
args: exports_external.array(exports_external.union([exports_external.string(), exports_external.number(), exports_external.boolean()])).optional(),
|
|
4989
|
+
messageId: exports_external.string().optional()
|
|
4990
|
+
});
|
|
4991
|
+
var readMessageSchema = messageIdSchema.extend({
|
|
4992
|
+
body: exports_external.boolean().optional(),
|
|
4993
|
+
html: exports_external.boolean().optional(),
|
|
4994
|
+
format: exports_external.enum(["full", "metadata", "minimal", "raw"]).optional()
|
|
4995
|
+
});
|
|
4996
|
+
var attachmentListSchema = messageIdSchema;
|
|
4997
|
+
var attachmentDownloadSchema = messageIdSchema.extend({
|
|
4998
|
+
attachmentId: exports_external.string().optional(),
|
|
4999
|
+
filename: exports_external.string().optional(),
|
|
5000
|
+
mimeType: exports_external.string().optional(),
|
|
5001
|
+
dir: exports_external.string().optional(),
|
|
5002
|
+
outputDir: exports_external.string().optional()
|
|
5003
|
+
});
|
|
5004
|
+
var historyListSchema = exports_external.object({
|
|
5005
|
+
startHistoryId: exports_external.string(),
|
|
5006
|
+
historyTypes: exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]).optional(),
|
|
5007
|
+
labelId: exports_external.string().optional(),
|
|
5008
|
+
maxResults: exports_external.coerce.number().int().positive().max(500).optional(),
|
|
5009
|
+
pageToken: exports_external.string().optional()
|
|
5010
|
+
});
|
|
5011
|
+
var replySchema = messageIdSchema.extend({
|
|
5012
|
+
body: exports_external.string(),
|
|
5013
|
+
html: exports_external.boolean().optional(),
|
|
5014
|
+
isHtml: exports_external.boolean().optional(),
|
|
5015
|
+
cc: exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]).optional(),
|
|
5016
|
+
bcc: exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]).optional()
|
|
5017
|
+
});
|
|
5018
|
+
var gmailConnector = defineConnector({
|
|
5019
|
+
meta: {
|
|
5020
|
+
name: "gmail",
|
|
5021
|
+
displayName: "Gmail",
|
|
5022
|
+
description: "Profile-aware Gmail mailbox operations for sync, labels, attachments, history, and replies.",
|
|
5023
|
+
category: "communication",
|
|
5024
|
+
tags: ["google", "gmail", "email", "mailbox"]
|
|
5025
|
+
},
|
|
5026
|
+
auth: {
|
|
5027
|
+
type: "oauth2",
|
|
5028
|
+
supportsProfiles: true,
|
|
5029
|
+
fields: [
|
|
5030
|
+
{ key: "clientId", env: "GMAIL_CLIENT_ID", label: "OAuth client ID" },
|
|
5031
|
+
{ key: "clientSecret", env: "GMAIL_CLIENT_SECRET", label: "OAuth client secret", secret: true }
|
|
5032
|
+
]
|
|
5033
|
+
},
|
|
5034
|
+
createContext: ({ profile }) => ({ profile: profile || "default" }),
|
|
5035
|
+
operations: {
|
|
5036
|
+
"profiles.list": {
|
|
5037
|
+
summary: "List configured Gmail profiles.",
|
|
5038
|
+
execute: () => ({ profiles: listProfiles() })
|
|
5039
|
+
},
|
|
5040
|
+
"profile.get": {
|
|
5041
|
+
summary: "Get the authenticated Gmail profile.",
|
|
5042
|
+
execute: async ({ context }) => requestJson(context.profile, "/users/me/profile", {})
|
|
5043
|
+
},
|
|
5044
|
+
"messages.list": {
|
|
5045
|
+
summary: "List Gmail messages.",
|
|
5046
|
+
inputSchema: listMessagesSchema,
|
|
5047
|
+
execute: async ({ context }, input) => {
|
|
5048
|
+
const labelIds = normalizeStringArray(input.labelIds ?? input.label);
|
|
5049
|
+
return requestJson(context.profile, "/users/me/messages", {
|
|
5050
|
+
maxResults: input.maxResults ?? input.max ?? 50,
|
|
5051
|
+
pageToken: input.pageToken,
|
|
5052
|
+
q: input.q ?? input.query,
|
|
5053
|
+
labelIds: labelIds.length > 0 ? labelIds.join(",") : undefined,
|
|
5054
|
+
includeSpamTrash: input.includeSpamTrash
|
|
5055
|
+
});
|
|
5056
|
+
}
|
|
5057
|
+
},
|
|
5058
|
+
"messages.read": {
|
|
5059
|
+
summary: "Read a Gmail message with optional extracted body.",
|
|
5060
|
+
inputSchema: readMessageSchema,
|
|
5061
|
+
execute: async ({ context }, input) => {
|
|
5062
|
+
const messageId = getMessageId(input);
|
|
5063
|
+
const message = await requestJson(context.profile, `/users/me/messages/${encodeURIComponent(messageId)}`, { format: input.format ?? "full" });
|
|
5064
|
+
const headers = headersToObject(message.payload?.headers ?? []);
|
|
5065
|
+
return {
|
|
5066
|
+
...message,
|
|
5067
|
+
from: headers.From ?? headers.from ?? "",
|
|
5068
|
+
to: headers.To ?? headers.to ?? "",
|
|
5069
|
+
cc: headers.Cc ?? headers.cc ?? "",
|
|
5070
|
+
subject: headers.Subject ?? headers.subject ?? "",
|
|
5071
|
+
date: headers.Date ?? headers.date ?? "",
|
|
5072
|
+
body: input.body ? extractBody(message, Boolean(input.html)) : undefined,
|
|
5073
|
+
size: message.sizeEstimate
|
|
5074
|
+
};
|
|
5075
|
+
}
|
|
5076
|
+
},
|
|
5077
|
+
"messages.getRaw": {
|
|
5078
|
+
summary: "Read raw base64url Gmail message content.",
|
|
5079
|
+
inputSchema: messageIdSchema,
|
|
5080
|
+
execute: async ({ context }, input) => {
|
|
5081
|
+
const messageId = getMessageId(input);
|
|
5082
|
+
return requestJson(context.profile, `/users/me/messages/${encodeURIComponent(messageId)}`, { format: "raw" });
|
|
5083
|
+
}
|
|
5084
|
+
},
|
|
5085
|
+
"messages.mark-read": {
|
|
5086
|
+
summary: "Mark a message as read.",
|
|
5087
|
+
inputSchema: messageIdSchema,
|
|
5088
|
+
execute: async ({ context }, input) => modifyMessage(context.profile, getMessageId(input), undefined, ["UNREAD"])
|
|
5089
|
+
},
|
|
5090
|
+
"messages.mark-unread": {
|
|
5091
|
+
summary: "Mark a message as unread.",
|
|
5092
|
+
inputSchema: messageIdSchema,
|
|
5093
|
+
execute: async ({ context }, input) => modifyMessage(context.profile, getMessageId(input), ["UNREAD"], undefined)
|
|
5094
|
+
},
|
|
5095
|
+
"messages.archive": {
|
|
5096
|
+
summary: "Archive a message by removing the INBOX label.",
|
|
5097
|
+
inputSchema: messageIdSchema,
|
|
5098
|
+
execute: async ({ context }, input) => modifyMessage(context.profile, getMessageId(input), undefined, ["INBOX"])
|
|
5099
|
+
},
|
|
5100
|
+
"messages.star": {
|
|
5101
|
+
summary: "Star a message.",
|
|
5102
|
+
inputSchema: messageIdSchema,
|
|
5103
|
+
execute: async ({ context }, input) => modifyMessage(context.profile, getMessageId(input), ["STARRED"], undefined)
|
|
5104
|
+
},
|
|
5105
|
+
"messages.reply": {
|
|
5106
|
+
summary: "Reply to a Gmail message in the same thread.",
|
|
5107
|
+
inputSchema: replySchema,
|
|
5108
|
+
execute: async ({ context }, input) => replyToMessage(context.profile, getMessageId(input), input)
|
|
5109
|
+
},
|
|
5110
|
+
"attachments.list": {
|
|
5111
|
+
summary: "List Gmail message attachments.",
|
|
5112
|
+
inputSchema: attachmentListSchema,
|
|
5113
|
+
execute: async ({ context }, input) => {
|
|
5114
|
+
const message = await requestJson(context.profile, `/users/me/messages/${encodeURIComponent(getMessageId(input))}`, { format: "full" });
|
|
5115
|
+
return collectAttachments(message.payload);
|
|
5116
|
+
}
|
|
5117
|
+
},
|
|
5118
|
+
"attachments.download": {
|
|
5119
|
+
summary: "Download one or all Gmail message attachments to disk.",
|
|
5120
|
+
inputSchema: attachmentDownloadSchema,
|
|
5121
|
+
execute: async ({ context }, input) => downloadAttachments(context.profile, input)
|
|
5122
|
+
},
|
|
5123
|
+
"labels.list": {
|
|
5124
|
+
summary: "List Gmail labels.",
|
|
5125
|
+
execute: async ({ context }) => requestJson(context.profile, "/users/me/labels", {})
|
|
5126
|
+
},
|
|
5127
|
+
"history.list": {
|
|
5128
|
+
summary: "List Gmail mailbox history from a history id.",
|
|
5129
|
+
inputSchema: historyListSchema,
|
|
5130
|
+
execute: async ({ context }, input) => requestJson(context.profile, "/users/me/history", {
|
|
5131
|
+
startHistoryId: input.startHistoryId,
|
|
5132
|
+
historyTypes: normalizeStringArray(input.historyTypes).join(",") || undefined,
|
|
5133
|
+
labelId: input.labelId,
|
|
5134
|
+
maxResults: input.maxResults,
|
|
5135
|
+
pageToken: input.pageToken
|
|
5136
|
+
})
|
|
5137
|
+
}
|
|
5138
|
+
}
|
|
5139
|
+
});
|
|
5140
|
+
async function modifyMessage(profile, messageId, addLabelIds, removeLabelIds) {
|
|
5141
|
+
return requestJson(profile, `/users/me/messages/${encodeURIComponent(messageId)}/modify`, {}, {
|
|
5142
|
+
method: "POST",
|
|
5143
|
+
body: {
|
|
5144
|
+
addLabelIds: addLabelIds ?? [],
|
|
5145
|
+
removeLabelIds: removeLabelIds ?? []
|
|
5146
|
+
}
|
|
5147
|
+
});
|
|
5148
|
+
}
|
|
5149
|
+
async function replyToMessage(profile, messageId, input) {
|
|
5150
|
+
const original = await requestJson(profile, `/users/me/messages/${encodeURIComponent(messageId)}`, { format: "full" });
|
|
5151
|
+
const headers = headersToObject(original.payload?.headers ?? []);
|
|
5152
|
+
const subject = normalizeReplySubject(headers.Subject ?? headers.subject ?? "");
|
|
5153
|
+
const to = headers.From ?? headers.from ?? "";
|
|
5154
|
+
const messageIdHeader = headers["Message-ID"] ?? headers["Message-Id"] ?? headers["message-id"] ?? "";
|
|
5155
|
+
const references = [headers.References ?? headers.references, messageIdHeader].filter(Boolean).join(" ");
|
|
5156
|
+
const raw = buildRawEmail({
|
|
5157
|
+
to,
|
|
5158
|
+
cc: normalizeStringArray(input.cc),
|
|
5159
|
+
bcc: normalizeStringArray(input.bcc),
|
|
5160
|
+
subject,
|
|
5161
|
+
body: input.body,
|
|
5162
|
+
isHtml: Boolean(input.html ?? input.isHtml),
|
|
5163
|
+
inReplyTo: messageIdHeader,
|
|
5164
|
+
references
|
|
5165
|
+
});
|
|
5166
|
+
return requestJson(profile, "/users/me/messages/send", {}, {
|
|
5167
|
+
method: "POST",
|
|
5168
|
+
body: {
|
|
5169
|
+
raw: Buffer.from(raw).toString("base64url"),
|
|
5170
|
+
threadId: original.threadId
|
|
5171
|
+
}
|
|
5172
|
+
});
|
|
5173
|
+
}
|
|
5174
|
+
async function downloadAttachments(profile, input) {
|
|
5175
|
+
const messageId = getMessageId(input);
|
|
5176
|
+
const outputDir = input.dir ?? input.outputDir ?? join2(configDirs()[0], "attachments", messageId);
|
|
5177
|
+
mkdirSync(outputDir, { recursive: true });
|
|
5178
|
+
const attachments = input.attachmentId && input.filename ? [{
|
|
5179
|
+
attachmentId: input.attachmentId,
|
|
5180
|
+
filename: input.filename,
|
|
5181
|
+
mimeType: input.mimeType ?? "application/octet-stream",
|
|
5182
|
+
size: 0
|
|
5183
|
+
}] : collectAttachments((await requestJson(profile, `/users/me/messages/${encodeURIComponent(messageId)}`, { format: "full" })).payload);
|
|
5184
|
+
const downloaded = [];
|
|
5185
|
+
for (const attachment of attachments) {
|
|
5186
|
+
const data = await requestJson(profile, `/users/me/messages/${encodeURIComponent(messageId)}/attachments/${encodeURIComponent(attachment.attachmentId)}`, {});
|
|
5187
|
+
const filename = safeFilename(attachment.filename);
|
|
5188
|
+
const path = join2(outputDir, filename);
|
|
5189
|
+
const buffer = Buffer.from(data.data, "base64url");
|
|
5190
|
+
writeFileSync(path, buffer);
|
|
5191
|
+
downloaded.push({
|
|
5192
|
+
filename,
|
|
5193
|
+
path,
|
|
5194
|
+
size: buffer.length,
|
|
5195
|
+
mimeType: attachment.mimeType
|
|
5196
|
+
});
|
|
5197
|
+
}
|
|
5198
|
+
return downloaded;
|
|
5199
|
+
}
|
|
5200
|
+
async function requestJson(profile, path, params, options = {}) {
|
|
5201
|
+
const token = await getValidAccessToken(profile);
|
|
5202
|
+
const url = new URL(`${GMAIL_API_BASE}${path}`);
|
|
5203
|
+
for (const [key, value] of Object.entries(params)) {
|
|
5204
|
+
if (value !== undefined && value !== null && value !== "")
|
|
5205
|
+
url.searchParams.append(key, String(value));
|
|
5206
|
+
}
|
|
5207
|
+
const response = await fetch(url, {
|
|
5208
|
+
method: options.method ?? "GET",
|
|
5209
|
+
headers: {
|
|
5210
|
+
Authorization: `Bearer ${token}`,
|
|
5211
|
+
Accept: "application/json",
|
|
5212
|
+
...options.body ? { "Content-Type": "application/json" } : {}
|
|
5213
|
+
},
|
|
5214
|
+
body: options.body ? JSON.stringify(options.body) : undefined
|
|
5215
|
+
});
|
|
5216
|
+
const text = await response.text();
|
|
5217
|
+
const data = text ? JSON.parse(text) : {};
|
|
5218
|
+
if (!response.ok) {
|
|
5219
|
+
const error = data;
|
|
5220
|
+
throw new Error(`Gmail request failed (${response.status}): ${error.error?.message ?? response.statusText}`);
|
|
5221
|
+
}
|
|
5222
|
+
return data;
|
|
5223
|
+
}
|
|
5224
|
+
async function getValidAccessToken(profile) {
|
|
5225
|
+
if (process.env.GMAIL_ACCESS_TOKEN)
|
|
5226
|
+
return process.env.GMAIL_ACCESS_TOKEN;
|
|
5227
|
+
const tokens = loadTokens(profile);
|
|
5228
|
+
if (!tokens?.accessToken && !tokens?.refreshToken) {
|
|
5229
|
+
throw new Error(`Gmail profile "${profile}" is not authenticated. Run: connectors auth gmail`);
|
|
5230
|
+
}
|
|
5231
|
+
if (tokens.accessToken && (!tokens.expiresAt || Date.now() < tokens.expiresAt - REFRESH_BUFFER_MS))
|
|
5232
|
+
return tokens.accessToken;
|
|
5233
|
+
if (!tokens.refreshToken)
|
|
5234
|
+
return tokens.accessToken ?? "";
|
|
5235
|
+
return (await refreshAccessToken(profile, tokens)).accessToken ?? "";
|
|
5236
|
+
}
|
|
5237
|
+
async function refreshAccessToken(profile, currentTokens) {
|
|
5238
|
+
const credentials = loadCredentials(profile);
|
|
5239
|
+
if (!credentials.clientId || !credentials.clientSecret)
|
|
5240
|
+
throw new Error("Gmail OAuth credentials are not configured. Run: connectors auth gmail");
|
|
5241
|
+
if (!currentTokens.refreshToken)
|
|
5242
|
+
throw new Error(`Gmail profile "${profile}" has no refresh token. Run: connectors auth gmail`);
|
|
5243
|
+
const response = await fetch(TOKEN_URL, {
|
|
5244
|
+
method: "POST",
|
|
5245
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
5246
|
+
body: new URLSearchParams({
|
|
5247
|
+
client_id: credentials.clientId,
|
|
5248
|
+
client_secret: credentials.clientSecret,
|
|
5249
|
+
refresh_token: currentTokens.refreshToken,
|
|
5250
|
+
grant_type: "refresh_token"
|
|
5251
|
+
})
|
|
5252
|
+
});
|
|
5253
|
+
const data = await response.json().catch(() => ({}));
|
|
5254
|
+
if (!response.ok || !data.access_token)
|
|
5255
|
+
throw new Error(`Gmail token refresh failed: ${data.error_description || data.error || response.statusText}`);
|
|
5256
|
+
const tokens = {
|
|
5257
|
+
accessToken: data.access_token,
|
|
5258
|
+
refreshToken: currentTokens.refreshToken,
|
|
5259
|
+
expiresAt: Date.now() + (data.expires_in ?? 3600) * 1000,
|
|
5260
|
+
tokenType: data.token_type ?? currentTokens.tokenType,
|
|
5261
|
+
scope: data.scope ?? currentTokens.scope
|
|
5262
|
+
};
|
|
5263
|
+
saveTokens(profile, tokens);
|
|
5264
|
+
return tokens;
|
|
5265
|
+
}
|
|
5266
|
+
function listProfiles() {
|
|
5267
|
+
const profiles = new Set;
|
|
5268
|
+
for (const baseDir of configDirs()) {
|
|
5269
|
+
const profilesDir = join2(baseDir, "profiles");
|
|
5270
|
+
if (!existsSync2(profilesDir))
|
|
5271
|
+
continue;
|
|
5272
|
+
for (const entry of readdirSync(profilesDir, { withFileTypes: true })) {
|
|
5273
|
+
if (entry.isDirectory())
|
|
5274
|
+
profiles.add(entry.name);
|
|
5275
|
+
if (entry.isFile() && entry.name.endsWith(".json"))
|
|
5276
|
+
profiles.add(basename(entry.name, ".json"));
|
|
5277
|
+
}
|
|
5278
|
+
}
|
|
5279
|
+
return Array.from(profiles).sort((a, b) => a.localeCompare(b));
|
|
5280
|
+
}
|
|
5281
|
+
function loadCredentials(profile) {
|
|
5282
|
+
const envClientId = process.env.GMAIL_CLIENT_ID ?? process.env.GOOGLE_CLIENT_ID;
|
|
5283
|
+
const envClientSecret = process.env.GMAIL_CLIENT_SECRET ?? process.env.GOOGLE_CLIENT_SECRET;
|
|
5284
|
+
if (envClientId && envClientSecret)
|
|
5285
|
+
return { clientId: envClientId, clientSecret: envClientSecret };
|
|
5286
|
+
for (const baseDir of configDirs()) {
|
|
5287
|
+
const credentials = {
|
|
5288
|
+
...readJson(join2(baseDir, "credentials.json")),
|
|
5289
|
+
...readJson(join2(baseDir, "profiles", profile, "config.json"))
|
|
5290
|
+
};
|
|
5291
|
+
if (credentials.clientId || credentials.clientSecret)
|
|
5292
|
+
return credentials;
|
|
5293
|
+
}
|
|
5294
|
+
return {};
|
|
5295
|
+
}
|
|
5296
|
+
function loadTokens(profile) {
|
|
5297
|
+
for (const baseDir of configDirs()) {
|
|
5298
|
+
const fromProfile = readJson(join2(baseDir, "profiles", profile, "tokens.json"));
|
|
5299
|
+
if (fromProfile)
|
|
5300
|
+
return fromProfile;
|
|
5301
|
+
const flat = readJson(join2(baseDir, "profiles", `${profile}.json`));
|
|
5302
|
+
if (flat)
|
|
5303
|
+
return flat.tokens ?? (flat.accessToken || flat.refreshToken ? flat : null);
|
|
5304
|
+
}
|
|
5305
|
+
return null;
|
|
5306
|
+
}
|
|
5307
|
+
function saveTokens(profile, tokens) {
|
|
5308
|
+
const baseDir = configDirs().find((dir) => existsSync2(dir)) ?? configDirs()[0];
|
|
5309
|
+
const profileDir = join2(baseDir, "profiles", profile);
|
|
5310
|
+
mkdirSync(profileDir, { recursive: true });
|
|
5311
|
+
writeFileSync(join2(profileDir, "tokens.json"), JSON.stringify(tokens, null, 2), { mode: 384 });
|
|
5312
|
+
}
|
|
5313
|
+
function configDirs() {
|
|
5314
|
+
const explicit = process.env.HASNA_GMAIL_CONNECTOR_DIR ?? process.env.GMAIL_CONNECTOR_DIR;
|
|
5315
|
+
if (explicit)
|
|
5316
|
+
return [explicit];
|
|
5317
|
+
const baseDir = process.env.HASNA_CONNECTORS_DIR ?? join2(homedir(), ".hasna", "connectors");
|
|
5318
|
+
return [join2(baseDir, "connect-gmail"), join2(baseDir, "gmail")];
|
|
5319
|
+
}
|
|
5320
|
+
function readJson(path) {
|
|
5321
|
+
if (!existsSync2(path))
|
|
5322
|
+
return null;
|
|
5323
|
+
try {
|
|
5324
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
5325
|
+
} catch {
|
|
5326
|
+
return null;
|
|
5327
|
+
}
|
|
5328
|
+
}
|
|
5329
|
+
function getMessageId(input) {
|
|
5330
|
+
const id = input.messageId ?? (input.args?.[0] != null ? String(input.args[0]) : undefined);
|
|
5331
|
+
if (!id)
|
|
5332
|
+
throw new Error("Gmail messageId is required");
|
|
5333
|
+
return id;
|
|
5334
|
+
}
|
|
5335
|
+
function headersToObject(headers) {
|
|
5336
|
+
const out = {};
|
|
5337
|
+
for (const header of headers)
|
|
5338
|
+
out[header.name] = header.value;
|
|
5339
|
+
return out;
|
|
5340
|
+
}
|
|
5341
|
+
function extractBody(message, preferHtml = false) {
|
|
5342
|
+
if (!message.payload)
|
|
5343
|
+
return "";
|
|
5344
|
+
const targetType = preferHtml ? "text/html" : "text/plain";
|
|
5345
|
+
const parts = [];
|
|
5346
|
+
collectTextParts(message.payload, parts);
|
|
5347
|
+
return parts.find((part) => part.mimeType === targetType)?.data ?? parts.find((part) => part.mimeType.startsWith("text/"))?.data ?? "";
|
|
5348
|
+
}
|
|
5349
|
+
function collectTextParts(part, results) {
|
|
5350
|
+
const mimeType = (part.mimeType ?? "").split(";")[0].trim().toLowerCase();
|
|
5351
|
+
if (part.body?.data && mimeType.startsWith("text/")) {
|
|
5352
|
+
results.push({ mimeType, data: Buffer.from(part.body.data, "base64url").toString("utf8") });
|
|
5353
|
+
}
|
|
5354
|
+
for (const child of part.parts ?? [])
|
|
5355
|
+
collectTextParts(child, results);
|
|
5356
|
+
}
|
|
5357
|
+
function collectAttachments(part, attachments = []) {
|
|
5358
|
+
if (!part)
|
|
5359
|
+
return attachments;
|
|
5360
|
+
if (part.body?.attachmentId && part.filename) {
|
|
5361
|
+
attachments.push({
|
|
5362
|
+
attachmentId: part.body.attachmentId,
|
|
5363
|
+
filename: part.filename,
|
|
5364
|
+
mimeType: part.mimeType ?? "application/octet-stream",
|
|
5365
|
+
size: part.body.size ?? 0,
|
|
5366
|
+
partId: part.partId
|
|
5367
|
+
});
|
|
5368
|
+
}
|
|
5369
|
+
for (const child of part.parts ?? [])
|
|
5370
|
+
collectAttachments(child, attachments);
|
|
5371
|
+
return attachments;
|
|
5372
|
+
}
|
|
5373
|
+
function normalizeStringArray(value) {
|
|
5374
|
+
if (!value)
|
|
5375
|
+
return [];
|
|
5376
|
+
return Array.isArray(value) ? value : value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
5377
|
+
}
|
|
5378
|
+
function normalizeReplySubject(subject) {
|
|
5379
|
+
return subject.toLowerCase().startsWith("re:") ? subject : `Re: ${subject}`;
|
|
5380
|
+
}
|
|
5381
|
+
function buildRawEmail(input) {
|
|
5382
|
+
const headers = [
|
|
5383
|
+
`To: ${input.to}`,
|
|
5384
|
+
input.cc.length ? `Cc: ${input.cc.join(", ")}` : "",
|
|
5385
|
+
input.bcc.length ? `Bcc: ${input.bcc.join(", ")}` : "",
|
|
5386
|
+
`Subject: ${input.subject}`,
|
|
5387
|
+
input.inReplyTo ? `In-Reply-To: ${input.inReplyTo}` : "",
|
|
5388
|
+
input.references ? `References: ${input.references}` : "",
|
|
5389
|
+
"MIME-Version: 1.0",
|
|
5390
|
+
`Content-Type: ${input.isHtml ? "text/html" : "text/plain"}; charset=UTF-8`
|
|
5391
|
+
].filter(Boolean);
|
|
5392
|
+
return `${headers.join(`\r
|
|
5393
|
+
`)}\r
|
|
5394
|
+
\r
|
|
5395
|
+
${input.body}`;
|
|
5396
|
+
}
|
|
5397
|
+
function safeFilename(filename) {
|
|
5398
|
+
return basename(filename.replace(/[\u00A0\u2000-\u200B\u202F\u205F\u3000]/g, " ")).replace(/[\/\\]/g, "_");
|
|
5399
|
+
}
|
|
5400
|
+
|
|
5401
|
+
// src/core/connectors/googledrive.ts
|
|
5402
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, readdirSync as readdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
5403
|
+
import { homedir as homedir2 } from "os";
|
|
5404
|
+
import { basename as basename2, join as join3 } from "path";
|
|
5405
|
+
var DRIVE_API_BASE = "https://www.googleapis.com/drive/v3";
|
|
5406
|
+
var TOKEN_URL2 = "https://oauth2.googleapis.com/token";
|
|
5407
|
+
var REFRESH_BUFFER_MS2 = 5 * 60 * 1000;
|
|
4977
5408
|
var DEFAULT_FILE_FIELDS = [
|
|
4978
5409
|
"id",
|
|
4979
5410
|
"name",
|
|
@@ -5054,12 +5485,12 @@ var googleDriveConnector = defineConnector({
|
|
|
5054
5485
|
operations: {
|
|
5055
5486
|
"profiles.list": {
|
|
5056
5487
|
summary: "List configured Google Drive profiles.",
|
|
5057
|
-
execute: () => ({ profiles:
|
|
5488
|
+
execute: () => ({ profiles: listProfiles2() })
|
|
5058
5489
|
},
|
|
5059
5490
|
"files.list": {
|
|
5060
5491
|
summary: "List Google Drive files.",
|
|
5061
5492
|
inputSchema: listFilesSchema,
|
|
5062
|
-
execute: async ({ context }, input) =>
|
|
5493
|
+
execute: async ({ context }, input) => requestJson2(context.profile, "/files", {
|
|
5063
5494
|
pageSize: input.pageSize ?? 1000,
|
|
5064
5495
|
pageToken: input.pageToken,
|
|
5065
5496
|
q: input.q,
|
|
@@ -5074,7 +5505,7 @@ var googleDriveConnector = defineConnector({
|
|
|
5074
5505
|
"files.get": {
|
|
5075
5506
|
summary: "Get Google Drive file metadata.",
|
|
5076
5507
|
inputSchema: fileIdSchema,
|
|
5077
|
-
execute: async ({ context }, input) =>
|
|
5508
|
+
execute: async ({ context }, input) => requestJson2(context.profile, `/files/${encodeURIComponent(input.fileId)}`, {
|
|
5078
5509
|
fields: input.fields ?? DEFAULT_FILE_FIELDS,
|
|
5079
5510
|
supportsAllDrives: true
|
|
5080
5511
|
})
|
|
@@ -5083,7 +5514,7 @@ var googleDriveConnector = defineConnector({
|
|
|
5083
5514
|
summary: "Download or export a Google Drive file as base64 content.",
|
|
5084
5515
|
inputSchema: downloadSchema,
|
|
5085
5516
|
execute: async ({ context }, input) => {
|
|
5086
|
-
const file = input.file ?? await
|
|
5517
|
+
const file = input.file ?? await requestJson2(context.profile, `/files/${encodeURIComponent(input.fileId)}`, { fields: DEFAULT_FILE_FIELDS, supportsAllDrives: true });
|
|
5087
5518
|
const exportMimeType = file.mimeType.startsWith("application/vnd.google-apps.") ? input.exportMimeType ?? defaultExportMimeType(file.mimeType) : undefined;
|
|
5088
5519
|
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 });
|
|
5089
5520
|
const mimeType = exportMimeType ?? file.mimeType ?? "application/octet-stream";
|
|
@@ -5097,7 +5528,7 @@ var googleDriveConnector = defineConnector({
|
|
|
5097
5528
|
"drives.list": {
|
|
5098
5529
|
summary: "List Google shared drives.",
|
|
5099
5530
|
inputSchema: listDrivesSchema,
|
|
5100
|
-
execute: async ({ context }, input) =>
|
|
5531
|
+
execute: async ({ context }, input) => requestJson2(context.profile, "/drives", {
|
|
5101
5532
|
pageSize: input.pageSize ?? 100,
|
|
5102
5533
|
pageToken: input.pageToken,
|
|
5103
5534
|
q: input.q
|
|
@@ -5105,7 +5536,7 @@ var googleDriveConnector = defineConnector({
|
|
|
5105
5536
|
}
|
|
5106
5537
|
}
|
|
5107
5538
|
});
|
|
5108
|
-
async function
|
|
5539
|
+
async function requestJson2(profile, path, params) {
|
|
5109
5540
|
const response = await request(profile, path, params);
|
|
5110
5541
|
const text = await response.text();
|
|
5111
5542
|
return text ? JSON.parse(text) : {};
|
|
@@ -5114,7 +5545,7 @@ async function requestBinary(profile, path, params) {
|
|
|
5114
5545
|
return (await request(profile, path, params)).arrayBuffer();
|
|
5115
5546
|
}
|
|
5116
5547
|
async function request(profile, path, params) {
|
|
5117
|
-
const token = await
|
|
5548
|
+
const token = await getValidAccessToken2(profile);
|
|
5118
5549
|
const url = new URL(`${DRIVE_API_BASE}${path}`);
|
|
5119
5550
|
for (const [key, value] of Object.entries(params)) {
|
|
5120
5551
|
if (value !== undefined && value !== null && value !== "")
|
|
@@ -5127,26 +5558,26 @@ async function request(profile, path, params) {
|
|
|
5127
5558
|
}
|
|
5128
5559
|
return response;
|
|
5129
5560
|
}
|
|
5130
|
-
async function
|
|
5561
|
+
async function getValidAccessToken2(profile) {
|
|
5131
5562
|
if (process.env.GOOGLE_ACCESS_TOKEN)
|
|
5132
5563
|
return process.env.GOOGLE_ACCESS_TOKEN;
|
|
5133
|
-
const tokens =
|
|
5564
|
+
const tokens = loadTokens2(profile);
|
|
5134
5565
|
if (!tokens?.accessToken && !tokens?.refreshToken) {
|
|
5135
5566
|
throw new Error(`Google Drive profile "${profile}" is not authenticated. Run: connectors auth googledrive`);
|
|
5136
5567
|
}
|
|
5137
|
-
if (tokens.accessToken && (!tokens.expiresAt || Date.now() < tokens.expiresAt -
|
|
5568
|
+
if (tokens.accessToken && (!tokens.expiresAt || Date.now() < tokens.expiresAt - REFRESH_BUFFER_MS2))
|
|
5138
5569
|
return tokens.accessToken;
|
|
5139
5570
|
if (!tokens.refreshToken)
|
|
5140
5571
|
return tokens.accessToken ?? "";
|
|
5141
|
-
return (await
|
|
5572
|
+
return (await refreshAccessToken2(profile, tokens)).accessToken ?? "";
|
|
5142
5573
|
}
|
|
5143
|
-
async function
|
|
5144
|
-
const credentials =
|
|
5574
|
+
async function refreshAccessToken2(profile, currentTokens) {
|
|
5575
|
+
const credentials = loadCredentials2(profile);
|
|
5145
5576
|
if (!credentials.clientId || !credentials.clientSecret)
|
|
5146
5577
|
throw new Error("Google Drive OAuth credentials are not configured. Run: connectors auth googledrive");
|
|
5147
5578
|
if (!currentTokens.refreshToken)
|
|
5148
5579
|
throw new Error(`Google Drive profile "${profile}" has no refresh token. Run: connectors auth googledrive`);
|
|
5149
|
-
const response = await fetch(
|
|
5580
|
+
const response = await fetch(TOKEN_URL2, {
|
|
5150
5581
|
method: "POST",
|
|
5151
5582
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
5152
5583
|
body: new URLSearchParams({
|
|
@@ -5166,68 +5597,68 @@ async function refreshAccessToken(profile, currentTokens) {
|
|
|
5166
5597
|
tokenType: data.token_type ?? currentTokens.tokenType,
|
|
5167
5598
|
scope: data.scope ?? currentTokens.scope
|
|
5168
5599
|
};
|
|
5169
|
-
|
|
5600
|
+
saveTokens2(profile, tokens);
|
|
5170
5601
|
return tokens;
|
|
5171
5602
|
}
|
|
5172
|
-
function
|
|
5603
|
+
function listProfiles2() {
|
|
5173
5604
|
const profiles = new Set;
|
|
5174
|
-
for (const baseDir of
|
|
5175
|
-
const profilesDir =
|
|
5176
|
-
if (!
|
|
5605
|
+
for (const baseDir of configDirs2()) {
|
|
5606
|
+
const profilesDir = join3(baseDir, "profiles");
|
|
5607
|
+
if (!existsSync3(profilesDir))
|
|
5177
5608
|
continue;
|
|
5178
|
-
for (const entry of
|
|
5609
|
+
for (const entry of readdirSync2(profilesDir, { withFileTypes: true })) {
|
|
5179
5610
|
if (entry.isDirectory())
|
|
5180
5611
|
profiles.add(entry.name);
|
|
5181
5612
|
if (entry.isFile() && entry.name.endsWith(".json"))
|
|
5182
|
-
profiles.add(
|
|
5613
|
+
profiles.add(basename2(entry.name, ".json"));
|
|
5183
5614
|
}
|
|
5184
5615
|
}
|
|
5185
5616
|
return Array.from(profiles).sort((a, b) => a.localeCompare(b));
|
|
5186
5617
|
}
|
|
5187
|
-
function
|
|
5618
|
+
function loadCredentials2(profile) {
|
|
5188
5619
|
const envClientId = process.env.GOOGLE_CLIENT_ID;
|
|
5189
5620
|
const envClientSecret = process.env.GOOGLE_CLIENT_SECRET;
|
|
5190
5621
|
if (envClientId && envClientSecret)
|
|
5191
5622
|
return { clientId: envClientId, clientSecret: envClientSecret };
|
|
5192
|
-
for (const baseDir of
|
|
5623
|
+
for (const baseDir of configDirs2()) {
|
|
5193
5624
|
const credentials = {
|
|
5194
|
-
...
|
|
5195
|
-
...
|
|
5625
|
+
...readJson2(join3(baseDir, "credentials.json")),
|
|
5626
|
+
...readJson2(join3(baseDir, "profiles", profile, "config.json"))
|
|
5196
5627
|
};
|
|
5197
5628
|
if (credentials.clientId || credentials.clientSecret)
|
|
5198
5629
|
return credentials;
|
|
5199
5630
|
}
|
|
5200
5631
|
return {};
|
|
5201
5632
|
}
|
|
5202
|
-
function
|
|
5203
|
-
for (const baseDir of
|
|
5204
|
-
const fromProfile =
|
|
5633
|
+
function loadTokens2(profile) {
|
|
5634
|
+
for (const baseDir of configDirs2()) {
|
|
5635
|
+
const fromProfile = readJson2(join3(baseDir, "profiles", profile, "tokens.json"));
|
|
5205
5636
|
if (fromProfile)
|
|
5206
5637
|
return fromProfile;
|
|
5207
|
-
const flat =
|
|
5638
|
+
const flat = readJson2(join3(baseDir, "profiles", `${profile}.json`));
|
|
5208
5639
|
if (flat)
|
|
5209
5640
|
return flat.tokens ?? (flat.accessToken || flat.refreshToken ? flat : null);
|
|
5210
5641
|
}
|
|
5211
5642
|
return null;
|
|
5212
5643
|
}
|
|
5213
|
-
function
|
|
5214
|
-
const baseDir =
|
|
5215
|
-
const profileDir =
|
|
5216
|
-
|
|
5217
|
-
|
|
5644
|
+
function saveTokens2(profile, tokens) {
|
|
5645
|
+
const baseDir = configDirs2().find((dir) => existsSync3(dir)) ?? configDirs2()[0];
|
|
5646
|
+
const profileDir = join3(baseDir, "profiles", profile);
|
|
5647
|
+
mkdirSync2(profileDir, { recursive: true });
|
|
5648
|
+
writeFileSync2(join3(profileDir, "tokens.json"), JSON.stringify(tokens, null, 2), { mode: 384 });
|
|
5218
5649
|
}
|
|
5219
|
-
function
|
|
5650
|
+
function configDirs2() {
|
|
5220
5651
|
const explicit = process.env.HASNA_GOOGLE_DRIVE_CONNECTOR_DIR ?? process.env.GOOGLE_DRIVE_CONNECTOR_DIR;
|
|
5221
5652
|
if (explicit)
|
|
5222
5653
|
return [explicit];
|
|
5223
|
-
const baseDir = process.env.HASNA_CONNECTORS_DIR ??
|
|
5224
|
-
return [
|
|
5654
|
+
const baseDir = process.env.HASNA_CONNECTORS_DIR ?? join3(homedir2(), ".hasna", "connectors");
|
|
5655
|
+
return [join3(baseDir, "connect-googledrive"), join3(baseDir, "googledrive")];
|
|
5225
5656
|
}
|
|
5226
|
-
function
|
|
5227
|
-
if (!
|
|
5657
|
+
function readJson2(path) {
|
|
5658
|
+
if (!existsSync3(path))
|
|
5228
5659
|
return null;
|
|
5229
5660
|
try {
|
|
5230
|
-
return JSON.parse(
|
|
5661
|
+
return JSON.parse(readFileSync2(path, "utf8"));
|
|
5231
5662
|
} catch {
|
|
5232
5663
|
return null;
|
|
5233
5664
|
}
|
|
@@ -5259,7 +5690,7 @@ function extractGoogleError(body) {
|
|
|
5259
5690
|
// package.json
|
|
5260
5691
|
var package_default = {
|
|
5261
5692
|
name: "@hasna/connectors",
|
|
5262
|
-
version: "1.3.
|
|
5693
|
+
version: "1.3.26",
|
|
5263
5694
|
description: "Open source connector library - Install API connectors with a single command",
|
|
5264
5695
|
type: "module",
|
|
5265
5696
|
bin: {
|
|
@@ -5347,13 +5778,13 @@ var package_default = {
|
|
|
5347
5778
|
|
|
5348
5779
|
// src/core/connectors/imessage.ts
|
|
5349
5780
|
import {
|
|
5350
|
-
existsSync as
|
|
5351
|
-
mkdirSync as
|
|
5352
|
-
readFileSync as
|
|
5353
|
-
readdirSync as
|
|
5781
|
+
existsSync as existsSync6,
|
|
5782
|
+
mkdirSync as mkdirSync5,
|
|
5783
|
+
readFileSync as readFileSync4,
|
|
5784
|
+
readdirSync as readdirSync5,
|
|
5354
5785
|
rmSync,
|
|
5355
5786
|
statSync as statSync2,
|
|
5356
|
-
writeFileSync as
|
|
5787
|
+
writeFileSync as writeFileSync4
|
|
5357
5788
|
} from "fs";
|
|
5358
5789
|
import { join as join7 } from "path";
|
|
5359
5790
|
|
|
@@ -5361,21 +5792,21 @@ import { join as join7 } from "path";
|
|
|
5361
5792
|
import { createRequire } from "module";
|
|
5362
5793
|
import { Database } from "bun:sqlite";
|
|
5363
5794
|
import {
|
|
5364
|
-
existsSync as
|
|
5365
|
-
mkdirSync as
|
|
5366
|
-
readdirSync as
|
|
5795
|
+
existsSync as existsSync4,
|
|
5796
|
+
mkdirSync as mkdirSync3,
|
|
5797
|
+
readdirSync as readdirSync3,
|
|
5367
5798
|
copyFileSync
|
|
5368
5799
|
} from "fs";
|
|
5369
|
-
import { homedir as
|
|
5370
|
-
import { join as
|
|
5371
|
-
import { existsSync as existsSync22, mkdirSync as mkdirSync22, readFileSync as
|
|
5800
|
+
import { homedir as homedir3 } from "os";
|
|
5801
|
+
import { join as join4, relative } from "path";
|
|
5802
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync22, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
5372
5803
|
import { homedir as homedir22 } from "os";
|
|
5373
5804
|
import { join as join22 } from "path";
|
|
5374
5805
|
import { readdirSync as readdirSync22, existsSync as existsSync32 } from "fs";
|
|
5375
5806
|
import { join as join32 } from "path";
|
|
5376
|
-
import { homedir as
|
|
5807
|
+
import { homedir as homedir32 } from "os";
|
|
5377
5808
|
import { homedir as homedir4 } from "os";
|
|
5378
|
-
import { join as
|
|
5809
|
+
import { join as join42 } from "path";
|
|
5379
5810
|
import { join as join6, dirname as dirname2 } from "path";
|
|
5380
5811
|
import { homedir as homedir5, platform } from "os";
|
|
5381
5812
|
var __create = Object.create;
|
|
@@ -14541,17 +14972,17 @@ var init_zod = __esm(() => {
|
|
|
14541
14972
|
init_external();
|
|
14542
14973
|
});
|
|
14543
14974
|
function getDataDir(serviceName) {
|
|
14544
|
-
const dir =
|
|
14545
|
-
|
|
14975
|
+
const dir = join4(HASNA_DIR, serviceName);
|
|
14976
|
+
mkdirSync3(dir, { recursive: true });
|
|
14546
14977
|
return dir;
|
|
14547
14978
|
}
|
|
14548
14979
|
function getDbPath(serviceName) {
|
|
14549
14980
|
const dir = getDataDir(serviceName);
|
|
14550
|
-
return
|
|
14981
|
+
return join4(dir, `${serviceName}.db`);
|
|
14551
14982
|
}
|
|
14552
14983
|
var HASNA_DIR;
|
|
14553
14984
|
var init_dotfile = __esm(() => {
|
|
14554
|
-
HASNA_DIR =
|
|
14985
|
+
HASNA_DIR = join4(homedir3(), ".hasna");
|
|
14555
14986
|
});
|
|
14556
14987
|
var exports_config = {};
|
|
14557
14988
|
__export2(exports_config, {
|
|
@@ -14574,7 +15005,7 @@ function getCloudConfig() {
|
|
|
14574
15005
|
return CloudConfigSchema.parse({});
|
|
14575
15006
|
}
|
|
14576
15007
|
try {
|
|
14577
|
-
const raw =
|
|
15008
|
+
const raw = readFileSync3(CONFIG_PATH, "utf-8");
|
|
14578
15009
|
return CloudConfigSchema.parse(JSON.parse(raw));
|
|
14579
15010
|
} catch {
|
|
14580
15011
|
return CloudConfigSchema.parse({});
|
|
@@ -14582,7 +15013,7 @@ function getCloudConfig() {
|
|
|
14582
15013
|
}
|
|
14583
15014
|
function saveCloudConfig(config) {
|
|
14584
15015
|
mkdirSync22(CONFIG_DIR, { recursive: true });
|
|
14585
|
-
|
|
15016
|
+
writeFileSync3(CONFIG_PATH, JSON.stringify(config, null, 2) + `
|
|
14586
15017
|
`, "utf-8");
|
|
14587
15018
|
}
|
|
14588
15019
|
function getConnectionString(dbName) {
|
|
@@ -14646,7 +15077,7 @@ function isSyncExcludedTable(table) {
|
|
|
14646
15077
|
return SYNC_EXCLUDED_TABLE_PATTERNS.some((p) => p.test(table));
|
|
14647
15078
|
}
|
|
14648
15079
|
function discoverServices() {
|
|
14649
|
-
const dataDir = join32(
|
|
15080
|
+
const dataDir = join32(homedir32(), ".hasna");
|
|
14650
15081
|
if (!existsSync32(dataDir))
|
|
14651
15082
|
return [];
|
|
14652
15083
|
try {
|
|
@@ -14668,7 +15099,7 @@ function discoverSyncableServices() {
|
|
|
14668
15099
|
return local.filter((s) => pgSet.has(s));
|
|
14669
15100
|
}
|
|
14670
15101
|
function getServiceDbPath(service) {
|
|
14671
|
-
const dataDir = join32(
|
|
15102
|
+
const dataDir = join32(homedir32(), ".hasna", service);
|
|
14672
15103
|
if (!existsSync32(dataDir))
|
|
14673
15104
|
return null;
|
|
14674
15105
|
const candidates = [
|
|
@@ -14865,7 +15296,7 @@ class SyncProgressTracker {
|
|
|
14865
15296
|
init_adapter();
|
|
14866
15297
|
init_config();
|
|
14867
15298
|
init_discover();
|
|
14868
|
-
var AUTO_SYNC_CONFIG_PATH =
|
|
15299
|
+
var AUTO_SYNC_CONFIG_PATH = join42(homedir4(), ".hasna", "cloud", "config.json");
|
|
14869
15300
|
init_config();
|
|
14870
15301
|
init_adapter();
|
|
14871
15302
|
init_dotfile();
|
|
@@ -14885,13 +15316,13 @@ init_adapter();
|
|
|
14885
15316
|
// src/db/database.ts
|
|
14886
15317
|
import { dirname as dirname3, join as join5 } from "path";
|
|
14887
15318
|
import { homedir as homedir6 } from "os";
|
|
14888
|
-
import { mkdirSync as
|
|
15319
|
+
import { mkdirSync as mkdirSync4, existsSync as existsSync5, readdirSync as readdirSync4, copyFileSync as copyFileSync2, statSync } from "fs";
|
|
14889
15320
|
function mergeDirectoryContents(sourceDir, targetDir) {
|
|
14890
|
-
if (!
|
|
15321
|
+
if (!existsSync5(sourceDir)) {
|
|
14891
15322
|
return;
|
|
14892
15323
|
}
|
|
14893
|
-
|
|
14894
|
-
for (const entry of
|
|
15324
|
+
mkdirSync4(targetDir, { recursive: true });
|
|
15325
|
+
for (const entry of readdirSync4(sourceDir)) {
|
|
14895
15326
|
const sourcePath = join5(sourceDir, entry);
|
|
14896
15327
|
const targetPath = join5(targetDir, entry);
|
|
14897
15328
|
try {
|
|
@@ -14900,7 +15331,7 @@ function mergeDirectoryContents(sourceDir, targetDir) {
|
|
|
14900
15331
|
mergeDirectoryContents(sourcePath, targetPath);
|
|
14901
15332
|
continue;
|
|
14902
15333
|
}
|
|
14903
|
-
if (!
|
|
15334
|
+
if (!existsSync5(targetPath)) {
|
|
14904
15335
|
copyFileSync2(sourcePath, targetPath);
|
|
14905
15336
|
}
|
|
14906
15337
|
} catch {}
|
|
@@ -14910,7 +15341,7 @@ function getConnectorsHome() {
|
|
|
14910
15341
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || homedir6();
|
|
14911
15342
|
const newDir = join5(home, ".hasna", "connectors");
|
|
14912
15343
|
const legacyDirs = [join5(home, ".connectors"), join5(home, ".connect")];
|
|
14913
|
-
|
|
15344
|
+
mkdirSync4(newDir, { recursive: true });
|
|
14914
15345
|
for (const legacyDir of legacyDirs) {
|
|
14915
15346
|
try {
|
|
14916
15347
|
mergeDirectoryContents(legacyDir, newDir);
|
|
@@ -15089,19 +15520,19 @@ function getProfilesDir() {
|
|
|
15089
15520
|
}
|
|
15090
15521
|
function getCurrentProfile() {
|
|
15091
15522
|
const currentProfileFile = join7(getConfigDir2(), "current_profile");
|
|
15092
|
-
if (!
|
|
15523
|
+
if (!existsSync6(currentProfileFile)) {
|
|
15093
15524
|
return "default";
|
|
15094
15525
|
}
|
|
15095
15526
|
try {
|
|
15096
|
-
return
|
|
15527
|
+
return readFileSync4(currentProfileFile, "utf-8").trim() || "default";
|
|
15097
15528
|
} catch {
|
|
15098
15529
|
return "default";
|
|
15099
15530
|
}
|
|
15100
15531
|
}
|
|
15101
15532
|
function setCurrentProfile(profile) {
|
|
15102
15533
|
const configDir = getConfigDir2();
|
|
15103
|
-
|
|
15104
|
-
|
|
15534
|
+
mkdirSync5(configDir, { recursive: true });
|
|
15535
|
+
writeFileSync4(join7(configDir, "current_profile"), profile);
|
|
15105
15536
|
}
|
|
15106
15537
|
function getFlatProfilePath(profile) {
|
|
15107
15538
|
return join7(getProfilesDir(), `${profile}.json`);
|
|
@@ -15111,7 +15542,7 @@ function getDirectoryProfilePath(profile) {
|
|
|
15111
15542
|
}
|
|
15112
15543
|
function loadJsonFile(path) {
|
|
15113
15544
|
try {
|
|
15114
|
-
return JSON.parse(
|
|
15545
|
+
return JSON.parse(readFileSync4(path, "utf-8"));
|
|
15115
15546
|
} catch {
|
|
15116
15547
|
return {};
|
|
15117
15548
|
}
|
|
@@ -15127,8 +15558,8 @@ function sanitizeProfileConfig(config) {
|
|
|
15127
15558
|
};
|
|
15128
15559
|
}
|
|
15129
15560
|
function loadProfile(profile = getCurrentProfile()) {
|
|
15130
|
-
const flatConfig =
|
|
15131
|
-
const directoryConfig =
|
|
15561
|
+
const flatConfig = existsSync6(getFlatProfilePath(profile)) ? loadJsonFile(getFlatProfilePath(profile)) : {};
|
|
15562
|
+
const directoryConfig = existsSync6(getDirectoryProfilePath(profile)) ? loadJsonFile(getDirectoryProfilePath(profile)) : {};
|
|
15132
15563
|
return sanitizeProfileConfig({
|
|
15133
15564
|
...flatConfig,
|
|
15134
15565
|
...directoryConfig
|
|
@@ -15136,24 +15567,24 @@ function loadProfile(profile = getCurrentProfile()) {
|
|
|
15136
15567
|
}
|
|
15137
15568
|
function writeProfile(profile, config) {
|
|
15138
15569
|
const profilesDir = getProfilesDir();
|
|
15139
|
-
|
|
15140
|
-
|
|
15570
|
+
mkdirSync5(profilesDir, { recursive: true });
|
|
15571
|
+
writeFileSync4(getFlatProfilePath(profile), JSON.stringify(config, null, 2) + `
|
|
15141
15572
|
`);
|
|
15142
15573
|
}
|
|
15143
15574
|
function profileExists(profile) {
|
|
15144
15575
|
if (profile === "default") {
|
|
15145
15576
|
return true;
|
|
15146
15577
|
}
|
|
15147
|
-
return
|
|
15578
|
+
return existsSync6(getFlatProfilePath(profile)) || existsSync6(join7(getProfilesDir(), profile));
|
|
15148
15579
|
}
|
|
15149
|
-
function
|
|
15580
|
+
function listProfiles3() {
|
|
15150
15581
|
const profilesDir = getProfilesDir();
|
|
15151
15582
|
const seen = new Set(["default"]);
|
|
15152
|
-
if (!
|
|
15583
|
+
if (!existsSync6(profilesDir)) {
|
|
15153
15584
|
return [...seen];
|
|
15154
15585
|
}
|
|
15155
15586
|
try {
|
|
15156
|
-
for (const entry of
|
|
15587
|
+
for (const entry of readdirSync5(profilesDir)) {
|
|
15157
15588
|
const fullPath = join7(profilesDir, entry);
|
|
15158
15589
|
const stat = statSync2(fullPath);
|
|
15159
15590
|
if (stat.isDirectory()) {
|
|
@@ -15176,10 +15607,10 @@ function createProfile(profile, config = {}) {
|
|
|
15176
15607
|
function clearProfile(profile = getCurrentProfile()) {
|
|
15177
15608
|
const flatPath = getFlatProfilePath(profile);
|
|
15178
15609
|
const directoryPath = join7(getProfilesDir(), profile);
|
|
15179
|
-
if (
|
|
15610
|
+
if (existsSync6(flatPath)) {
|
|
15180
15611
|
rmSync(flatPath);
|
|
15181
15612
|
}
|
|
15182
|
-
if (
|
|
15613
|
+
if (existsSync6(directoryPath)) {
|
|
15183
15614
|
rmSync(directoryPath, { recursive: true, force: true });
|
|
15184
15615
|
}
|
|
15185
15616
|
}
|
|
@@ -15475,7 +15906,7 @@ async function sendMessage(context, input) {
|
|
|
15475
15906
|
direction: "outbound"
|
|
15476
15907
|
});
|
|
15477
15908
|
}
|
|
15478
|
-
async function
|
|
15909
|
+
async function replyToMessage2(context, input) {
|
|
15479
15910
|
const payload = await bridgeRequest(context, "/messages/reply", {
|
|
15480
15911
|
method: "POST",
|
|
15481
15912
|
body: {
|
|
@@ -15589,7 +16020,7 @@ async function runProfileCommand2(args, context) {
|
|
|
15589
16020
|
switch (subcommand) {
|
|
15590
16021
|
case "list": {
|
|
15591
16022
|
const current = getCurrentProfile();
|
|
15592
|
-
const profiles =
|
|
16023
|
+
const profiles = listProfiles3();
|
|
15593
16024
|
return successOutput({ current, profiles }, context.format, () => profiles.map((profile) => `${profile}${profile === current ? " (active)" : ""}`).join(`
|
|
15594
16025
|
`));
|
|
15595
16026
|
}
|
|
@@ -15763,7 +16194,7 @@ async function runMessageCommand(args, context) {
|
|
|
15763
16194
|
if (!conversationId || !text) {
|
|
15764
16195
|
return failure2("Usage: connect-imessage message reply --conversation <id> --text <text>");
|
|
15765
16196
|
}
|
|
15766
|
-
return successOutput(await
|
|
16197
|
+
return successOutput(await replyToMessage2(resolved, {
|
|
15767
16198
|
conversationId,
|
|
15768
16199
|
text,
|
|
15769
16200
|
replyToMessageId: asString2(options.replyTo),
|
|
@@ -15921,7 +16352,7 @@ var imessageConnector = defineConnector({
|
|
|
15921
16352
|
summary: "Reply to an existing conversation through the bridge",
|
|
15922
16353
|
inputSchema: messageReplyInputSchema,
|
|
15923
16354
|
async execute({ context }, input) {
|
|
15924
|
-
return
|
|
16355
|
+
return replyToMessage2(context, input);
|
|
15925
16356
|
}
|
|
15926
16357
|
}
|
|
15927
16358
|
},
|
|
@@ -15984,19 +16415,19 @@ var imessageConnector = defineConnector({
|
|
|
15984
16415
|
});
|
|
15985
16416
|
|
|
15986
16417
|
// src/core/connectors/stripe.ts
|
|
15987
|
-
import { existsSync as
|
|
15988
|
-
import { dirname as dirname4, join as
|
|
16418
|
+
import { existsSync as existsSync7 } from "fs";
|
|
16419
|
+
import { dirname as dirname4, join as join9 } from "path";
|
|
15989
16420
|
import { fileURLToPath as fileURLToPath2, pathToFileURL as pathToFileURL2 } from "url";
|
|
15990
16421
|
var __dirname3 = dirname4(fileURLToPath2(import.meta.url));
|
|
15991
16422
|
function resolveStripeConnectorDir() {
|
|
15992
16423
|
const candidates = [
|
|
15993
|
-
|
|
15994
|
-
|
|
15995
|
-
|
|
15996
|
-
|
|
16424
|
+
join9(__dirname3, "..", "..", "..", "connectors", "connect-stripe"),
|
|
16425
|
+
join9(__dirname3, "..", "..", "connectors", "connect-stripe"),
|
|
16426
|
+
join9(__dirname3, "..", "connectors", "connect-stripe"),
|
|
16427
|
+
join9(process.cwd(), "connectors", "connect-stripe")
|
|
15997
16428
|
];
|
|
15998
16429
|
for (const candidate of candidates) {
|
|
15999
|
-
if (
|
|
16430
|
+
if (existsSync7(candidate)) {
|
|
16000
16431
|
return candidate;
|
|
16001
16432
|
}
|
|
16002
16433
|
}
|
|
@@ -16235,10 +16666,10 @@ function buildCommandHelp2(spec) {
|
|
|
16235
16666
|
var ROOT_HELP3 = buildRootHelp2(COMMAND_SPECS2);
|
|
16236
16667
|
var COMMAND_HELP3 = Object.fromEntries(COMMAND_SPECS2.map((spec) => [spec.name, buildCommandHelp2(spec)]));
|
|
16237
16668
|
async function loadStripeApiModule() {
|
|
16238
|
-
return await import(pathToFileURL2(
|
|
16669
|
+
return await import(pathToFileURL2(join9(CONNECTOR_DIR2, "src", "api", "index.ts")).href);
|
|
16239
16670
|
}
|
|
16240
16671
|
async function loadStripeConfigModule() {
|
|
16241
|
-
return await import(pathToFileURL2(
|
|
16672
|
+
return await import(pathToFileURL2(join9(CONNECTOR_DIR2, "src", "utils", "config.ts")).href);
|
|
16242
16673
|
}
|
|
16243
16674
|
function extractGlobalArgs3(args) {
|
|
16244
16675
|
const remaining = [];
|
|
@@ -16850,6 +17281,7 @@ var stripeConnector = defineConnector({
|
|
|
16850
17281
|
|
|
16851
17282
|
// src/core/builtins.ts
|
|
16852
17283
|
var INTERNAL_CONNECTOR_DEFINITIONS = [
|
|
17284
|
+
gmailConnector,
|
|
16853
17285
|
githubConnector,
|
|
16854
17286
|
googleDriveConnector,
|
|
16855
17287
|
imessageConnector,
|
|
@@ -23134,17 +23566,17 @@ function loadConnectorVersions() {
|
|
|
23134
23566
|
versionsLoaded = true;
|
|
23135
23567
|
const thisDir = dirname5(fileURLToPath3(import.meta.url));
|
|
23136
23568
|
const candidates = [
|
|
23137
|
-
|
|
23138
|
-
|
|
23569
|
+
join10(thisDir, "..", "connectors"),
|
|
23570
|
+
join10(thisDir, "..", "..", "connectors")
|
|
23139
23571
|
];
|
|
23140
|
-
const connectorsDir = candidates.find((d) =>
|
|
23572
|
+
const connectorsDir = candidates.find((d) => existsSync8(d));
|
|
23141
23573
|
if (!connectorsDir)
|
|
23142
23574
|
return;
|
|
23143
23575
|
for (const connector of CONNECTORS) {
|
|
23144
23576
|
try {
|
|
23145
|
-
const pkgPath =
|
|
23146
|
-
if (
|
|
23147
|
-
const pkg = JSON.parse(
|
|
23577
|
+
const pkgPath = join10(connectorsDir, `connect-${connector.name}`, "package.json");
|
|
23578
|
+
if (existsSync8(pkgPath)) {
|
|
23579
|
+
const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
|
|
23148
23580
|
connector.version = pkg.version || "0.0.0";
|
|
23149
23581
|
continue;
|
|
23150
23582
|
}
|
|
@@ -23156,16 +23588,16 @@ function loadConnectorVersions() {
|
|
|
23156
23588
|
}
|
|
23157
23589
|
}
|
|
23158
23590
|
// src/lib/installer.ts
|
|
23159
|
-
import { existsSync as
|
|
23160
|
-
import { join as
|
|
23591
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5, readdirSync as readdirSync6, statSync as statSync3, rmSync as rmSync2 } from "fs";
|
|
23592
|
+
import { join as join11, dirname as dirname6 } from "path";
|
|
23161
23593
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
23162
23594
|
var __dirname4 = dirname6(fileURLToPath4(import.meta.url));
|
|
23163
23595
|
function resolveConnectorsDir() {
|
|
23164
|
-
const fromBin =
|
|
23165
|
-
if (
|
|
23596
|
+
const fromBin = join11(__dirname4, "..", "connectors");
|
|
23597
|
+
if (existsSync9(fromBin))
|
|
23166
23598
|
return fromBin;
|
|
23167
|
-
const fromSrc =
|
|
23168
|
-
if (
|
|
23599
|
+
const fromSrc = join11(__dirname4, "..", "..", "connectors");
|
|
23600
|
+
if (existsSync9(fromSrc))
|
|
23169
23601
|
return fromSrc;
|
|
23170
23602
|
return fromBin;
|
|
23171
23603
|
}
|
|
@@ -23177,21 +23609,21 @@ function normalizeConnectorName(name) {
|
|
|
23177
23609
|
return name.startsWith("connect-") ? name.slice("connect-".length) : name;
|
|
23178
23610
|
}
|
|
23179
23611
|
function getProjectConnectorsDir(targetDir) {
|
|
23180
|
-
return
|
|
23612
|
+
return join11(targetDir, PROJECT_CONNECTORS_DIRNAME);
|
|
23181
23613
|
}
|
|
23182
23614
|
function getEnablementManifestPath(targetDir) {
|
|
23183
|
-
return
|
|
23615
|
+
return join11(getProjectConnectorsDir(targetDir), ENABLEMENT_MANIFEST_FILENAME);
|
|
23184
23616
|
}
|
|
23185
23617
|
function getLegacyInstallPath(targetDir, name) {
|
|
23186
|
-
return
|
|
23618
|
+
return join11(getProjectConnectorsDir(targetDir), `connect-${normalizeConnectorName(name)}`);
|
|
23187
23619
|
}
|
|
23188
23620
|
function loadEnablementManifest(targetDir) {
|
|
23189
23621
|
const manifestPath = getEnablementManifestPath(targetDir);
|
|
23190
|
-
if (!
|
|
23622
|
+
if (!existsSync9(manifestPath)) {
|
|
23191
23623
|
return null;
|
|
23192
23624
|
}
|
|
23193
23625
|
try {
|
|
23194
|
-
const raw = JSON.parse(
|
|
23626
|
+
const raw = JSON.parse(readFileSync6(manifestPath, "utf-8"));
|
|
23195
23627
|
if (!Array.isArray(raw.connectors)) {
|
|
23196
23628
|
return null;
|
|
23197
23629
|
}
|
|
@@ -23207,11 +23639,11 @@ function loadEnablementManifest(targetDir) {
|
|
|
23207
23639
|
}
|
|
23208
23640
|
function getLegacyInstalledConnectors(targetDir) {
|
|
23209
23641
|
const connectorsDir = getProjectConnectorsDir(targetDir);
|
|
23210
|
-
if (!
|
|
23642
|
+
if (!existsSync9(connectorsDir)) {
|
|
23211
23643
|
return [];
|
|
23212
23644
|
}
|
|
23213
|
-
return
|
|
23214
|
-
const fullPath =
|
|
23645
|
+
return readdirSync6(connectorsDir).filter((entry) => {
|
|
23646
|
+
const fullPath = join11(connectorsDir, entry);
|
|
23215
23647
|
return entry.startsWith("connect-") && statSync3(fullPath).isDirectory();
|
|
23216
23648
|
}).map((entry) => entry.replace("connect-", "")).sort();
|
|
23217
23649
|
}
|
|
@@ -23220,7 +23652,7 @@ function getEnabledConnectors(targetDir) {
|
|
|
23220
23652
|
return [...new Set([...manifestConnectors, ...getLegacyInstalledConnectors(targetDir)])].sort();
|
|
23221
23653
|
}
|
|
23222
23654
|
function updateConnectorsIndex(connectorsDir, connectors18) {
|
|
23223
|
-
const indexPath =
|
|
23655
|
+
const indexPath = join11(connectorsDir, ENABLEMENT_INDEX_FILENAME);
|
|
23224
23656
|
const connectorList = connectors18.map((connector) => ` "${connector}",`).join(`
|
|
23225
23657
|
`);
|
|
23226
23658
|
const content = `/**
|
|
@@ -23236,28 +23668,28 @@ ${connectorList}
|
|
|
23236
23668
|
|
|
23237
23669
|
export type EnabledConnectorName = typeof enabledConnectors[number];
|
|
23238
23670
|
`;
|
|
23239
|
-
|
|
23671
|
+
writeFileSync5(indexPath, content);
|
|
23240
23672
|
}
|
|
23241
23673
|
function writeEnablementManifest(targetDir, connectors18) {
|
|
23242
23674
|
const connectorsDir = getProjectConnectorsDir(targetDir);
|
|
23243
|
-
|
|
23675
|
+
mkdirSync6(connectorsDir, { recursive: true });
|
|
23244
23676
|
const manifest = {
|
|
23245
23677
|
version: 1,
|
|
23246
23678
|
mode: "internal",
|
|
23247
23679
|
updatedAt: new Date().toISOString(),
|
|
23248
23680
|
connectors: [...new Set(connectors18.map((value) => normalizeConnectorName(value)))].sort()
|
|
23249
23681
|
};
|
|
23250
|
-
|
|
23682
|
+
writeFileSync5(getEnablementManifestPath(targetDir), JSON.stringify(manifest, null, 2) + `
|
|
23251
23683
|
`);
|
|
23252
23684
|
updateConnectorsIndex(connectorsDir, manifest.connectors);
|
|
23253
23685
|
}
|
|
23254
23686
|
function getConnectorPath(name) {
|
|
23255
23687
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
23256
|
-
return
|
|
23688
|
+
return join11(CONNECTORS_DIR, connectorName);
|
|
23257
23689
|
}
|
|
23258
23690
|
function connectorExists(name) {
|
|
23259
23691
|
const normalizedName = normalizeConnectorName(name);
|
|
23260
|
-
return hasInternalConnectorDefinition(normalizedName) ||
|
|
23692
|
+
return hasInternalConnectorDefinition(normalizedName) || existsSync9(getConnectorPath(normalizedName));
|
|
23261
23693
|
}
|
|
23262
23694
|
function installConnector(name, options = {}) {
|
|
23263
23695
|
const { targetDir = process.cwd(), overwrite = false } = options;
|
|
@@ -23290,7 +23722,7 @@ function installConnector(name, options = {}) {
|
|
|
23290
23722
|
try {
|
|
23291
23723
|
const nextEnabled = [...new Set([...installed, normalizedName])].sort();
|
|
23292
23724
|
writeEnablementManifest(targetDir, nextEnabled);
|
|
23293
|
-
if (overwrite &&
|
|
23725
|
+
if (overwrite && existsSync9(legacyInstallPath)) {
|
|
23294
23726
|
rmSync2(legacyInstallPath, { recursive: true });
|
|
23295
23727
|
}
|
|
23296
23728
|
return {
|
|
@@ -23325,9 +23757,9 @@ function parseConnectorDocs(raw) {
|
|
|
23325
23757
|
function getConnectorDocs(name) {
|
|
23326
23758
|
const normalizedName = normalizeConnectorName(name);
|
|
23327
23759
|
const connectorPath = getConnectorPath(normalizedName);
|
|
23328
|
-
const claudeMdPath =
|
|
23329
|
-
if (
|
|
23330
|
-
return parseConnectorDocs(
|
|
23760
|
+
const claudeMdPath = join11(connectorPath, "CLAUDE.md");
|
|
23761
|
+
if (existsSync9(claudeMdPath)) {
|
|
23762
|
+
return parseConnectorDocs(readFileSync6(claudeMdPath, "utf-8"));
|
|
23331
23763
|
}
|
|
23332
23764
|
const internalDocs = getInternalConnectorDefinition(normalizedName)?.docsMarkdown;
|
|
23333
23765
|
if (internalDocs) {
|
|
@@ -23371,20 +23803,20 @@ function removeConnector(name, targetDir = process.cwd()) {
|
|
|
23371
23803
|
const nextEnabled = installed.filter((connector) => connector !== normalizedName);
|
|
23372
23804
|
writeEnablementManifest(targetDir, nextEnabled);
|
|
23373
23805
|
const legacyInstallPath = getLegacyInstallPath(targetDir, normalizedName);
|
|
23374
|
-
if (
|
|
23806
|
+
if (existsSync9(legacyInstallPath)) {
|
|
23375
23807
|
rmSync2(legacyInstallPath, { recursive: true });
|
|
23376
23808
|
}
|
|
23377
23809
|
return true;
|
|
23378
23810
|
}
|
|
23379
23811
|
// src/lib/runner.ts
|
|
23380
|
-
import { existsSync as
|
|
23381
|
-
import { join as
|
|
23812
|
+
import { existsSync as existsSync11, readdirSync as readdirSync8 } from "fs";
|
|
23813
|
+
import { join as join13, dirname as dirname7 } from "path";
|
|
23382
23814
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
23383
23815
|
import { spawn } from "child_process";
|
|
23384
23816
|
|
|
23385
23817
|
// src/server/auth.ts
|
|
23386
|
-
import { existsSync as
|
|
23387
|
-
import { join as
|
|
23818
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7, writeFileSync as writeFileSync6, mkdirSync as mkdirSync7, readdirSync as readdirSync7, rmSync as rmSync3, statSync as statSync4 } from "fs";
|
|
23819
|
+
import { join as join12 } from "path";
|
|
23388
23820
|
var oauthStateStore = new Map;
|
|
23389
23821
|
var GOOGLE_SCOPES = {
|
|
23390
23822
|
gmail: [
|
|
@@ -23437,14 +23869,14 @@ function getAuthType(name) {
|
|
|
23437
23869
|
}
|
|
23438
23870
|
function getConnectorConfigDir(name) {
|
|
23439
23871
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
23440
|
-
return
|
|
23872
|
+
return join12(getConnectorsHome(), connectorName);
|
|
23441
23873
|
}
|
|
23442
23874
|
function getCurrentProfile2(name) {
|
|
23443
23875
|
const configDir = getConnectorConfigDir(name);
|
|
23444
|
-
const currentProfileFile =
|
|
23445
|
-
if (
|
|
23876
|
+
const currentProfileFile = join12(configDir, "current_profile");
|
|
23877
|
+
if (existsSync10(currentProfileFile)) {
|
|
23446
23878
|
try {
|
|
23447
|
-
return
|
|
23879
|
+
return readFileSync7(currentProfileFile, "utf-8").trim() || "default";
|
|
23448
23880
|
} catch {
|
|
23449
23881
|
return "default";
|
|
23450
23882
|
}
|
|
@@ -23456,16 +23888,16 @@ function loadProfileConfig(name) {
|
|
|
23456
23888
|
const profile = getCurrentProfile2(name);
|
|
23457
23889
|
let flatConfig = {};
|
|
23458
23890
|
let dirConfig = {};
|
|
23459
|
-
const profileFile =
|
|
23460
|
-
if (
|
|
23891
|
+
const profileFile = join12(configDir, "profiles", `${profile}.json`);
|
|
23892
|
+
if (existsSync10(profileFile)) {
|
|
23461
23893
|
try {
|
|
23462
|
-
flatConfig = JSON.parse(
|
|
23894
|
+
flatConfig = JSON.parse(readFileSync7(profileFile, "utf-8"));
|
|
23463
23895
|
} catch {}
|
|
23464
23896
|
}
|
|
23465
|
-
const profileDirConfig =
|
|
23466
|
-
if (
|
|
23897
|
+
const profileDirConfig = join12(configDir, "profiles", profile, "config.json");
|
|
23898
|
+
if (existsSync10(profileDirConfig)) {
|
|
23467
23899
|
try {
|
|
23468
|
-
dirConfig = JSON.parse(
|
|
23900
|
+
dirConfig = JSON.parse(readFileSync7(profileDirConfig, "utf-8"));
|
|
23469
23901
|
} catch {}
|
|
23470
23902
|
}
|
|
23471
23903
|
if (Object.keys(flatConfig).length === 0 && Object.keys(dirConfig).length === 0) {
|
|
@@ -23473,13 +23905,13 @@ function loadProfileConfig(name) {
|
|
|
23473
23905
|
}
|
|
23474
23906
|
return { ...flatConfig, ...dirConfig };
|
|
23475
23907
|
}
|
|
23476
|
-
function
|
|
23908
|
+
function loadTokens3(name) {
|
|
23477
23909
|
const configDir = getConnectorConfigDir(name);
|
|
23478
23910
|
const profile = getCurrentProfile2(name);
|
|
23479
|
-
const tokensFile =
|
|
23480
|
-
if (
|
|
23911
|
+
const tokensFile = join12(configDir, "profiles", profile, "tokens.json");
|
|
23912
|
+
if (existsSync10(tokensFile)) {
|
|
23481
23913
|
try {
|
|
23482
|
-
return JSON.parse(
|
|
23914
|
+
return JSON.parse(readFileSync7(tokensFile, "utf-8"));
|
|
23483
23915
|
} catch {
|
|
23484
23916
|
return null;
|
|
23485
23917
|
}
|
|
@@ -23502,10 +23934,10 @@ function getEnvVars(name) {
|
|
|
23502
23934
|
}
|
|
23503
23935
|
function getOAuthConfig(name) {
|
|
23504
23936
|
const configDir = getConnectorConfigDir(name);
|
|
23505
|
-
const credentialsFile =
|
|
23506
|
-
if (
|
|
23937
|
+
const credentialsFile = join12(configDir, "credentials.json");
|
|
23938
|
+
if (existsSync10(credentialsFile)) {
|
|
23507
23939
|
try {
|
|
23508
|
-
const creds = JSON.parse(
|
|
23940
|
+
const creds = JSON.parse(readFileSync7(credentialsFile, "utf-8"));
|
|
23509
23941
|
return { clientId: creds.clientId, clientSecret: creds.clientSecret };
|
|
23510
23942
|
} catch {}
|
|
23511
23943
|
}
|
|
@@ -23519,11 +23951,11 @@ function getOAuthConfig(name) {
|
|
|
23519
23951
|
// src/lib/runner.ts
|
|
23520
23952
|
var __dirname5 = dirname7(fileURLToPath5(import.meta.url));
|
|
23521
23953
|
function resolveConnectorsDir2() {
|
|
23522
|
-
const fromBin =
|
|
23523
|
-
if (
|
|
23954
|
+
const fromBin = join13(__dirname5, "..", "connectors");
|
|
23955
|
+
if (existsSync11(fromBin))
|
|
23524
23956
|
return fromBin;
|
|
23525
|
-
const fromSrc =
|
|
23526
|
-
if (
|
|
23957
|
+
const fromSrc = join13(__dirname5, "..", "..", "connectors");
|
|
23958
|
+
if (existsSync11(fromSrc))
|
|
23527
23959
|
return fromSrc;
|
|
23528
23960
|
return fromBin;
|
|
23529
23961
|
}
|
|
@@ -23576,7 +24008,7 @@ function buildEnvWithCredentials(connectorName, baseEnv) {
|
|
|
23576
24008
|
}
|
|
23577
24009
|
if (getAuthType(connectorName) === "oauth") {
|
|
23578
24010
|
const oauthConfig = getOAuthConfig(connectorName);
|
|
23579
|
-
const tokens =
|
|
24011
|
+
const tokens = loadTokens3(connectorName);
|
|
23580
24012
|
for (const { variable } of getEnvVars(connectorName)) {
|
|
23581
24013
|
if (env[variable])
|
|
23582
24014
|
continue;
|
|
@@ -23597,9 +24029,9 @@ function buildEnvWithCredentials(connectorName, baseEnv) {
|
|
|
23597
24029
|
}
|
|
23598
24030
|
function getConnectorCliPath(name) {
|
|
23599
24031
|
const safeName = name.replace(/[^a-z0-9-]/g, "");
|
|
23600
|
-
const connectorDir =
|
|
23601
|
-
const cliPath =
|
|
23602
|
-
if (
|
|
24032
|
+
const connectorDir = join13(CONNECTORS_DIR2, `connect-${safeName}`);
|
|
24033
|
+
const cliPath = join13(connectorDir, "src", "cli", "index.ts");
|
|
24034
|
+
if (existsSync11(cliPath))
|
|
23603
24035
|
return cliPath;
|
|
23604
24036
|
return null;
|
|
23605
24037
|
}
|
|
@@ -23871,7 +24303,7 @@ async function getConnectorCommandHelp(name, command) {
|
|
|
23871
24303
|
function getConnectorsWithCli() {
|
|
23872
24304
|
const connectors18 = new Set;
|
|
23873
24305
|
try {
|
|
23874
|
-
const dirs =
|
|
24306
|
+
const dirs = readdirSync8(CONNECTORS_DIR2);
|
|
23875
24307
|
for (const dir of dirs) {
|
|
23876
24308
|
if (!dir.startsWith("connect-"))
|
|
23877
24309
|
continue;
|