@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/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 existsSync7, readFileSync as readFileSync4 } from "fs";
19
- import { join as join9, dirname as dirname5 } from "path";
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 = /^[a-z0-9:._-]+$/;
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/googledrive.ts
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 DRIVE_API_BASE = "https://www.googleapis.com/drive/v3";
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: listProfiles() })
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) => requestJson(context.profile, "/files", {
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) => requestJson(context.profile, `/files/${encodeURIComponent(input.fileId)}`, {
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 requestJson(context.profile, `/files/${encodeURIComponent(input.fileId)}`, { fields: DEFAULT_FILE_FIELDS, supportsAllDrives: true });
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) => requestJson(context.profile, "/drives", {
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 requestJson(profile, path, params) {
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 getValidAccessToken(profile);
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 getValidAccessToken(profile) {
5561
+ async function getValidAccessToken2(profile) {
5131
5562
  if (process.env.GOOGLE_ACCESS_TOKEN)
5132
5563
  return process.env.GOOGLE_ACCESS_TOKEN;
5133
- const tokens = loadTokens(profile);
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 - REFRESH_BUFFER_MS))
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 refreshAccessToken(profile, tokens)).accessToken ?? "";
5572
+ return (await refreshAccessToken2(profile, tokens)).accessToken ?? "";
5142
5573
  }
5143
- async function refreshAccessToken(profile, currentTokens) {
5144
- const credentials = loadCredentials(profile);
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(TOKEN_URL, {
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
- saveTokens(profile, tokens);
5600
+ saveTokens2(profile, tokens);
5170
5601
  return tokens;
5171
5602
  }
5172
- function listProfiles() {
5603
+ function listProfiles2() {
5173
5604
  const profiles = new Set;
5174
- for (const baseDir of configDirs()) {
5175
- const profilesDir = join2(baseDir, "profiles");
5176
- if (!existsSync2(profilesDir))
5605
+ for (const baseDir of configDirs2()) {
5606
+ const profilesDir = join3(baseDir, "profiles");
5607
+ if (!existsSync3(profilesDir))
5177
5608
  continue;
5178
- for (const entry of readdirSync(profilesDir, { withFileTypes: true })) {
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(basename(entry.name, ".json"));
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 loadCredentials(profile) {
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 configDirs()) {
5623
+ for (const baseDir of configDirs2()) {
5193
5624
  const credentials = {
5194
- ...readJson(join2(baseDir, "credentials.json")),
5195
- ...readJson(join2(baseDir, "profiles", profile, "config.json"))
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 loadTokens(profile) {
5203
- for (const baseDir of configDirs()) {
5204
- const fromProfile = readJson(join2(baseDir, "profiles", profile, "tokens.json"));
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 = readJson(join2(baseDir, "profiles", `${profile}.json`));
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 saveTokens(profile, tokens) {
5214
- const baseDir = configDirs().find((dir) => existsSync2(dir)) ?? configDirs()[0];
5215
- const profileDir = join2(baseDir, "profiles", profile);
5216
- mkdirSync(profileDir, { recursive: true });
5217
- writeFileSync(join2(profileDir, "tokens.json"), JSON.stringify(tokens, null, 2), { mode: 384 });
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 configDirs() {
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 ?? join2(homedir(), ".hasna", "connectors");
5224
- return [join2(baseDir, "connect-googledrive"), join2(baseDir, "googledrive")];
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 readJson(path) {
5227
- if (!existsSync2(path))
5657
+ function readJson2(path) {
5658
+ if (!existsSync3(path))
5228
5659
  return null;
5229
5660
  try {
5230
- return JSON.parse(readFileSync(path, "utf8"));
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.25",
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 existsSync5,
5351
- mkdirSync as mkdirSync4,
5352
- readFileSync as readFileSync3,
5353
- readdirSync as readdirSync4,
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 writeFileSync3
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 existsSync3,
5365
- mkdirSync as mkdirSync2,
5366
- readdirSync as readdirSync2,
5795
+ existsSync as existsSync4,
5796
+ mkdirSync as mkdirSync3,
5797
+ readdirSync as readdirSync3,
5367
5798
  copyFileSync
5368
5799
  } from "fs";
5369
- import { homedir as homedir2 } from "os";
5370
- import { join as join3, relative } from "path";
5371
- import { existsSync as existsSync22, mkdirSync as mkdirSync22, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
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 homedir3 } from "os";
5807
+ import { homedir as homedir32 } from "os";
5377
5808
  import { homedir as homedir4 } from "os";
5378
- import { join as join4 } from "path";
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 = join3(HASNA_DIR, serviceName);
14545
- mkdirSync2(dir, { recursive: true });
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 join3(dir, `${serviceName}.db`);
14981
+ return join4(dir, `${serviceName}.db`);
14551
14982
  }
14552
14983
  var HASNA_DIR;
14553
14984
  var init_dotfile = __esm(() => {
14554
- HASNA_DIR = join3(homedir2(), ".hasna");
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 = readFileSync2(CONFIG_PATH, "utf-8");
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
- writeFileSync2(CONFIG_PATH, JSON.stringify(config, null, 2) + `
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(homedir3(), ".hasna");
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(homedir3(), ".hasna", service);
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 = join4(homedir4(), ".hasna", "cloud", "config.json");
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 mkdirSync3, existsSync as existsSync4, readdirSync as readdirSync3, copyFileSync as copyFileSync2, statSync } from "fs";
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 (!existsSync4(sourceDir)) {
15321
+ if (!existsSync5(sourceDir)) {
14891
15322
  return;
14892
15323
  }
14893
- mkdirSync3(targetDir, { recursive: true });
14894
- for (const entry of readdirSync3(sourceDir)) {
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 (!existsSync4(targetPath)) {
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
- mkdirSync3(newDir, { recursive: true });
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 (!existsSync5(currentProfileFile)) {
15523
+ if (!existsSync6(currentProfileFile)) {
15093
15524
  return "default";
15094
15525
  }
15095
15526
  try {
15096
- return readFileSync3(currentProfileFile, "utf-8").trim() || "default";
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
- mkdirSync4(configDir, { recursive: true });
15104
- writeFileSync3(join7(configDir, "current_profile"), profile);
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(readFileSync3(path, "utf-8"));
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 = existsSync5(getFlatProfilePath(profile)) ? loadJsonFile(getFlatProfilePath(profile)) : {};
15131
- const directoryConfig = existsSync5(getDirectoryProfilePath(profile)) ? loadJsonFile(getDirectoryProfilePath(profile)) : {};
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
- mkdirSync4(profilesDir, { recursive: true });
15140
- writeFileSync3(getFlatProfilePath(profile), JSON.stringify(config, null, 2) + `
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 existsSync5(getFlatProfilePath(profile)) || existsSync5(join7(getProfilesDir(), profile));
15578
+ return existsSync6(getFlatProfilePath(profile)) || existsSync6(join7(getProfilesDir(), profile));
15148
15579
  }
15149
- function listProfiles2() {
15580
+ function listProfiles3() {
15150
15581
  const profilesDir = getProfilesDir();
15151
15582
  const seen = new Set(["default"]);
15152
- if (!existsSync5(profilesDir)) {
15583
+ if (!existsSync6(profilesDir)) {
15153
15584
  return [...seen];
15154
15585
  }
15155
15586
  try {
15156
- for (const entry of readdirSync4(profilesDir)) {
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 (existsSync5(flatPath)) {
15610
+ if (existsSync6(flatPath)) {
15180
15611
  rmSync(flatPath);
15181
15612
  }
15182
- if (existsSync5(directoryPath)) {
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 replyToMessage(context, input) {
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 = listProfiles2();
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 replyToMessage(resolved, {
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 replyToMessage(context, input);
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 existsSync6 } from "fs";
15988
- import { dirname as dirname4, join as join8 } from "path";
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
- join8(__dirname3, "..", "..", "..", "connectors", "connect-stripe"),
15994
- join8(__dirname3, "..", "..", "connectors", "connect-stripe"),
15995
- join8(__dirname3, "..", "connectors", "connect-stripe"),
15996
- join8(process.cwd(), "connectors", "connect-stripe")
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 (existsSync6(candidate)) {
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(join8(CONNECTOR_DIR2, "src", "api", "index.ts")).href);
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(join8(CONNECTOR_DIR2, "src", "utils", "config.ts")).href);
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
- join9(thisDir, "..", "connectors"),
23138
- join9(thisDir, "..", "..", "connectors")
23569
+ join10(thisDir, "..", "connectors"),
23570
+ join10(thisDir, "..", "..", "connectors")
23139
23571
  ];
23140
- const connectorsDir = candidates.find((d) => existsSync7(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 = join9(connectorsDir, `connect-${connector.name}`, "package.json");
23146
- if (existsSync7(pkgPath)) {
23147
- const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
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 existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4, readdirSync as readdirSync5, statSync as statSync3, rmSync as rmSync2 } from "fs";
23160
- import { join as join10, dirname as dirname6 } from "path";
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 = join10(__dirname4, "..", "connectors");
23165
- if (existsSync8(fromBin))
23596
+ const fromBin = join11(__dirname4, "..", "connectors");
23597
+ if (existsSync9(fromBin))
23166
23598
  return fromBin;
23167
- const fromSrc = join10(__dirname4, "..", "..", "connectors");
23168
- if (existsSync8(fromSrc))
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 join10(targetDir, PROJECT_CONNECTORS_DIRNAME);
23612
+ return join11(targetDir, PROJECT_CONNECTORS_DIRNAME);
23181
23613
  }
23182
23614
  function getEnablementManifestPath(targetDir) {
23183
- return join10(getProjectConnectorsDir(targetDir), ENABLEMENT_MANIFEST_FILENAME);
23615
+ return join11(getProjectConnectorsDir(targetDir), ENABLEMENT_MANIFEST_FILENAME);
23184
23616
  }
23185
23617
  function getLegacyInstallPath(targetDir, name) {
23186
- return join10(getProjectConnectorsDir(targetDir), `connect-${normalizeConnectorName(name)}`);
23618
+ return join11(getProjectConnectorsDir(targetDir), `connect-${normalizeConnectorName(name)}`);
23187
23619
  }
23188
23620
  function loadEnablementManifest(targetDir) {
23189
23621
  const manifestPath = getEnablementManifestPath(targetDir);
23190
- if (!existsSync8(manifestPath)) {
23622
+ if (!existsSync9(manifestPath)) {
23191
23623
  return null;
23192
23624
  }
23193
23625
  try {
23194
- const raw = JSON.parse(readFileSync5(manifestPath, "utf-8"));
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 (!existsSync8(connectorsDir)) {
23642
+ if (!existsSync9(connectorsDir)) {
23211
23643
  return [];
23212
23644
  }
23213
- return readdirSync5(connectorsDir).filter((entry) => {
23214
- const fullPath = join10(connectorsDir, entry);
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 = join10(connectorsDir, ENABLEMENT_INDEX_FILENAME);
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
- writeFileSync4(indexPath, content);
23671
+ writeFileSync5(indexPath, content);
23240
23672
  }
23241
23673
  function writeEnablementManifest(targetDir, connectors18) {
23242
23674
  const connectorsDir = getProjectConnectorsDir(targetDir);
23243
- mkdirSync5(connectorsDir, { recursive: true });
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
- writeFileSync4(getEnablementManifestPath(targetDir), JSON.stringify(manifest, null, 2) + `
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 join10(CONNECTORS_DIR, connectorName);
23688
+ return join11(CONNECTORS_DIR, connectorName);
23257
23689
  }
23258
23690
  function connectorExists(name) {
23259
23691
  const normalizedName = normalizeConnectorName(name);
23260
- return hasInternalConnectorDefinition(normalizedName) || existsSync8(getConnectorPath(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 && existsSync8(legacyInstallPath)) {
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 = join10(connectorPath, "CLAUDE.md");
23329
- if (existsSync8(claudeMdPath)) {
23330
- return parseConnectorDocs(readFileSync5(claudeMdPath, "utf-8"));
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 (existsSync8(legacyInstallPath)) {
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 existsSync10, readdirSync as readdirSync7 } from "fs";
23381
- import { join as join12, dirname as dirname7 } from "path";
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 existsSync9, readFileSync as readFileSync6, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, readdirSync as readdirSync6, rmSync as rmSync3, statSync as statSync4 } from "fs";
23387
- import { join as join11 } from "path";
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 join11(getConnectorsHome(), connectorName);
23872
+ return join12(getConnectorsHome(), connectorName);
23441
23873
  }
23442
23874
  function getCurrentProfile2(name) {
23443
23875
  const configDir = getConnectorConfigDir(name);
23444
- const currentProfileFile = join11(configDir, "current_profile");
23445
- if (existsSync9(currentProfileFile)) {
23876
+ const currentProfileFile = join12(configDir, "current_profile");
23877
+ if (existsSync10(currentProfileFile)) {
23446
23878
  try {
23447
- return readFileSync6(currentProfileFile, "utf-8").trim() || "default";
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 = join11(configDir, "profiles", `${profile}.json`);
23460
- if (existsSync9(profileFile)) {
23891
+ const profileFile = join12(configDir, "profiles", `${profile}.json`);
23892
+ if (existsSync10(profileFile)) {
23461
23893
  try {
23462
- flatConfig = JSON.parse(readFileSync6(profileFile, "utf-8"));
23894
+ flatConfig = JSON.parse(readFileSync7(profileFile, "utf-8"));
23463
23895
  } catch {}
23464
23896
  }
23465
- const profileDirConfig = join11(configDir, "profiles", profile, "config.json");
23466
- if (existsSync9(profileDirConfig)) {
23897
+ const profileDirConfig = join12(configDir, "profiles", profile, "config.json");
23898
+ if (existsSync10(profileDirConfig)) {
23467
23899
  try {
23468
- dirConfig = JSON.parse(readFileSync6(profileDirConfig, "utf-8"));
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 loadTokens2(name) {
23908
+ function loadTokens3(name) {
23477
23909
  const configDir = getConnectorConfigDir(name);
23478
23910
  const profile = getCurrentProfile2(name);
23479
- const tokensFile = join11(configDir, "profiles", profile, "tokens.json");
23480
- if (existsSync9(tokensFile)) {
23911
+ const tokensFile = join12(configDir, "profiles", profile, "tokens.json");
23912
+ if (existsSync10(tokensFile)) {
23481
23913
  try {
23482
- return JSON.parse(readFileSync6(tokensFile, "utf-8"));
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 = join11(configDir, "credentials.json");
23506
- if (existsSync9(credentialsFile)) {
23937
+ const credentialsFile = join12(configDir, "credentials.json");
23938
+ if (existsSync10(credentialsFile)) {
23507
23939
  try {
23508
- const creds = JSON.parse(readFileSync6(credentialsFile, "utf-8"));
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 = join12(__dirname5, "..", "connectors");
23523
- if (existsSync10(fromBin))
23954
+ const fromBin = join13(__dirname5, "..", "connectors");
23955
+ if (existsSync11(fromBin))
23524
23956
  return fromBin;
23525
- const fromSrc = join12(__dirname5, "..", "..", "connectors");
23526
- if (existsSync10(fromSrc))
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 = loadTokens2(connectorName);
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 = join12(CONNECTORS_DIR2, `connect-${safeName}`);
23601
- const cliPath = join12(connectorDir, "src", "cli", "index.ts");
23602
- if (existsSync10(cliPath))
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 = readdirSync7(CONNECTORS_DIR2);
24306
+ const dirs = readdirSync8(CONNECTORS_DIR2);
23875
24307
  for (const dir of dirs) {
23876
24308
  if (!dir.startsWith("connect-"))
23877
24309
  continue;