@hasna/connectors 1.3.23 → 1.3.25

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.
Files changed (36) hide show
  1. package/bin/index.js +492 -153
  2. package/bin/mcp.js +1078 -595
  3. package/bin/serve.js +774 -436
  4. package/connectors/connect-cloudflare/bun.lock +32 -0
  5. package/connectors/connect-gmail/bin/index.js +7027 -0
  6. package/connectors/connect-googledrive/bin/index.js +5958 -0
  7. package/connectors/connect-imessage/bin/.gitkeep +2 -0
  8. package/connectors/connect-imessage/bin/index.js +3016 -0
  9. package/connectors/connect-imessage/bun.lock +32 -0
  10. package/connectors/connect-imessage/package.json +46 -0
  11. package/connectors/connect-imessage/src/api/client.ts +139 -0
  12. package/connectors/connect-imessage/src/api/conversations.ts +49 -0
  13. package/connectors/connect-imessage/src/api/health.ts +16 -0
  14. package/connectors/connect-imessage/src/api/index.ts +62 -0
  15. package/connectors/connect-imessage/src/api/messages.ts +119 -0
  16. package/connectors/connect-imessage/src/cli/index.ts +258 -0
  17. package/connectors/connect-imessage/src/index.ts +26 -0
  18. package/connectors/connect-imessage/src/types/index.ts +134 -0
  19. package/connectors/connect-imessage/src/utils/config.ts +219 -0
  20. package/connectors/connect-imessage/src/utils/output.ts +121 -0
  21. package/connectors/connect-imessage/tsconfig.json +16 -0
  22. package/dist/core/builtins.test.d.ts +1 -0
  23. package/dist/core/connectors/googledrive.d.ts +6 -0
  24. package/dist/core/connectors/internal-operations.test.d.ts +1 -0
  25. package/dist/core/connectors/internal-runtime.test.d.ts +1 -0
  26. package/dist/core/errors.test.d.ts +1 -0
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.js +640 -86
  29. package/dist/lib/runner-auth.test.d.ts +1 -0
  30. package/dist/lib/runner.d.ts +31 -0
  31. package/dist/lib/test-endpoints.test.d.ts +1 -0
  32. package/dist/lib/workflow-runner.d.ts +7 -0
  33. package/dist/server/auth-exchange.test.d.ts +1 -0
  34. package/dist/server/auth-refresh.test.d.ts +1 -0
  35. package/dist/server/auth.d.ts +1 -0
  36. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ var __export = (target, all) => {
15
15
  };
16
16
 
17
17
  // src/lib/registry.ts
18
- import { existsSync as existsSync8, readFileSync as readFileSync3 } from "fs";
18
+ import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
19
19
  import { join as join9, dirname as dirname5 } from "path";
20
20
  import { fileURLToPath as fileURLToPath3 } from "url";
21
21
 
@@ -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-z0-9:._-]+$/;
46
46
  function defineConnector(definition) {
47
47
  const { meta, auth, operations } = definition;
48
48
  if (!CONNECTOR_NAME_RE.test(meta.name)) {
@@ -136,7 +136,7 @@ import { existsSync } from "fs";
136
136
  import { dirname, join } from "path";
137
137
  import { fileURLToPath, pathToFileURL } from "url";
138
138
 
139
- // ../../../home/hasna/workspace/hasna/opensource/open-connectors/node_modules/zod/v3/external.js
139
+ // node_modules/zod/v3/external.js
140
140
  var exports_external = {};
141
141
  __export(exports_external, {
142
142
  void: () => voidType,
@@ -248,7 +248,7 @@ __export(exports_external, {
248
248
  BRAND: () => BRAND
249
249
  });
250
250
 
251
- // ../../../home/hasna/workspace/hasna/opensource/open-connectors/node_modules/zod/v3/helpers/util.js
251
+ // node_modules/zod/v3/helpers/util.js
252
252
  var util;
253
253
  (function(util2) {
254
254
  util2.assertEqual = (_) => {};
@@ -379,7 +379,7 @@ var getParsedType = (data) => {
379
379
  }
380
380
  };
381
381
 
382
- // ../../../home/hasna/workspace/hasna/opensource/open-connectors/node_modules/zod/v3/ZodError.js
382
+ // node_modules/zod/v3/ZodError.js
383
383
  var ZodIssueCode = util.arrayToEnum([
384
384
  "invalid_type",
385
385
  "invalid_literal",
@@ -498,7 +498,7 @@ ZodError.create = (issues) => {
498
498
  return error;
499
499
  };
500
500
 
501
- // ../../../home/hasna/workspace/hasna/opensource/open-connectors/node_modules/zod/v3/locales/en.js
501
+ // node_modules/zod/v3/locales/en.js
502
502
  var errorMap = (issue, _ctx) => {
503
503
  let message;
504
504
  switch (issue.code) {
@@ -601,7 +601,7 @@ var errorMap = (issue, _ctx) => {
601
601
  };
602
602
  var en_default = errorMap;
603
603
 
604
- // ../../../home/hasna/workspace/hasna/opensource/open-connectors/node_modules/zod/v3/errors.js
604
+ // node_modules/zod/v3/errors.js
605
605
  var overrideErrorMap = en_default;
606
606
  function setErrorMap(map) {
607
607
  overrideErrorMap = map;
@@ -609,7 +609,7 @@ function setErrorMap(map) {
609
609
  function getErrorMap() {
610
610
  return overrideErrorMap;
611
611
  }
612
- // ../../../home/hasna/workspace/hasna/opensource/open-connectors/node_modules/zod/v3/helpers/parseUtil.js
612
+ // node_modules/zod/v3/helpers/parseUtil.js
613
613
  var makeIssue = (params) => {
614
614
  const { data, path, errorMaps, issueData } = params;
615
615
  const fullPath = [...path, ...issueData.path || []];
@@ -715,14 +715,14 @@ var isAborted = (x) => x.status === "aborted";
715
715
  var isDirty = (x) => x.status === "dirty";
716
716
  var isValid = (x) => x.status === "valid";
717
717
  var isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise;
718
- // ../../../home/hasna/workspace/hasna/opensource/open-connectors/node_modules/zod/v3/helpers/errorUtil.js
718
+ // node_modules/zod/v3/helpers/errorUtil.js
719
719
  var errorUtil;
720
720
  (function(errorUtil2) {
721
721
  errorUtil2.errToObj = (message) => typeof message === "string" ? { message } : message || {};
722
722
  errorUtil2.toString = (message) => typeof message === "string" ? message : message?.message;
723
723
  })(errorUtil || (errorUtil = {}));
724
724
 
725
- // ../../../home/hasna/workspace/hasna/opensource/open-connectors/node_modules/zod/v3/types.js
725
+ // node_modules/zod/v3/types.js
726
726
  class ParseInputLazyPath {
727
727
  constructor(parent, value, path, key) {
728
728
  this._cachedPath = [];
@@ -4966,10 +4966,300 @@ var githubConnector = defineConnector({
4966
4966
  }
4967
4967
  }
4968
4968
  });
4969
+
4970
+ // src/core/connectors/googledrive.ts
4971
+ import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, writeFileSync } from "fs";
4972
+ import { homedir } from "os";
4973
+ import { basename, join as join2 } from "path";
4974
+ var DRIVE_API_BASE = "https://www.googleapis.com/drive/v3";
4975
+ var TOKEN_URL = "https://oauth2.googleapis.com/token";
4976
+ var REFRESH_BUFFER_MS = 5 * 60 * 1000;
4977
+ var DEFAULT_FILE_FIELDS = [
4978
+ "id",
4979
+ "name",
4980
+ "mimeType",
4981
+ "parents",
4982
+ "version",
4983
+ "md5Checksum",
4984
+ "size",
4985
+ "modifiedTime",
4986
+ "createdTime",
4987
+ "trashed",
4988
+ "webViewLink",
4989
+ "webContentLink"
4990
+ ].join(",");
4991
+ var DEFAULT_EXPORT_FORMATS = {
4992
+ document: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
4993
+ spreadsheet: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
4994
+ presentation: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
4995
+ drawing: "image/png"
4996
+ };
4997
+ var EXPORT_EXTENSIONS = {
4998
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": ".docx",
4999
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": ".xlsx",
5000
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation": ".pptx",
5001
+ "application/pdf": ".pdf",
5002
+ "text/plain": ".txt",
5003
+ "text/csv": ".csv",
5004
+ "image/png": ".png",
5005
+ "image/jpeg": ".jpg",
5006
+ "image/svg+xml": ".svg"
5007
+ };
5008
+ var listFilesSchema = exports_external.object({
5009
+ pageSize: exports_external.coerce.number().int().positive().max(1000).optional(),
5010
+ pageToken: exports_external.string().optional(),
5011
+ q: exports_external.string().optional(),
5012
+ fields: exports_external.string().optional(),
5013
+ orderBy: exports_external.string().optional(),
5014
+ corpora: exports_external.enum(["user", "drive", "allDrives"]).optional(),
5015
+ driveId: exports_external.string().optional(),
5016
+ supportsAllDrives: exports_external.boolean().optional(),
5017
+ includeItemsFromAllDrives: exports_external.boolean().optional()
5018
+ });
5019
+ var listDrivesSchema = exports_external.object({
5020
+ pageSize: exports_external.coerce.number().int().positive().max(100).optional(),
5021
+ pageToken: exports_external.string().optional(),
5022
+ q: exports_external.string().optional()
5023
+ });
5024
+ var fileIdSchema = exports_external.object({
5025
+ fileId: exports_external.string(),
5026
+ fields: exports_external.string().optional()
5027
+ });
5028
+ var downloadSchema = exports_external.object({
5029
+ fileId: exports_external.string(),
5030
+ file: exports_external.object({
5031
+ id: exports_external.string(),
5032
+ name: exports_external.string(),
5033
+ mimeType: exports_external.string()
5034
+ }).optional(),
5035
+ exportMimeType: exports_external.string().optional()
5036
+ });
5037
+ var googleDriveConnector = defineConnector({
5038
+ meta: {
5039
+ name: "googledrive",
5040
+ displayName: "Google Drive",
5041
+ description: "Profile-aware Google Drive discovery and file download operations.",
5042
+ category: "storage",
5043
+ tags: ["google", "drive", "files", "storage"]
5044
+ },
5045
+ auth: {
5046
+ type: "oauth2",
5047
+ supportsProfiles: true,
5048
+ fields: [
5049
+ { key: "clientId", env: "GOOGLE_CLIENT_ID", label: "OAuth client ID" },
5050
+ { key: "clientSecret", env: "GOOGLE_CLIENT_SECRET", label: "OAuth client secret", secret: true }
5051
+ ]
5052
+ },
5053
+ createContext: ({ profile }) => ({ profile: profile || "default" }),
5054
+ operations: {
5055
+ "profiles.list": {
5056
+ summary: "List configured Google Drive profiles.",
5057
+ execute: () => ({ profiles: listProfiles() })
5058
+ },
5059
+ "files.list": {
5060
+ summary: "List Google Drive files.",
5061
+ inputSchema: listFilesSchema,
5062
+ execute: async ({ context }, input) => requestJson(context.profile, "/files", {
5063
+ pageSize: input.pageSize ?? 1000,
5064
+ pageToken: input.pageToken,
5065
+ q: input.q,
5066
+ fields: input.fields ?? `nextPageToken,files(${DEFAULT_FILE_FIELDS})`,
5067
+ orderBy: input.orderBy ?? "modifiedTime desc",
5068
+ corpora: input.corpora,
5069
+ driveId: input.driveId,
5070
+ supportsAllDrives: input.supportsAllDrives ?? true,
5071
+ includeItemsFromAllDrives: input.includeItemsFromAllDrives ?? false
5072
+ })
5073
+ },
5074
+ "files.get": {
5075
+ summary: "Get Google Drive file metadata.",
5076
+ inputSchema: fileIdSchema,
5077
+ execute: async ({ context }, input) => requestJson(context.profile, `/files/${encodeURIComponent(input.fileId)}`, {
5078
+ fields: input.fields ?? DEFAULT_FILE_FIELDS,
5079
+ supportsAllDrives: true
5080
+ })
5081
+ },
5082
+ "files.download": {
5083
+ summary: "Download or export a Google Drive file as base64 content.",
5084
+ inputSchema: downloadSchema,
5085
+ execute: async ({ context }, input) => {
5086
+ const file = input.file ?? await requestJson(context.profile, `/files/${encodeURIComponent(input.fileId)}`, { fields: DEFAULT_FILE_FIELDS, supportsAllDrives: true });
5087
+ const exportMimeType = file.mimeType.startsWith("application/vnd.google-apps.") ? input.exportMimeType ?? defaultExportMimeType(file.mimeType) : undefined;
5088
+ 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
+ const mimeType = exportMimeType ?? file.mimeType ?? "application/octet-stream";
5090
+ return {
5091
+ dataBase64: Buffer.from(data).toString("base64"),
5092
+ filename: exportMimeType ? `${file.name}${extensionForMimeType(exportMimeType)}` : file.name,
5093
+ mimeType
5094
+ };
5095
+ }
5096
+ },
5097
+ "drives.list": {
5098
+ summary: "List Google shared drives.",
5099
+ inputSchema: listDrivesSchema,
5100
+ execute: async ({ context }, input) => requestJson(context.profile, "/drives", {
5101
+ pageSize: input.pageSize ?? 100,
5102
+ pageToken: input.pageToken,
5103
+ q: input.q
5104
+ })
5105
+ }
5106
+ }
5107
+ });
5108
+ async function requestJson(profile, path, params) {
5109
+ const response = await request(profile, path, params);
5110
+ const text = await response.text();
5111
+ return text ? JSON.parse(text) : {};
5112
+ }
5113
+ async function requestBinary(profile, path, params) {
5114
+ return (await request(profile, path, params)).arrayBuffer();
5115
+ }
5116
+ async function request(profile, path, params) {
5117
+ const token = await getValidAccessToken(profile);
5118
+ const url = new URL(`${DRIVE_API_BASE}${path}`);
5119
+ for (const [key, value] of Object.entries(params)) {
5120
+ if (value !== undefined && value !== null && value !== "")
5121
+ url.searchParams.set(key, String(value));
5122
+ }
5123
+ const response = await fetch(url, { headers: { Authorization: `Bearer ${token}`, Accept: "application/json" } });
5124
+ if (!response.ok) {
5125
+ const body = await response.text().catch(() => "");
5126
+ throw new Error(`Google Drive request failed (${response.status}): ${extractGoogleError(body) || response.statusText}`);
5127
+ }
5128
+ return response;
5129
+ }
5130
+ async function getValidAccessToken(profile) {
5131
+ if (process.env.GOOGLE_ACCESS_TOKEN)
5132
+ return process.env.GOOGLE_ACCESS_TOKEN;
5133
+ const tokens = loadTokens(profile);
5134
+ if (!tokens?.accessToken && !tokens?.refreshToken) {
5135
+ throw new Error(`Google Drive profile "${profile}" is not authenticated. Run: connectors auth googledrive`);
5136
+ }
5137
+ if (tokens.accessToken && (!tokens.expiresAt || Date.now() < tokens.expiresAt - REFRESH_BUFFER_MS))
5138
+ return tokens.accessToken;
5139
+ if (!tokens.refreshToken)
5140
+ return tokens.accessToken ?? "";
5141
+ return (await refreshAccessToken(profile, tokens)).accessToken ?? "";
5142
+ }
5143
+ async function refreshAccessToken(profile, currentTokens) {
5144
+ const credentials = loadCredentials(profile);
5145
+ if (!credentials.clientId || !credentials.clientSecret)
5146
+ throw new Error("Google Drive OAuth credentials are not configured. Run: connectors auth googledrive");
5147
+ if (!currentTokens.refreshToken)
5148
+ throw new Error(`Google Drive profile "${profile}" has no refresh token. Run: connectors auth googledrive`);
5149
+ const response = await fetch(TOKEN_URL, {
5150
+ method: "POST",
5151
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
5152
+ body: new URLSearchParams({
5153
+ client_id: credentials.clientId,
5154
+ client_secret: credentials.clientSecret,
5155
+ refresh_token: currentTokens.refreshToken,
5156
+ grant_type: "refresh_token"
5157
+ })
5158
+ });
5159
+ const data = await response.json().catch(() => ({}));
5160
+ if (!response.ok || !data.access_token)
5161
+ throw new Error(`Google Drive token refresh failed: ${data.error_description || data.error || response.statusText}`);
5162
+ const tokens = {
5163
+ accessToken: data.access_token,
5164
+ refreshToken: currentTokens.refreshToken,
5165
+ expiresAt: Date.now() + (data.expires_in ?? 3600) * 1000,
5166
+ tokenType: data.token_type ?? currentTokens.tokenType,
5167
+ scope: data.scope ?? currentTokens.scope
5168
+ };
5169
+ saveTokens(profile, tokens);
5170
+ return tokens;
5171
+ }
5172
+ function listProfiles() {
5173
+ const profiles = new Set;
5174
+ for (const baseDir of configDirs()) {
5175
+ const profilesDir = join2(baseDir, "profiles");
5176
+ if (!existsSync2(profilesDir))
5177
+ continue;
5178
+ for (const entry of readdirSync(profilesDir, { withFileTypes: true })) {
5179
+ if (entry.isDirectory())
5180
+ profiles.add(entry.name);
5181
+ if (entry.isFile() && entry.name.endsWith(".json"))
5182
+ profiles.add(basename(entry.name, ".json"));
5183
+ }
5184
+ }
5185
+ return Array.from(profiles).sort((a, b) => a.localeCompare(b));
5186
+ }
5187
+ function loadCredentials(profile) {
5188
+ const envClientId = process.env.GOOGLE_CLIENT_ID;
5189
+ const envClientSecret = process.env.GOOGLE_CLIENT_SECRET;
5190
+ if (envClientId && envClientSecret)
5191
+ return { clientId: envClientId, clientSecret: envClientSecret };
5192
+ for (const baseDir of configDirs()) {
5193
+ const credentials = {
5194
+ ...readJson(join2(baseDir, "credentials.json")),
5195
+ ...readJson(join2(baseDir, "profiles", profile, "config.json"))
5196
+ };
5197
+ if (credentials.clientId || credentials.clientSecret)
5198
+ return credentials;
5199
+ }
5200
+ return {};
5201
+ }
5202
+ function loadTokens(profile) {
5203
+ for (const baseDir of configDirs()) {
5204
+ const fromProfile = readJson(join2(baseDir, "profiles", profile, "tokens.json"));
5205
+ if (fromProfile)
5206
+ return fromProfile;
5207
+ const flat = readJson(join2(baseDir, "profiles", `${profile}.json`));
5208
+ if (flat)
5209
+ return flat.tokens ?? (flat.accessToken || flat.refreshToken ? flat : null);
5210
+ }
5211
+ return null;
5212
+ }
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 });
5218
+ }
5219
+ function configDirs() {
5220
+ const explicit = process.env.HASNA_GOOGLE_DRIVE_CONNECTOR_DIR ?? process.env.GOOGLE_DRIVE_CONNECTOR_DIR;
5221
+ if (explicit)
5222
+ return [explicit];
5223
+ const baseDir = process.env.HASNA_CONNECTORS_DIR ?? join2(homedir(), ".hasna", "connectors");
5224
+ return [join2(baseDir, "connect-googledrive"), join2(baseDir, "googledrive")];
5225
+ }
5226
+ function readJson(path) {
5227
+ if (!existsSync2(path))
5228
+ return null;
5229
+ try {
5230
+ return JSON.parse(readFileSync(path, "utf8"));
5231
+ } catch {
5232
+ return null;
5233
+ }
5234
+ }
5235
+ function defaultExportMimeType(googleMimeType) {
5236
+ if (googleMimeType.endsWith(".document"))
5237
+ return DEFAULT_EXPORT_FORMATS.document;
5238
+ if (googleMimeType.endsWith(".spreadsheet"))
5239
+ return DEFAULT_EXPORT_FORMATS.spreadsheet;
5240
+ if (googleMimeType.endsWith(".presentation"))
5241
+ return DEFAULT_EXPORT_FORMATS.presentation;
5242
+ if (googleMimeType.endsWith(".drawing"))
5243
+ return DEFAULT_EXPORT_FORMATS.drawing;
5244
+ throw new Error(`Cannot export Google Workspace file type: ${googleMimeType}`);
5245
+ }
5246
+ function extensionForMimeType(mimeType) {
5247
+ return EXPORT_EXTENSIONS[mimeType] ?? "";
5248
+ }
5249
+ function extractGoogleError(body) {
5250
+ if (!body)
5251
+ return "";
5252
+ try {
5253
+ const parsed = JSON.parse(body);
5254
+ return parsed.error?.message ?? body;
5255
+ } catch {
5256
+ return body;
5257
+ }
5258
+ }
4969
5259
  // package.json
4970
5260
  var package_default = {
4971
5261
  name: "@hasna/connectors",
4972
- version: "1.3.23",
5262
+ version: "1.3.25",
4973
5263
  description: "Open source connector library - Install API connectors with a single command",
4974
5264
  type: "module",
4975
5265
  bin: {
@@ -5057,32 +5347,32 @@ var package_default = {
5057
5347
 
5058
5348
  // src/core/connectors/imessage.ts
5059
5349
  import {
5060
- existsSync as existsSync6,
5061
- mkdirSync as mkdirSync5,
5062
- readFileSync as readFileSync2,
5063
- readdirSync as readdirSync5,
5350
+ existsSync as existsSync5,
5351
+ mkdirSync as mkdirSync4,
5352
+ readFileSync as readFileSync3,
5353
+ readdirSync as readdirSync4,
5064
5354
  rmSync,
5065
5355
  statSync as statSync2,
5066
- writeFileSync as writeFileSync2
5356
+ writeFileSync as writeFileSync3
5067
5357
  } from "fs";
5068
5358
  import { join as join7 } from "path";
5069
5359
 
5070
- // ../../../home/hasna/workspace/hasna/opensource/open-connectors/node_modules/@hasna/cloud/dist/index.js
5360
+ // node_modules/@hasna/cloud/dist/index.js
5071
5361
  import { createRequire } from "module";
5072
5362
  import { Database } from "bun:sqlite";
5073
5363
  import {
5074
- existsSync as existsSync2,
5075
- mkdirSync,
5076
- readdirSync,
5364
+ existsSync as existsSync3,
5365
+ mkdirSync as mkdirSync2,
5366
+ readdirSync as readdirSync2,
5077
5367
  copyFileSync
5078
5368
  } from "fs";
5079
- import { homedir } from "os";
5080
- import { join as join2, relative } from "path";
5081
- import { existsSync as existsSync22, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "fs";
5082
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";
5372
+ import { homedir as homedir22 } from "os";
5083
5373
  import { join as join22 } from "path";
5084
- import { readdirSync as readdirSync2, existsSync as existsSync3 } from "fs";
5085
- import { join as join3 } from "path";
5374
+ import { readdirSync as readdirSync22, existsSync as existsSync32 } from "fs";
5375
+ import { join as join32 } from "path";
5086
5376
  import { homedir as homedir3 } from "os";
5087
5377
  import { homedir as homedir4 } from "os";
5088
5378
  import { join as join4 } from "path";
@@ -14251,17 +14541,17 @@ var init_zod = __esm(() => {
14251
14541
  init_external();
14252
14542
  });
14253
14543
  function getDataDir(serviceName) {
14254
- const dir = join2(HASNA_DIR, serviceName);
14255
- mkdirSync(dir, { recursive: true });
14544
+ const dir = join3(HASNA_DIR, serviceName);
14545
+ mkdirSync2(dir, { recursive: true });
14256
14546
  return dir;
14257
14547
  }
14258
14548
  function getDbPath(serviceName) {
14259
14549
  const dir = getDataDir(serviceName);
14260
- return join2(dir, `${serviceName}.db`);
14550
+ return join3(dir, `${serviceName}.db`);
14261
14551
  }
14262
14552
  var HASNA_DIR;
14263
14553
  var init_dotfile = __esm(() => {
14264
- HASNA_DIR = join2(homedir(), ".hasna");
14554
+ HASNA_DIR = join3(homedir2(), ".hasna");
14265
14555
  });
14266
14556
  var exports_config = {};
14267
14557
  __export2(exports_config, {
@@ -14284,15 +14574,15 @@ function getCloudConfig() {
14284
14574
  return CloudConfigSchema.parse({});
14285
14575
  }
14286
14576
  try {
14287
- const raw = readFileSync(CONFIG_PATH, "utf-8");
14577
+ const raw = readFileSync2(CONFIG_PATH, "utf-8");
14288
14578
  return CloudConfigSchema.parse(JSON.parse(raw));
14289
14579
  } catch {
14290
14580
  return CloudConfigSchema.parse({});
14291
14581
  }
14292
14582
  }
14293
14583
  function saveCloudConfig(config) {
14294
- mkdirSync2(CONFIG_DIR, { recursive: true });
14295
- writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + `
14584
+ mkdirSync22(CONFIG_DIR, { recursive: true });
14585
+ writeFileSync2(CONFIG_PATH, JSON.stringify(config, null, 2) + `
14296
14586
  `, "utf-8");
14297
14587
  }
14298
14588
  function getConnectionString(dbName) {
@@ -14340,7 +14630,7 @@ var init_config = __esm(() => {
14340
14630
  schedule_minutes: exports_external2.number().default(0)
14341
14631
  }).default({})
14342
14632
  });
14343
- CONFIG_DIR = join22(homedir2(), ".hasna", "cloud");
14633
+ CONFIG_DIR = join22(homedir22(), ".hasna", "cloud");
14344
14634
  CONFIG_PATH = join22(CONFIG_DIR, "config.json");
14345
14635
  });
14346
14636
  var exports_discover = {};
@@ -14356,11 +14646,11 @@ function isSyncExcludedTable(table) {
14356
14646
  return SYNC_EXCLUDED_TABLE_PATTERNS.some((p) => p.test(table));
14357
14647
  }
14358
14648
  function discoverServices() {
14359
- const dataDir = join3(homedir3(), ".hasna");
14360
- if (!existsSync3(dataDir))
14649
+ const dataDir = join32(homedir3(), ".hasna");
14650
+ if (!existsSync32(dataDir))
14361
14651
  return [];
14362
14652
  try {
14363
- const entries = readdirSync2(dataDir, { withFileTypes: true });
14653
+ const entries = readdirSync22(dataDir, { withFileTypes: true });
14364
14654
  return entries.filter((e) => {
14365
14655
  if (!e.isDirectory())
14366
14656
  return false;
@@ -14378,24 +14668,24 @@ function discoverSyncableServices() {
14378
14668
  return local.filter((s) => pgSet.has(s));
14379
14669
  }
14380
14670
  function getServiceDbPath(service) {
14381
- const dataDir = join3(homedir3(), ".hasna", service);
14382
- if (!existsSync3(dataDir))
14671
+ const dataDir = join32(homedir3(), ".hasna", service);
14672
+ if (!existsSync32(dataDir))
14383
14673
  return null;
14384
14674
  const candidates = [
14385
- join3(dataDir, `${service}.db`),
14386
- join3(dataDir, "data.db"),
14387
- join3(dataDir, "database.db")
14675
+ join32(dataDir, `${service}.db`),
14676
+ join32(dataDir, "data.db"),
14677
+ join32(dataDir, "database.db")
14388
14678
  ];
14389
14679
  try {
14390
- const files = readdirSync2(dataDir);
14680
+ const files = readdirSync22(dataDir);
14391
14681
  for (const f of files) {
14392
14682
  if (f.endsWith(".db") && !f.endsWith("-wal") && !f.endsWith("-shm")) {
14393
- candidates.push(join3(dataDir, f));
14683
+ candidates.push(join32(dataDir, f));
14394
14684
  }
14395
14685
  }
14396
14686
  } catch {}
14397
14687
  for (const p of candidates) {
14398
- if (existsSync3(p))
14688
+ if (existsSync32(p))
14399
14689
  return p;
14400
14690
  }
14401
14691
  return null;
@@ -14799,19 +15089,19 @@ function getProfilesDir() {
14799
15089
  }
14800
15090
  function getCurrentProfile() {
14801
15091
  const currentProfileFile = join7(getConfigDir2(), "current_profile");
14802
- if (!existsSync6(currentProfileFile)) {
15092
+ if (!existsSync5(currentProfileFile)) {
14803
15093
  return "default";
14804
15094
  }
14805
15095
  try {
14806
- return readFileSync2(currentProfileFile, "utf-8").trim() || "default";
15096
+ return readFileSync3(currentProfileFile, "utf-8").trim() || "default";
14807
15097
  } catch {
14808
15098
  return "default";
14809
15099
  }
14810
15100
  }
14811
15101
  function setCurrentProfile(profile) {
14812
15102
  const configDir = getConfigDir2();
14813
- mkdirSync5(configDir, { recursive: true });
14814
- writeFileSync2(join7(configDir, "current_profile"), profile);
15103
+ mkdirSync4(configDir, { recursive: true });
15104
+ writeFileSync3(join7(configDir, "current_profile"), profile);
14815
15105
  }
14816
15106
  function getFlatProfilePath(profile) {
14817
15107
  return join7(getProfilesDir(), `${profile}.json`);
@@ -14821,7 +15111,7 @@ function getDirectoryProfilePath(profile) {
14821
15111
  }
14822
15112
  function loadJsonFile(path) {
14823
15113
  try {
14824
- return JSON.parse(readFileSync2(path, "utf-8"));
15114
+ return JSON.parse(readFileSync3(path, "utf-8"));
14825
15115
  } catch {
14826
15116
  return {};
14827
15117
  }
@@ -14837,8 +15127,8 @@ function sanitizeProfileConfig(config) {
14837
15127
  };
14838
15128
  }
14839
15129
  function loadProfile(profile = getCurrentProfile()) {
14840
- const flatConfig = existsSync6(getFlatProfilePath(profile)) ? loadJsonFile(getFlatProfilePath(profile)) : {};
14841
- const directoryConfig = existsSync6(getDirectoryProfilePath(profile)) ? loadJsonFile(getDirectoryProfilePath(profile)) : {};
15130
+ const flatConfig = existsSync5(getFlatProfilePath(profile)) ? loadJsonFile(getFlatProfilePath(profile)) : {};
15131
+ const directoryConfig = existsSync5(getDirectoryProfilePath(profile)) ? loadJsonFile(getDirectoryProfilePath(profile)) : {};
14842
15132
  return sanitizeProfileConfig({
14843
15133
  ...flatConfig,
14844
15134
  ...directoryConfig
@@ -14846,24 +15136,24 @@ function loadProfile(profile = getCurrentProfile()) {
14846
15136
  }
14847
15137
  function writeProfile(profile, config) {
14848
15138
  const profilesDir = getProfilesDir();
14849
- mkdirSync5(profilesDir, { recursive: true });
14850
- writeFileSync2(getFlatProfilePath(profile), JSON.stringify(config, null, 2) + `
15139
+ mkdirSync4(profilesDir, { recursive: true });
15140
+ writeFileSync3(getFlatProfilePath(profile), JSON.stringify(config, null, 2) + `
14851
15141
  `);
14852
15142
  }
14853
15143
  function profileExists(profile) {
14854
15144
  if (profile === "default") {
14855
15145
  return true;
14856
15146
  }
14857
- return existsSync6(getFlatProfilePath(profile)) || existsSync6(join7(getProfilesDir(), profile));
15147
+ return existsSync5(getFlatProfilePath(profile)) || existsSync5(join7(getProfilesDir(), profile));
14858
15148
  }
14859
- function listProfiles() {
15149
+ function listProfiles2() {
14860
15150
  const profilesDir = getProfilesDir();
14861
15151
  const seen = new Set(["default"]);
14862
- if (!existsSync6(profilesDir)) {
15152
+ if (!existsSync5(profilesDir)) {
14863
15153
  return [...seen];
14864
15154
  }
14865
15155
  try {
14866
- for (const entry of readdirSync5(profilesDir)) {
15156
+ for (const entry of readdirSync4(profilesDir)) {
14867
15157
  const fullPath = join7(profilesDir, entry);
14868
15158
  const stat = statSync2(fullPath);
14869
15159
  if (stat.isDirectory()) {
@@ -14886,10 +15176,10 @@ function createProfile(profile, config = {}) {
14886
15176
  function clearProfile(profile = getCurrentProfile()) {
14887
15177
  const flatPath = getFlatProfilePath(profile);
14888
15178
  const directoryPath = join7(getProfilesDir(), profile);
14889
- if (existsSync6(flatPath)) {
15179
+ if (existsSync5(flatPath)) {
14890
15180
  rmSync(flatPath);
14891
15181
  }
14892
- if (existsSync6(directoryPath)) {
15182
+ if (existsSync5(directoryPath)) {
14893
15183
  rmSync(directoryPath, { recursive: true, force: true });
14894
15184
  }
14895
15185
  }
@@ -15299,7 +15589,7 @@ async function runProfileCommand2(args, context) {
15299
15589
  switch (subcommand) {
15300
15590
  case "list": {
15301
15591
  const current = getCurrentProfile();
15302
- const profiles = listProfiles();
15592
+ const profiles = listProfiles2();
15303
15593
  return successOutput({ current, profiles }, context.format, () => profiles.map((profile) => `${profile}${profile === current ? " (active)" : ""}`).join(`
15304
15594
  `));
15305
15595
  }
@@ -15694,7 +15984,7 @@ var imessageConnector = defineConnector({
15694
15984
  });
15695
15985
 
15696
15986
  // src/core/connectors/stripe.ts
15697
- import { existsSync as existsSync7 } from "fs";
15987
+ import { existsSync as existsSync6 } from "fs";
15698
15988
  import { dirname as dirname4, join as join8 } from "path";
15699
15989
  import { fileURLToPath as fileURLToPath2, pathToFileURL as pathToFileURL2 } from "url";
15700
15990
  var __dirname3 = dirname4(fileURLToPath2(import.meta.url));
@@ -15706,7 +15996,7 @@ function resolveStripeConnectorDir() {
15706
15996
  join8(process.cwd(), "connectors", "connect-stripe")
15707
15997
  ];
15708
15998
  for (const candidate of candidates) {
15709
- if (existsSync7(candidate)) {
15999
+ if (existsSync6(candidate)) {
15710
16000
  return candidate;
15711
16001
  }
15712
16002
  }
@@ -16561,6 +16851,7 @@ var stripeConnector = defineConnector({
16561
16851
  // src/core/builtins.ts
16562
16852
  var INTERNAL_CONNECTOR_DEFINITIONS = [
16563
16853
  githubConnector,
16854
+ googleDriveConnector,
16564
16855
  imessageConnector,
16565
16856
  stripeConnector
16566
16857
  ];
@@ -22846,14 +23137,14 @@ function loadConnectorVersions() {
22846
23137
  join9(thisDir, "..", "connectors"),
22847
23138
  join9(thisDir, "..", "..", "connectors")
22848
23139
  ];
22849
- const connectorsDir = candidates.find((d) => existsSync8(d));
23140
+ const connectorsDir = candidates.find((d) => existsSync7(d));
22850
23141
  if (!connectorsDir)
22851
23142
  return;
22852
23143
  for (const connector of CONNECTORS) {
22853
23144
  try {
22854
23145
  const pkgPath = join9(connectorsDir, `connect-${connector.name}`, "package.json");
22855
- if (existsSync8(pkgPath)) {
22856
- const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
23146
+ if (existsSync7(pkgPath)) {
23147
+ const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
22857
23148
  connector.version = pkg.version || "0.0.0";
22858
23149
  continue;
22859
23150
  }
@@ -22865,16 +23156,16 @@ function loadConnectorVersions() {
22865
23156
  }
22866
23157
  }
22867
23158
  // src/lib/installer.ts
22868
- import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync3, readdirSync as readdirSync6, statSync as statSync3, rmSync as rmSync2 } from "fs";
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";
22869
23160
  import { join as join10, dirname as dirname6 } from "path";
22870
23161
  import { fileURLToPath as fileURLToPath4 } from "url";
22871
23162
  var __dirname4 = dirname6(fileURLToPath4(import.meta.url));
22872
23163
  function resolveConnectorsDir() {
22873
23164
  const fromBin = join10(__dirname4, "..", "connectors");
22874
- if (existsSync9(fromBin))
23165
+ if (existsSync8(fromBin))
22875
23166
  return fromBin;
22876
23167
  const fromSrc = join10(__dirname4, "..", "..", "connectors");
22877
- if (existsSync9(fromSrc))
23168
+ if (existsSync8(fromSrc))
22878
23169
  return fromSrc;
22879
23170
  return fromBin;
22880
23171
  }
@@ -22896,11 +23187,11 @@ function getLegacyInstallPath(targetDir, name) {
22896
23187
  }
22897
23188
  function loadEnablementManifest(targetDir) {
22898
23189
  const manifestPath = getEnablementManifestPath(targetDir);
22899
- if (!existsSync9(manifestPath)) {
23190
+ if (!existsSync8(manifestPath)) {
22900
23191
  return null;
22901
23192
  }
22902
23193
  try {
22903
- const raw = JSON.parse(readFileSync4(manifestPath, "utf-8"));
23194
+ const raw = JSON.parse(readFileSync5(manifestPath, "utf-8"));
22904
23195
  if (!Array.isArray(raw.connectors)) {
22905
23196
  return null;
22906
23197
  }
@@ -22916,10 +23207,10 @@ function loadEnablementManifest(targetDir) {
22916
23207
  }
22917
23208
  function getLegacyInstalledConnectors(targetDir) {
22918
23209
  const connectorsDir = getProjectConnectorsDir(targetDir);
22919
- if (!existsSync9(connectorsDir)) {
23210
+ if (!existsSync8(connectorsDir)) {
22920
23211
  return [];
22921
23212
  }
22922
- return readdirSync6(connectorsDir).filter((entry) => {
23213
+ return readdirSync5(connectorsDir).filter((entry) => {
22923
23214
  const fullPath = join10(connectorsDir, entry);
22924
23215
  return entry.startsWith("connect-") && statSync3(fullPath).isDirectory();
22925
23216
  }).map((entry) => entry.replace("connect-", "")).sort();
@@ -22945,18 +23236,18 @@ ${connectorList}
22945
23236
 
22946
23237
  export type EnabledConnectorName = typeof enabledConnectors[number];
22947
23238
  `;
22948
- writeFileSync3(indexPath, content);
23239
+ writeFileSync4(indexPath, content);
22949
23240
  }
22950
23241
  function writeEnablementManifest(targetDir, connectors18) {
22951
23242
  const connectorsDir = getProjectConnectorsDir(targetDir);
22952
- mkdirSync6(connectorsDir, { recursive: true });
23243
+ mkdirSync5(connectorsDir, { recursive: true });
22953
23244
  const manifest = {
22954
23245
  version: 1,
22955
23246
  mode: "internal",
22956
23247
  updatedAt: new Date().toISOString(),
22957
23248
  connectors: [...new Set(connectors18.map((value) => normalizeConnectorName(value)))].sort()
22958
23249
  };
22959
- writeFileSync3(getEnablementManifestPath(targetDir), JSON.stringify(manifest, null, 2) + `
23250
+ writeFileSync4(getEnablementManifestPath(targetDir), JSON.stringify(manifest, null, 2) + `
22960
23251
  `);
22961
23252
  updateConnectorsIndex(connectorsDir, manifest.connectors);
22962
23253
  }
@@ -22966,7 +23257,7 @@ function getConnectorPath(name) {
22966
23257
  }
22967
23258
  function connectorExists(name) {
22968
23259
  const normalizedName = normalizeConnectorName(name);
22969
- return hasInternalConnectorDefinition(normalizedName) || existsSync9(getConnectorPath(normalizedName));
23260
+ return hasInternalConnectorDefinition(normalizedName) || existsSync8(getConnectorPath(normalizedName));
22970
23261
  }
22971
23262
  function installConnector(name, options = {}) {
22972
23263
  const { targetDir = process.cwd(), overwrite = false } = options;
@@ -22999,7 +23290,7 @@ function installConnector(name, options = {}) {
22999
23290
  try {
23000
23291
  const nextEnabled = [...new Set([...installed, normalizedName])].sort();
23001
23292
  writeEnablementManifest(targetDir, nextEnabled);
23002
- if (overwrite && existsSync9(legacyInstallPath)) {
23293
+ if (overwrite && existsSync8(legacyInstallPath)) {
23003
23294
  rmSync2(legacyInstallPath, { recursive: true });
23004
23295
  }
23005
23296
  return {
@@ -23035,8 +23326,8 @@ function getConnectorDocs(name) {
23035
23326
  const normalizedName = normalizeConnectorName(name);
23036
23327
  const connectorPath = getConnectorPath(normalizedName);
23037
23328
  const claudeMdPath = join10(connectorPath, "CLAUDE.md");
23038
- if (existsSync9(claudeMdPath)) {
23039
- return parseConnectorDocs(readFileSync4(claudeMdPath, "utf-8"));
23329
+ if (existsSync8(claudeMdPath)) {
23330
+ return parseConnectorDocs(readFileSync5(claudeMdPath, "utf-8"));
23040
23331
  }
23041
23332
  const internalDocs = getInternalConnectorDefinition(normalizedName)?.docsMarkdown;
23042
23333
  if (internalDocs) {
@@ -23080,22 +23371,158 @@ function removeConnector(name, targetDir = process.cwd()) {
23080
23371
  const nextEnabled = installed.filter((connector) => connector !== normalizedName);
23081
23372
  writeEnablementManifest(targetDir, nextEnabled);
23082
23373
  const legacyInstallPath = getLegacyInstallPath(targetDir, normalizedName);
23083
- if (existsSync9(legacyInstallPath)) {
23374
+ if (existsSync8(legacyInstallPath)) {
23084
23375
  rmSync2(legacyInstallPath, { recursive: true });
23085
23376
  }
23086
23377
  return true;
23087
23378
  }
23088
23379
  // src/lib/runner.ts
23089
23380
  import { existsSync as existsSync10, readdirSync as readdirSync7 } from "fs";
23090
- import { join as join11, dirname as dirname7 } from "path";
23381
+ import { join as join12, dirname as dirname7 } from "path";
23091
23382
  import { fileURLToPath as fileURLToPath5 } from "url";
23092
23383
  import { spawn } from "child_process";
23384
+
23385
+ // 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";
23388
+ var oauthStateStore = new Map;
23389
+ var GOOGLE_SCOPES = {
23390
+ gmail: [
23391
+ "https://www.googleapis.com/auth/gmail.readonly",
23392
+ "https://www.googleapis.com/auth/gmail.send",
23393
+ "https://www.googleapis.com/auth/gmail.compose",
23394
+ "https://www.googleapis.com/auth/gmail.modify",
23395
+ "https://www.googleapis.com/auth/gmail.labels",
23396
+ "https://mail.google.com/"
23397
+ ].join(" "),
23398
+ googlecalendar: [
23399
+ "https://www.googleapis.com/auth/calendar",
23400
+ "https://www.googleapis.com/auth/calendar.events"
23401
+ ].join(" "),
23402
+ googledrive: [
23403
+ "https://www.googleapis.com/auth/drive",
23404
+ "https://www.googleapis.com/auth/drive.file"
23405
+ ].join(" "),
23406
+ googledocs: [
23407
+ "https://www.googleapis.com/auth/documents",
23408
+ "https://www.googleapis.com/auth/drive.file"
23409
+ ].join(" "),
23410
+ googlesheets: [
23411
+ "https://www.googleapis.com/auth/spreadsheets",
23412
+ "https://www.googleapis.com/auth/drive.file"
23413
+ ].join(" "),
23414
+ googletasks: [
23415
+ "https://www.googleapis.com/auth/tasks"
23416
+ ].join(" "),
23417
+ googlecontacts: [
23418
+ "https://www.googleapis.com/auth/contacts",
23419
+ "https://www.googleapis.com/auth/contacts.readonly"
23420
+ ].join(" "),
23421
+ google: [
23422
+ "openid",
23423
+ "https://www.googleapis.com/auth/userinfo.email",
23424
+ "https://www.googleapis.com/auth/userinfo.profile"
23425
+ ].join(" ")
23426
+ };
23427
+ function getAuthType(name) {
23428
+ const docs = getConnectorDocs(name);
23429
+ if (!docs?.auth)
23430
+ return "apikey";
23431
+ const authLower = docs.auth.toLowerCase();
23432
+ if (authLower.includes("oauth"))
23433
+ return "oauth";
23434
+ if (authLower.includes("bearer token"))
23435
+ return "bearer";
23436
+ return "apikey";
23437
+ }
23438
+ function getConnectorConfigDir(name) {
23439
+ const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
23440
+ return join11(getConnectorsHome(), connectorName);
23441
+ }
23442
+ function getCurrentProfile2(name) {
23443
+ const configDir = getConnectorConfigDir(name);
23444
+ const currentProfileFile = join11(configDir, "current_profile");
23445
+ if (existsSync9(currentProfileFile)) {
23446
+ try {
23447
+ return readFileSync6(currentProfileFile, "utf-8").trim() || "default";
23448
+ } catch {
23449
+ return "default";
23450
+ }
23451
+ }
23452
+ return "default";
23453
+ }
23454
+ function loadProfileConfig(name) {
23455
+ const configDir = getConnectorConfigDir(name);
23456
+ const profile = getCurrentProfile2(name);
23457
+ let flatConfig = {};
23458
+ let dirConfig = {};
23459
+ const profileFile = join11(configDir, "profiles", `${profile}.json`);
23460
+ if (existsSync9(profileFile)) {
23461
+ try {
23462
+ flatConfig = JSON.parse(readFileSync6(profileFile, "utf-8"));
23463
+ } catch {}
23464
+ }
23465
+ const profileDirConfig = join11(configDir, "profiles", profile, "config.json");
23466
+ if (existsSync9(profileDirConfig)) {
23467
+ try {
23468
+ dirConfig = JSON.parse(readFileSync6(profileDirConfig, "utf-8"));
23469
+ } catch {}
23470
+ }
23471
+ if (Object.keys(flatConfig).length === 0 && Object.keys(dirConfig).length === 0) {
23472
+ return {};
23473
+ }
23474
+ return { ...flatConfig, ...dirConfig };
23475
+ }
23476
+ function loadTokens2(name) {
23477
+ const configDir = getConnectorConfigDir(name);
23478
+ const profile = getCurrentProfile2(name);
23479
+ const tokensFile = join11(configDir, "profiles", profile, "tokens.json");
23480
+ if (existsSync9(tokensFile)) {
23481
+ try {
23482
+ return JSON.parse(readFileSync6(tokensFile, "utf-8"));
23483
+ } catch {
23484
+ return null;
23485
+ }
23486
+ }
23487
+ const profileConfig = loadProfileConfig(name);
23488
+ if (profileConfig.refreshToken || profileConfig.accessToken) {
23489
+ return {
23490
+ accessToken: profileConfig.accessToken ?? "",
23491
+ refreshToken: profileConfig.refreshToken,
23492
+ expiresAt: profileConfig.expiresAt ?? 0,
23493
+ tokenType: profileConfig.tokenType,
23494
+ scope: profileConfig.scope
23495
+ };
23496
+ }
23497
+ return null;
23498
+ }
23499
+ function getEnvVars(name) {
23500
+ const docs = getConnectorDocs(name);
23501
+ return docs?.envVars || [];
23502
+ }
23503
+ function getOAuthConfig(name) {
23504
+ const configDir = getConnectorConfigDir(name);
23505
+ const credentialsFile = join11(configDir, "credentials.json");
23506
+ if (existsSync9(credentialsFile)) {
23507
+ try {
23508
+ const creds = JSON.parse(readFileSync6(credentialsFile, "utf-8"));
23509
+ return { clientId: creds.clientId, clientSecret: creds.clientSecret };
23510
+ } catch {}
23511
+ }
23512
+ const config = loadProfileConfig(name);
23513
+ return {
23514
+ clientId: config.clientId,
23515
+ clientSecret: config.clientSecret
23516
+ };
23517
+ }
23518
+
23519
+ // src/lib/runner.ts
23093
23520
  var __dirname5 = dirname7(fileURLToPath5(import.meta.url));
23094
23521
  function resolveConnectorsDir2() {
23095
- const fromBin = join11(__dirname5, "..", "connectors");
23522
+ const fromBin = join12(__dirname5, "..", "connectors");
23096
23523
  if (existsSync10(fromBin))
23097
23524
  return fromBin;
23098
- const fromSrc = join11(__dirname5, "..", "..", "connectors");
23525
+ const fromSrc = join12(__dirname5, "..", "..", "connectors");
23099
23526
  if (existsSync10(fromSrc))
23100
23527
  return fromSrc;
23101
23528
  return fromBin;
@@ -23147,12 +23574,31 @@ function buildEnvWithCredentials(connectorName, baseEnv) {
23147
23574
  }
23148
23575
  }
23149
23576
  }
23577
+ if (getAuthType(connectorName) === "oauth") {
23578
+ const oauthConfig = getOAuthConfig(connectorName);
23579
+ const tokens = loadTokens2(connectorName);
23580
+ for (const { variable } of getEnvVars(connectorName)) {
23581
+ if (env[variable])
23582
+ continue;
23583
+ if (variable.endsWith("_CLIENT_ID") && oauthConfig.clientId) {
23584
+ env[variable] = oauthConfig.clientId;
23585
+ } else if (variable.endsWith("_CLIENT_SECRET") && oauthConfig.clientSecret) {
23586
+ env[variable] = oauthConfig.clientSecret;
23587
+ } else if (variable.endsWith("_ACCESS_TOKEN") && tokens?.accessToken) {
23588
+ env[variable] = tokens.accessToken;
23589
+ } else if (variable.endsWith("_REFRESH_TOKEN") && tokens?.refreshToken) {
23590
+ env[variable] = tokens.refreshToken;
23591
+ } else if (variable.endsWith("_TOKEN_EXPIRES_AT") && tokens?.expiresAt) {
23592
+ env[variable] = String(tokens.expiresAt);
23593
+ }
23594
+ }
23595
+ }
23150
23596
  return env;
23151
23597
  }
23152
23598
  function getConnectorCliPath(name) {
23153
23599
  const safeName = name.replace(/[^a-z0-9-]/g, "");
23154
- const connectorDir = join11(CONNECTORS_DIR2, `connect-${safeName}`);
23155
- const cliPath = join11(connectorDir, "src", "cli", "index.ts");
23600
+ const connectorDir = join12(CONNECTORS_DIR2, `connect-${safeName}`);
23601
+ const cliPath = join12(connectorDir, "src", "cli", "index.ts");
23156
23602
  if (existsSync10(cliPath))
23157
23603
  return cliPath;
23158
23604
  return null;
@@ -23191,7 +23637,7 @@ function parseCommanderHelpOperations(helpText) {
23191
23637
  inCommands = false;
23192
23638
  continue;
23193
23639
  }
23194
- const row = line.match(/^ {2}(\S.*?)(?: {2,}(.+))?$/);
23640
+ const row = line.match(/^ {2}(?! )(\S.*?)(?: {2,}(.+))?$/);
23195
23641
  if (!row)
23196
23642
  continue;
23197
23643
  const usage = row[1].trim();
@@ -23228,6 +23674,112 @@ function runConnectorCommand(name, args, timeoutMs = 30000) {
23228
23674
  }
23229
23675
  return runLegacyConnectorCommand(name, args, timeoutMs);
23230
23676
  }
23677
+ async function runConnectorOperation(args) {
23678
+ const internal = getInternalConnectorDefinition(args.connector);
23679
+ if (internal?.operations[args.operation]) {
23680
+ try {
23681
+ const operationData = await executeConnectorOperation(internal, {
23682
+ operation: args.operation,
23683
+ input: args.input,
23684
+ profile: args.profile
23685
+ });
23686
+ const commandResult = normalizeOperationReturn(operationData);
23687
+ return {
23688
+ connector: args.connector,
23689
+ operation: args.operation,
23690
+ profile: args.profile,
23691
+ ...commandResult
23692
+ };
23693
+ } catch (error) {
23694
+ return {
23695
+ connector: args.connector,
23696
+ operation: args.operation,
23697
+ profile: args.profile,
23698
+ stdout: "",
23699
+ stderr: error.message,
23700
+ exitCode: 1,
23701
+ success: false
23702
+ };
23703
+ }
23704
+ }
23705
+ const commandArgs = buildConnectorOperationArgs(args);
23706
+ const result = await runConnectorCommand(args.connector, commandArgs, args.timeoutMs ?? 30000);
23707
+ const response = {
23708
+ ...result,
23709
+ connector: args.connector,
23710
+ operation: args.operation,
23711
+ profile: args.profile
23712
+ };
23713
+ if (args.parseJson !== false && result.stdout) {
23714
+ try {
23715
+ response.data = JSON.parse(result.stdout);
23716
+ } catch {}
23717
+ }
23718
+ return response;
23719
+ }
23720
+ function normalizeOperationReturn(value) {
23721
+ if (isRunResult(value)) {
23722
+ const result = value;
23723
+ const response = {
23724
+ ...result
23725
+ };
23726
+ if (result.stdout) {
23727
+ try {
23728
+ response.data = JSON.parse(result.stdout);
23729
+ } catch {}
23730
+ }
23731
+ return response;
23732
+ }
23733
+ return {
23734
+ data: value,
23735
+ stdout: JSON.stringify(value),
23736
+ stderr: "",
23737
+ exitCode: 0,
23738
+ success: true
23739
+ };
23740
+ }
23741
+ function isRunResult(value) {
23742
+ if (!value || typeof value !== "object")
23743
+ return false;
23744
+ const candidate = value;
23745
+ return typeof candidate.stdout === "string" && typeof candidate.stderr === "string" && typeof candidate.exitCode === "number" && typeof candidate.success === "boolean";
23746
+ }
23747
+ function buildConnectorOperationArgs(args) {
23748
+ const commandArgs = [];
23749
+ if (args.profile) {
23750
+ commandArgs.push("--profile", args.profile);
23751
+ }
23752
+ commandArgs.push(...args.operation.split(".").filter(Boolean));
23753
+ for (const positional of args.input?.args ?? []) {
23754
+ commandArgs.push(String(positional));
23755
+ }
23756
+ let hasFormat = false;
23757
+ for (const [key, value] of Object.entries(args.input ?? {})) {
23758
+ if (key === "args")
23759
+ continue;
23760
+ if (value === undefined || value === null)
23761
+ continue;
23762
+ const flag = `--${key.replace(/_/g, "-").replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`)}`;
23763
+ if (flag === "--format" || flag === "--json")
23764
+ hasFormat = true;
23765
+ if (typeof value === "boolean") {
23766
+ if (value)
23767
+ commandArgs.push(flag);
23768
+ continue;
23769
+ }
23770
+ if (Array.isArray(value)) {
23771
+ for (const item of value) {
23772
+ commandArgs.push(flag, String(item));
23773
+ }
23774
+ continue;
23775
+ }
23776
+ commandArgs.push(flag, String(value));
23777
+ }
23778
+ if (args.parseJson !== false && !hasFormat) {
23779
+ commandArgs.push("--format", "json");
23780
+ }
23781
+ return commandArgs;
23782
+ }
23231
23783
  function runLegacyConnectorCommand(name, args, timeoutMs = 30000) {
23232
23784
  const cliPath = getConnectorCliPath(name);
23233
23785
  if (!cliPath) {
@@ -23338,6 +23890,7 @@ function getConnectorsWithCli() {
23338
23890
  }
23339
23891
  export {
23340
23892
  searchConnectors,
23893
+ runConnectorOperation,
23341
23894
  runConnectorCommand,
23342
23895
  removeConnector,
23343
23896
  loadConnectorVersions,
@@ -23358,6 +23911,7 @@ export {
23358
23911
  executeConnectorOperation,
23359
23912
  defineConnector,
23360
23913
  connectorExists,
23914
+ buildConnectorOperationArgs,
23361
23915
  ConnectorOperationNotFoundError,
23362
23916
  ConnectorDefinitionError,
23363
23917
  CONNECTORS,