@tangle-network/agent-integrations 0.53.30 → 0.53.33

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.
@@ -182,6 +182,12 @@ __export(adapters_exports, {
182
182
  copyAiConnector: () => copyAiConnector,
183
183
  couchbaseConnector: () => couchbaseConnector,
184
184
  createKafkaConnector: () => createKafkaConnector,
185
+ createMongoDbConnector: () => createMongoDbConnector,
186
+ createMySqlConnector: () => createMySqlConnector,
187
+ createPostgresConnector: () => createPostgresConnector,
188
+ createRabbitMqConnector: () => createRabbitMqConnector,
189
+ createRedisConnector: () => createRedisConnector,
190
+ createRedshiftConnector: () => createRedshiftConnector,
185
191
  createSftpConnector: () => createSftpConnector,
186
192
  createTangleIdentityClient: () => createTangleIdentityClient,
187
193
  crispConnector: () => crispConnector,
@@ -218,6 +224,7 @@ __export(adapters_exports, {
218
224
  dripConnector: () => dripConnector,
219
225
  dropboxConnector: () => dropboxConnector,
220
226
  dubConnector: () => dubConnector,
227
+ duckdbConnector: () => duckdbConnector,
221
228
  dumplingAiConnector: () => dumplingAiConnector,
222
229
  dustConnector: () => dustConnector,
223
230
  easyPeasyAiConnector: () => easyPeasyAiConnector,
@@ -438,9 +445,11 @@ __export(adapters_exports, {
438
445
  mondayConnector: () => mondayConnector,
439
446
  mongodbConnector: () => mongodbConnector,
440
447
  mycaseConnector: () => mycaseConnector,
448
+ mysqlConnector: () => mysqlConnector,
441
449
  n8nConnector: () => n8nConnector,
442
450
  netlifyConnector: () => netlifyConnector,
443
451
  netsuiteConnector: () => netsuiteConnector,
452
+ neverbounceConnector: () => neverbounceConnector,
444
453
  niftyConnector: () => niftyConnector,
445
454
  ninjapipeConnector: () => ninjapipeConnector,
446
455
  nocodbConnector: () => nocodbConnector,
@@ -508,6 +517,7 @@ __export(adapters_exports, {
508
517
  quadernoConnector: () => quadernoConnector,
509
518
  quickbooksConnector: () => quickbooksConnector,
510
519
  quickzuConnector: () => quickzuConnector,
520
+ rabbitMqConnector: () => rabbitMqConnector,
511
521
  raiaAiConnector: () => raiaAiConnector,
512
522
  rampConnector: () => rampConnector,
513
523
  rapidtextAiConnector: () => rapidtextAiConnector,
@@ -515,6 +525,8 @@ __export(adapters_exports, {
515
525
  recallAiConnector: () => recallAiConnector,
516
526
  recurlyConnector: () => recurlyConnector,
517
527
  redditConnector: () => redditConnector,
528
+ redisConnector: () => redisConnector,
529
+ redshiftConnector: () => redshiftConnector,
518
530
  reoonVerifierConnector: () => reoonVerifierConnector,
519
531
  replyIoConnector: () => replyIoConnector,
520
532
  resolveConnectorAdapterFactoryOptions: () => resolveConnectorAdapterFactoryOptions,
@@ -1123,6 +1135,10 @@ function sameUrl(left, right) {
1123
1135
  function applyCredentials(headers, url, placement, credentials) {
1124
1136
  const token = credentialToken(credentials);
1125
1137
  if (placement.kind === "bearer") headers.authorization = `Bearer ${token}`;
1138
+ if (placement.kind === "authorization-by-auth") {
1139
+ const prefix = credentials.kind === "oauth2" ? placement.oauth2Prefix ?? "Bearer " : placement.apiKeyPrefix ?? "";
1140
+ headers.authorization = `${prefix}${token}`;
1141
+ }
1126
1142
  if (placement.kind === "basic-api-key") {
1127
1143
  headers.authorization = `Basic ${Buffer.from(`${token}:`).toString("base64")}`;
1128
1144
  }
@@ -6500,6 +6516,294 @@ var digitalPilotConnector = declarativeRestConnector({
6500
6516
  ]
6501
6517
  });
6502
6518
 
6519
+ // src/connectors/adapters/duckdb.ts
6520
+ import {
6521
+ DuckDBInstance
6522
+ } from "@duckdb/node-api";
6523
+ var MAX_ARGUMENTS = 100;
6524
+ var MAX_COLUMNS2 = 256;
6525
+ var MAX_EXECUTION_MS = 5e3;
6526
+ var MAX_INPUT_BYTES = 10 * 1024 * 1024;
6527
+ var MAX_QUERY_BYTES = 2e4;
6528
+ var MAX_RESULT_BYTES = 10 * 1024 * 1024;
6529
+ var MAX_ROWS = 1e4;
6530
+ var MAX_SCHEMA_DEPTH = 16;
6531
+ var MAX_TABLES = 16;
6532
+ var TABLE_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,62}$/;
6533
+ var duckdbConnector = {
6534
+ manifest: {
6535
+ kind: "duckdb",
6536
+ displayName: "DuckDB",
6537
+ description: "Load bounded JSON tables into a throwaway in-memory DuckDB database and run a parameterized query.",
6538
+ auth: { kind: "none" },
6539
+ defaultConsistencyModel: "advisory",
6540
+ category: "database",
6541
+ capabilities: [
6542
+ {
6543
+ name: "create.and.query.db",
6544
+ class: "read",
6545
+ description: "Create in-memory tables from JSON arrays and return a bounded parameterized SQL query result.",
6546
+ parameters: {
6547
+ type: "object",
6548
+ properties: {
6549
+ tables: {
6550
+ type: "array",
6551
+ minItems: 1,
6552
+ maxItems: MAX_TABLES,
6553
+ items: {
6554
+ type: "object",
6555
+ properties: {
6556
+ name: { type: "string", pattern: TABLE_NAME.source, maxLength: 63 },
6557
+ data: { type: "array", maxItems: MAX_ROWS, items: { type: "object" } },
6558
+ schema: { type: "object", maxProperties: MAX_COLUMNS2 }
6559
+ },
6560
+ required: ["name", "data"],
6561
+ additionalProperties: false
6562
+ }
6563
+ },
6564
+ query: {
6565
+ type: "string",
6566
+ minLength: 1,
6567
+ maxLength: MAX_QUERY_BYTES,
6568
+ description: "A single relation-returning SQL query. Use $1, $2, and args for dynamic values."
6569
+ },
6570
+ args: {
6571
+ type: "array",
6572
+ maxItems: MAX_ARGUMENTS,
6573
+ items: { type: ["string", "number", "boolean", "null"] }
6574
+ },
6575
+ maxRows: { type: "integer", minimum: 1, maximum: MAX_ROWS, default: 1e3 }
6576
+ },
6577
+ required: ["tables", "query"],
6578
+ additionalProperties: false
6579
+ }
6580
+ }
6581
+ ]
6582
+ },
6583
+ async executeRead({ capabilityName, args }) {
6584
+ if (capabilityName !== "create.and.query.db") {
6585
+ throw new Error(`Unknown DuckDB capability: ${capabilityName}`);
6586
+ }
6587
+ const tables = readTables(args.tables);
6588
+ const query2 = readQuery(args.query);
6589
+ const queryArgs = readArguments(args.args);
6590
+ const maxRows = readBoundedInteger(args.maxRows, 1e3, 1, MAX_ROWS, "maxRows");
6591
+ const instance = await DuckDBInstance.create(":memory:");
6592
+ let connection;
6593
+ let timedOut = false;
6594
+ let timeout;
6595
+ try {
6596
+ const activeConnection = await instance.connect();
6597
+ connection = activeConnection;
6598
+ timeout = setTimeout(() => {
6599
+ timedOut = true;
6600
+ activeConnection.interrupt();
6601
+ }, MAX_EXECUTION_MS);
6602
+ await configureConnection(activeConnection);
6603
+ throwIfTimedOut(timedOut);
6604
+ for (const table of tables) {
6605
+ await loadTable(activeConnection, table);
6606
+ throwIfTimedOut(timedOut);
6607
+ }
6608
+ const reader = await activeConnection.runAndReadAll(
6609
+ `SELECT * FROM (${query2}) AS "_tangle_result" LIMIT ${maxRows + 1}`,
6610
+ queryArgs
6611
+ );
6612
+ throwIfTimedOut(timedOut);
6613
+ const allRows = reader.getRowObjectsJson();
6614
+ const truncated = allRows.length > maxRows;
6615
+ const rows = truncated ? allRows.slice(0, maxRows) : allRows;
6616
+ assertResultSize(rows);
6617
+ return {
6618
+ data: {
6619
+ rows,
6620
+ rowCount: rows.length,
6621
+ truncated,
6622
+ columns: reader.columnNameAndTypeObjectsJson()
6623
+ },
6624
+ fetchedAt: Date.now()
6625
+ };
6626
+ } catch (error) {
6627
+ if (timedOut) throw new Error(`DuckDB execution exceeded ${MAX_EXECUTION_MS}ms`);
6628
+ throw error;
6629
+ } finally {
6630
+ if (timeout) clearTimeout(timeout);
6631
+ try {
6632
+ connection?.closeSync();
6633
+ } finally {
6634
+ instance.closeSync();
6635
+ }
6636
+ }
6637
+ },
6638
+ async test() {
6639
+ const instance = await DuckDBInstance.create(":memory:");
6640
+ let connection;
6641
+ try {
6642
+ const activeConnection = await instance.connect();
6643
+ connection = activeConnection;
6644
+ await configureConnection(activeConnection);
6645
+ const reader = await activeConnection.runAndReadAll("SELECT 1 AS ok");
6646
+ if (reader.getRowObjectsJson()[0]?.ok !== 1) return { ok: false, reason: "DuckDB SELECT 1 returned an unexpected result" };
6647
+ return { ok: true };
6648
+ } catch (error) {
6649
+ return { ok: false, reason: error instanceof Error ? error.message : String(error) };
6650
+ } finally {
6651
+ try {
6652
+ connection?.closeSync();
6653
+ } finally {
6654
+ instance.closeSync();
6655
+ }
6656
+ }
6657
+ }
6658
+ };
6659
+ async function configureConnection(connection) {
6660
+ await connection.run(`
6661
+ SET memory_limit = '256MB';
6662
+ SET max_temp_directory_size = '0B';
6663
+ SET threads = 2;
6664
+ SET enable_logging = false;
6665
+ SET enable_external_access = false;
6666
+ SET lock_configuration = true;
6667
+ `);
6668
+ }
6669
+ async function loadTable(connection, table) {
6670
+ const sourceData = stringifyJson(table.data, `${table.name}.data`);
6671
+ let sourceSchema;
6672
+ if (table.schema) {
6673
+ assertDuckDbSchema(table.schema, `${table.name}.schema`);
6674
+ sourceSchema = stringifyJson([table.schema], `${table.name}.schema`);
6675
+ } else {
6676
+ if (table.data.length === 0) {
6677
+ throw new Error(`${table.name}.schema is required when data is empty`);
6678
+ }
6679
+ const detected = await connection.runAndReadAll(
6680
+ "SELECT json_structure($sourceData) AS schema",
6681
+ { sourceData }
6682
+ );
6683
+ const value = detected.getRowsJson()[0]?.[0];
6684
+ if (typeof value !== "string") throw new Error(`Could not infer a schema for ${table.name}`);
6685
+ let detectedSchema;
6686
+ try {
6687
+ detectedSchema = JSON.parse(value);
6688
+ } catch {
6689
+ throw new Error(`Could not parse the inferred schema for ${table.name}`);
6690
+ }
6691
+ assertDuckDbSchema(detectedSchema, `${table.name}.inferredSchema`);
6692
+ sourceSchema = value;
6693
+ }
6694
+ await connection.run(
6695
+ `CREATE TABLE ${quoteIdentifier(table.name)} AS
6696
+ SELECT UNNEST(JSON_TRANSFORM($sourceData, $sourceSchema), recursive := true)`,
6697
+ { sourceData, sourceSchema }
6698
+ );
6699
+ }
6700
+ function readTables(value) {
6701
+ if (!Array.isArray(value) || value.length === 0 || value.length > MAX_TABLES) {
6702
+ throw new Error(`tables must contain 1 through ${MAX_TABLES} entries`);
6703
+ }
6704
+ assertInputSize(value);
6705
+ let totalRows = 0;
6706
+ const tables = value.map((entry, tableIndex) => {
6707
+ if (!isPlainRecord(entry)) throw new Error(`tables[${tableIndex}] must be an object`);
6708
+ const { name, data: data4, schema } = entry;
6709
+ if (typeof name !== "string" || !TABLE_NAME.test(name)) {
6710
+ throw new Error(`tables[${tableIndex}].name must be a safe SQL identifier`);
6711
+ }
6712
+ if (!Array.isArray(data4) || data4.length > MAX_ROWS) {
6713
+ throw new Error(`tables[${tableIndex}].data must contain at most ${MAX_ROWS} rows`);
6714
+ }
6715
+ const records = data4.map((record, rowIndex) => {
6716
+ if (!isPlainRecord(record)) throw new Error(`tables[${tableIndex}].data[${rowIndex}] must be an object`);
6717
+ if (Object.keys(record).length > MAX_COLUMNS2) {
6718
+ throw new Error(`tables[${tableIndex}].data[${rowIndex}] exceeds ${MAX_COLUMNS2} columns`);
6719
+ }
6720
+ return record;
6721
+ });
6722
+ const columns = new Set(records.flatMap((record) => Object.keys(record)));
6723
+ if (columns.size > MAX_COLUMNS2) {
6724
+ throw new Error(`tables[${tableIndex}].data exceeds ${MAX_COLUMNS2} distinct columns`);
6725
+ }
6726
+ totalRows += records.length;
6727
+ if (totalRows > MAX_ROWS) throw new Error(`tables exceed the ${MAX_ROWS}-row total limit`);
6728
+ if (schema !== void 0 && (!isPlainRecord(schema) || Object.keys(schema).length > MAX_COLUMNS2)) {
6729
+ throw new Error(`tables[${tableIndex}].schema must contain at most ${MAX_COLUMNS2} fields`);
6730
+ }
6731
+ return { name, data: records, schema };
6732
+ });
6733
+ if (new Set(tables.map((table) => table.name.toLowerCase())).size !== tables.length) {
6734
+ throw new Error("table names must be unique ignoring case");
6735
+ }
6736
+ return tables;
6737
+ }
6738
+ function readQuery(value) {
6739
+ if (typeof value !== "string" || value.trim().length === 0) throw new Error("query is required");
6740
+ if (Buffer.byteLength(value, "utf8") > MAX_QUERY_BYTES) {
6741
+ throw new Error(`query exceeds the ${MAX_QUERY_BYTES}-byte limit`);
6742
+ }
6743
+ return value.trim().replace(/;\s*$/, "");
6744
+ }
6745
+ function readArguments(value) {
6746
+ if (value === void 0 || value === null) return {};
6747
+ if (!Array.isArray(value) || value.length > MAX_ARGUMENTS) {
6748
+ throw new Error(`args must contain at most ${MAX_ARGUMENTS} scalar values`);
6749
+ }
6750
+ return Object.fromEntries(value.map((entry, index) => {
6751
+ if (entry !== null && typeof entry !== "string" && typeof entry !== "number" && typeof entry !== "boolean") {
6752
+ throw new Error(`args[${index}] must be a string, number, boolean, or null`);
6753
+ }
6754
+ if (typeof entry === "number" && !Number.isFinite(entry)) throw new Error(`args[${index}] must be finite`);
6755
+ return [String(index + 1), entry];
6756
+ }));
6757
+ }
6758
+ function assertInputSize(value) {
6759
+ const serialized = stringifyJson(value, "tables");
6760
+ if (Buffer.byteLength(serialized, "utf8") > MAX_INPUT_BYTES) {
6761
+ throw new Error(`tables exceed the ${MAX_INPUT_BYTES}-byte input limit`);
6762
+ }
6763
+ }
6764
+ function assertResultSize(rows) {
6765
+ const serialized = stringifyJson(rows, "DuckDB result");
6766
+ if (Buffer.byteLength(serialized, "utf8") > MAX_RESULT_BYTES) {
6767
+ throw new Error(`DuckDB result exceeds the ${MAX_RESULT_BYTES}-byte output limit`);
6768
+ }
6769
+ }
6770
+ function assertDuckDbSchema(value, label) {
6771
+ let leaves = 0;
6772
+ const visit = (entry, depth) => {
6773
+ if (depth > MAX_SCHEMA_DEPTH) throw new Error(`${label} exceeds ${MAX_SCHEMA_DEPTH} nested levels`);
6774
+ if (typeof entry === "string") {
6775
+ leaves += 1;
6776
+ if (leaves > MAX_COLUMNS2) throw new Error(`${label} exceeds ${MAX_COLUMNS2} leaf columns`);
6777
+ return;
6778
+ }
6779
+ if (Array.isArray(entry)) {
6780
+ if (entry.length !== 1) throw new Error(`${label} array schemas must contain exactly one element type`);
6781
+ visit(entry[0], depth + 1);
6782
+ return;
6783
+ }
6784
+ if (!isPlainRecord(entry) || Object.keys(entry).length === 0) {
6785
+ throw new Error(`${label} must describe at least one DuckDB column type`);
6786
+ }
6787
+ for (const child of Object.values(entry)) visit(child, depth + 1);
6788
+ };
6789
+ visit(value, 0);
6790
+ }
6791
+ function stringifyJson(value, label) {
6792
+ try {
6793
+ const serialized = JSON.stringify(value);
6794
+ if (serialized === void 0) throw new Error("undefined");
6795
+ return serialized;
6796
+ } catch {
6797
+ throw new Error(`${label} must be JSON-serializable`);
6798
+ }
6799
+ }
6800
+ function quoteIdentifier(value) {
6801
+ return `"${value.replaceAll('"', '""')}"`;
6802
+ }
6803
+ function throwIfTimedOut(timedOut) {
6804
+ if (timedOut) throw new Error(`DuckDB execution exceeded ${MAX_EXECUTION_MS}ms`);
6805
+ }
6806
+
6503
6807
  // src/connectors/adapters/docsbot.ts
6504
6808
  var docsbotConnector = declarativeRestConnector({
6505
6809
  kind: "docsbot",
@@ -6917,7 +7221,7 @@ var elevenlabsConnector = declarativeRestConnector({
6917
7221
  // src/connectors/adapters/excel-files.ts
6918
7222
  import readXlsxFile from "read-excel-file/node";
6919
7223
  import writeXlsxFile from "write-excel-file/node";
6920
- var MAX_COLUMNS2 = 256;
7224
+ var MAX_COLUMNS3 = 256;
6921
7225
  var MAX_SHEETS = 50;
6922
7226
  var MAX_UNCOMPRESSED_WORKBOOK_BYTES = 50 * 1024 * 1024;
6923
7227
  var MAX_ZIP_ENTRIES = 1e3;
@@ -6958,7 +7262,7 @@ var excelFilesConnector = {
6958
7262
  type: "array",
6959
7263
  minItems: 1,
6960
7264
  maxItems: MAX_RECORDS,
6961
- items: { type: "array", maxItems: MAX_COLUMNS2 }
7265
+ items: { type: "array", maxItems: MAX_COLUMNS3 }
6962
7266
  },
6963
7267
  sheetName: { type: "string", minLength: 1, maxLength: 31, default: "Sheet1" }
6964
7268
  },
@@ -6988,8 +7292,8 @@ var excelFilesConnector = {
6988
7292
  totalRows += sheet.data.length;
6989
7293
  if (totalRows > MAX_RECORDS) throw new Error(`workbook exceeds the ${MAX_RECORDS}-row limit`);
6990
7294
  for (const [rowIndex, row] of sheet.data.entries()) {
6991
- if (row.length > MAX_COLUMNS2) {
6992
- throw new Error(`sheet ${sheet.sheet} row ${rowIndex + 1} exceeds the ${MAX_COLUMNS2}-column limit`);
7295
+ if (row.length > MAX_COLUMNS3) {
7296
+ throw new Error(`sheet ${sheet.sheet} row ${rowIndex + 1} exceeds the ${MAX_COLUMNS3}-column limit`);
6993
7297
  }
6994
7298
  }
6995
7299
  return { name: sheet.sheet, rows: jsonSafe(sheet.data) };
@@ -7003,7 +7307,7 @@ var excelFilesConnector = {
7003
7307
  if (capabilityName !== "excel.create") throw new Error(`Unknown Excel capability: ${capabilityName}`);
7004
7308
  const rows = readRows(args.rows);
7005
7309
  for (const [index, row] of rows.entries()) {
7006
- if (row.length > MAX_COLUMNS2) throw new Error(`rows[${index}] exceeds the ${MAX_COLUMNS2}-column limit`);
7310
+ if (row.length > MAX_COLUMNS3) throw new Error(`rows[${index}] exceeds the ${MAX_COLUMNS3}-column limit`);
7007
7311
  }
7008
7312
  const sheetName = readOptionalString(args.sheetName, "sheetName") ?? "Sheet1";
7009
7313
  validateSheetName(sheetName);
@@ -16301,16 +16605,27 @@ var clickupConnector = declarativeRestConnector({
16301
16605
  displayName: "ClickUp",
16302
16606
  description: "Read and mutate ClickUp workspaces, spaces, folders, lists, tasks, comments, and time entries via the ClickUp REST v2 API.",
16303
16607
  auth: {
16304
- kind: "oauth2",
16305
- authorizationUrl: "https://app.clickup.com/api",
16306
- tokenUrl: "https://api.clickup.com/api/v2/oauth/token",
16307
- scopes: [],
16308
- clientIdEnv: "CLICKUP_OAUTH_CLIENT_ID",
16309
- clientSecretEnv: "CLICKUP_OAUTH_CLIENT_SECRET"
16608
+ kind: "one_of",
16609
+ preferred: "api-key",
16610
+ options: [
16611
+ {
16612
+ kind: "api-key",
16613
+ hint: "ClickUp personal API token (starts with pk_)."
16614
+ },
16615
+ {
16616
+ kind: "oauth2",
16617
+ authorizationUrl: "https://app.clickup.com/api",
16618
+ tokenUrl: "https://api.clickup.com/api/v2/oauth/token",
16619
+ scopes: [],
16620
+ clientIdEnv: "CLICKUP_OAUTH_CLIENT_ID",
16621
+ clientSecretEnv: "CLICKUP_OAUTH_CLIENT_SECRET"
16622
+ }
16623
+ ]
16310
16624
  },
16311
16625
  category: "other",
16312
16626
  defaultConsistencyModel: "authoritative",
16313
16627
  baseUrl: "https://api.clickup.com/api/v2",
16628
+ credentialPlacement: { kind: "authorization-by-auth" },
16314
16629
  // GET /user — returns the authorized user; used as a cheap liveness probe.
16315
16630
  test: { method: "GET", path: "/user" },
16316
16631
  capabilities: [
@@ -38895,6 +39210,628 @@ var mollieConnector = declarativeRestConnector({
38895
39210
  ]
38896
39211
  });
38897
39212
 
39213
+ // src/connectors/adapters/miro.ts
39214
+ var miroConnector = declarativeRestConnector({
39215
+ kind: "miro",
39216
+ displayName: "Miro",
39217
+ description: "Read and edit Miro boards: list and search boards, read board items (sticky notes, shapes, text, cards, images, frames, connectors), create and update items, and post board content back into the source of truth.",
39218
+ auth: {
39219
+ kind: "oauth2",
39220
+ authorizationUrl: "https://miro.com/oauth/authorize",
39221
+ tokenUrl: "https://api.miro.com/v1/oauth/token",
39222
+ scopes: [
39223
+ "boards:read",
39224
+ "boards:write",
39225
+ "identity:read"
39226
+ ],
39227
+ clientIdEnv: "MIRO_OAUTH_CLIENT_ID",
39228
+ clientSecretEnv: "MIRO_OAUTH_CLIENT_SECRET"
39229
+ },
39230
+ category: "doc",
39231
+ defaultConsistencyModel: "authoritative",
39232
+ baseUrl: "https://api.miro.com",
39233
+ defaultHeaders: { accept: "application/json" },
39234
+ // GET /v2/me returns the authenticated user — Miro's documented health probe.
39235
+ test: { method: "GET", path: "/v2/me" },
39236
+ capabilities: [
39237
+ {
39238
+ name: "me.get",
39239
+ class: "read",
39240
+ description: "Return the authenticated Miro user.",
39241
+ parameters: { type: "object", properties: {} },
39242
+ request: { method: "GET", path: "/v2/me" },
39243
+ requiredScopes: ["identity:read"]
39244
+ },
39245
+ {
39246
+ name: "boards.list",
39247
+ class: "read",
39248
+ description: "List boards accessible to the authenticated user. Supports cursor pagination via `cursor` and team / sort filters.",
39249
+ parameters: {
39250
+ type: "object",
39251
+ properties: {
39252
+ team_id: { type: "string", description: "Filter to a single team id." },
39253
+ query: { type: "string", description: "Free-text board name filter." },
39254
+ owner: { type: "string", description: "Filter by owner user id." },
39255
+ limit: { type: "integer", minimum: 1, maximum: 50 },
39256
+ offset: { type: "integer", minimum: 0 },
39257
+ sort: {
39258
+ type: "string",
39259
+ enum: ["default", "last_modified", "last_opened", "last_created", "alphabetically"]
39260
+ }
39261
+ }
39262
+ },
39263
+ request: {
39264
+ method: "GET",
39265
+ path: "/v2/boards",
39266
+ query: {
39267
+ team_id: "{team_id}",
39268
+ query: "{query}",
39269
+ owner: "{owner}",
39270
+ limit: "{limit}",
39271
+ offset: "{offset}",
39272
+ sort: "{sort}"
39273
+ }
39274
+ },
39275
+ requiredScopes: ["boards:read"]
39276
+ },
39277
+ {
39278
+ name: "boards.get",
39279
+ class: "read",
39280
+ description: "Fetch a single Miro board by id.",
39281
+ parameters: {
39282
+ type: "object",
39283
+ properties: { board_id: { type: "string" } },
39284
+ required: ["board_id"]
39285
+ },
39286
+ request: { method: "GET", path: "/v2/boards/{board_id}" },
39287
+ requiredScopes: ["boards:read"]
39288
+ },
39289
+ {
39290
+ name: "boards.members.list",
39291
+ class: "read",
39292
+ description: "List members (collaborators) of a Miro board.",
39293
+ parameters: {
39294
+ type: "object",
39295
+ properties: {
39296
+ board_id: { type: "string" },
39297
+ limit: { type: "integer", minimum: 1, maximum: 50 },
39298
+ offset: { type: "integer", minimum: 0 }
39299
+ },
39300
+ required: ["board_id"]
39301
+ },
39302
+ request: {
39303
+ method: "GET",
39304
+ path: "/v2/boards/{board_id}/members",
39305
+ query: { limit: "{limit}", offset: "{offset}" }
39306
+ },
39307
+ requiredScopes: ["boards:read"]
39308
+ },
39309
+ {
39310
+ name: "items.list",
39311
+ class: "read",
39312
+ description: "List all items on a board, optionally filtered by item type (sticky_note, text, shape, card, image, frame, connector, embed, app_card, document).",
39313
+ parameters: {
39314
+ type: "object",
39315
+ properties: {
39316
+ board_id: { type: "string" },
39317
+ type: {
39318
+ type: "string",
39319
+ enum: [
39320
+ "sticky_note",
39321
+ "text",
39322
+ "shape",
39323
+ "card",
39324
+ "image",
39325
+ "frame",
39326
+ "connector",
39327
+ "embed",
39328
+ "app_card",
39329
+ "document",
39330
+ "preview"
39331
+ ]
39332
+ },
39333
+ limit: { type: "integer", minimum: 1, maximum: 50 },
39334
+ cursor: { type: "string" }
39335
+ },
39336
+ required: ["board_id"]
39337
+ },
39338
+ request: {
39339
+ method: "GET",
39340
+ path: "/v2/boards/{board_id}/items",
39341
+ query: { type: "{type}", limit: "{limit}", cursor: "{cursor}" }
39342
+ },
39343
+ requiredScopes: ["boards:read"]
39344
+ },
39345
+ {
39346
+ name: "items.get",
39347
+ class: "read",
39348
+ description: "Fetch a single board item by id.",
39349
+ parameters: {
39350
+ type: "object",
39351
+ properties: {
39352
+ board_id: { type: "string" },
39353
+ item_id: { type: "string" }
39354
+ },
39355
+ required: ["board_id", "item_id"]
39356
+ },
39357
+ request: { method: "GET", path: "/v2/boards/{board_id}/items/{item_id}" },
39358
+ requiredScopes: ["boards:read"]
39359
+ },
39360
+ {
39361
+ name: "connectors.list",
39362
+ class: "read",
39363
+ description: "List connector lines on a board (arrows / lines between items).",
39364
+ parameters: {
39365
+ type: "object",
39366
+ properties: {
39367
+ board_id: { type: "string" },
39368
+ limit: { type: "integer", minimum: 1, maximum: 50 },
39369
+ cursor: { type: "string" }
39370
+ },
39371
+ required: ["board_id"]
39372
+ },
39373
+ request: {
39374
+ method: "GET",
39375
+ path: "/v2/boards/{board_id}/connectors",
39376
+ query: { limit: "{limit}", cursor: "{cursor}" }
39377
+ },
39378
+ requiredScopes: ["boards:read"]
39379
+ },
39380
+ {
39381
+ name: "tags.list",
39382
+ class: "read",
39383
+ description: "List tags defined on a board.",
39384
+ parameters: {
39385
+ type: "object",
39386
+ properties: {
39387
+ board_id: { type: "string" },
39388
+ limit: { type: "integer", minimum: 1, maximum: 50 },
39389
+ offset: { type: "integer", minimum: 0 }
39390
+ },
39391
+ required: ["board_id"]
39392
+ },
39393
+ request: {
39394
+ method: "GET",
39395
+ path: "/v2/boards/{board_id}/tags",
39396
+ query: { limit: "{limit}", offset: "{offset}" }
39397
+ },
39398
+ requiredScopes: ["boards:read"]
39399
+ },
39400
+ {
39401
+ name: "boards.create",
39402
+ class: "mutation",
39403
+ description: "Create a new Miro board. Accepts an optional name, description, team_id, and sharing policy. Returns the new board id used by every items.* endpoint.",
39404
+ parameters: {
39405
+ type: "object",
39406
+ properties: {
39407
+ name: { type: "string", maxLength: 60 },
39408
+ description: { type: "string", maxLength: 300 },
39409
+ team_id: { type: "string" },
39410
+ policy: {
39411
+ type: "object",
39412
+ description: "Permissions + sharing policy. See https://developers.miro.com/reference/create-board for the full PolicyChange shape."
39413
+ }
39414
+ },
39415
+ required: ["name"]
39416
+ },
39417
+ request: {
39418
+ method: "POST",
39419
+ path: "/v2/boards",
39420
+ body: {
39421
+ name: "{name}",
39422
+ description: "{description}",
39423
+ teamId: "{team_id}",
39424
+ policy: "{policy}"
39425
+ }
39426
+ },
39427
+ cas: "native-idempotency",
39428
+ requiredScopes: ["boards:write"]
39429
+ },
39430
+ {
39431
+ name: "boards.update",
39432
+ class: "mutation",
39433
+ description: "Update a Miro board (name, description, team, or sharing policy).",
39434
+ parameters: {
39435
+ type: "object",
39436
+ properties: {
39437
+ board_id: { type: "string" },
39438
+ name: { type: "string", maxLength: 60 },
39439
+ description: { type: "string", maxLength: 300 },
39440
+ team_id: { type: "string" },
39441
+ policy: { type: "object" }
39442
+ },
39443
+ required: ["board_id"]
39444
+ },
39445
+ request: {
39446
+ method: "PATCH",
39447
+ path: "/v2/boards/{board_id}",
39448
+ body: {
39449
+ name: "{name}",
39450
+ description: "{description}",
39451
+ teamId: "{team_id}",
39452
+ policy: "{policy}"
39453
+ }
39454
+ },
39455
+ cas: "native-idempotency",
39456
+ requiredScopes: ["boards:write"]
39457
+ },
39458
+ {
39459
+ name: "boards.delete",
39460
+ class: "mutation",
39461
+ description: "Delete a Miro board (irreversible).",
39462
+ parameters: {
39463
+ type: "object",
39464
+ properties: { board_id: { type: "string" } },
39465
+ required: ["board_id"]
39466
+ },
39467
+ request: { method: "DELETE", path: "/v2/boards/{board_id}" },
39468
+ cas: "native-idempotency",
39469
+ requiredScopes: ["boards:write"]
39470
+ },
39471
+ {
39472
+ name: "sticky_notes.create",
39473
+ class: "mutation",
39474
+ description: "Create a sticky note on a board. `data.content` accepts plain text; `style.fillColor` is a Miro sticky-note color keyword (e.g. yellow, light_yellow, pink).",
39475
+ parameters: {
39476
+ type: "object",
39477
+ properties: {
39478
+ board_id: { type: "string" },
39479
+ data: {
39480
+ type: "object",
39481
+ properties: {
39482
+ content: { type: "string" },
39483
+ shape: { type: "string", enum: ["square", "rectangle"] }
39484
+ },
39485
+ required: ["content"]
39486
+ },
39487
+ style: {
39488
+ type: "object",
39489
+ properties: {
39490
+ fillColor: { type: "string" },
39491
+ textAlign: { type: "string", enum: ["left", "center", "right"] },
39492
+ textAlignVertical: { type: "string", enum: ["top", "middle", "bottom"] }
39493
+ }
39494
+ },
39495
+ position: {
39496
+ type: "object",
39497
+ properties: {
39498
+ x: { type: "number" },
39499
+ y: { type: "number" },
39500
+ origin: { type: "string", enum: ["center"] }
39501
+ }
39502
+ },
39503
+ geometry: {
39504
+ type: "object",
39505
+ properties: {
39506
+ width: { type: "number" },
39507
+ height: { type: "number" }
39508
+ }
39509
+ },
39510
+ parent: {
39511
+ type: "object",
39512
+ description: "Attach the sticky note to a frame: { id: <frame_item_id> }.",
39513
+ properties: { id: { type: "string" } }
39514
+ }
39515
+ },
39516
+ required: ["board_id", "data"]
39517
+ },
39518
+ request: {
39519
+ method: "POST",
39520
+ path: "/v2/boards/{board_id}/sticky_notes",
39521
+ body: {
39522
+ data: "{data}",
39523
+ style: "{style}",
39524
+ position: "{position}",
39525
+ geometry: "{geometry}",
39526
+ parent: "{parent}"
39527
+ }
39528
+ },
39529
+ cas: "native-idempotency",
39530
+ requiredScopes: ["boards:write"]
39531
+ },
39532
+ {
39533
+ name: "sticky_notes.update",
39534
+ class: "mutation",
39535
+ description: "Update a sticky note (content, style, position, geometry, or parent frame).",
39536
+ parameters: {
39537
+ type: "object",
39538
+ properties: {
39539
+ board_id: { type: "string" },
39540
+ item_id: { type: "string" },
39541
+ data: { type: "object" },
39542
+ style: { type: "object" },
39543
+ position: { type: "object" },
39544
+ geometry: { type: "object" },
39545
+ parent: { type: "object" }
39546
+ },
39547
+ required: ["board_id", "item_id"]
39548
+ },
39549
+ request: {
39550
+ method: "PATCH",
39551
+ path: "/v2/boards/{board_id}/sticky_notes/{item_id}",
39552
+ body: {
39553
+ data: "{data}",
39554
+ style: "{style}",
39555
+ position: "{position}",
39556
+ geometry: "{geometry}",
39557
+ parent: "{parent}"
39558
+ }
39559
+ },
39560
+ cas: "native-idempotency",
39561
+ requiredScopes: ["boards:write"]
39562
+ },
39563
+ {
39564
+ name: "text.create",
39565
+ class: "mutation",
39566
+ description: "Create a text item on a board.",
39567
+ parameters: {
39568
+ type: "object",
39569
+ properties: {
39570
+ board_id: { type: "string" },
39571
+ data: {
39572
+ type: "object",
39573
+ properties: { content: { type: "string" } },
39574
+ required: ["content"]
39575
+ },
39576
+ style: { type: "object" },
39577
+ position: { type: "object" },
39578
+ geometry: { type: "object" },
39579
+ parent: { type: "object" }
39580
+ },
39581
+ required: ["board_id", "data"]
39582
+ },
39583
+ request: {
39584
+ method: "POST",
39585
+ path: "/v2/boards/{board_id}/texts",
39586
+ body: {
39587
+ data: "{data}",
39588
+ style: "{style}",
39589
+ position: "{position}",
39590
+ geometry: "{geometry}",
39591
+ parent: "{parent}"
39592
+ }
39593
+ },
39594
+ cas: "native-idempotency",
39595
+ requiredScopes: ["boards:write"]
39596
+ },
39597
+ {
39598
+ name: "shapes.create",
39599
+ class: "mutation",
39600
+ description: "Create a shape item on a board. `data.shape` selects the geometric primitive (rectangle, round_rectangle, circle, triangle, rhombus, etc.).",
39601
+ parameters: {
39602
+ type: "object",
39603
+ properties: {
39604
+ board_id: { type: "string" },
39605
+ data: {
39606
+ type: "object",
39607
+ properties: {
39608
+ shape: {
39609
+ type: "string",
39610
+ description: "Miro shape kind; full enum at https://developers.miro.com/reference/create-shape-item."
39611
+ },
39612
+ content: { type: "string" }
39613
+ },
39614
+ required: ["shape"]
39615
+ },
39616
+ style: { type: "object" },
39617
+ position: { type: "object" },
39618
+ geometry: { type: "object" },
39619
+ parent: { type: "object" }
39620
+ },
39621
+ required: ["board_id", "data"]
39622
+ },
39623
+ request: {
39624
+ method: "POST",
39625
+ path: "/v2/boards/{board_id}/shapes",
39626
+ body: {
39627
+ data: "{data}",
39628
+ style: "{style}",
39629
+ position: "{position}",
39630
+ geometry: "{geometry}",
39631
+ parent: "{parent}"
39632
+ }
39633
+ },
39634
+ cas: "native-idempotency",
39635
+ requiredScopes: ["boards:write"]
39636
+ },
39637
+ {
39638
+ name: "cards.create",
39639
+ class: "mutation",
39640
+ description: "Create a card item (title + description + assignee + due-date) on a board.",
39641
+ parameters: {
39642
+ type: "object",
39643
+ properties: {
39644
+ board_id: { type: "string" },
39645
+ data: {
39646
+ type: "object",
39647
+ properties: {
39648
+ title: { type: "string" },
39649
+ description: { type: "string" },
39650
+ dueDate: { type: "string", format: "date-time" },
39651
+ assigneeId: { type: "string" }
39652
+ },
39653
+ required: ["title"]
39654
+ },
39655
+ style: { type: "object" },
39656
+ position: { type: "object" },
39657
+ geometry: { type: "object" },
39658
+ parent: { type: "object" }
39659
+ },
39660
+ required: ["board_id", "data"]
39661
+ },
39662
+ request: {
39663
+ method: "POST",
39664
+ path: "/v2/boards/{board_id}/cards",
39665
+ body: {
39666
+ data: "{data}",
39667
+ style: "{style}",
39668
+ position: "{position}",
39669
+ geometry: "{geometry}",
39670
+ parent: "{parent}"
39671
+ }
39672
+ },
39673
+ cas: "native-idempotency",
39674
+ requiredScopes: ["boards:write"]
39675
+ },
39676
+ {
39677
+ name: "frames.create",
39678
+ class: "mutation",
39679
+ description: "Create a frame on a board. Frames group items; child items can be attached via `parent.id` on item creation.",
39680
+ parameters: {
39681
+ type: "object",
39682
+ properties: {
39683
+ board_id: { type: "string" },
39684
+ data: {
39685
+ type: "object",
39686
+ properties: {
39687
+ title: { type: "string" },
39688
+ format: { type: "string", enum: ["custom"] },
39689
+ type: { type: "string", enum: ["freeform"] }
39690
+ }
39691
+ },
39692
+ style: { type: "object" },
39693
+ position: { type: "object" },
39694
+ geometry: { type: "object" }
39695
+ },
39696
+ required: ["board_id"]
39697
+ },
39698
+ request: {
39699
+ method: "POST",
39700
+ path: "/v2/boards/{board_id}/frames",
39701
+ body: {
39702
+ data: "{data}",
39703
+ style: "{style}",
39704
+ position: "{position}",
39705
+ geometry: "{geometry}"
39706
+ }
39707
+ },
39708
+ cas: "native-idempotency",
39709
+ requiredScopes: ["boards:write"]
39710
+ },
39711
+ {
39712
+ name: "images.create.by_url",
39713
+ class: "mutation",
39714
+ description: "Create an image item from a public URL (Miro fetches the image server-side).",
39715
+ parameters: {
39716
+ type: "object",
39717
+ properties: {
39718
+ board_id: { type: "string" },
39719
+ data: {
39720
+ type: "object",
39721
+ properties: {
39722
+ url: { type: "string", format: "uri" },
39723
+ title: { type: "string" }
39724
+ },
39725
+ required: ["url"]
39726
+ },
39727
+ position: { type: "object" },
39728
+ geometry: { type: "object" },
39729
+ parent: { type: "object" }
39730
+ },
39731
+ required: ["board_id", "data"]
39732
+ },
39733
+ request: {
39734
+ method: "POST",
39735
+ path: "/v2/boards/{board_id}/images",
39736
+ body: {
39737
+ data: "{data}",
39738
+ position: "{position}",
39739
+ geometry: "{geometry}",
39740
+ parent: "{parent}"
39741
+ }
39742
+ },
39743
+ cas: "native-idempotency",
39744
+ requiredScopes: ["boards:write"]
39745
+ },
39746
+ {
39747
+ name: "connectors.create",
39748
+ class: "mutation",
39749
+ description: "Create a connector line between two items on the board. `startItem.id` and `endItem.id` reference existing item ids.",
39750
+ parameters: {
39751
+ type: "object",
39752
+ properties: {
39753
+ board_id: { type: "string" },
39754
+ startItem: {
39755
+ type: "object",
39756
+ properties: { id: { type: "string" } },
39757
+ required: ["id"]
39758
+ },
39759
+ endItem: {
39760
+ type: "object",
39761
+ properties: { id: { type: "string" } },
39762
+ required: ["id"]
39763
+ },
39764
+ captions: {
39765
+ type: "array",
39766
+ items: { type: "object", properties: { content: { type: "string" } } }
39767
+ },
39768
+ style: { type: "object" },
39769
+ shape: { type: "string", enum: ["straight", "elbowed", "curved"] }
39770
+ },
39771
+ required: ["board_id", "startItem", "endItem"]
39772
+ },
39773
+ request: {
39774
+ method: "POST",
39775
+ path: "/v2/boards/{board_id}/connectors",
39776
+ body: {
39777
+ startItem: "{startItem}",
39778
+ endItem: "{endItem}",
39779
+ captions: "{captions}",
39780
+ style: "{style}",
39781
+ shape: "{shape}"
39782
+ }
39783
+ },
39784
+ cas: "native-idempotency",
39785
+ requiredScopes: ["boards:write"]
39786
+ },
39787
+ {
39788
+ name: "items.delete",
39789
+ class: "mutation",
39790
+ description: "Delete an item from a board (works across all item types).",
39791
+ parameters: {
39792
+ type: "object",
39793
+ properties: {
39794
+ board_id: { type: "string" },
39795
+ item_id: { type: "string" }
39796
+ },
39797
+ required: ["board_id", "item_id"]
39798
+ },
39799
+ request: { method: "DELETE", path: "/v2/boards/{board_id}/items/{item_id}" },
39800
+ cas: "native-idempotency",
39801
+ requiredScopes: ["boards:write"]
39802
+ },
39803
+ {
39804
+ name: "boards.share",
39805
+ class: "mutation",
39806
+ description: "Invite users to a Miro board by email. Roles: viewer, commenter, editor, coowner.",
39807
+ parameters: {
39808
+ type: "object",
39809
+ properties: {
39810
+ board_id: { type: "string" },
39811
+ emails: { type: "array", items: { type: "string", format: "email" } },
39812
+ role: {
39813
+ type: "string",
39814
+ enum: ["viewer", "commenter", "editor", "coowner"]
39815
+ },
39816
+ message: { type: "string" }
39817
+ },
39818
+ required: ["board_id", "emails", "role"]
39819
+ },
39820
+ request: {
39821
+ method: "POST",
39822
+ path: "/v2/boards/{board_id}/members",
39823
+ body: {
39824
+ emails: "{emails}",
39825
+ role: "{role}",
39826
+ message: "{message}"
39827
+ }
39828
+ },
39829
+ cas: "native-idempotency",
39830
+ requiredScopes: ["boards:write"]
39831
+ }
39832
+ ]
39833
+ });
39834
+
38898
39835
  // src/connectors/adapters/monday.ts
38899
39836
  var BOARD_FRAGMENT = `
38900
39837
  id
@@ -39019,7 +39956,7 @@ var mondayConnector = declarativeRestConnector({
39019
39956
  auth: {
39020
39957
  kind: "oauth2",
39021
39958
  authorizationUrl: "https://auth.monday.com/oauth2/authorize",
39022
- tokenUrl: "https://auth.monday.com/oauth2/token",
39959
+ tokenUrl: "https://auth.monday.com/oauth_ms/oauth/token",
39023
39960
  scopes: [
39024
39961
  "me:read",
39025
39962
  "boards:read",
@@ -39409,6 +40346,475 @@ var mondayConnector = declarativeRestConnector({
39409
40346
  ]
39410
40347
  });
39411
40348
 
40349
+ // src/connectors/adapters/mongodb.ts
40350
+ import { isIP as isIP3 } from "net";
40351
+ import { createSecureContext } from "tls";
40352
+ import {
40353
+ BSON,
40354
+ MongoClient
40355
+ } from "mongodb";
40356
+ var MAX_NAME_BYTES = 120;
40357
+ var MAX_FIELD_BYTES = 256;
40358
+ var MAX_FILTERS = 20;
40359
+ var MAX_PROJECTION_FIELDS = 64;
40360
+ var MAX_SORT_FIELDS = 8;
40361
+ var MAX_COLLECTIONS = 1e3;
40362
+ var MAX_INDEXES = 200;
40363
+ var MAX_DOCUMENTS = 1e3;
40364
+ var MAX_RESULT_BYTES2 = 10 * 1024 * 1024;
40365
+ var MAX_FILTER_BYTES = 1024 * 1024;
40366
+ var MAX_SCALAR_STRING_BYTES = 64 * 1024;
40367
+ var MAX_TLS_CA_BYTES = 256 * 1024;
40368
+ function createMongoDbConnector(options = {}) {
40369
+ const createClient = options.createClient ?? defaultCreateClient;
40370
+ const resolveHost = options.resolveHost ?? resolvePublicHostAddresses;
40371
+ return {
40372
+ manifest: {
40373
+ kind: "mongodb",
40374
+ displayName: "MongoDB",
40375
+ description: "Inspect MongoDB collections and indexes and run bounded structured document reads over a verified TLS connection.",
40376
+ auth: {
40377
+ kind: "api-key",
40378
+ hint: "JSON with a public MongoDB host, database, user, password, optional port/auth source, and optional TLS CA. Verified TLS is mandatory."
40379
+ },
40380
+ category: "database",
40381
+ defaultConsistencyModel: "authoritative",
40382
+ rateLimit: { requests: 120, windowMs: 6e4, scope: "data-source" },
40383
+ capabilities: [
40384
+ readCapability6("mongodb.collections.list", "List collections visible in the configured database.", {
40385
+ type: "object",
40386
+ properties: {},
40387
+ additionalProperties: false
40388
+ }),
40389
+ readCapability6("mongodb.collections.describe", "Read options and metadata for one collection.", collectionSchema()),
40390
+ readCapability6("mongodb.indexes.list", "List bounded index metadata for one collection.", collectionSchema()),
40391
+ readCapability6("mongodb.documents.find", "Read bounded documents using fixed scalar predicates, projection, and sort fields.", {
40392
+ type: "object",
40393
+ properties: {
40394
+ collection: nameParameter("Collection name."),
40395
+ filters: filterArraySchema(),
40396
+ fields: {
40397
+ type: "array",
40398
+ minItems: 1,
40399
+ maxItems: MAX_PROJECTION_FIELDS,
40400
+ uniqueItems: true,
40401
+ items: fieldParameter()
40402
+ },
40403
+ includeId: { type: "boolean", default: true },
40404
+ sort: {
40405
+ type: "array",
40406
+ maxItems: MAX_SORT_FIELDS,
40407
+ items: {
40408
+ type: "object",
40409
+ properties: {
40410
+ field: fieldParameter(),
40411
+ direction: { type: "string", enum: ["asc", "desc"], default: "asc" }
40412
+ },
40413
+ required: ["field"],
40414
+ additionalProperties: false
40415
+ }
40416
+ },
40417
+ limit: { type: "integer", minimum: 1, maximum: MAX_DOCUMENTS, default: 100 },
40418
+ skip: { type: "integer", minimum: 0, maximum: 1e6, default: 0 }
40419
+ },
40420
+ required: ["collection"],
40421
+ additionalProperties: false
40422
+ }),
40423
+ readCapability6("mongodb.documents.count", "Count documents matching fixed scalar predicates within a bounded server execution time.", {
40424
+ type: "object",
40425
+ properties: {
40426
+ collection: nameParameter("Collection name."),
40427
+ filters: filterArraySchema()
40428
+ },
40429
+ required: ["collection"],
40430
+ additionalProperties: false
40431
+ })
40432
+ ]
40433
+ },
40434
+ async test(source) {
40435
+ try {
40436
+ await withClient(source, createClient, resolveHost, async (client, credentials) => {
40437
+ const response = await client.db(credentials.database).command(
40438
+ { ping: 1 },
40439
+ { maxTimeMS: credentials.commandTimeoutMs }
40440
+ );
40441
+ if (response.ok !== 1) throw new Error("MongoDB ping returned an unexpected response");
40442
+ });
40443
+ return { ok: true };
40444
+ } catch (error) {
40445
+ return { ok: false, reason: safeErrorMessage(error, credentialSecrets(source)) };
40446
+ }
40447
+ },
40448
+ async executeRead(invocation) {
40449
+ const request4 = prepareRead(invocation);
40450
+ const data4 = await withClient(invocation.source, createClient, resolveHost, async (client, credentials) => {
40451
+ return executeRead(request4, client.db(credentials.database), credentials.commandTimeoutMs);
40452
+ });
40453
+ return { data: data4, fetchedAt: Date.now() };
40454
+ }
40455
+ };
40456
+ }
40457
+ var mongodbConnector = createMongoDbConnector();
40458
+ function defaultCreateClient(uri, options) {
40459
+ return new MongoClient(uri, options);
40460
+ }
40461
+ async function withClient(source, createClient, resolveHost, run) {
40462
+ const credentials = readCredentials2(source);
40463
+ const addresses = await resolveHost(credentials.host);
40464
+ if (addresses.length === 0) throw new Error("MongoDB host did not resolve");
40465
+ const uriHost = isIP3(credentials.host) === 6 ? `[${credentials.host}]` : credentials.host;
40466
+ const client = createClient(`mongodb://${uriHost}:${credentials.port}/`, {
40467
+ appName: "tangle-integration-hub",
40468
+ auth: { username: credentials.user, password: credentials.password },
40469
+ authSource: credentials.authSource,
40470
+ connectTimeoutMS: credentials.connectTimeoutMs,
40471
+ directConnection: true,
40472
+ lookup: pinnedLookup(addresses[0]),
40473
+ maxIdleTimeMS: 5e3,
40474
+ maxPoolSize: 1,
40475
+ minPoolSize: 0,
40476
+ rejectUnauthorized: true,
40477
+ retryReads: true,
40478
+ retryWrites: false,
40479
+ serverSelectionTimeoutMS: credentials.connectTimeoutMs,
40480
+ servername: isIP3(credentials.host) === 0 ? credentials.host : void 0,
40481
+ secureContext: createSecureContext({ ca: credentials.tlsCa, minVersion: "TLSv1.2" }),
40482
+ socketTimeoutMS: credentials.commandTimeoutMs,
40483
+ tls: true
40484
+ });
40485
+ try {
40486
+ await client.connect();
40487
+ return await run(client, credentials);
40488
+ } catch (error) {
40489
+ throw new Error(safeErrorMessage(error, credentials.secrets));
40490
+ } finally {
40491
+ await client.close().catch(() => void 0);
40492
+ }
40493
+ }
40494
+ async function executeRead(request4, database, commandTimeoutMs) {
40495
+ if (request4.kind === "collections.list") {
40496
+ const collections = await readCursor(
40497
+ database.listCollections({}, { nameOnly: true, maxTimeMS: commandTimeoutMs }),
40498
+ MAX_COLLECTIONS,
40499
+ "MongoDB collection list"
40500
+ );
40501
+ return boundedResult({ collections }, "MongoDB collection list");
40502
+ }
40503
+ if (request4.kind === "collections.describe") {
40504
+ const matches = await readCursor(
40505
+ database.listCollections({ name: request4.collection }, { nameOnly: false, maxTimeMS: commandTimeoutMs }),
40506
+ 1,
40507
+ "MongoDB collection description"
40508
+ );
40509
+ return boundedResult({ collection: matches[0] ?? null }, "MongoDB collection description");
40510
+ }
40511
+ if (request4.kind === "indexes.list") {
40512
+ const indexes = await readCursor(
40513
+ database.collection(request4.collection).listIndexes({ maxTimeMS: commandTimeoutMs }),
40514
+ MAX_INDEXES,
40515
+ "MongoDB index list"
40516
+ );
40517
+ return boundedResult({ collection: request4.collection, indexes }, "MongoDB index list");
40518
+ }
40519
+ if (request4.kind === "documents.find") {
40520
+ const cursor = database.collection(request4.collection).find(request4.filter, {
40521
+ ...request4.projection ? { projection: request4.projection } : {},
40522
+ maxTimeMS: commandTimeoutMs
40523
+ });
40524
+ if (Object.keys(request4.sort).length > 0) cursor.sort(request4.sort);
40525
+ cursor.skip(request4.skip).limit(request4.limit);
40526
+ const documents = await readCursor(cursor, request4.limit, "MongoDB document result");
40527
+ return boundedResult({ collection: request4.collection, documents }, "MongoDB document result");
40528
+ }
40529
+ if (request4.kind === "documents.count") {
40530
+ const count = await database.collection(request4.collection).countDocuments(request4.filter, { maxTimeMS: commandTimeoutMs });
40531
+ if (!Number.isSafeInteger(count) || count < 0) throw new Error("MongoDB returned a malformed document count");
40532
+ return { collection: request4.collection, count };
40533
+ }
40534
+ }
40535
+ function prepareRead(invocation) {
40536
+ if (invocation.capabilityName === "mongodb.collections.list") return { kind: "collections.list" };
40537
+ if (invocation.capabilityName === "mongodb.collections.describe") {
40538
+ return { kind: "collections.describe", collection: readCollectionName(invocation.args.collection) };
40539
+ }
40540
+ if (invocation.capabilityName === "mongodb.indexes.list") {
40541
+ return { kind: "indexes.list", collection: readCollectionName(invocation.args.collection) };
40542
+ }
40543
+ if (invocation.capabilityName === "mongodb.documents.find") {
40544
+ return {
40545
+ kind: "documents.find",
40546
+ collection: readCollectionName(invocation.args.collection),
40547
+ filter: readFilters(invocation.args.filters),
40548
+ projection: readProjection(invocation.args.fields, invocation.args.includeId),
40549
+ sort: readSort(invocation.args.sort),
40550
+ limit: readBoundedInteger(invocation.args.limit, 100, 1, MAX_DOCUMENTS, "limit"),
40551
+ skip: readBoundedInteger(invocation.args.skip, 0, 0, 1e6, "skip")
40552
+ };
40553
+ }
40554
+ if (invocation.capabilityName === "mongodb.documents.count") {
40555
+ return {
40556
+ kind: "documents.count",
40557
+ collection: readCollectionName(invocation.args.collection),
40558
+ filter: readFilters(invocation.args.filters)
40559
+ };
40560
+ }
40561
+ throw new Error(`Unknown MongoDB read capability: ${invocation.capabilityName}`);
40562
+ }
40563
+ async function readCursor(cursor, maximum, label) {
40564
+ const entries = [];
40565
+ let serializedBytes = 2;
40566
+ try {
40567
+ while (entries.length < maximum) {
40568
+ const entry = await cursor.next();
40569
+ if (entry === null) return entries;
40570
+ serializedBytes += Buffer.byteLength(
40571
+ JSON.stringify(BSON.EJSON.serialize(entry, { relaxed: true })),
40572
+ "utf8"
40573
+ ) + 1;
40574
+ if (serializedBytes > MAX_RESULT_BYTES2) {
40575
+ throw new Error(`${label} exceeds the ${MAX_RESULT_BYTES2}-byte limit`);
40576
+ }
40577
+ entries.push(entry);
40578
+ }
40579
+ if (await cursor.next() !== null) throw new Error(`${label} exceeds ${maximum} entries`);
40580
+ return entries;
40581
+ } finally {
40582
+ await cursor.close().catch(() => void 0);
40583
+ }
40584
+ }
40585
+ function readCredentials2(source) {
40586
+ let raw;
40587
+ if (source.credentials.kind === "custom") raw = source.credentials.values;
40588
+ else if (source.credentials.kind === "api-key") {
40589
+ try {
40590
+ raw = JSON.parse(source.credentials.apiKey);
40591
+ } catch {
40592
+ throw new Error("MongoDB credential must be valid JSON");
40593
+ }
40594
+ } else {
40595
+ throw new Error("MongoDB requires a structured credential bundle");
40596
+ }
40597
+ if (!isPlainRecord(raw)) throw new Error("MongoDB credential must be a JSON object");
40598
+ const host = readHost(raw.host);
40599
+ const database = readDatabaseName(raw.database, "database");
40600
+ const user = readCredentialString(raw.user ?? raw.username, "user", 128);
40601
+ const password = readCredentialString(raw.password, "password", 4096);
40602
+ const authSource = raw.authSource === void 0 ? "admin" : readDatabaseName(raw.authSource, "authSource");
40603
+ const tlsCa = readOptionalString(raw.tlsCa, "tlsCa");
40604
+ if (tlsCa && Buffer.byteLength(tlsCa, "utf8") > MAX_TLS_CA_BYTES) {
40605
+ throw new Error(`MongoDB tlsCa exceeds the ${MAX_TLS_CA_BYTES}-byte limit`);
40606
+ }
40607
+ return {
40608
+ host,
40609
+ port: readBoundedInteger(raw.port, 27017, 1, 65535, "port"),
40610
+ database,
40611
+ user,
40612
+ password,
40613
+ authSource,
40614
+ tlsCa,
40615
+ connectTimeoutMs: readBoundedInteger(raw.connectTimeoutMs, 1e4, 1e3, 3e4, "connectTimeoutMs"),
40616
+ commandTimeoutMs: readBoundedInteger(raw.commandTimeoutMs, 3e4, 1e3, 6e4, "commandTimeoutMs"),
40617
+ secrets: [password]
40618
+ };
40619
+ }
40620
+ function readFilters(value) {
40621
+ if (value === void 0 || value === null) return {};
40622
+ if (!Array.isArray(value) || value.length > MAX_FILTERS) {
40623
+ throw new Error(`filters must contain at most ${MAX_FILTERS} entries`);
40624
+ }
40625
+ const predicates = value.map((entry, index) => {
40626
+ if (!isPlainRecord(entry)) throw new Error(`filters[${index}] must be an object`);
40627
+ const field = readField(entry.field, `filters[${index}].field`);
40628
+ const operator = entry.operator;
40629
+ if (!["eq", "ne", "lt", "lte", "gt", "gte"].includes(String(operator))) {
40630
+ throw new Error(`filters[${index}].operator is unsupported`);
40631
+ }
40632
+ const scalar = readScalar(entry.value, `filters[${index}].value`);
40633
+ return { [field]: { [mongoOperator(String(operator))]: scalar } };
40634
+ });
40635
+ const filter = predicates.length === 0 ? {} : { $and: predicates };
40636
+ if (Buffer.byteLength(JSON.stringify(filter), "utf8") > MAX_FILTER_BYTES) {
40637
+ throw new Error(`MongoDB filters exceed the ${MAX_FILTER_BYTES}-byte limit`);
40638
+ }
40639
+ return filter;
40640
+ }
40641
+ function readProjection(fieldsValue, includeIdValue) {
40642
+ const includeId = includeIdValue === void 0 || includeIdValue === null ? true : readBoolean2(includeIdValue, "includeId");
40643
+ if (fieldsValue === void 0 || fieldsValue === null) return includeId ? void 0 : { _id: 0 };
40644
+ const fields = readFieldArray(fieldsValue, "fields", MAX_PROJECTION_FIELDS, true);
40645
+ return Object.fromEntries([
40646
+ ...fields.map((field) => [field, 1]),
40647
+ ...!includeId && !fields.includes("_id") ? [["_id", 0]] : []
40648
+ ]);
40649
+ }
40650
+ function readSort(value) {
40651
+ if (value === void 0 || value === null) return {};
40652
+ if (!Array.isArray(value) || value.length > MAX_SORT_FIELDS) {
40653
+ throw new Error(`sort must contain at most ${MAX_SORT_FIELDS} entries`);
40654
+ }
40655
+ const entries = value.map((entry, index) => {
40656
+ if (!isPlainRecord(entry)) throw new Error(`sort[${index}] must be an object`);
40657
+ const field = readField(entry.field, `sort[${index}].field`);
40658
+ const direction = entry.direction ?? "asc";
40659
+ if (direction !== "asc" && direction !== "desc") {
40660
+ throw new Error(`sort[${index}].direction must be asc or desc`);
40661
+ }
40662
+ return [field, direction === "asc" ? 1 : -1];
40663
+ });
40664
+ if (new Set(entries.map(([field]) => field)).size !== entries.length) {
40665
+ throw new Error("sort must not contain duplicate fields");
40666
+ }
40667
+ return Object.fromEntries(entries);
40668
+ }
40669
+ function readFieldArray(value, label, maximum, required) {
40670
+ if (!Array.isArray(value) || required && value.length === 0 || value.length > maximum) {
40671
+ throw new Error(`${label} must contain ${required ? "1-" : "0-"}${maximum} fields`);
40672
+ }
40673
+ const fields = value.map((entry, index) => readField(entry, `${label}[${index}]`));
40674
+ if (new Set(fields).size !== fields.length) throw new Error(`${label} must not contain duplicates`);
40675
+ return fields;
40676
+ }
40677
+ function readScalar(value, label) {
40678
+ if (value === null || typeof value === "boolean") return value;
40679
+ if (typeof value === "number") {
40680
+ if (!Number.isFinite(value)) throw new Error(`${label} must be finite`);
40681
+ return value;
40682
+ }
40683
+ if (typeof value === "string") {
40684
+ if (Buffer.byteLength(value, "utf8") > MAX_SCALAR_STRING_BYTES) {
40685
+ throw new Error(`${label} exceeds the ${MAX_SCALAR_STRING_BYTES}-byte limit`);
40686
+ }
40687
+ return value;
40688
+ }
40689
+ throw new Error(`${label} must be a JSON scalar or null`);
40690
+ }
40691
+ function mongoOperator(value) {
40692
+ return { eq: "$eq", ne: "$ne", lt: "$lt", lte: "$lte", gt: "$gt", gte: "$gte" }[value];
40693
+ }
40694
+ function boundedResult(value, label) {
40695
+ const serialized = BSON.EJSON.serialize(value, { relaxed: true });
40696
+ if (Buffer.byteLength(JSON.stringify(serialized), "utf8") > MAX_RESULT_BYTES2) {
40697
+ throw new Error(`${label} exceeds the ${MAX_RESULT_BYTES2}-byte limit`);
40698
+ }
40699
+ return serialized;
40700
+ }
40701
+ function readHost(value) {
40702
+ const host = readCredentialString(value, "host", 253);
40703
+ const ipVersion = isIP3(host);
40704
+ if (ipVersion !== 0) {
40705
+ if (!isPublicNetworkAddress(host)) throw new Error("MongoDB host is not a public network target");
40706
+ return host;
40707
+ }
40708
+ const normalized = host.toLowerCase();
40709
+ if (normalized === "localhost" || normalized.endsWith(".localhost") || normalized.endsWith(".local") || /[\s/@:\[\]]/.test(host)) {
40710
+ throw new Error("MongoDB host must be a public hostname or IP address without a scheme or port");
40711
+ }
40712
+ return host;
40713
+ }
40714
+ function readName(value, label) {
40715
+ if (typeof value !== "string" || value.length === 0 || Buffer.byteLength(value, "utf8") > MAX_NAME_BYTES || /[\u0000-\u001f\u007f/\\]/.test(value)) {
40716
+ throw new Error(`${label} must be a non-empty MongoDB name under ${MAX_NAME_BYTES} bytes`);
40717
+ }
40718
+ return value;
40719
+ }
40720
+ function readCollectionName(value) {
40721
+ const collection = readName(value, "collection");
40722
+ if (collection.startsWith("system.") || collection.includes("$")) {
40723
+ throw new Error("collection must not target MongoDB system or command namespaces");
40724
+ }
40725
+ return collection;
40726
+ }
40727
+ function readDatabaseName(value, label) {
40728
+ const database = readName(value, label);
40729
+ if (Buffer.byteLength(database, "utf8") > 63 || !/^[A-Za-z0-9_-]+$/.test(database)) {
40730
+ throw new Error(`${label} must use only letters, numbers, underscores, or hyphens and stay under 63 bytes`);
40731
+ }
40732
+ return database;
40733
+ }
40734
+ function readField(value, label) {
40735
+ if (typeof value !== "string" || value.length === 0 || Buffer.byteLength(value, "utf8") > MAX_FIELD_BYTES || !/^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/.test(value)) {
40736
+ throw new Error(`${label} must be a dotted MongoDB field path under ${MAX_FIELD_BYTES} bytes`);
40737
+ }
40738
+ return value;
40739
+ }
40740
+ function readCredentialString(value, label, maximum) {
40741
+ if (typeof value !== "string" || value.length === 0 || value.length > maximum || label !== "password" && /[\u0000-\u001f\u007f]/.test(value)) {
40742
+ throw new Error(`MongoDB credential ${label} must be a non-empty string under ${maximum} characters`);
40743
+ }
40744
+ return value;
40745
+ }
40746
+ function readBoolean2(value, label) {
40747
+ if (typeof value !== "boolean") throw new Error(`${label} must be a boolean`);
40748
+ return value;
40749
+ }
40750
+ function pinnedLookup(address) {
40751
+ const family = isIP3(address);
40752
+ return (_hostname, options, callback) => {
40753
+ const normalizedOptions = typeof options === "number" ? { family: options } : options;
40754
+ if (normalizedOptions?.family && normalizedOptions.family !== family) {
40755
+ callback(new Error("MongoDB pinned address does not match the requested network family"), "", 0);
40756
+ return;
40757
+ }
40758
+ if (normalizedOptions?.all) {
40759
+ callback(null, [{ address, family }], void 0);
40760
+ return;
40761
+ }
40762
+ callback(null, address, family);
40763
+ };
40764
+ }
40765
+ function safeErrorMessage(error, secrets) {
40766
+ let message = error instanceof Error ? error.message : String(error);
40767
+ for (const secret of secrets) {
40768
+ if (secret.length >= 4) message = message.replaceAll(secret, "[REDACTED]");
40769
+ }
40770
+ return message;
40771
+ }
40772
+ function credentialSecrets(source) {
40773
+ try {
40774
+ return readCredentials2(source).secrets;
40775
+ } catch {
40776
+ return [];
40777
+ }
40778
+ }
40779
+ function collectionSchema() {
40780
+ return {
40781
+ type: "object",
40782
+ properties: { collection: nameParameter("Collection name.") },
40783
+ required: ["collection"],
40784
+ additionalProperties: false
40785
+ };
40786
+ }
40787
+ function filterArraySchema() {
40788
+ return {
40789
+ type: "array",
40790
+ maxItems: MAX_FILTERS,
40791
+ items: {
40792
+ type: "object",
40793
+ properties: {
40794
+ field: fieldParameter(),
40795
+ operator: { type: "string", enum: ["eq", "ne", "lt", "lte", "gt", "gte"] },
40796
+ value: { type: ["string", "number", "boolean", "null"] }
40797
+ },
40798
+ required: ["field", "operator", "value"],
40799
+ additionalProperties: false
40800
+ }
40801
+ };
40802
+ }
40803
+ function nameParameter(description) {
40804
+ return { type: "string", minLength: 1, maxLength: MAX_NAME_BYTES, description };
40805
+ }
40806
+ function fieldParameter() {
40807
+ return {
40808
+ type: "string",
40809
+ minLength: 1,
40810
+ maxLength: MAX_FIELD_BYTES,
40811
+ pattern: "^[A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*)*$"
40812
+ };
40813
+ }
40814
+ function readCapability6(name, description, parameters) {
40815
+ return { name, class: "read", description, parameters };
40816
+ }
40817
+
39412
40818
  // src/connectors/adapters/mycase.ts
39413
40819
  var pageProperties = {
39414
40820
  page: { type: "integer", minimum: 1 },
@@ -43883,7 +45289,7 @@ var pipedriveConnector = declarativeRestConnector({
43883
45289
  // src/connectors/adapters/parquet-files.ts
43884
45290
  import { parquetReadObjects } from "hyparquet";
43885
45291
  import { parquetWriteBuffer } from "hyparquet-writer";
43886
- var MAX_COLUMNS3 = 256;
45292
+ var MAX_COLUMNS4 = 256;
43887
45293
  var parquetFilesConnector = {
43888
45294
  manifest: {
43889
45295
  kind: "parquet-files",
@@ -43901,7 +45307,7 @@ var parquetFilesConnector = {
43901
45307
  type: "object",
43902
45308
  properties: {
43903
45309
  fileBase64: { type: "string", description: "Parquet file content encoded as canonical base64." },
43904
- columns: { type: "array", maxItems: MAX_COLUMNS3, items: { type: "string", minLength: 1 } },
45310
+ columns: { type: "array", maxItems: MAX_COLUMNS4, items: { type: "string", minLength: 1 } },
43905
45311
  rowStart: { type: "integer", minimum: 0, default: 0 },
43906
45312
  rowLimit: { type: "integer", minimum: 1, maximum: MAX_RECORDS, default: MAX_RECORDS }
43907
45313
  },
@@ -43947,8 +45353,8 @@ var parquetFilesConnector = {
43947
45353
  if (capabilityName !== "parquet.create") throw new Error(`Unknown Parquet capability: ${capabilityName}`);
43948
45354
  const records = readRecords(args.records);
43949
45355
  const columnNames = [...new Set(records.flatMap((record) => Object.keys(record)))];
43950
- if (columnNames.length === 0 || columnNames.length > MAX_COLUMNS3) {
43951
- throw new Error(`records must contain 1 through ${MAX_COLUMNS3} columns`);
45356
+ if (columnNames.length === 0 || columnNames.length > MAX_COLUMNS4) {
45357
+ throw new Error(`records must contain 1 through ${MAX_COLUMNS4} columns`);
43952
45358
  }
43953
45359
  if (columnNames.some((name) => name.length === 0)) throw new Error("column names must not be empty");
43954
45360
  const columnData = columnNames.map((name) => {
@@ -43978,8 +45384,8 @@ function asyncBuffer(file) {
43978
45384
  }
43979
45385
  function readColumns2(value) {
43980
45386
  if (value === void 0 || value === null) return void 0;
43981
- if (!Array.isArray(value) || value.length === 0 || value.length > MAX_COLUMNS3) {
43982
- throw new Error(`columns must contain 1 through ${MAX_COLUMNS3} names`);
45387
+ if (!Array.isArray(value) || value.length === 0 || value.length > MAX_COLUMNS4) {
45388
+ throw new Error(`columns must contain 1 through ${MAX_COLUMNS4} names`);
43983
45389
  }
43984
45390
  const columns = value.map((entry, index) => {
43985
45391
  if (typeof entry !== "string" || entry.length === 0) throw new Error(`columns[${index}] must be a non-empty string`);
@@ -44435,6 +45841,1143 @@ var quickbooksConnector = declarativeRestConnector({
44435
45841
  ]
44436
45842
  });
44437
45843
 
45844
+ // src/connectors/adapters/rabbitmq.ts
45845
+ import { createHash as createHash7 } from "crypto";
45846
+ import { isIP as isIP4 } from "net";
45847
+ import {
45848
+ connect as amqpConnect
45849
+ } from "amqplib";
45850
+ var MAX_MESSAGE_BYTES3 = 1024 * 1024;
45851
+ var MAX_NAME_BYTES2 = 255;
45852
+ var MAX_PEM_BYTES = 64 * 1024;
45853
+ var MAX_CA_CERTIFICATES = 16;
45854
+ var MAX_CA_BYTES = 256 * 1024;
45855
+ function createRabbitMqConnector(options = {}) {
45856
+ const connect = options.connect ?? ((connectOptions, socketOptions) => amqpConnect(connectOptions, socketOptions));
45857
+ const resolveHost = options.resolveHost ?? resolvePublicHostAddresses;
45858
+ return {
45859
+ manifest: {
45860
+ kind: "rabbitmq",
45861
+ displayName: "RabbitMQ",
45862
+ description: "Inspect queues and exchanges and publish confirmed JSON messages over verified TLS.",
45863
+ auth: {
45864
+ kind: "api-key",
45865
+ hint: "JSON with a public RabbitMQ host, username, password, virtual host, and optional TLS client credentials."
45866
+ },
45867
+ defaultConsistencyModel: "advisory",
45868
+ category: "webhook",
45869
+ rateLimit: { requests: 120, windowMs: 6e4, scope: "data-source" },
45870
+ capabilities: [
45871
+ readCapability7("rabbitmq.queues.inspect", "Check a queue and return its current message and consumer counts.", {
45872
+ type: "object",
45873
+ properties: { queue: nameSchema("queue") },
45874
+ required: ["queue"],
45875
+ additionalProperties: false
45876
+ }),
45877
+ readCapability7("rabbitmq.exchanges.inspect", "Check whether a named exchange exists and is visible to the connection.", {
45878
+ type: "object",
45879
+ properties: { exchange: nameSchema("exchange") },
45880
+ required: ["exchange"],
45881
+ additionalProperties: false
45882
+ }),
45883
+ mutationCapability6("send.message.to.queue", "Publish a persistent JSON message directly to an existing queue with broker confirmation.", {
45884
+ type: "object",
45885
+ properties: {
45886
+ queue: nameSchema("queue"),
45887
+ data: {},
45888
+ persistent: { type: "boolean", default: true },
45889
+ expirationMs: { type: "integer", minimum: 1, maximum: 6048e5 },
45890
+ priority: { type: "integer", minimum: 0, maximum: 255 }
45891
+ },
45892
+ required: ["queue", "data"],
45893
+ additionalProperties: false
45894
+ }),
45895
+ mutationCapability6("send.message.to.exchange", "Publish a persistent JSON message to an existing exchange with broker confirmation.", {
45896
+ type: "object",
45897
+ properties: {
45898
+ exchange: nameSchema("exchange"),
45899
+ routingKey: { type: "string", maxLength: MAX_NAME_BYTES2, default: "" },
45900
+ data: {},
45901
+ persistent: { type: "boolean", default: true },
45902
+ expirationMs: { type: "integer", minimum: 1, maximum: 6048e5 },
45903
+ priority: { type: "integer", minimum: 0, maximum: 255 }
45904
+ },
45905
+ required: ["exchange", "data"],
45906
+ additionalProperties: false
45907
+ })
45908
+ ]
45909
+ },
45910
+ async executeRead({ source, capabilityName, args }) {
45911
+ if (capabilityName === "rabbitmq.queues.inspect") {
45912
+ const queue = readName2(args.queue, "queue");
45913
+ const data4 = await withChannel(source, connect, resolveHost, async (channel) => {
45914
+ const details = await channel.checkQueue(queue);
45915
+ return { queue: details.queue, messageCount: details.messageCount, consumerCount: details.consumerCount };
45916
+ });
45917
+ return { data: data4, fetchedAt: Date.now() };
45918
+ }
45919
+ if (capabilityName === "rabbitmq.exchanges.inspect") {
45920
+ const exchange = readName2(args.exchange, "exchange");
45921
+ const data4 = await withChannel(source, connect, resolveHost, async (channel) => {
45922
+ await channel.checkExchange(exchange);
45923
+ return { exchange, exists: true };
45924
+ });
45925
+ return { data: data4, fetchedAt: Date.now() };
45926
+ }
45927
+ throw new Error(`Unknown RabbitMQ read capability: ${capabilityName}`);
45928
+ },
45929
+ async executeMutation({ source, capabilityName, args, idempotencyKey }) {
45930
+ let data4;
45931
+ if (capabilityName === "send.message.to.queue") {
45932
+ const queue = readName2(args.queue, "queue");
45933
+ const body = readJsonMessage(args.data);
45934
+ const publishOptions = readPublishOptions(args, idempotencyKey);
45935
+ data4 = await withConfirmChannel(source, connect, resolveHost, async (channel) => {
45936
+ await channel.checkQueue(queue);
45937
+ await publishConfirmed(channel, publishOptions, (options2) => channel.sendToQueue(queue, body, options2));
45938
+ return { queue, confirmed: true, messageId: publishOptions.messageId, byteLength: body.byteLength };
45939
+ });
45940
+ } else if (capabilityName === "send.message.to.exchange") {
45941
+ const exchange = readName2(args.exchange, "exchange");
45942
+ const routingKey = readRoutingKey(args.routingKey);
45943
+ const body = readJsonMessage(args.data);
45944
+ const publishOptions = readPublishOptions(args, idempotencyKey);
45945
+ data4 = await withConfirmChannel(source, connect, resolveHost, async (channel) => {
45946
+ await channel.checkExchange(exchange);
45947
+ await publishConfirmed(channel, publishOptions, (options2) => channel.publish(exchange, routingKey, body, options2));
45948
+ return { exchange, routingKey, confirmed: true, messageId: publishOptions.messageId, byteLength: body.byteLength };
45949
+ });
45950
+ } else {
45951
+ throw new Error(`Unknown RabbitMQ mutation capability: ${capabilityName}`);
45952
+ }
45953
+ return { status: "committed", data: data4, committedAt: Date.now(), idempotentReplay: false };
45954
+ },
45955
+ async test(source) {
45956
+ try {
45957
+ const credentials = readCredentials3(source);
45958
+ await resolveHost(credentials.host);
45959
+ const model2 = await connect(credentials.connectOptions, credentials.socketOptions);
45960
+ await model2.close();
45961
+ return { ok: true };
45962
+ } catch (error) {
45963
+ return { ok: false, reason: safeErrorMessage2(error, credentialSecrets2(source)) };
45964
+ }
45965
+ }
45966
+ };
45967
+ }
45968
+ var rabbitMqConnector = createRabbitMqConnector();
45969
+ async function withChannel(source, connect, resolveHost, run) {
45970
+ const credentials = readCredentials3(source);
45971
+ await resolveHost(credentials.host);
45972
+ let model2;
45973
+ let channel;
45974
+ try {
45975
+ model2 = await connect(credentials.connectOptions, credentials.socketOptions);
45976
+ channel = await model2.createChannel();
45977
+ return await run(channel);
45978
+ } catch (error) {
45979
+ throw new Error(safeErrorMessage2(error, credentials.secrets));
45980
+ } finally {
45981
+ await channel?.close().catch(() => void 0);
45982
+ await model2?.close().catch(() => void 0);
45983
+ }
45984
+ }
45985
+ async function withConfirmChannel(source, connect, resolveHost, run) {
45986
+ const credentials = readCredentials3(source);
45987
+ await resolveHost(credentials.host);
45988
+ let model2;
45989
+ let channel;
45990
+ try {
45991
+ model2 = await connect(credentials.connectOptions, credentials.socketOptions);
45992
+ channel = await model2.createConfirmChannel();
45993
+ return await run(channel);
45994
+ } catch (error) {
45995
+ throw new Error(safeErrorMessage2(error, credentials.secrets));
45996
+ } finally {
45997
+ await channel?.close().catch(() => void 0);
45998
+ await model2?.close().catch(() => void 0);
45999
+ }
46000
+ }
46001
+ async function publishConfirmed(channel, publishOptions, publish) {
46002
+ let returned;
46003
+ const onReturn = (message) => {
46004
+ returned = message;
46005
+ };
46006
+ channel.on("return", onReturn);
46007
+ try {
46008
+ publish(publishOptions);
46009
+ await channel.waitForConfirms();
46010
+ if (returned) throw new Error("RabbitMQ accepted but could not route the message");
46011
+ } finally {
46012
+ channel.removeListener("return", onReturn);
46013
+ }
46014
+ }
46015
+ function readCredentials3(source) {
46016
+ let raw;
46017
+ if (source.credentials.kind === "custom") raw = source.credentials.values;
46018
+ else if (source.credentials.kind === "api-key") {
46019
+ try {
46020
+ raw = JSON.parse(source.credentials.apiKey);
46021
+ } catch {
46022
+ throw new Error("RabbitMQ credential must be valid JSON");
46023
+ }
46024
+ } else {
46025
+ throw new Error("RabbitMQ requires a structured credential bundle");
46026
+ }
46027
+ if (!isPlainRecord(raw)) throw new Error("RabbitMQ credential must be a JSON object");
46028
+ const host = readHost2(raw.host);
46029
+ const port = readBoundedInteger(raw.port, 5671, 1, 65535, "port");
46030
+ const username = readRequiredString(raw.username, "username", 1024);
46031
+ const password = readRequiredString(raw.password, "password", 4096);
46032
+ const vhost = readOptionalString(raw.vhost, "vhost") ?? "/";
46033
+ if (Buffer.byteLength(vhost, "utf8") > MAX_NAME_BYTES2 || /[\u0000-\u001f\u007f]/.test(vhost)) {
46034
+ throw new Error(`vhost must be at most ${MAX_NAME_BYTES2} bytes without control characters`);
46035
+ }
46036
+ const ca = readPem(raw.tlsCa, "tlsCa", true);
46037
+ const cert = readPem(raw.tlsCert, "tlsCert", false);
46038
+ const key = readPem(raw.tlsKey, "tlsKey", false);
46039
+ if (Boolean(cert) !== Boolean(key)) throw new Error("tlsCert and tlsKey must be supplied together");
46040
+ const passphrase = readOptionalString(raw.tlsPassphrase, "tlsPassphrase");
46041
+ return {
46042
+ host,
46043
+ connectOptions: {
46044
+ protocol: "amqps",
46045
+ hostname: host,
46046
+ port,
46047
+ username,
46048
+ password,
46049
+ vhost,
46050
+ heartbeat: readBoundedInteger(raw.heartbeatSeconds, 30, 5, 300, "heartbeatSeconds"),
46051
+ frameMax: MAX_MESSAGE_BYTES3 + 4096
46052
+ },
46053
+ socketOptions: {
46054
+ minVersion: "TLSv1.2",
46055
+ rejectUnauthorized: true,
46056
+ servername: isIP4(host) === 0 ? host : void 0,
46057
+ lookup: publicDnsLookup,
46058
+ timeout: readBoundedInteger(raw.connectionTimeoutMs, 1e4, 1e3, 3e4, "connectionTimeoutMs"),
46059
+ noDelay: true,
46060
+ keepAlive: true,
46061
+ keepAliveDelay: 6e4,
46062
+ ca,
46063
+ cert,
46064
+ key,
46065
+ passphrase
46066
+ },
46067
+ secrets: [password, ...cert ? [cert] : [], ...key ? [key] : [], ...passphrase ? [passphrase] : []]
46068
+ };
46069
+ }
46070
+ function readHost2(value) {
46071
+ const host = readRequiredString(value, "host", 253);
46072
+ const ipVersion = isIP4(host);
46073
+ if (ipVersion !== 0) {
46074
+ if (!isPublicNetworkAddress(host)) throw new Error("RabbitMQ host is not a public network target");
46075
+ return host;
46076
+ }
46077
+ const normalized = host.toLowerCase();
46078
+ if (normalized === "localhost" || normalized.endsWith(".localhost") || normalized.endsWith(".local") || /[\s/@:\[\]]/.test(host)) {
46079
+ throw new Error("RabbitMQ host must be a public hostname or IP address without a scheme or port");
46080
+ }
46081
+ return host;
46082
+ }
46083
+ function readPublishOptions(args, idempotencyKey) {
46084
+ const expirationMs = args.expirationMs === void 0 ? void 0 : readBoundedInteger(args.expirationMs, 0, 1, 6048e5, "expirationMs");
46085
+ const priority = args.priority === void 0 ? void 0 : readBoundedInteger(args.priority, 0, 0, 255, "priority");
46086
+ return {
46087
+ mandatory: true,
46088
+ persistent: readBoolean(args.persistent, true, "persistent"),
46089
+ contentType: "application/json",
46090
+ contentEncoding: "utf-8",
46091
+ messageId: createHash7("sha256").update(idempotencyKey).digest("hex"),
46092
+ timestamp: Math.floor(Date.now() / 1e3),
46093
+ appId: "tangle-integration-hub",
46094
+ expiration: expirationMs === void 0 ? void 0 : String(expirationMs),
46095
+ priority
46096
+ };
46097
+ }
46098
+ function readJsonMessage(value) {
46099
+ if (value === void 0) throw new Error("data is required");
46100
+ let serialized;
46101
+ try {
46102
+ serialized = JSON.stringify(value);
46103
+ } catch {
46104
+ throw new Error("data must be JSON-serializable");
46105
+ }
46106
+ if (serialized === void 0) throw new Error("data must be JSON-serializable");
46107
+ const body = Buffer.from(serialized);
46108
+ if (body.byteLength > MAX_MESSAGE_BYTES3) throw new Error(`data exceeds the ${MAX_MESSAGE_BYTES3}-byte limit`);
46109
+ return body;
46110
+ }
46111
+ function readName2(value, label) {
46112
+ const name = readRequiredString(value, label, MAX_NAME_BYTES2);
46113
+ if (Buffer.byteLength(name, "utf8") > MAX_NAME_BYTES2 || /[\u0000-\u001f\u007f]/.test(name)) {
46114
+ throw new Error(`${label} must be at most ${MAX_NAME_BYTES2} bytes without control characters`);
46115
+ }
46116
+ return name;
46117
+ }
46118
+ function readRoutingKey(value) {
46119
+ if (value === void 0 || value === null || value === "") return "";
46120
+ return readName2(value, "routingKey");
46121
+ }
46122
+ function readRequiredString(value, label, maxLength) {
46123
+ if (typeof value !== "string" || value.length === 0 || value.length > maxLength) {
46124
+ throw new Error(`${label} must be a non-empty string no longer than ${maxLength} characters`);
46125
+ }
46126
+ return value;
46127
+ }
46128
+ function readPem(value, label, allowArray) {
46129
+ if (value === void 0 || value === null) return void 0;
46130
+ const values = Array.isArray(value) && allowArray ? value : [value];
46131
+ if (values.length === 0 || values.length > MAX_CA_CERTIFICATES || values.some((entry) => typeof entry !== "string" || entry.length === 0 || Buffer.byteLength(entry, "utf8") > MAX_PEM_BYTES) || values.reduce((total, entry) => total + (typeof entry === "string" ? Buffer.byteLength(entry, "utf8") : 0), 0) > MAX_CA_BYTES) {
46132
+ throw new Error(
46133
+ allowArray ? `${label} must contain 1-${MAX_CA_CERTIFICATES} PEM strings, each under ${MAX_PEM_BYTES} bytes and ${MAX_CA_BYTES} bytes total` : `${label} must be a PEM string under ${MAX_PEM_BYTES} bytes`
46134
+ );
46135
+ }
46136
+ return allowArray ? values : values[0];
46137
+ }
46138
+ function credentialSecrets2(source) {
46139
+ try {
46140
+ return readCredentials3(source).secrets;
46141
+ } catch {
46142
+ return [];
46143
+ }
46144
+ }
46145
+ function safeErrorMessage2(error, secrets) {
46146
+ let message = error instanceof Error ? error.message : String(error);
46147
+ for (const secret of secrets) {
46148
+ if (secret.length >= 4) message = message.replaceAll(secret, "[REDACTED]");
46149
+ }
46150
+ return message;
46151
+ }
46152
+ function readCapability7(name, description, parameters) {
46153
+ return { name, class: "read", description, parameters };
46154
+ }
46155
+ function mutationCapability6(name, description, parameters) {
46156
+ return { name, class: "mutation", description, parameters, cas: "none", externalEffect: true };
46157
+ }
46158
+ function nameSchema(label) {
46159
+ return { type: "string", minLength: 1, maxLength: MAX_NAME_BYTES2, description: `Existing RabbitMQ ${label} name.` };
46160
+ }
46161
+
46162
+ // src/connectors/adapters/redis.ts
46163
+ import { isIP as isIP5 } from "net";
46164
+ import {
46165
+ createClient as createRedisClient
46166
+ } from "redis";
46167
+ var MAX_KEY_BYTES = 1024;
46168
+ var MAX_PATTERN_BYTES = 4096;
46169
+ var MAX_VALUE_BYTES = 1024 * 1024;
46170
+ var MAX_SCAN_KEYS = 1e3;
46171
+ var MAX_SCAN_BYTES = 1024 * 1024;
46172
+ var MAX_TLS_CA_BYTES2 = 256 * 1024;
46173
+ var MAX_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
46174
+ var SCAN_SCRIPT = `
46175
+ local page
46176
+ if ARGV[4] == '' then
46177
+ page = redis.call('SCAN', ARGV[1], 'MATCH', ARGV[2], 'COUNT', ARGV[3])
46178
+ else
46179
+ page = redis.call('SCAN', ARGV[1], 'MATCH', ARGV[2], 'COUNT', ARGV[3], 'TYPE', ARGV[4])
46180
+ end
46181
+ local keys = page[2]
46182
+ if #keys > tonumber(ARGV[5]) then return redis.error_reply('Redis SCAN page exceeds the configured key limit') end
46183
+ local bytes = 0
46184
+ for _, key in ipairs(keys) do
46185
+ if string.len(key) > tonumber(ARGV[7]) then return redis.error_reply('Redis SCAN key exceeds the configured key limit') end
46186
+ bytes = bytes + string.len(key)
46187
+ if bytes > tonumber(ARGV[6]) then return redis.error_reply('Redis SCAN page exceeds the configured byte limit') end
46188
+ end
46189
+ return page
46190
+ `;
46191
+ var INSPECT_SCRIPT = `
46192
+ local kind = redis.call('TYPE', KEYS[1])
46193
+ if type(kind) == 'table' then kind = kind['ok'] end
46194
+ return { kind, redis.call('PTTL', KEYS[1]) }
46195
+ `;
46196
+ var READ_STRING_SCRIPT = `
46197
+ local kind = redis.call('TYPE', KEYS[1])
46198
+ if type(kind) == 'table' then kind = kind['ok'] end
46199
+ local ttl = redis.call('PTTL', KEYS[1])
46200
+ if kind == 'none' then return { kind, ttl, false, 0 } end
46201
+ if kind ~= 'string' then return redis.error_reply('WRONGTYPE key does not contain a string') end
46202
+ local length = redis.call('STRLEN', KEYS[1])
46203
+ if length > tonumber(ARGV[1]) then return redis.error_reply('Redis value exceeds the configured read limit') end
46204
+ return { kind, ttl, redis.call('GET', KEYS[1]), length }
46205
+ `;
46206
+ var COMPARE_SET_SCRIPT = `
46207
+ if redis.call('GET', KEYS[1]) ~= ARGV[1] then return 0 end
46208
+ if ARGV[3] ~= '' then
46209
+ redis.call('SET', KEYS[1], ARGV[2], 'PX', ARGV[3])
46210
+ elseif ARGV[4] == '1' then
46211
+ redis.call('SET', KEYS[1], ARGV[2], 'KEEPTTL')
46212
+ else
46213
+ redis.call('SET', KEYS[1], ARGV[2])
46214
+ end
46215
+ return 1
46216
+ `;
46217
+ var COMPARE_DELETE_SCRIPT = `
46218
+ if redis.call('GET', KEYS[1]) ~= ARGV[1] then return 0 end
46219
+ return redis.call('DEL', KEYS[1])
46220
+ `;
46221
+ function createRedisConnector(options = {}) {
46222
+ const createClient = options.createClient ?? defaultCreateClient2;
46223
+ const resolveHost = options.resolveHost ?? resolvePublicHostAddresses;
46224
+ return {
46225
+ manifest: {
46226
+ kind: "redis",
46227
+ displayName: "Redis",
46228
+ description: "Inspect and scan Redis keys and perform bounded, approved string compare-and-swap mutations over verified TLS.",
46229
+ auth: {
46230
+ kind: "api-key",
46231
+ hint: "JSON with a public Redis host, password, optional ACL username/database, and optional TLS CA. Verified TLS is mandatory."
46232
+ },
46233
+ defaultConsistencyModel: "authoritative",
46234
+ category: "database",
46235
+ rateLimit: { requests: 120, windowMs: 6e4, scope: "data-source" },
46236
+ capabilities: [
46237
+ readCapability8("redis.keys.scan", "Read one bounded SCAN page without blocking the server with KEYS.", {
46238
+ type: "object",
46239
+ properties: {
46240
+ cursor: { type: "string", pattern: "^[0-9]+$", default: "0" },
46241
+ match: { type: "string", maxLength: MAX_PATTERN_BYTES, default: "*" },
46242
+ count: { type: "integer", minimum: 1, maximum: MAX_SCAN_KEYS, default: 100 },
46243
+ type: { type: "string", enum: ["string", "list", "set", "zset", "hash", "stream"] }
46244
+ },
46245
+ additionalProperties: false
46246
+ }),
46247
+ readCapability8("redis.key.inspect", "Read a key type and remaining expiry atomically.", keySchema()),
46248
+ readCapability8("redis.string.get", "Read one bounded string value, type, and remaining expiry atomically.", keySchema()),
46249
+ mutationCapability7("redis.string.set", "Set a bounded string only when the key is absent, present, or matches an expected value.", {
46250
+ type: "object",
46251
+ properties: {
46252
+ key: keyParameter(),
46253
+ value: { type: "string", maxLength: MAX_VALUE_BYTES },
46254
+ condition: { type: "string", enum: ["absent", "present", "matches"] },
46255
+ expectedValue: { type: "string", maxLength: MAX_VALUE_BYTES },
46256
+ ttlMs: { type: "integer", minimum: 1, maximum: MAX_TTL_MS },
46257
+ keepTtl: { type: "boolean", default: false }
46258
+ },
46259
+ required: ["key", "value", "condition"],
46260
+ additionalProperties: false
46261
+ }),
46262
+ mutationCapability7("redis.string.delete", "Delete a string key only when its current value exactly matches the caller expectation.", {
46263
+ type: "object",
46264
+ properties: {
46265
+ key: keyParameter(),
46266
+ expectedValue: { type: "string", maxLength: MAX_VALUE_BYTES }
46267
+ },
46268
+ required: ["key", "expectedValue"],
46269
+ additionalProperties: false
46270
+ })
46271
+ ]
46272
+ },
46273
+ async test(source) {
46274
+ try {
46275
+ await withClient2(source, createClient, resolveHost, async (client) => {
46276
+ const response = await client.ping();
46277
+ if (response !== "PONG") throw new Error("Redis PING returned an unexpected response");
46278
+ });
46279
+ return { ok: true };
46280
+ } catch (error) {
46281
+ return { ok: false, reason: safeErrorMessage3(error, credentialSecrets3(source)) };
46282
+ }
46283
+ },
46284
+ async executeRead({ source, capabilityName, args }) {
46285
+ if (capabilityName === "redis.keys.scan") {
46286
+ const cursor = readCursor2(args.cursor);
46287
+ const match = readPattern(args.match);
46288
+ const count = readBoundedInteger(args.count, 100, 1, MAX_SCAN_KEYS, "count");
46289
+ const type = readScanType(args.type);
46290
+ const data4 = await withClient2(source, createClient, resolveHost, async (client) => {
46291
+ const reply = readArrayReply(await client.eval(SCAN_SCRIPT, {
46292
+ keys: [],
46293
+ arguments: [
46294
+ cursor,
46295
+ match,
46296
+ String(count),
46297
+ type ?? "",
46298
+ String(MAX_SCAN_KEYS),
46299
+ String(MAX_SCAN_BYTES),
46300
+ String(MAX_KEY_BYTES)
46301
+ ]
46302
+ }), "scan");
46303
+ const keys = readStringArray(reply[1], "scan keys");
46304
+ assertScanPage(keys);
46305
+ return { cursor: readCursor2(readReplyString(reply[0], "cursor")), keys };
46306
+ });
46307
+ return { data: data4, fetchedAt: Date.now() };
46308
+ }
46309
+ if (capabilityName === "redis.key.inspect") {
46310
+ const key = readKey(args.key);
46311
+ const data4 = await withClient2(source, createClient, resolveHost, async (client) => {
46312
+ const reply = readArrayReply(await client.eval(INSPECT_SCRIPT, { keys: [key], arguments: [] }), "inspect");
46313
+ const type = readReplyString(reply[0], "type");
46314
+ return { key, exists: type !== "none", type, ttlMs: normalizeTtl(reply[1]) };
46315
+ });
46316
+ return { data: data4, fetchedAt: Date.now() };
46317
+ }
46318
+ if (capabilityName === "redis.string.get") {
46319
+ const key = readKey(args.key);
46320
+ const data4 = await withClient2(source, createClient, resolveHost, async (client) => {
46321
+ const reply = readArrayReply(await client.eval(READ_STRING_SCRIPT, {
46322
+ keys: [key],
46323
+ arguments: [String(MAX_VALUE_BYTES)]
46324
+ }), "string read");
46325
+ const type = readReplyString(reply[0], "type");
46326
+ const exists = type !== "none";
46327
+ const value = exists ? readReplyString(reply[2], "value") : null;
46328
+ if (value !== null && Buffer.byteLength(value, "utf8") > MAX_VALUE_BYTES) {
46329
+ throw new Error(`Redis value exceeds the ${MAX_VALUE_BYTES}-byte limit`);
46330
+ }
46331
+ return {
46332
+ key,
46333
+ exists,
46334
+ type,
46335
+ ttlMs: normalizeTtl(reply[1]),
46336
+ value,
46337
+ byteLength: exists ? readReplyInteger(reply[3], "byteLength") : 0
46338
+ };
46339
+ });
46340
+ return { data: data4, fetchedAt: Date.now() };
46341
+ }
46342
+ throw new Error(`Unknown Redis read capability: ${capabilityName}`);
46343
+ },
46344
+ async executeMutation({ source, capabilityName, args }) {
46345
+ if (capabilityName === "redis.string.set") {
46346
+ const input = readSetInput(args);
46347
+ return withClient2(source, createClient, resolveHost, async (client) => {
46348
+ let committed;
46349
+ if (input.condition === "matches") {
46350
+ committed = readReplyInteger(await client.eval(COMPARE_SET_SCRIPT, {
46351
+ keys: [input.key],
46352
+ arguments: [input.expectedValue, input.value, input.ttlMs === void 0 ? "" : String(input.ttlMs), input.keepTtl ? "1" : "0"]
46353
+ }), "compare-and-set result") === 1;
46354
+ } else {
46355
+ const response = await client.set(input.key, input.value, {
46356
+ condition: input.condition === "absent" ? "NX" : "XX",
46357
+ expiration: input.ttlMs === void 0 ? input.keepTtl ? "KEEPTTL" : void 0 : { type: "PX", value: input.ttlMs }
46358
+ });
46359
+ committed = response === "OK";
46360
+ }
46361
+ if (!committed) return conflict(`Redis key ${input.key} did not satisfy condition ${input.condition}`);
46362
+ return committedResult({ key: input.key, condition: input.condition, byteLength: Buffer.byteLength(input.value, "utf8") });
46363
+ });
46364
+ }
46365
+ if (capabilityName === "redis.string.delete") {
46366
+ const key = readKey(args.key);
46367
+ const expectedValue = readValue(args.expectedValue, "expectedValue");
46368
+ return withClient2(source, createClient, resolveHost, async (client) => {
46369
+ const deleted = readReplyInteger(await client.eval(COMPARE_DELETE_SCRIPT, {
46370
+ keys: [key],
46371
+ arguments: [expectedValue]
46372
+ }), "compare-and-delete result");
46373
+ if (deleted !== 1) return conflict(`Redis key ${key} did not match the expected value`);
46374
+ return committedResult({ key, deleted: true });
46375
+ });
46376
+ }
46377
+ throw new Error(`Unknown Redis mutation capability: ${capabilityName}`);
46378
+ }
46379
+ };
46380
+ }
46381
+ var redisConnector = createRedisConnector();
46382
+ function defaultCreateClient2(options) {
46383
+ return createRedisClient(options);
46384
+ }
46385
+ async function withClient2(source, createClient, resolveHost, run) {
46386
+ const credentials = readCredentials4(source);
46387
+ const addresses = await resolveHost(credentials.host);
46388
+ if (addresses.length === 0) throw new Error("Redis host did not resolve");
46389
+ let client;
46390
+ try {
46391
+ client = createClient({
46392
+ username: credentials.username,
46393
+ password: credentials.password,
46394
+ database: credentials.database,
46395
+ name: "tangle-integration-hub",
46396
+ disableOfflineQueue: true,
46397
+ commandsQueueMaxLength: 10,
46398
+ maintNotifications: "disabled",
46399
+ commandOptions: { abortSignal: AbortSignal.timeout(credentials.commandTimeoutMs) },
46400
+ socket: {
46401
+ host: addresses[0],
46402
+ port: credentials.port,
46403
+ tls: true,
46404
+ servername: isIP5(credentials.host) === 0 ? credentials.host : void 0,
46405
+ minVersion: "TLSv1.2",
46406
+ rejectUnauthorized: true,
46407
+ ca: credentials.tlsCa,
46408
+ connectTimeout: credentials.connectTimeoutMs,
46409
+ socketTimeout: credentials.commandTimeoutMs,
46410
+ reconnectStrategy: false
46411
+ }
46412
+ });
46413
+ client.on("error", () => void 0);
46414
+ await client.connect();
46415
+ return await run(client);
46416
+ } catch (error) {
46417
+ throw new Error(safeErrorMessage3(error, credentials.secrets));
46418
+ } finally {
46419
+ if (client?.isOpen) await client.close().catch(() => client?.destroy());
46420
+ else client?.destroy();
46421
+ }
46422
+ }
46423
+ function readCredentials4(source) {
46424
+ let raw;
46425
+ if (source.credentials.kind === "custom") raw = source.credentials.values;
46426
+ else if (source.credentials.kind === "api-key") {
46427
+ try {
46428
+ raw = JSON.parse(source.credentials.apiKey);
46429
+ } catch {
46430
+ throw new Error("Redis credential must be valid JSON");
46431
+ }
46432
+ } else {
46433
+ throw new Error("Redis requires a structured credential bundle");
46434
+ }
46435
+ if (!isPlainRecord(raw)) throw new Error("Redis credential must be a JSON object");
46436
+ const host = readHost3(raw.host);
46437
+ const username = readOptionalString(raw.username, "username");
46438
+ if (username && (username.length > 128 || /[\u0000-\u001f\u007f]/.test(username))) {
46439
+ throw new Error("Redis username must be at most 128 characters without control characters");
46440
+ }
46441
+ const password = readRequiredString2(raw.password, "password", 4096);
46442
+ const tlsCa = readOptionalString(raw.tlsCa, "tlsCa");
46443
+ if (tlsCa && Buffer.byteLength(tlsCa, "utf8") > MAX_TLS_CA_BYTES2) {
46444
+ throw new Error(`Redis tlsCa exceeds the ${MAX_TLS_CA_BYTES2}-byte limit`);
46445
+ }
46446
+ return {
46447
+ host,
46448
+ port: readBoundedInteger(raw.port, 6380, 1, 65535, "port"),
46449
+ username,
46450
+ password,
46451
+ database: readBoundedInteger(raw.database, 0, 0, 65535, "database"),
46452
+ tlsCa,
46453
+ connectTimeoutMs: readBoundedInteger(raw.connectTimeoutMs, 1e4, 1e3, 3e4, "connectTimeoutMs"),
46454
+ commandTimeoutMs: readBoundedInteger(raw.commandTimeoutMs, 1e4, 1e3, 3e4, "commandTimeoutMs"),
46455
+ secrets: [password]
46456
+ };
46457
+ }
46458
+ function readHost3(value) {
46459
+ const host = readRequiredString2(value, "host", 253);
46460
+ const ipVersion = isIP5(host);
46461
+ if (ipVersion !== 0) {
46462
+ if (!isPublicNetworkAddress(host)) throw new Error("Redis host is not a public network target");
46463
+ return host;
46464
+ }
46465
+ const normalized = host.toLowerCase();
46466
+ if (normalized === "localhost" || normalized.endsWith(".localhost") || normalized.endsWith(".local") || /[\s/@:\[\]]/.test(host)) {
46467
+ throw new Error("Redis host must be a public hostname or IP address without a scheme or port");
46468
+ }
46469
+ return host;
46470
+ }
46471
+ function readSetInput(args) {
46472
+ const key = readKey(args.key);
46473
+ const value = readValue(args.value, "value");
46474
+ const condition = args.condition;
46475
+ if (!["absent", "present", "matches"].includes(String(condition))) {
46476
+ throw new Error("condition must be absent, present, or matches");
46477
+ }
46478
+ const expectedValue = args.expectedValue === void 0 ? void 0 : readValue(args.expectedValue, "expectedValue");
46479
+ if (condition === "matches" && expectedValue === void 0) throw new Error("expectedValue is required when condition is matches");
46480
+ if (condition !== "matches" && expectedValue !== void 0) throw new Error("expectedValue is only valid when condition is matches");
46481
+ const ttlMs = args.ttlMs === void 0 ? void 0 : readBoundedInteger(args.ttlMs, 0, 1, MAX_TTL_MS, "ttlMs");
46482
+ const keepTtl = readBoolean(args.keepTtl, false, "keepTtl");
46483
+ if (ttlMs !== void 0 && keepTtl) throw new Error("ttlMs and keepTtl cannot be used together");
46484
+ return { key, value, condition, expectedValue, ttlMs, keepTtl };
46485
+ }
46486
+ function readCursor2(value) {
46487
+ if (value === void 0 || value === null || value === "") return "0";
46488
+ if (typeof value !== "string" || !/^[0-9]+$/.test(value) || value.length > 32) {
46489
+ throw new Error("cursor must be a Redis numeric cursor string");
46490
+ }
46491
+ return value;
46492
+ }
46493
+ function readPattern(value) {
46494
+ if (value === void 0 || value === null || value === "") return "*";
46495
+ if (typeof value !== "string" || Buffer.byteLength(value, "utf8") > MAX_PATTERN_BYTES || /[\u0000-\u001f\u007f]/.test(value)) {
46496
+ throw new Error(`match must be under ${MAX_PATTERN_BYTES} bytes without control characters`);
46497
+ }
46498
+ return value;
46499
+ }
46500
+ function readScanType(value) {
46501
+ if (value === void 0 || value === null || value === "") return void 0;
46502
+ if (!["string", "list", "set", "zset", "hash", "stream"].includes(String(value))) {
46503
+ throw new Error("type must be string, list, set, zset, hash, or stream");
46504
+ }
46505
+ return String(value);
46506
+ }
46507
+ function assertScanPage(keys) {
46508
+ if (!Array.isArray(keys) || keys.length > MAX_SCAN_KEYS) {
46509
+ throw new Error(`Redis SCAN page exceeds ${MAX_SCAN_KEYS} keys`);
46510
+ }
46511
+ if (keys.some((key) => typeof key !== "string" || Buffer.byteLength(key, "utf8") > MAX_KEY_BYTES || /[\u0000-\u001f\u007f]/.test(key)) || Buffer.byteLength(JSON.stringify(keys), "utf8") > MAX_SCAN_BYTES) {
46512
+ throw new Error(`Redis SCAN page exceeds the ${MAX_SCAN_BYTES}-byte limit`);
46513
+ }
46514
+ }
46515
+ function readKey(value) {
46516
+ return readBoundedString(value, "key", MAX_KEY_BYTES);
46517
+ }
46518
+ function readValue(value, label) {
46519
+ if (typeof value !== "string") throw new Error(`${label} must be a string`);
46520
+ if (Buffer.byteLength(value, "utf8") > MAX_VALUE_BYTES) {
46521
+ throw new Error(`${label} exceeds the ${MAX_VALUE_BYTES}-byte limit`);
46522
+ }
46523
+ return value;
46524
+ }
46525
+ function readBoundedString(value, label, maxBytes) {
46526
+ if (typeof value !== "string" || value.length === 0 || Buffer.byteLength(value, "utf8") > maxBytes || /[\u0000-\u001f\u007f]/.test(value)) {
46527
+ throw new Error(`${label} must be a non-empty string under ${maxBytes} bytes without control characters`);
46528
+ }
46529
+ return value;
46530
+ }
46531
+ function readRequiredString2(value, label, maxLength) {
46532
+ if (typeof value !== "string" || value.length === 0 || value.length > maxLength) {
46533
+ throw new Error(`${label} must be a non-empty string no longer than ${maxLength} characters`);
46534
+ }
46535
+ return value;
46536
+ }
46537
+ function readArrayReply(value, label) {
46538
+ if (!Array.isArray(value)) throw new Error(`Redis ${label} returned a malformed response`);
46539
+ return value;
46540
+ }
46541
+ function readStringArray(value, label) {
46542
+ if (!Array.isArray(value)) throw new Error(`Redis response ${label} is malformed`);
46543
+ return value.map((entry) => readReplyString(entry, label));
46544
+ }
46545
+ function readReplyString(value, label) {
46546
+ if (typeof value === "string") return value;
46547
+ if (Buffer.isBuffer(value)) return value.toString("utf8");
46548
+ throw new Error(`Redis response ${label} is malformed`);
46549
+ }
46550
+ function readReplyInteger(value, label) {
46551
+ const parsed = typeof value === "bigint" ? Number(value) : typeof value === "string" ? Number(value) : value;
46552
+ if (typeof parsed !== "number" || !Number.isSafeInteger(parsed)) throw new Error(`Redis response ${label} is malformed`);
46553
+ return parsed;
46554
+ }
46555
+ function normalizeTtl(value) {
46556
+ const ttl = readReplyInteger(value, "ttlMs");
46557
+ return ttl >= 0 ? ttl : null;
46558
+ }
46559
+ function safeErrorMessage3(error, secrets) {
46560
+ let message = error instanceof Error ? error.message : String(error);
46561
+ for (const secret of secrets) {
46562
+ if (secret.length >= 4) message = message.replaceAll(secret, "[REDACTED]");
46563
+ }
46564
+ return message;
46565
+ }
46566
+ function credentialSecrets3(source) {
46567
+ try {
46568
+ return readCredentials4(source).secrets;
46569
+ } catch {
46570
+ return [];
46571
+ }
46572
+ }
46573
+ function committedResult(data4) {
46574
+ return { status: "committed", data: data4, committedAt: Date.now(), idempotentReplay: false };
46575
+ }
46576
+ function conflict(message) {
46577
+ return { status: "conflict", alternatives: [], currentState: null, message };
46578
+ }
46579
+ function readCapability8(name, description, parameters) {
46580
+ return { name, class: "read", description, parameters };
46581
+ }
46582
+ function mutationCapability7(name, description, parameters) {
46583
+ return { name, class: "mutation", description, parameters, cas: "optimistic-read-verify", externalEffect: true };
46584
+ }
46585
+ function keyParameter() {
46586
+ return { type: "string", minLength: 1, maxLength: MAX_KEY_BYTES };
46587
+ }
46588
+ function keySchema() {
46589
+ return {
46590
+ type: "object",
46591
+ properties: { key: keyParameter() },
46592
+ required: ["key"],
46593
+ additionalProperties: false
46594
+ };
46595
+ }
46596
+
46597
+ // src/connectors/adapters/redshift.ts
46598
+ import { isIP as isIP6 } from "net";
46599
+ import {
46600
+ Client as PgClient
46601
+ } from "pg";
46602
+ var MAX_IDENTIFIER_BYTES = 127;
46603
+ var MAX_COLUMNS5 = 64;
46604
+ var MAX_FILTERS2 = 20;
46605
+ var MAX_ORDER_COLUMNS = 8;
46606
+ var MAX_PARAMETERS_BYTES = 10 * 1024 * 1024;
46607
+ var MAX_RESULT_ROWS = 1e4;
46608
+ var MAX_RESULT_BYTES3 = 10 * 1024 * 1024;
46609
+ var MAX_TLS_CA_BYTES3 = 256 * 1024;
46610
+ var REDSHIFT_PROVIDER = {
46611
+ kind: "redshift",
46612
+ displayName: "Amazon Redshift",
46613
+ description: "Inspect Redshift schemas and tables and run bounded structured row reads over the verified PostgreSQL wire protocol.",
46614
+ authHint: "JSON with a public Redshift host, database, user, password, optional port, and optional TLS CA. Verified TLS is mandatory.",
46615
+ defaultPort: 5439
46616
+ };
46617
+ function createRedshiftConnector(options = {}) {
46618
+ return createPostgresWireReadConnector(REDSHIFT_PROVIDER, options);
46619
+ }
46620
+ function createPostgresWireReadConnector(provider2, options = {}) {
46621
+ const createClient = options.createClient ?? defaultCreateClient3;
46622
+ const resolveHost = options.resolveHost ?? resolvePublicHostAddresses;
46623
+ return {
46624
+ manifest: {
46625
+ kind: provider2.kind,
46626
+ displayName: provider2.displayName,
46627
+ description: provider2.description,
46628
+ auth: {
46629
+ kind: "api-key",
46630
+ hint: provider2.authHint
46631
+ },
46632
+ defaultConsistencyModel: "authoritative",
46633
+ category: "database",
46634
+ rateLimit: { requests: 120, windowMs: 6e4, scope: "data-source" },
46635
+ capabilities: [
46636
+ readCapability9(`${provider2.kind}.schemas.list`, `List schemas visible to the connected ${provider2.displayName} user.`, emptySchema2()),
46637
+ readCapability9(`${provider2.kind}.tables.list`, "List tables and views in one schema.", {
46638
+ type: "object",
46639
+ properties: { schema: identifierSchema("Schema name; defaults to public.") },
46640
+ additionalProperties: false
46641
+ }),
46642
+ readCapability9(`${provider2.kind}.tables.describe`, "Read ordered column metadata for one table or view.", {
46643
+ type: "object",
46644
+ properties: {
46645
+ schema: identifierSchema("Schema name; defaults to public."),
46646
+ table: identifierSchema("Table or view name.")
46647
+ },
46648
+ required: ["table"],
46649
+ additionalProperties: false
46650
+ }),
46651
+ readCapability9(`${provider2.kind}.rows.select`, "Read bounded rows using an identifier-safe query builder with scalar predicates.", {
46652
+ type: "object",
46653
+ properties: {
46654
+ schema: identifierSchema("Schema name; defaults to public."),
46655
+ table: identifierSchema("Table or view name."),
46656
+ columns: {
46657
+ type: "array",
46658
+ minItems: 1,
46659
+ maxItems: MAX_COLUMNS5,
46660
+ uniqueItems: true,
46661
+ items: identifierSchema("Column name.")
46662
+ },
46663
+ filters: {
46664
+ type: "array",
46665
+ maxItems: MAX_FILTERS2,
46666
+ items: {
46667
+ type: "object",
46668
+ properties: {
46669
+ column: identifierSchema("Column name."),
46670
+ operator: { type: "string", enum: ["eq", "ne", "lt", "lte", "gt", "gte", "like", "is-null", "not-null"] },
46671
+ value: { type: ["string", "number", "boolean", "null"] }
46672
+ },
46673
+ required: ["column", "operator"],
46674
+ additionalProperties: false
46675
+ }
46676
+ },
46677
+ orderBy: {
46678
+ type: "array",
46679
+ maxItems: MAX_ORDER_COLUMNS,
46680
+ items: {
46681
+ type: "object",
46682
+ properties: {
46683
+ column: identifierSchema("Column name."),
46684
+ direction: { type: "string", enum: ["asc", "desc"], default: "asc" }
46685
+ },
46686
+ required: ["column"],
46687
+ additionalProperties: false
46688
+ }
46689
+ },
46690
+ limit: { type: "integer", minimum: 1, maximum: MAX_RESULT_ROWS, default: 100 },
46691
+ offset: { type: "integer", minimum: 0, maximum: 1e6, default: 0 }
46692
+ },
46693
+ required: ["table", "columns"],
46694
+ additionalProperties: false
46695
+ })
46696
+ ]
46697
+ },
46698
+ async test(source) {
46699
+ try {
46700
+ await withClient3(source, provider2, createClient, resolveHost, async (client) => {
46701
+ await client.query({ text: "SELECT current_database() AS database_name, current_user AS user_name", values: [] });
46702
+ });
46703
+ return { ok: true };
46704
+ } catch (error) {
46705
+ return { ok: false, reason: safeErrorMessage4(error, credentialSecrets4(source, provider2)) };
46706
+ }
46707
+ },
46708
+ async executeRead(inv) {
46709
+ const query2 = buildQuery(inv, provider2);
46710
+ const data4 = await withClient3(inv.source, provider2, createClient, resolveHost, async (client) => {
46711
+ await client.query({ text: "BEGIN READ ONLY", values: [] });
46712
+ try {
46713
+ const result = await client.query(query2);
46714
+ return boundedResult2(result, provider2.displayName);
46715
+ } finally {
46716
+ await client.query({ text: "ROLLBACK", values: [] }).catch(() => void 0);
46717
+ }
46718
+ });
46719
+ return { data: data4, fetchedAt: Date.now() };
46720
+ }
46721
+ };
46722
+ }
46723
+ var redshiftConnector = createRedshiftConnector();
46724
+ function defaultCreateClient3(config) {
46725
+ return new PgClient(config);
46726
+ }
46727
+ async function withClient3(source, provider2, createClient, resolveHost, run) {
46728
+ const credentials = readCredentials5(source, provider2);
46729
+ const addresses = await resolveHost(credentials.host);
46730
+ if (addresses.length === 0) throw new Error(`${provider2.displayName} host did not resolve`);
46731
+ let client;
46732
+ try {
46733
+ client = createClient({
46734
+ host: addresses[0],
46735
+ port: credentials.port,
46736
+ user: credentials.user,
46737
+ password: credentials.password,
46738
+ database: credentials.database,
46739
+ application_name: "tangle-integration-hub",
46740
+ connectionTimeoutMillis: credentials.connectTimeoutMs,
46741
+ query_timeout: credentials.queryTimeoutMs,
46742
+ statement_timeout: credentials.queryTimeoutMs,
46743
+ lock_timeout: credentials.queryTimeoutMs,
46744
+ keepAlive: true,
46745
+ keepAliveInitialDelayMillis: 6e4,
46746
+ ssl: {
46747
+ servername: isIP6(credentials.host) === 0 ? credentials.host : void 0,
46748
+ minVersion: "TLSv1.2",
46749
+ rejectUnauthorized: true,
46750
+ ca: credentials.tlsCa
46751
+ }
46752
+ });
46753
+ client.on("error", () => void 0);
46754
+ await client.connect();
46755
+ return await run(client);
46756
+ } catch (error) {
46757
+ throw new Error(safeErrorMessage4(error, credentials.secrets));
46758
+ } finally {
46759
+ await client?.end().catch(() => void 0);
46760
+ }
46761
+ }
46762
+ function readCredentials5(source, provider2) {
46763
+ let raw;
46764
+ if (source.credentials.kind === "custom") raw = source.credentials.values;
46765
+ else if (source.credentials.kind === "api-key") {
46766
+ try {
46767
+ raw = JSON.parse(source.credentials.apiKey);
46768
+ } catch {
46769
+ throw new Error(`${provider2.displayName} credential must be valid JSON`);
46770
+ }
46771
+ } else {
46772
+ throw new Error(`${provider2.displayName} requires a structured credential bundle`);
46773
+ }
46774
+ if (!isPlainRecord(raw)) throw new Error(`${provider2.displayName} credential must be a JSON object`);
46775
+ const host = readHost4(raw.host, provider2.displayName);
46776
+ const user = readCredentialString2(raw.user ?? raw.username, "user", 128, provider2.displayName);
46777
+ const password = readCredentialString2(raw.password, "password", 4096, provider2.displayName);
46778
+ const database = readCredentialString2(raw.database, "database", MAX_IDENTIFIER_BYTES, provider2.displayName);
46779
+ const tlsCa = readOptionalString(raw.tlsCa, "tlsCa");
46780
+ if (tlsCa && Buffer.byteLength(tlsCa, "utf8") > MAX_TLS_CA_BYTES3) {
46781
+ throw new Error(`${provider2.displayName} tlsCa exceeds the ${MAX_TLS_CA_BYTES3}-byte limit`);
46782
+ }
46783
+ return {
46784
+ host,
46785
+ port: readBoundedInteger(raw.port, provider2.defaultPort, 1, 65535, "port"),
46786
+ user,
46787
+ password,
46788
+ database,
46789
+ tlsCa,
46790
+ connectTimeoutMs: readBoundedInteger(raw.connectTimeoutMs, 1e4, 1e3, 3e4, "connectTimeoutMs"),
46791
+ queryTimeoutMs: readBoundedInteger(raw.queryTimeoutMs, 3e4, 1e3, 6e4, "queryTimeoutMs"),
46792
+ secrets: [password]
46793
+ };
46794
+ }
46795
+ function buildQuery(inv, provider2) {
46796
+ if (inv.capabilityName === `${provider2.kind}.schemas.list`) {
46797
+ return {
46798
+ text: `SELECT schema_name AS "schemaName", schema_owner AS "schemaOwner" FROM information_schema.schemata WHERE schema_name NOT LIKE 'pg_%' AND schema_name <> 'information_schema' ORDER BY schema_name LIMIT ${MAX_RESULT_ROWS + 1}`,
46799
+ values: []
46800
+ };
46801
+ }
46802
+ if (inv.capabilityName === `${provider2.kind}.tables.list`) {
46803
+ return {
46804
+ text: `SELECT table_schema AS "schemaName", table_name AS "tableName", table_type AS "tableType" FROM information_schema.tables WHERE table_schema = $1 ORDER BY table_name LIMIT ${MAX_RESULT_ROWS + 1}`,
46805
+ values: [readSchema(inv.args.schema)]
46806
+ };
46807
+ }
46808
+ if (inv.capabilityName === `${provider2.kind}.tables.describe`) {
46809
+ return {
46810
+ text: `SELECT table_schema AS "schemaName", table_name AS "tableName", column_name AS "columnName", ordinal_position AS "ordinalPosition", column_default AS "columnDefault", is_nullable AS "isNullable", data_type AS "dataType", character_maximum_length AS "characterMaximumLength", numeric_precision AS "numericPrecision", numeric_scale AS "numericScale" FROM information_schema.columns WHERE table_schema = $1 AND table_name = $2 ORDER BY ordinal_position LIMIT ${MAX_RESULT_ROWS + 1}`,
46811
+ values: [readSchema(inv.args.schema), readIdentifier(inv.args.table, "table")]
46812
+ };
46813
+ }
46814
+ if (inv.capabilityName === `${provider2.kind}.rows.select`) return buildRowSelect(inv.args, provider2.displayName);
46815
+ throw new Error(`Unknown ${provider2.displayName} read capability: ${inv.capabilityName}`);
46816
+ }
46817
+ function buildRowSelect(args, providerLabel) {
46818
+ const schema = readSchema(args.schema);
46819
+ const table = readIdentifier(args.table, "table");
46820
+ const columns = readIdentifierArray(args.columns, "columns", MAX_COLUMNS5, true);
46821
+ const filters = readFilters2(args.filters);
46822
+ const orderBy = readOrderBy(args.orderBy);
46823
+ const limit = readBoundedInteger(args.limit, 100, 1, MAX_RESULT_ROWS, "limit");
46824
+ const offset = readBoundedInteger(args.offset, 0, 0, 1e6, "offset");
46825
+ const values = [];
46826
+ const predicates = filters.map((filter) => {
46827
+ const column = quoteIdentifier2(filter.column);
46828
+ if (filter.operator === "is-null") return `${column} IS NULL`;
46829
+ if (filter.operator === "not-null") return `${column} IS NOT NULL`;
46830
+ values.push(filter.value);
46831
+ return `${column} ${sqlOperator(filter.operator)} $${values.length}`;
46832
+ });
46833
+ assertParameterBytes(values, providerLabel);
46834
+ const where = predicates.length > 0 ? ` WHERE ${predicates.join(" AND ")}` : "";
46835
+ const order = orderBy.length > 0 ? ` ORDER BY ${orderBy.map((entry) => `${quoteIdentifier2(entry.column)} ${entry.direction.toUpperCase()}`).join(", ")}` : "";
46836
+ return {
46837
+ text: `SELECT ${columns.map(quoteIdentifier2).join(", ")} FROM ${quoteIdentifier2(schema)}.${quoteIdentifier2(table)}${where}${order} LIMIT ${limit} OFFSET ${offset}`,
46838
+ values
46839
+ };
46840
+ }
46841
+ function readFilters2(value) {
46842
+ if (value === void 0 || value === null) return [];
46843
+ if (!Array.isArray(value) || value.length > MAX_FILTERS2) throw new Error(`filters must contain at most ${MAX_FILTERS2} entries`);
46844
+ return value.map((entry, index) => {
46845
+ if (!isPlainRecord(entry)) throw new Error(`filters[${index}] must be an object`);
46846
+ const column = readIdentifier(entry.column, `filters[${index}].column`);
46847
+ const operator = entry.operator;
46848
+ if (!["eq", "ne", "lt", "lte", "gt", "gte", "like", "is-null", "not-null"].includes(String(operator))) {
46849
+ throw new Error(`filters[${index}].operator is unsupported`);
46850
+ }
46851
+ const valueRequired = !["is-null", "not-null"].includes(String(operator));
46852
+ if (valueRequired) assertScalar(entry.value, `filters[${index}].value`);
46853
+ else if (entry.value !== void 0) throw new Error(`filters[${index}].value is not valid for ${operator}`);
46854
+ if (valueRequired && entry.value === null) throw new Error(`filters[${index}] must use is-null or not-null for null values`);
46855
+ if (operator === "like" && typeof entry.value !== "string") throw new Error(`filters[${index}].value must be a string for like`);
46856
+ return { column, operator: String(operator), value: entry.value };
46857
+ });
46858
+ }
46859
+ function readOrderBy(value) {
46860
+ if (value === void 0 || value === null) return [];
46861
+ if (!Array.isArray(value) || value.length > MAX_ORDER_COLUMNS) throw new Error(`orderBy must contain at most ${MAX_ORDER_COLUMNS} entries`);
46862
+ return value.map((entry, index) => {
46863
+ if (!isPlainRecord(entry)) throw new Error(`orderBy[${index}] must be an object`);
46864
+ const column = readIdentifier(entry.column, `orderBy[${index}].column`);
46865
+ const direction = entry.direction ?? "asc";
46866
+ if (direction !== "asc" && direction !== "desc") throw new Error(`orderBy[${index}].direction must be asc or desc`);
46867
+ return { column, direction };
46868
+ });
46869
+ }
46870
+ function readIdentifierArray(value, label, max, required) {
46871
+ if (!Array.isArray(value) || required && value.length === 0 || value.length > max) {
46872
+ throw new Error(`${label} must contain ${required ? "1-" : "0-"}${max} identifiers`);
46873
+ }
46874
+ const identifiers = value.map((entry, index) => readIdentifier(entry, `${label}[${index}]`));
46875
+ if (new Set(identifiers).size !== identifiers.length) throw new Error(`${label} must not contain duplicates`);
46876
+ return identifiers;
46877
+ }
46878
+ function boundedResult2(result, providerLabel) {
46879
+ if (!Array.isArray(result.rows) || result.rows.length > MAX_RESULT_ROWS) {
46880
+ throw new Error(`${providerLabel} result exceeds ${MAX_RESULT_ROWS} rows`);
46881
+ }
46882
+ if (result.rowCount !== null && (!Number.isSafeInteger(result.rowCount) || result.rowCount < 0 || result.rowCount > MAX_RESULT_ROWS)) {
46883
+ throw new Error(`${providerLabel} result returned a malformed row count`);
46884
+ }
46885
+ const data4 = {
46886
+ rows: jsonSafe(result.rows),
46887
+ columns: result.fields.map((field) => ({
46888
+ name: field.name,
46889
+ tableId: field.tableID,
46890
+ columnId: field.columnID,
46891
+ dataTypeId: field.dataTypeID
46892
+ })),
46893
+ rowCount: result.rowCount ?? result.rows.length
46894
+ };
46895
+ const serialized = JSON.stringify(data4);
46896
+ if (Buffer.byteLength(serialized, "utf8") > MAX_RESULT_BYTES3) {
46897
+ throw new Error(`${providerLabel} result exceeds the ${MAX_RESULT_BYTES3}-byte limit`);
46898
+ }
46899
+ return data4;
46900
+ }
46901
+ function assertParameterBytes(values, providerLabel) {
46902
+ if (Buffer.byteLength(JSON.stringify(values), "utf8") > MAX_PARAMETERS_BYTES) {
46903
+ throw new Error(`${providerLabel} filter values exceed the ${MAX_PARAMETERS_BYTES}-byte limit`);
46904
+ }
46905
+ }
46906
+ function assertScalar(value, label) {
46907
+ if (value !== null && !["string", "number", "boolean"].includes(typeof value)) throw new Error(`${label} must be a JSON scalar or null`);
46908
+ if (typeof value === "number" && !Number.isFinite(value)) throw new Error(`${label} must be finite`);
46909
+ }
46910
+ function sqlOperator(value) {
46911
+ return { eq: "=", ne: "<>", lt: "<", lte: "<=", gt: ">", gte: ">=", like: "LIKE" }[value];
46912
+ }
46913
+ function readSchema(value) {
46914
+ return value === void 0 || value === null ? "public" : readIdentifier(value, "schema");
46915
+ }
46916
+ function readIdentifier(value, label) {
46917
+ if (typeof value !== "string" || value.length === 0 || Buffer.byteLength(value, "utf8") > MAX_IDENTIFIER_BYTES || !/^[A-Za-z_][A-Za-z0-9_$]*$/.test(value)) {
46918
+ throw new Error(`${label} must be a SQL identifier under ${MAX_IDENTIFIER_BYTES} bytes`);
46919
+ }
46920
+ return value;
46921
+ }
46922
+ function quoteIdentifier2(value) {
46923
+ return `"${value.replaceAll('"', '""')}"`;
46924
+ }
46925
+ function readHost4(value, providerLabel) {
46926
+ const host = readCredentialString2(value, "host", 253, providerLabel);
46927
+ const ipVersion = isIP6(host);
46928
+ if (ipVersion !== 0) {
46929
+ if (!isPublicNetworkAddress(host)) throw new Error(`${providerLabel} host is not a public network target`);
46930
+ return host;
46931
+ }
46932
+ const normalized = host.toLowerCase();
46933
+ if (normalized === "localhost" || normalized.endsWith(".localhost") || normalized.endsWith(".local") || /[\s/@:\[\]]/.test(host)) {
46934
+ throw new Error(`${providerLabel} host must be a public hostname or IP address without a scheme or port`);
46935
+ }
46936
+ return host;
46937
+ }
46938
+ function readCredentialString2(value, label, maxLength, providerLabel) {
46939
+ if (typeof value !== "string" || value.length === 0 || value.length > maxLength || label !== "password" && /[\u0000-\u001f\u007f]/.test(value)) {
46940
+ throw new Error(`${providerLabel} credential ${label} must be a non-empty string under ${maxLength} characters`);
46941
+ }
46942
+ return value;
46943
+ }
46944
+ function safeErrorMessage4(error, secrets) {
46945
+ let message = error instanceof Error ? error.message : String(error);
46946
+ for (const secret of secrets) {
46947
+ if (secret.length >= 4) message = message.replaceAll(secret, "[REDACTED]");
46948
+ }
46949
+ return message;
46950
+ }
46951
+ function credentialSecrets4(source, provider2) {
46952
+ try {
46953
+ return readCredentials5(source, provider2).secrets;
46954
+ } catch {
46955
+ return [];
46956
+ }
46957
+ }
46958
+ function emptySchema2() {
46959
+ return { type: "object", properties: {}, additionalProperties: false };
46960
+ }
46961
+ function identifierSchema(description) {
46962
+ return { type: "string", minLength: 1, maxLength: MAX_IDENTIFIER_BYTES, pattern: "^[A-Za-z_][A-Za-z0-9_$]*$", description };
46963
+ }
46964
+ function readCapability9(name, description, parameters) {
46965
+ return { name, class: "read", description, parameters };
46966
+ }
46967
+
46968
+ // src/connectors/adapters/postgres.ts
46969
+ var POSTGRES_PROVIDER = {
46970
+ kind: "postgres",
46971
+ displayName: "PostgreSQL",
46972
+ description: "Inspect PostgreSQL schemas and tables and run bounded structured row reads over a verified TLS connection.",
46973
+ authHint: "JSON with a public PostgreSQL host, database, user, password, optional port, and optional TLS CA. Verified TLS is mandatory.",
46974
+ defaultPort: 5432
46975
+ };
46976
+ function createPostgresConnector(options = {}) {
46977
+ return createPostgresWireReadConnector(POSTGRES_PROVIDER, options);
46978
+ }
46979
+ var postgresConnector = createPostgresConnector();
46980
+
44438
46981
  // src/connectors/adapters/recall-ai.ts
44439
46982
  var recallAiRegions = [
44440
46983
  "https://us-east-1.recall.ai",
@@ -45371,7 +47914,7 @@ function createSftpConnector(options = {}) {
45371
47914
  ]
45372
47915
  },
45373
47916
  async executeRead({ source, capabilityName, args }) {
45374
- const credentials = readCredentials2(source);
47917
+ const credentials = readCredentials6(source);
45375
47918
  if (capabilityName === "sftp.list") {
45376
47919
  const path = resolveRemotePath(credentials.rootPath, args.path ?? "/");
45377
47920
  const limit = readBoundedInteger(args.limit, MAX_LIST_ENTRIES, 1, MAX_LIST_ENTRIES, "limit");
@@ -45404,7 +47947,7 @@ function createSftpConnector(options = {}) {
45404
47947
  throw new Error(`Unknown SFTP read capability: ${capabilityName}`);
45405
47948
  },
45406
47949
  async executeMutation({ source, capabilityName, args }) {
45407
- const credentials = readCredentials2(source);
47950
+ const credentials = readCredentials6(source);
45408
47951
  const prepared = prepareMutation(capabilityName, args, credentials.rootPath);
45409
47952
  return withSftp(credentials, createClient, lookupHost, async (client) => {
45410
47953
  let data4;
@@ -45438,7 +47981,7 @@ function createSftpConnector(options = {}) {
45438
47981
  },
45439
47982
  async test(source) {
45440
47983
  try {
45441
- const credentials = readCredentials2(source);
47984
+ const credentials = readCredentials6(source);
45442
47985
  await withSftp(credentials, createClient, lookupHost, (client) => client.cwd());
45443
47986
  return { ok: true };
45444
47987
  } catch (error) {
@@ -45506,7 +48049,7 @@ async function withSftp(credentials, createClient, lookupHost, run) {
45506
48049
  await client.end().catch(() => false);
45507
48050
  }
45508
48051
  }
45509
- function readCredentials2(source) {
48052
+ function readCredentials6(source) {
45510
48053
  let raw;
45511
48054
  if (source.credentials.kind === "custom") raw = source.credentials.values;
45512
48055
  else if (source.credentials.kind === "api-key") {
@@ -48855,7 +51398,15 @@ var squareConnector = declarativeRestConnector({
48855
51398
  kind: "oauth2",
48856
51399
  authorizationUrl: "https://connect.squareup.com/oauth2/authorize",
48857
51400
  tokenUrl: "https://connect.squareup.com/oauth2/token",
48858
- scopes: ["CUSTOMERS_READ", "CUSTOMERS_WRITE", "PAYMENTS_READ", "PAYMENTS_WRITE", "INVOICES_READ", "INVOICES_WRITE"],
51401
+ scopes: [
51402
+ "CUSTOMERS_READ",
51403
+ "CUSTOMERS_WRITE",
51404
+ "PAYMENTS_READ",
51405
+ "PAYMENTS_WRITE",
51406
+ "INVOICES_READ",
51407
+ "INVOICES_WRITE",
51408
+ "ITEMS_WRITE"
51409
+ ],
48859
51410
  clientIdEnv: "SQUARE_OAUTH_CLIENT_ID",
48860
51411
  clientSecretEnv: "SQUARE_OAUTH_CLIENT_SECRET"
48861
51412
  },
@@ -55209,17 +57760,17 @@ var zohoBookingsConnector = {
55209
57760
  category: "calendar",
55210
57761
  defaultConsistencyModel: "authoritative",
55211
57762
  capabilities: [
55212
- readCapability6("workspaces.list", "List Zoho Bookings workspaces.", {}),
55213
- readCapability6("services.list", "List services, optionally within one workspace.", {
57763
+ readCapability10("workspaces.list", "List Zoho Bookings workspaces.", {}),
57764
+ readCapability10("services.list", "List services, optionally within one workspace.", {
55214
57765
  workspace_id: { type: "string" }
55215
57766
  }),
55216
- readCapability6("resources.list", "List bookable resources, optionally for one service.", {
57767
+ readCapability10("resources.list", "List bookable resources, optionally for one service.", {
55217
57768
  service_id: { type: "string" }
55218
57769
  }),
55219
- readCapability6("staff.list", "List staff, optionally for one service.", {
57770
+ readCapability10("staff.list", "List staff, optionally for one service.", {
55220
57771
  service_id: { type: "string" }
55221
57772
  }),
55222
- readCapability6("appointments.list", "List appointments from a required start time.", {
57773
+ readCapability10("appointments.list", "List appointments from a required start time.", {
55223
57774
  from_time: {
55224
57775
  type: "string",
55225
57776
  description: "Zoho timestamp in dd-MMM-yyyy HH:mm:ss format."
@@ -55229,17 +57780,17 @@ var zohoBookingsConnector = {
55229
57780
  staff_id: { type: "string" },
55230
57781
  status: { type: "string" }
55231
57782
  }, ["from_time"]),
55232
- readCapability6("appointments.get", "Read one appointment by booking id.", {
57783
+ readCapability10("appointments.get", "Read one appointment by booking id.", {
55233
57784
  booking_id: { type: "string" }
55234
57785
  }, ["booking_id"]),
55235
- readCapability6("availability.fetch", "Fetch open time slots for a service and date.", {
57786
+ readCapability10("availability.fetch", "Fetch open time slots for a service and date.", {
55236
57787
  service_id: { type: "string" },
55237
57788
  selected_date: { type: "string", description: "Date in YYYY-MM-DD format." },
55238
57789
  staff_id: { type: "string" },
55239
57790
  group_id: { type: "string" },
55240
57791
  resource_id: { type: "string" }
55241
57792
  }, ["service_id", "selected_date"]),
55242
- mutationCapability6("appointments.book", "Book an appointment for a customer.", {
57793
+ mutationCapability8("appointments.book", "Book an appointment for a customer.", {
55243
57794
  service_id: { type: "string" },
55244
57795
  from_time: { type: "string", description: "Zoho timestamp in dd-MMM-yyyy HH:mm:ss format." },
55245
57796
  customer_details: {
@@ -55255,13 +57806,13 @@ var zohoBookingsConnector = {
55255
57806
  additional_fields: { type: "object" },
55256
57807
  payment_info: { type: "object" }
55257
57808
  }, ["service_id", "from_time", "customer_details"]),
55258
- mutationCapability6("appointments.reschedule", "Move an appointment to a new time, staff member, or group.", {
57809
+ mutationCapability8("appointments.reschedule", "Move an appointment to a new time, staff member, or group.", {
55259
57810
  booking_id: { type: "string" },
55260
57811
  start_time: { type: "string", description: "Zoho timestamp in dd-MMM-yyyy HH:mm:ss format." },
55261
57812
  staff_id: { type: "string" },
55262
57813
  group_id: { type: "string" }
55263
57814
  }, ["booking_id"]),
55264
- mutationCapability6("appointments.cancel", "Cancel an appointment by booking id.", {
57815
+ mutationCapability8("appointments.cancel", "Cancel an appointment by booking id.", {
55265
57816
  booking_id: { type: "string" }
55266
57817
  }, ["booking_id"])
55267
57818
  ]
@@ -55378,7 +57929,7 @@ var zohoBookingsConnector = {
55378
57929
  }
55379
57930
  }
55380
57931
  };
55381
- function readCapability6(name, description, properties, required = []) {
57932
+ function readCapability10(name, description, properties, required = []) {
55382
57933
  return {
55383
57934
  name,
55384
57935
  class: "read",
@@ -55387,7 +57938,7 @@ function readCapability6(name, description, properties, required = []) {
55387
57938
  requiredScopes: ["zohobookings.data.READ"]
55388
57939
  };
55389
57940
  }
55390
- function mutationCapability6(name, description, properties, required) {
57941
+ function mutationCapability8(name, description, properties, required) {
55391
57942
  return {
55392
57943
  name,
55393
57944
  class: "mutation",
@@ -62731,6 +65282,393 @@ var metabaseConnector = declarativeRestConnector({
62731
65282
  ]
62732
65283
  });
62733
65284
 
65285
+ // src/connectors/adapters/mysql.ts
65286
+ import { connect as createSocket, isIP as isIP7 } from "net";
65287
+ import {
65288
+ createConnection as createMysqlConnection
65289
+ } from "mysql2/promise";
65290
+ var MAX_PARAMETERS = 1e3;
65291
+ var MAX_PARAMETER_BYTES = 10 * 1024 * 1024;
65292
+ var MAX_RESULT_ROWS2 = 1e4;
65293
+ var MAX_RESULT_BYTES4 = 10 * 1024 * 1024;
65294
+ var DEFAULT_QUERY_TIMEOUT_MS = 3e4;
65295
+ function createMySqlConnector(options = {}) {
65296
+ const createConnection = options.createConnection ?? defaultCreateConnection;
65297
+ const resolveHost = options.resolveHost ?? resolvePublicHostAddresses;
65298
+ return {
65299
+ manifest: {
65300
+ kind: "mysql",
65301
+ displayName: "MySQL",
65302
+ description: "Inspect schemas and run bounded parameterized reads or approved compare-and-swap writes against MySQL over verified TLS.",
65303
+ auth: {
65304
+ kind: "api-key",
65305
+ hint: "JSON with host, port, user, password, optional database, and optional tlsCa. TLS and public network targets are mandatory."
65306
+ },
65307
+ defaultConsistencyModel: "authoritative",
65308
+ category: "database",
65309
+ rateLimit: { requests: 120, windowMs: 6e4, scope: "data-source" },
65310
+ capabilities: [
65311
+ {
65312
+ name: "mysql.databases.list",
65313
+ class: "read",
65314
+ description: "List databases visible to the connected MySQL user.",
65315
+ parameters: emptySchema3()
65316
+ },
65317
+ {
65318
+ name: "mysql.tables.list",
65319
+ class: "read",
65320
+ description: "List base tables and views in one database.",
65321
+ parameters: {
65322
+ type: "object",
65323
+ properties: { database: identifierSchema2("Database name; defaults to the connection database.") },
65324
+ additionalProperties: false
65325
+ }
65326
+ },
65327
+ {
65328
+ name: "mysql.tables.describe",
65329
+ class: "read",
65330
+ description: "Read columns, types, nullability, defaults, and keys for one table.",
65331
+ parameters: {
65332
+ type: "object",
65333
+ properties: {
65334
+ database: identifierSchema2("Database name; defaults to the connection database."),
65335
+ table: identifierSchema2("Table name.")
65336
+ },
65337
+ required: ["table"],
65338
+ additionalProperties: false
65339
+ }
65340
+ },
65341
+ {
65342
+ name: "mysql.query",
65343
+ class: "read",
65344
+ description: "Run one parameterized SELECT, SHOW, DESCRIBE, or EXPLAIN statement inside a read-only transaction.",
65345
+ parameters: statementSchema(false)
65346
+ },
65347
+ {
65348
+ name: "mysql.execute",
65349
+ class: "mutation",
65350
+ description: "Run one approved parameterized INSERT, UPDATE, DELETE, or REPLACE statement and commit only when the affected-row count matches the caller expectation.",
65351
+ parameters: statementSchema(true),
65352
+ cas: "optimistic-read-verify",
65353
+ externalEffect: true
65354
+ }
65355
+ ]
65356
+ },
65357
+ async test(source) {
65358
+ try {
65359
+ await withConnection(source, createConnection, resolveHost, async (connection) => {
65360
+ await connection.ping();
65361
+ });
65362
+ return { ok: true };
65363
+ } catch (error) {
65364
+ return { ok: false, reason: safeErrorMessage5(error) };
65365
+ }
65366
+ },
65367
+ async executeRead(inv) {
65368
+ const query2 = readQuery2(inv);
65369
+ assertReadStatement(query2.statement);
65370
+ const data4 = await withConnection(inv.source, createConnection, resolveHost, async (connection) => {
65371
+ await executeStatement(connection, {
65372
+ statement: "START TRANSACTION READ ONLY",
65373
+ parameters: []
65374
+ }, queryTimeout(inv.source));
65375
+ try {
65376
+ const [rows, fields] = await executeStatement(connection, query2, queryTimeout(inv.source));
65377
+ if (!Array.isArray(rows)) throw new Error("MySQL read returned a non-row result");
65378
+ return boundedResult3(rows, fields);
65379
+ } finally {
65380
+ await connection.rollback().catch(() => void 0);
65381
+ }
65382
+ });
65383
+ return { data: data4, fetchedAt: Date.now() };
65384
+ },
65385
+ async executeMutation(inv) {
65386
+ if (inv.capabilityName !== "mysql.execute") {
65387
+ throw new Error(`Unknown MySQL mutation capability: ${inv.capabilityName}`);
65388
+ }
65389
+ const query2 = readStatementArgs(inv.args);
65390
+ assertMutationStatement(query2.statement);
65391
+ const expectedAffectedRows = readBoundedInteger(
65392
+ inv.args.expectedAffectedRows,
65393
+ -1,
65394
+ 0,
65395
+ MAX_RESULT_ROWS2,
65396
+ "expectedAffectedRows"
65397
+ );
65398
+ if (expectedAffectedRows < 0) throw new Error("expectedAffectedRows is required");
65399
+ return withConnection(inv.source, createConnection, resolveHost, async (connection) => {
65400
+ await connection.beginTransaction();
65401
+ try {
65402
+ const [result] = await executeStatement(connection, query2, queryTimeout(inv.source));
65403
+ const affectedRows = readAffectedRows(result);
65404
+ if (affectedRows !== expectedAffectedRows) {
65405
+ await connection.rollback();
65406
+ return {
65407
+ status: "conflict",
65408
+ alternatives: [],
65409
+ currentState: { affectedRows },
65410
+ message: `MySQL write affected ${affectedRows} rows; expected ${expectedAffectedRows}. The transaction was rolled back.`
65411
+ };
65412
+ }
65413
+ await connection.commit();
65414
+ return committedMutation(result, affectedRows);
65415
+ } catch (error) {
65416
+ await connection.rollback().catch(() => void 0);
65417
+ throw error;
65418
+ }
65419
+ });
65420
+ }
65421
+ };
65422
+ }
65423
+ var mysqlConnector = createMySqlConnector();
65424
+ async function defaultCreateConnection(config) {
65425
+ return createMysqlConnection(config);
65426
+ }
65427
+ async function withConnection(source, createConnection, resolveHost, run) {
65428
+ const credentials = readCredentials7(source);
65429
+ const addresses = await resolveHost(credentials.host);
65430
+ if (addresses.length === 0) throw new Error("MySQL host did not resolve");
65431
+ const address = addresses[0];
65432
+ let connection;
65433
+ try {
65434
+ connection = await createConnection({
65435
+ host: credentials.host,
65436
+ port: credentials.port,
65437
+ user: credentials.user,
65438
+ password: credentials.password,
65439
+ database: credentials.database,
65440
+ connectTimeout: credentials.connectTimeoutMs,
65441
+ multipleStatements: false,
65442
+ namedPlaceholders: false,
65443
+ supportBigNumbers: true,
65444
+ bigNumberStrings: true,
65445
+ decimalNumbers: false,
65446
+ dateStrings: true,
65447
+ timezone: "Z",
65448
+ charset: "utf8mb4",
65449
+ enableKeepAlive: true,
65450
+ maxPreparedStatements: 100,
65451
+ stream: () => createSocket({ host: address, port: credentials.port }),
65452
+ ssl: {
65453
+ ca: credentials.tlsCa,
65454
+ minVersion: "TLSv1.2",
65455
+ rejectUnauthorized: true,
65456
+ verifyIdentity: true
65457
+ }
65458
+ });
65459
+ return await run(connection);
65460
+ } finally {
65461
+ if (connection) await connection.end().catch(() => void 0);
65462
+ }
65463
+ }
65464
+ function readCredentials7(source) {
65465
+ let raw;
65466
+ if (source.credentials.kind === "custom") raw = source.credentials.values;
65467
+ else if (source.credentials.kind === "api-key") {
65468
+ try {
65469
+ raw = JSON.parse(source.credentials.apiKey);
65470
+ } catch {
65471
+ throw new Error("MySQL credential must be valid JSON");
65472
+ }
65473
+ } else {
65474
+ throw new Error("MySQL requires a structured credential bundle");
65475
+ }
65476
+ if (!isPlainRecord(raw)) throw new Error("MySQL credential must be a JSON object");
65477
+ const host = requiredCredentialString3(raw.host, "host", 253);
65478
+ validateHost(host);
65479
+ const user = requiredCredentialString3(raw.user ?? raw.username, "user", 128);
65480
+ const password = requiredCredentialString3(raw.password, "password", 4096);
65481
+ const database = readOptionalString(raw.database, "database");
65482
+ if (database && database.length > 64) throw new Error("MySQL credential database exceeds 64 characters");
65483
+ const tlsCa = readOptionalString(raw.tlsCa, "tlsCa");
65484
+ if (tlsCa && Buffer.byteLength(tlsCa, "utf8") > 1024 * 1024) {
65485
+ throw new Error("MySQL credential tlsCa exceeds the 1 MiB limit");
65486
+ }
65487
+ return {
65488
+ host,
65489
+ port: readBoundedInteger(raw.port, 3306, 1, 65535, "port"),
65490
+ user,
65491
+ password,
65492
+ database,
65493
+ tlsCa,
65494
+ connectTimeoutMs: readBoundedInteger(raw.connectTimeoutMs, 1e4, 1e3, 3e4, "connectTimeoutMs"),
65495
+ queryTimeoutMs: readBoundedInteger(raw.queryTimeoutMs, DEFAULT_QUERY_TIMEOUT_MS, 1e3, 6e4, "queryTimeoutMs")
65496
+ };
65497
+ }
65498
+ function readQuery2(inv) {
65499
+ if (inv.capabilityName === "mysql.databases.list") {
65500
+ return {
65501
+ statement: "SELECT SCHEMA_NAME AS databaseName, DEFAULT_CHARACTER_SET_NAME AS characterSet, DEFAULT_COLLATION_NAME AS collation FROM information_schema.SCHEMATA ORDER BY SCHEMA_NAME",
65502
+ parameters: []
65503
+ };
65504
+ }
65505
+ if (inv.capabilityName === "mysql.tables.list") {
65506
+ const database = readDatabase(inv.args.database, inv.source);
65507
+ return {
65508
+ statement: "SELECT TABLE_NAME AS tableName, TABLE_TYPE AS tableType, ENGINE AS engine, TABLE_ROWS AS estimatedRows, TABLE_COLLATION AS collation FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME",
65509
+ parameters: [database]
65510
+ };
65511
+ }
65512
+ if (inv.capabilityName === "mysql.tables.describe") {
65513
+ const database = readDatabase(inv.args.database, inv.source);
65514
+ const table = readIdentifier2(inv.args.table, "table");
65515
+ return {
65516
+ statement: "SELECT COLUMN_NAME AS columnName, ORDINAL_POSITION AS ordinalPosition, COLUMN_DEFAULT AS columnDefault, IS_NULLABLE AS isNullable, DATA_TYPE AS dataType, COLUMN_TYPE AS columnType, COLUMN_KEY AS columnKey, EXTRA AS extra FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? ORDER BY ORDINAL_POSITION",
65517
+ parameters: [database, table]
65518
+ };
65519
+ }
65520
+ if (inv.capabilityName === "mysql.query") return readStatementArgs(inv.args);
65521
+ throw new Error(`Unknown MySQL read capability: ${inv.capabilityName}`);
65522
+ }
65523
+ function readStatementArgs(args) {
65524
+ const statement = requiredString7(args.statement, "statement");
65525
+ if (Buffer.byteLength(statement, "utf8") > 1024 * 1024) throw new Error("statement exceeds the 1 MiB limit");
65526
+ const parameters = args.parameters === void 0 ? [] : args.parameters;
65527
+ if (!Array.isArray(parameters) || parameters.length > MAX_PARAMETERS) {
65528
+ throw new Error(`parameters must be an array with at most ${MAX_PARAMETERS} entries`);
65529
+ }
65530
+ for (const [index, value] of parameters.entries()) {
65531
+ if (value !== null && !["string", "number", "boolean"].includes(typeof value)) {
65532
+ throw new Error(`parameters[${index}] must be a JSON scalar or null`);
65533
+ }
65534
+ if (typeof value === "number" && !Number.isFinite(value)) {
65535
+ throw new Error(`parameters[${index}] must be finite`);
65536
+ }
65537
+ }
65538
+ if (Buffer.byteLength(JSON.stringify(parameters), "utf8") > MAX_PARAMETER_BYTES) {
65539
+ throw new Error(`parameters exceed the ${MAX_PARAMETER_BYTES}-byte limit`);
65540
+ }
65541
+ return { statement, parameters };
65542
+ }
65543
+ function assertReadStatement(statement) {
65544
+ const keyword = leadingKeyword(statement);
65545
+ if (!["SELECT", "SHOW", "DESCRIBE", "DESC", "EXPLAIN", "WITH"].includes(keyword)) {
65546
+ throw new Error("mysql.query accepts only SELECT, SHOW, DESCRIBE, or EXPLAIN statements");
65547
+ }
65548
+ if (/\b(?:INTO\s+(?:OUTFILE|DUMPFILE)|LOAD_FILE\s*\(|GET_LOCK\s*\(|RELEASE_LOCK\s*\(|SLEEP\s*\(|BENCHMARK\s*\(|FOR\s+UPDATE|LOCK\s+IN\s+SHARE\s+MODE)\b/i.test(statement)) {
65549
+ throw new Error("mysql.query rejects file, lock, and delay side effects");
65550
+ }
65551
+ }
65552
+ function assertMutationStatement(statement) {
65553
+ const keyword = leadingKeyword(statement);
65554
+ if (!["INSERT", "UPDATE", "DELETE", "REPLACE"].includes(keyword)) {
65555
+ throw new Error("mysql.execute accepts only INSERT, UPDATE, DELETE, or REPLACE statements");
65556
+ }
65557
+ }
65558
+ function leadingKeyword(statement) {
65559
+ const withoutComments = statement.replace(/^\s*(?:--[^\n]*(?:\n|$)|#[^\n]*(?:\n|$)|\/\*[\s\S]*?\*\/\s*)*/u, "").trimStart();
65560
+ return /^[A-Za-z]+/.exec(withoutComments)?.[0]?.toUpperCase() ?? "";
65561
+ }
65562
+ async function executeStatement(connection, query2, timeout) {
65563
+ return connection.execute({ sql: query2.statement, values: query2.parameters, timeout });
65564
+ }
65565
+ function boundedResult3(rows, fields) {
65566
+ if (rows.length > MAX_RESULT_ROWS2) throw new Error(`MySQL result exceeds ${MAX_RESULT_ROWS2} rows`);
65567
+ const data4 = {
65568
+ rows: jsonSafe(rows),
65569
+ columns: fields.map((field) => ({
65570
+ name: field.name,
65571
+ table: field.table,
65572
+ database: field.schema,
65573
+ type: field.type
65574
+ })),
65575
+ rowCount: rows.length
65576
+ };
65577
+ const serialized = JSON.stringify(data4);
65578
+ if (Buffer.byteLength(serialized, "utf8") > MAX_RESULT_BYTES4) {
65579
+ throw new Error(`MySQL result exceeds the ${MAX_RESULT_BYTES4}-byte limit`);
65580
+ }
65581
+ return data4;
65582
+ }
65583
+ function readAffectedRows(result) {
65584
+ if (!isPlainRecord(result) || !Number.isInteger(result.affectedRows) || result.affectedRows < 0) {
65585
+ throw new Error("MySQL mutation did not return an affected-row count");
65586
+ }
65587
+ return result.affectedRows;
65588
+ }
65589
+ function committedMutation(result, affectedRows) {
65590
+ const header2 = result;
65591
+ const rawInsertId = header2.insertId;
65592
+ const insertId = typeof rawInsertId === "number" && Number.isSafeInteger(rawInsertId) ? rawInsertId : typeof rawInsertId === "string" ? rawInsertId : void 0;
65593
+ return {
65594
+ status: "committed",
65595
+ data: jsonSafe({
65596
+ affectedRows,
65597
+ changedRows: header2.changedRows,
65598
+ insertId,
65599
+ warningStatus: header2.warningStatus
65600
+ }),
65601
+ committedAt: Date.now(),
65602
+ idempotentReplay: false
65603
+ };
65604
+ }
65605
+ function readDatabase(value, source) {
65606
+ const explicit = value === void 0 ? void 0 : readIdentifier2(value, "database");
65607
+ if (explicit) return explicit;
65608
+ const credentials = readCredentials7(source);
65609
+ if (!credentials.database) throw new Error("database is required when the connection has no default database");
65610
+ return credentials.database;
65611
+ }
65612
+ function queryTimeout(source) {
65613
+ return readCredentials7(source).queryTimeoutMs;
65614
+ }
65615
+ function requiredString7(value, label) {
65616
+ const parsed = readOptionalString(value, label);
65617
+ if (!parsed) throw new Error(`${label} is required`);
65618
+ return parsed;
65619
+ }
65620
+ function requiredCredentialString3(value, label, maxLength) {
65621
+ const parsed = readOptionalString(value, label);
65622
+ if (!parsed) throw new Error(`MySQL credential ${label} is required`);
65623
+ if (parsed.length > maxLength) throw new Error(`MySQL credential ${label} exceeds ${maxLength} characters`);
65624
+ return parsed;
65625
+ }
65626
+ function readIdentifier2(value, label) {
65627
+ const parsed = requiredString7(value, label);
65628
+ if (parsed.length > 64) throw new Error(`${label} exceeds 64 characters`);
65629
+ return parsed;
65630
+ }
65631
+ function validateHost(host) {
65632
+ const normalized = host.toLowerCase();
65633
+ if (host.length > 253 || host.includes("://") || /[\s/@]/.test(host) || normalized === "localhost" || normalized.endsWith(".localhost") || normalized.endsWith(".local") || isIP7(host) === 0 && !/^[A-Za-z0-9.-]+$/.test(host) || host.split(".").some((label) => !label || label.startsWith("-") || label.endsWith("-"))) {
65634
+ throw new Error("MySQL host must be a public hostname or IP address without a scheme");
65635
+ }
65636
+ }
65637
+ function emptySchema3() {
65638
+ return { type: "object", properties: {}, additionalProperties: false };
65639
+ }
65640
+ function identifierSchema2(description) {
65641
+ return { type: "string", minLength: 1, maxLength: 64, description };
65642
+ }
65643
+ function statementSchema(mutation) {
65644
+ const properties = {
65645
+ statement: { type: "string", minLength: 1, maxLength: 1024 * 1024 },
65646
+ parameters: {
65647
+ type: "array",
65648
+ maxItems: MAX_PARAMETERS,
65649
+ items: { type: ["string", "number", "boolean", "null"] },
65650
+ description: "Values bound to ? placeholders in order."
65651
+ }
65652
+ };
65653
+ if (mutation) {
65654
+ properties.expectedAffectedRows = {
65655
+ type: "integer",
65656
+ minimum: 0,
65657
+ maximum: MAX_RESULT_ROWS2,
65658
+ description: "Commit only when MySQL reports exactly this many affected rows."
65659
+ };
65660
+ }
65661
+ return {
65662
+ type: "object",
65663
+ properties,
65664
+ required: mutation ? ["statement", "expectedAffectedRows"] : ["statement"],
65665
+ additionalProperties: false
65666
+ };
65667
+ }
65668
+ function safeErrorMessage5(error) {
65669
+ return error instanceof Error && error.message ? error.message : "MySQL connection failed";
65670
+ }
65671
+
62734
65672
  // src/connectors/adapters/segment.ts
62735
65673
  var segmentConnector = declarativeRestConnector({
62736
65674
  kind: "segment",
@@ -63875,6 +66813,49 @@ var hunterConnector = declarativeRestConnector({
63875
66813
  ]
63876
66814
  });
63877
66815
 
66816
+ // src/connectors/adapters/neverbounce.ts
66817
+ var neverbounceConnector = declarativeRestConnector({
66818
+ kind: "neverbounce",
66819
+ displayName: "NeverBounce",
66820
+ description: "Verify email deliverability with the NeverBounce API.",
66821
+ auth: {
66822
+ kind: "api-key",
66823
+ hint: "NeverBounce API key from Apps > API in the NeverBounce dashboard."
66824
+ },
66825
+ category: "crm",
66826
+ defaultConsistencyModel: "authoritative",
66827
+ baseUrl: "https://api.neverbounce.com/v4.2",
66828
+ credentialPlacement: { kind: "query", parameter: "key" },
66829
+ test: {
66830
+ method: "GET",
66831
+ path: "/account/info"
66832
+ },
66833
+ capabilities: [
66834
+ {
66835
+ name: "verify.email.address",
66836
+ class: "mutation",
66837
+ description: "Verify one email address and return deliverability status such as valid, invalid, disposable, catch-all, or unknown.",
66838
+ parameters: {
66839
+ type: "object",
66840
+ properties: {
66841
+ email: {
66842
+ type: "string",
66843
+ description: "Email address to verify."
66844
+ }
66845
+ },
66846
+ required: ["email"]
66847
+ },
66848
+ request: {
66849
+ method: "GET",
66850
+ path: "/single/check",
66851
+ query: { email: "{email}" }
66852
+ },
66853
+ cas: "native-idempotency",
66854
+ externalEffect: true
66855
+ }
66856
+ ]
66857
+ });
66858
+
63878
66859
  // src/connectors/adapters/theirstack.ts
63879
66860
  var theirstackConnector = declarativeRestConnector({
63880
66861
  kind: "theirstack",
@@ -64226,6 +67207,7 @@ var CONNECTOR_ADAPTER_FACTORIES = [
64226
67207
  defineFactoryAdapter(() => digitalOceanConnector, {}),
64227
67208
  defineFactoryAdapter(() => clicksendConnector, {}),
64228
67209
  defineFactoryAdapter(() => metabaseConnector, {}),
67210
+ defineFactoryAdapter(() => mysqlConnector, {}),
64229
67211
  defineFactoryAdapter(
64230
67212
  () => microsoftDynamics365BusinessCentralConnector,
64231
67213
  microsoftOAuthEnvMap
@@ -64284,6 +67266,12 @@ var CONNECTOR_ADAPTER_FACTORIES = [
64284
67266
  defineFactoryAdapter(() => httpConnector, {}),
64285
67267
  defineFactoryAdapter(() => rssConnector, {}),
64286
67268
  defineFactoryAdapter(() => kafkaConnector, {}),
67269
+ defineFactoryAdapter(() => duckdbConnector, {}),
67270
+ defineFactoryAdapter(() => rabbitMqConnector, {}),
67271
+ defineFactoryAdapter(() => redisConnector, {}),
67272
+ defineFactoryAdapter(() => redshiftConnector, {}),
67273
+ defineFactoryAdapter(() => postgresConnector, {}),
67274
+ defineFactoryAdapter(() => mongodbConnector, {}),
64287
67275
  defineFactoryAdapter(() => csvFilesConnector, {}),
64288
67276
  defineFactoryAdapter(() => excelFilesConnector, {}),
64289
67277
  defineFactoryAdapter(() => parquetFilesConnector, {}),
@@ -64352,14 +67340,15 @@ var CONNECTOR_ADAPTER_FACTORIES = [
64352
67340
  clientId: "LINEAR_OAUTH_CLIENT_ID",
64353
67341
  clientSecret: "LINEAR_OAUTH_CLIENT_SECRET"
64354
67342
  }),
67343
+ defineFactoryAdapter(() => miroConnector, {
67344
+ clientId: "MIRO_OAUTH_CLIENT_ID",
67345
+ clientSecret: "MIRO_OAUTH_CLIENT_SECRET"
67346
+ }),
64355
67347
  defineFactoryAdapter(() => mondayConnector, {
64356
67348
  clientId: "MONDAY_OAUTH_CLIENT_ID",
64357
67349
  clientSecret: "MONDAY_OAUTH_CLIENT_SECRET"
64358
67350
  }),
64359
- defineFactoryAdapter(() => clickupConnector, {
64360
- clientId: "CLICKUP_OAUTH_CLIENT_ID",
64361
- clientSecret: "CLICKUP_OAUTH_CLIENT_SECRET"
64362
- }),
67351
+ defineFactoryAdapter(() => clickupConnector, {}),
64363
67352
  defineFactoryAdapter(() => basecampConnector, {
64364
67353
  clientId: "BASECAMP_OAUTH_CLIENT_ID",
64365
67354
  clientSecret: "BASECAMP_OAUTH_CLIENT_SECRET"
@@ -64581,6 +67570,7 @@ var CONNECTOR_ADAPTER_FACTORIES = [
64581
67570
  defineFactoryAdapter(() => builtwithConnector, {}),
64582
67571
  defineFactoryAdapter(() => fullenrichConnector, {}),
64583
67572
  defineFactoryAdapter(() => hunterConnector, {}),
67573
+ defineFactoryAdapter(() => neverbounceConnector, {}),
64584
67574
  defineFactoryAdapter(() => theirstackConnector, {}),
64585
67575
  defineFactoryAdapter(() => zerobounceConnector, {})
64586
67576
  ];
@@ -70966,677 +73956,6 @@ var figjamConnector = declarativeRestConnector({
70966
73956
  ]
70967
73957
  });
70968
73958
 
70969
- // src/connectors/adapters/miro.ts
70970
- var miroConnector = declarativeRestConnector({
70971
- kind: "miro",
70972
- displayName: "Miro",
70973
- description: "Read and edit Miro boards: list and search boards, read board items (sticky notes, shapes, text, cards, images, frames, connectors), create and update items, and post board content back into the source of truth.",
70974
- auth: {
70975
- kind: "oauth2",
70976
- authorizationUrl: "https://miro.com/oauth/authorize",
70977
- tokenUrl: "https://api.miro.com/v1/oauth/token",
70978
- scopes: [
70979
- "boards:read",
70980
- "boards:write",
70981
- "identity:read",
70982
- "team:read",
70983
- "organizations:read"
70984
- ],
70985
- clientIdEnv: "MIRO_OAUTH_CLIENT_ID",
70986
- clientSecretEnv: "MIRO_OAUTH_CLIENT_SECRET"
70987
- },
70988
- category: "doc",
70989
- defaultConsistencyModel: "authoritative",
70990
- baseUrl: "https://api.miro.com",
70991
- defaultHeaders: { accept: "application/json" },
70992
- // GET /v2/me returns the authenticated user — Miro's documented health probe.
70993
- test: { method: "GET", path: "/v2/me" },
70994
- capabilities: [
70995
- {
70996
- name: "me.get",
70997
- class: "read",
70998
- description: "Return the authenticated Miro user.",
70999
- parameters: { type: "object", properties: {} },
71000
- request: { method: "GET", path: "/v2/me" },
71001
- requiredScopes: ["identity:read"]
71002
- },
71003
- {
71004
- name: "boards.list",
71005
- class: "read",
71006
- description: "List boards accessible to the authenticated user. Supports cursor pagination via `cursor` and team / sort filters.",
71007
- parameters: {
71008
- type: "object",
71009
- properties: {
71010
- team_id: { type: "string", description: "Filter to a single team id." },
71011
- query: { type: "string", description: "Free-text board name filter." },
71012
- owner: { type: "string", description: "Filter by owner user id." },
71013
- limit: { type: "integer", minimum: 1, maximum: 50 },
71014
- offset: { type: "integer", minimum: 0 },
71015
- sort: {
71016
- type: "string",
71017
- enum: ["default", "last_modified", "last_opened", "last_created", "alphabetically"]
71018
- }
71019
- }
71020
- },
71021
- request: {
71022
- method: "GET",
71023
- path: "/v2/boards",
71024
- query: {
71025
- team_id: "{team_id}",
71026
- query: "{query}",
71027
- owner: "{owner}",
71028
- limit: "{limit}",
71029
- offset: "{offset}",
71030
- sort: "{sort}"
71031
- }
71032
- },
71033
- requiredScopes: ["boards:read"]
71034
- },
71035
- {
71036
- name: "boards.get",
71037
- class: "read",
71038
- description: "Fetch a single Miro board by id.",
71039
- parameters: {
71040
- type: "object",
71041
- properties: { board_id: { type: "string" } },
71042
- required: ["board_id"]
71043
- },
71044
- request: { method: "GET", path: "/v2/boards/{board_id}" },
71045
- requiredScopes: ["boards:read"]
71046
- },
71047
- {
71048
- name: "boards.members.list",
71049
- class: "read",
71050
- description: "List members (collaborators) of a Miro board.",
71051
- parameters: {
71052
- type: "object",
71053
- properties: {
71054
- board_id: { type: "string" },
71055
- limit: { type: "integer", minimum: 1, maximum: 50 },
71056
- offset: { type: "integer", minimum: 0 }
71057
- },
71058
- required: ["board_id"]
71059
- },
71060
- request: {
71061
- method: "GET",
71062
- path: "/v2/boards/{board_id}/members",
71063
- query: { limit: "{limit}", offset: "{offset}" }
71064
- },
71065
- requiredScopes: ["boards:read"]
71066
- },
71067
- {
71068
- name: "items.list",
71069
- class: "read",
71070
- description: "List all items on a board, optionally filtered by item type (sticky_note, text, shape, card, image, frame, connector, embed, app_card, document).",
71071
- parameters: {
71072
- type: "object",
71073
- properties: {
71074
- board_id: { type: "string" },
71075
- type: {
71076
- type: "string",
71077
- enum: [
71078
- "sticky_note",
71079
- "text",
71080
- "shape",
71081
- "card",
71082
- "image",
71083
- "frame",
71084
- "connector",
71085
- "embed",
71086
- "app_card",
71087
- "document",
71088
- "preview"
71089
- ]
71090
- },
71091
- limit: { type: "integer", minimum: 1, maximum: 50 },
71092
- cursor: { type: "string" }
71093
- },
71094
- required: ["board_id"]
71095
- },
71096
- request: {
71097
- method: "GET",
71098
- path: "/v2/boards/{board_id}/items",
71099
- query: { type: "{type}", limit: "{limit}", cursor: "{cursor}" }
71100
- },
71101
- requiredScopes: ["boards:read"]
71102
- },
71103
- {
71104
- name: "items.get",
71105
- class: "read",
71106
- description: "Fetch a single board item by id.",
71107
- parameters: {
71108
- type: "object",
71109
- properties: {
71110
- board_id: { type: "string" },
71111
- item_id: { type: "string" }
71112
- },
71113
- required: ["board_id", "item_id"]
71114
- },
71115
- request: { method: "GET", path: "/v2/boards/{board_id}/items/{item_id}" },
71116
- requiredScopes: ["boards:read"]
71117
- },
71118
- {
71119
- name: "connectors.list",
71120
- class: "read",
71121
- description: "List connector lines on a board (arrows / lines between items).",
71122
- parameters: {
71123
- type: "object",
71124
- properties: {
71125
- board_id: { type: "string" },
71126
- limit: { type: "integer", minimum: 1, maximum: 50 },
71127
- cursor: { type: "string" }
71128
- },
71129
- required: ["board_id"]
71130
- },
71131
- request: {
71132
- method: "GET",
71133
- path: "/v2/boards/{board_id}/connectors",
71134
- query: { limit: "{limit}", cursor: "{cursor}" }
71135
- },
71136
- requiredScopes: ["boards:read"]
71137
- },
71138
- {
71139
- name: "tags.list",
71140
- class: "read",
71141
- description: "List tags defined on a board.",
71142
- parameters: {
71143
- type: "object",
71144
- properties: {
71145
- board_id: { type: "string" },
71146
- limit: { type: "integer", minimum: 1, maximum: 50 },
71147
- offset: { type: "integer", minimum: 0 }
71148
- },
71149
- required: ["board_id"]
71150
- },
71151
- request: {
71152
- method: "GET",
71153
- path: "/v2/boards/{board_id}/tags",
71154
- query: { limit: "{limit}", offset: "{offset}" }
71155
- },
71156
- requiredScopes: ["boards:read"]
71157
- },
71158
- {
71159
- name: "organizations.get",
71160
- class: "read",
71161
- description: "Read an organization (Enterprise plan).",
71162
- parameters: {
71163
- type: "object",
71164
- properties: { org_id: { type: "string" } },
71165
- required: ["org_id"]
71166
- },
71167
- request: { method: "GET", path: "/v2/orgs/{org_id}" },
71168
- requiredScopes: ["organizations:read"]
71169
- },
71170
- {
71171
- name: "organizations.teams.list",
71172
- class: "read",
71173
- description: "List teams in an organization (Enterprise plan).",
71174
- parameters: {
71175
- type: "object",
71176
- properties: {
71177
- org_id: { type: "string" },
71178
- limit: { type: "integer", minimum: 1, maximum: 100 },
71179
- cursor: { type: "string" }
71180
- },
71181
- required: ["org_id"]
71182
- },
71183
- request: {
71184
- method: "GET",
71185
- path: "/v2/orgs/{org_id}/teams",
71186
- query: { limit: "{limit}", cursor: "{cursor}" }
71187
- },
71188
- requiredScopes: ["organizations:read"]
71189
- },
71190
- {
71191
- name: "teams.get",
71192
- class: "read",
71193
- description: "Fetch a single team by id.",
71194
- parameters: {
71195
- type: "object",
71196
- properties: {
71197
- org_id: { type: "string" },
71198
- team_id: { type: "string" }
71199
- },
71200
- required: ["org_id", "team_id"]
71201
- },
71202
- request: { method: "GET", path: "/v2/orgs/{org_id}/teams/{team_id}" },
71203
- requiredScopes: ["team:read"]
71204
- },
71205
- {
71206
- name: "boards.create",
71207
- class: "mutation",
71208
- description: "Create a new Miro board. Accepts an optional name, description, team_id, and sharing policy. Returns the new board id used by every items.* endpoint.",
71209
- parameters: {
71210
- type: "object",
71211
- properties: {
71212
- name: { type: "string", maxLength: 60 },
71213
- description: { type: "string", maxLength: 300 },
71214
- team_id: { type: "string" },
71215
- policy: {
71216
- type: "object",
71217
- description: "Permissions + sharing policy. See https://developers.miro.com/reference/create-board for the full PolicyChange shape."
71218
- }
71219
- },
71220
- required: ["name"]
71221
- },
71222
- request: {
71223
- method: "POST",
71224
- path: "/v2/boards",
71225
- body: {
71226
- name: "{name}",
71227
- description: "{description}",
71228
- teamId: "{team_id}",
71229
- policy: "{policy}"
71230
- }
71231
- },
71232
- cas: "native-idempotency",
71233
- requiredScopes: ["boards:write"]
71234
- },
71235
- {
71236
- name: "boards.update",
71237
- class: "mutation",
71238
- description: "Update a Miro board (name, description, team, or sharing policy).",
71239
- parameters: {
71240
- type: "object",
71241
- properties: {
71242
- board_id: { type: "string" },
71243
- name: { type: "string", maxLength: 60 },
71244
- description: { type: "string", maxLength: 300 },
71245
- team_id: { type: "string" },
71246
- policy: { type: "object" }
71247
- },
71248
- required: ["board_id"]
71249
- },
71250
- request: {
71251
- method: "PATCH",
71252
- path: "/v2/boards/{board_id}",
71253
- body: {
71254
- name: "{name}",
71255
- description: "{description}",
71256
- teamId: "{team_id}",
71257
- policy: "{policy}"
71258
- }
71259
- },
71260
- cas: "native-idempotency",
71261
- requiredScopes: ["boards:write"]
71262
- },
71263
- {
71264
- name: "boards.delete",
71265
- class: "mutation",
71266
- description: "Delete a Miro board (irreversible).",
71267
- parameters: {
71268
- type: "object",
71269
- properties: { board_id: { type: "string" } },
71270
- required: ["board_id"]
71271
- },
71272
- request: { method: "DELETE", path: "/v2/boards/{board_id}" },
71273
- cas: "native-idempotency",
71274
- requiredScopes: ["boards:write"]
71275
- },
71276
- {
71277
- name: "sticky_notes.create",
71278
- class: "mutation",
71279
- description: "Create a sticky note on a board. `data.content` accepts plain text; `style.fillColor` is a Miro sticky-note color keyword (e.g. yellow, light_yellow, pink).",
71280
- parameters: {
71281
- type: "object",
71282
- properties: {
71283
- board_id: { type: "string" },
71284
- data: {
71285
- type: "object",
71286
- properties: {
71287
- content: { type: "string" },
71288
- shape: { type: "string", enum: ["square", "rectangle"] }
71289
- },
71290
- required: ["content"]
71291
- },
71292
- style: {
71293
- type: "object",
71294
- properties: {
71295
- fillColor: { type: "string" },
71296
- textAlign: { type: "string", enum: ["left", "center", "right"] },
71297
- textAlignVertical: { type: "string", enum: ["top", "middle", "bottom"] }
71298
- }
71299
- },
71300
- position: {
71301
- type: "object",
71302
- properties: {
71303
- x: { type: "number" },
71304
- y: { type: "number" },
71305
- origin: { type: "string", enum: ["center"] }
71306
- }
71307
- },
71308
- geometry: {
71309
- type: "object",
71310
- properties: {
71311
- width: { type: "number" },
71312
- height: { type: "number" }
71313
- }
71314
- },
71315
- parent: {
71316
- type: "object",
71317
- description: "Attach the sticky note to a frame: { id: <frame_item_id> }.",
71318
- properties: { id: { type: "string" } }
71319
- }
71320
- },
71321
- required: ["board_id", "data"]
71322
- },
71323
- request: {
71324
- method: "POST",
71325
- path: "/v2/boards/{board_id}/sticky_notes",
71326
- body: {
71327
- data: "{data}",
71328
- style: "{style}",
71329
- position: "{position}",
71330
- geometry: "{geometry}",
71331
- parent: "{parent}"
71332
- }
71333
- },
71334
- cas: "native-idempotency",
71335
- requiredScopes: ["boards:write"]
71336
- },
71337
- {
71338
- name: "sticky_notes.update",
71339
- class: "mutation",
71340
- description: "Update a sticky note (content, style, position, geometry, or parent frame).",
71341
- parameters: {
71342
- type: "object",
71343
- properties: {
71344
- board_id: { type: "string" },
71345
- item_id: { type: "string" },
71346
- data: { type: "object" },
71347
- style: { type: "object" },
71348
- position: { type: "object" },
71349
- geometry: { type: "object" },
71350
- parent: { type: "object" }
71351
- },
71352
- required: ["board_id", "item_id"]
71353
- },
71354
- request: {
71355
- method: "PATCH",
71356
- path: "/v2/boards/{board_id}/sticky_notes/{item_id}",
71357
- body: {
71358
- data: "{data}",
71359
- style: "{style}",
71360
- position: "{position}",
71361
- geometry: "{geometry}",
71362
- parent: "{parent}"
71363
- }
71364
- },
71365
- cas: "native-idempotency",
71366
- requiredScopes: ["boards:write"]
71367
- },
71368
- {
71369
- name: "text.create",
71370
- class: "mutation",
71371
- description: "Create a text item on a board.",
71372
- parameters: {
71373
- type: "object",
71374
- properties: {
71375
- board_id: { type: "string" },
71376
- data: {
71377
- type: "object",
71378
- properties: { content: { type: "string" } },
71379
- required: ["content"]
71380
- },
71381
- style: { type: "object" },
71382
- position: { type: "object" },
71383
- geometry: { type: "object" },
71384
- parent: { type: "object" }
71385
- },
71386
- required: ["board_id", "data"]
71387
- },
71388
- request: {
71389
- method: "POST",
71390
- path: "/v2/boards/{board_id}/texts",
71391
- body: {
71392
- data: "{data}",
71393
- style: "{style}",
71394
- position: "{position}",
71395
- geometry: "{geometry}",
71396
- parent: "{parent}"
71397
- }
71398
- },
71399
- cas: "native-idempotency",
71400
- requiredScopes: ["boards:write"]
71401
- },
71402
- {
71403
- name: "shapes.create",
71404
- class: "mutation",
71405
- description: "Create a shape item on a board. `data.shape` selects the geometric primitive (rectangle, round_rectangle, circle, triangle, rhombus, etc.).",
71406
- parameters: {
71407
- type: "object",
71408
- properties: {
71409
- board_id: { type: "string" },
71410
- data: {
71411
- type: "object",
71412
- properties: {
71413
- shape: {
71414
- type: "string",
71415
- description: "Miro shape kind; full enum at https://developers.miro.com/reference/create-shape-item."
71416
- },
71417
- content: { type: "string" }
71418
- },
71419
- required: ["shape"]
71420
- },
71421
- style: { type: "object" },
71422
- position: { type: "object" },
71423
- geometry: { type: "object" },
71424
- parent: { type: "object" }
71425
- },
71426
- required: ["board_id", "data"]
71427
- },
71428
- request: {
71429
- method: "POST",
71430
- path: "/v2/boards/{board_id}/shapes",
71431
- body: {
71432
- data: "{data}",
71433
- style: "{style}",
71434
- position: "{position}",
71435
- geometry: "{geometry}",
71436
- parent: "{parent}"
71437
- }
71438
- },
71439
- cas: "native-idempotency",
71440
- requiredScopes: ["boards:write"]
71441
- },
71442
- {
71443
- name: "cards.create",
71444
- class: "mutation",
71445
- description: "Create a card item (title + description + assignee + due-date) on a board.",
71446
- parameters: {
71447
- type: "object",
71448
- properties: {
71449
- board_id: { type: "string" },
71450
- data: {
71451
- type: "object",
71452
- properties: {
71453
- title: { type: "string" },
71454
- description: { type: "string" },
71455
- dueDate: { type: "string", format: "date-time" },
71456
- assigneeId: { type: "string" }
71457
- },
71458
- required: ["title"]
71459
- },
71460
- style: { type: "object" },
71461
- position: { type: "object" },
71462
- geometry: { type: "object" },
71463
- parent: { type: "object" }
71464
- },
71465
- required: ["board_id", "data"]
71466
- },
71467
- request: {
71468
- method: "POST",
71469
- path: "/v2/boards/{board_id}/cards",
71470
- body: {
71471
- data: "{data}",
71472
- style: "{style}",
71473
- position: "{position}",
71474
- geometry: "{geometry}",
71475
- parent: "{parent}"
71476
- }
71477
- },
71478
- cas: "native-idempotency",
71479
- requiredScopes: ["boards:write"]
71480
- },
71481
- {
71482
- name: "frames.create",
71483
- class: "mutation",
71484
- description: "Create a frame on a board. Frames group items; child items can be attached via `parent.id` on item creation.",
71485
- parameters: {
71486
- type: "object",
71487
- properties: {
71488
- board_id: { type: "string" },
71489
- data: {
71490
- type: "object",
71491
- properties: {
71492
- title: { type: "string" },
71493
- format: { type: "string", enum: ["custom"] },
71494
- type: { type: "string", enum: ["freeform"] }
71495
- }
71496
- },
71497
- style: { type: "object" },
71498
- position: { type: "object" },
71499
- geometry: { type: "object" }
71500
- },
71501
- required: ["board_id"]
71502
- },
71503
- request: {
71504
- method: "POST",
71505
- path: "/v2/boards/{board_id}/frames",
71506
- body: {
71507
- data: "{data}",
71508
- style: "{style}",
71509
- position: "{position}",
71510
- geometry: "{geometry}"
71511
- }
71512
- },
71513
- cas: "native-idempotency",
71514
- requiredScopes: ["boards:write"]
71515
- },
71516
- {
71517
- name: "images.create.by_url",
71518
- class: "mutation",
71519
- description: "Create an image item from a public URL (Miro fetches the image server-side).",
71520
- parameters: {
71521
- type: "object",
71522
- properties: {
71523
- board_id: { type: "string" },
71524
- data: {
71525
- type: "object",
71526
- properties: {
71527
- url: { type: "string", format: "uri" },
71528
- title: { type: "string" }
71529
- },
71530
- required: ["url"]
71531
- },
71532
- position: { type: "object" },
71533
- geometry: { type: "object" },
71534
- parent: { type: "object" }
71535
- },
71536
- required: ["board_id", "data"]
71537
- },
71538
- request: {
71539
- method: "POST",
71540
- path: "/v2/boards/{board_id}/images",
71541
- body: {
71542
- data: "{data}",
71543
- position: "{position}",
71544
- geometry: "{geometry}",
71545
- parent: "{parent}"
71546
- }
71547
- },
71548
- cas: "native-idempotency",
71549
- requiredScopes: ["boards:write"]
71550
- },
71551
- {
71552
- name: "connectors.create",
71553
- class: "mutation",
71554
- description: "Create a connector line between two items on the board. `startItem.id` and `endItem.id` reference existing item ids.",
71555
- parameters: {
71556
- type: "object",
71557
- properties: {
71558
- board_id: { type: "string" },
71559
- startItem: {
71560
- type: "object",
71561
- properties: { id: { type: "string" } },
71562
- required: ["id"]
71563
- },
71564
- endItem: {
71565
- type: "object",
71566
- properties: { id: { type: "string" } },
71567
- required: ["id"]
71568
- },
71569
- captions: {
71570
- type: "array",
71571
- items: { type: "object", properties: { content: { type: "string" } } }
71572
- },
71573
- style: { type: "object" },
71574
- shape: { type: "string", enum: ["straight", "elbowed", "curved"] }
71575
- },
71576
- required: ["board_id", "startItem", "endItem"]
71577
- },
71578
- request: {
71579
- method: "POST",
71580
- path: "/v2/boards/{board_id}/connectors",
71581
- body: {
71582
- startItem: "{startItem}",
71583
- endItem: "{endItem}",
71584
- captions: "{captions}",
71585
- style: "{style}",
71586
- shape: "{shape}"
71587
- }
71588
- },
71589
- cas: "native-idempotency",
71590
- requiredScopes: ["boards:write"]
71591
- },
71592
- {
71593
- name: "items.delete",
71594
- class: "mutation",
71595
- description: "Delete an item from a board (works across all item types).",
71596
- parameters: {
71597
- type: "object",
71598
- properties: {
71599
- board_id: { type: "string" },
71600
- item_id: { type: "string" }
71601
- },
71602
- required: ["board_id", "item_id"]
71603
- },
71604
- request: { method: "DELETE", path: "/v2/boards/{board_id}/items/{item_id}" },
71605
- cas: "native-idempotency",
71606
- requiredScopes: ["boards:write"]
71607
- },
71608
- {
71609
- name: "boards.share",
71610
- class: "mutation",
71611
- description: "Invite users to a Miro board by email. Roles: viewer, commenter, editor, coowner.",
71612
- parameters: {
71613
- type: "object",
71614
- properties: {
71615
- board_id: { type: "string" },
71616
- emails: { type: "array", items: { type: "string", format: "email" } },
71617
- role: {
71618
- type: "string",
71619
- enum: ["viewer", "commenter", "editor", "coowner"]
71620
- },
71621
- message: { type: "string" }
71622
- },
71623
- required: ["board_id", "emails", "role"]
71624
- },
71625
- request: {
71626
- method: "POST",
71627
- path: "/v2/boards/{board_id}/members",
71628
- body: {
71629
- emails: "{emails}",
71630
- role: "{role}",
71631
- message: "{message}"
71632
- }
71633
- },
71634
- cas: "native-idempotency",
71635
- requiredScopes: ["boards:write"]
71636
- }
71637
- ]
71638
- });
71639
-
71640
73959
  // src/connectors/adapters/canva.ts
71641
73960
  var canvaConnector = declarativeRestConnector({
71642
73961
  kind: "canva",
@@ -119253,309 +121572,6 @@ var mindStudioConnector = declarativeRestConnector({
119253
121572
  ]
119254
121573
  });
119255
121574
 
119256
- // src/connectors/adapters/mongodb.ts
119257
- var mongodbConnector = declarativeRestConnector({
119258
- kind: "mongodb",
119259
- displayName: "MongoDB",
119260
- description: "Query, insert, update, and delete MongoDB documents via the Data API.",
119261
- auth: { kind: "api-key", hint: "MongoDB Data API key." },
119262
- category: "database",
119263
- defaultConsistencyModel: "authoritative",
119264
- baseUrl: "https://data.mongodb-api.com/app",
119265
- test: { method: "POST", path: "/{appId}/endpoint/data/v1/action/findOne" },
119266
- capabilities: [
119267
- {
119268
- name: "documents.find",
119269
- class: "read",
119270
- description: "Query documents in a collection.",
119271
- parameters: {
119272
- type: "object",
119273
- properties: {
119274
- appId: { type: "string", description: "MongoDB Data API application ID." },
119275
- dataSourceName: { type: "string", description: 'Data source name (e.g., "Cluster0").' },
119276
- databaseName: { type: "string", description: "Database name." },
119277
- collectionName: { type: "string", description: "Collection name." },
119278
- filter: { type: "object", description: 'Query filter (e.g., { "status": "active" }).' },
119279
- projection: { type: "object", description: "Fields to include/exclude." },
119280
- sort: { type: "object", description: "Sort criteria." },
119281
- limit: { type: "integer", description: "Maximum documents to return." },
119282
- skip: { type: "integer", description: "Documents to skip." }
119283
- },
119284
- required: ["appId", "dataSourceName", "databaseName", "collectionName"]
119285
- },
119286
- request: {
119287
- method: "POST",
119288
- path: "/{appId}/endpoint/data/v1/action/find",
119289
- body: {
119290
- dataSource: "{dataSourceName}",
119291
- database: "{databaseName}",
119292
- collection: "{collectionName}",
119293
- filter: "{filter}",
119294
- projection: "{projection}",
119295
- sort: "{sort}",
119296
- limit: "{limit}",
119297
- skip: "{skip}"
119298
- }
119299
- }
119300
- },
119301
- {
119302
- name: "documents.findOne",
119303
- class: "read",
119304
- description: "Find a single document matching a filter.",
119305
- parameters: {
119306
- type: "object",
119307
- properties: {
119308
- appId: { type: "string", description: "MongoDB Data API application ID." },
119309
- dataSourceName: { type: "string", description: "Data source name." },
119310
- databaseName: { type: "string", description: "Database name." },
119311
- collectionName: { type: "string", description: "Collection name." },
119312
- filter: { type: "object", description: "Query filter." },
119313
- projection: { type: "object", description: "Fields to include/exclude." }
119314
- },
119315
- required: ["appId", "dataSourceName", "databaseName", "collectionName"]
119316
- },
119317
- request: {
119318
- method: "POST",
119319
- path: "/{appId}/endpoint/data/v1/action/findOne",
119320
- body: {
119321
- dataSource: "{dataSourceName}",
119322
- database: "{databaseName}",
119323
- collection: "{collectionName}",
119324
- filter: "{filter}",
119325
- projection: "{projection}"
119326
- }
119327
- }
119328
- },
119329
- {
119330
- name: "documents.insertOne",
119331
- class: "mutation",
119332
- description: "Insert a single document into a collection.",
119333
- parameters: {
119334
- type: "object",
119335
- properties: {
119336
- appId: { type: "string", description: "MongoDB Data API application ID." },
119337
- dataSourceName: { type: "string", description: "Data source name." },
119338
- databaseName: { type: "string", description: "Database name." },
119339
- collectionName: { type: "string", description: "Collection name." },
119340
- document: { type: "object", description: "Document to insert." }
119341
- },
119342
- required: ["appId", "dataSourceName", "databaseName", "collectionName", "document"]
119343
- },
119344
- request: {
119345
- method: "POST",
119346
- path: "/{appId}/endpoint/data/v1/action/insertOne",
119347
- body: {
119348
- dataSource: "{dataSourceName}",
119349
- database: "{databaseName}",
119350
- collection: "{collectionName}",
119351
- document: "{document}"
119352
- }
119353
- },
119354
- cas: "native-idempotency"
119355
- },
119356
- {
119357
- name: "documents.insertMany",
119358
- class: "mutation",
119359
- description: "Insert multiple documents into a collection.",
119360
- parameters: {
119361
- type: "object",
119362
- properties: {
119363
- appId: { type: "string", description: "MongoDB Data API application ID." },
119364
- dataSourceName: { type: "string", description: "Data source name." },
119365
- databaseName: { type: "string", description: "Database name." },
119366
- collectionName: { type: "string", description: "Collection name." },
119367
- documents: { type: "array", items: { type: "object" }, description: "Array of documents to insert." }
119368
- },
119369
- required: ["appId", "dataSourceName", "databaseName", "collectionName", "documents"]
119370
- },
119371
- request: {
119372
- method: "POST",
119373
- path: "/{appId}/endpoint/data/v1/action/insertMany",
119374
- body: {
119375
- dataSource: "{dataSourceName}",
119376
- database: "{databaseName}",
119377
- collection: "{collectionName}",
119378
- documents: "{documents}"
119379
- }
119380
- },
119381
- cas: "native-idempotency"
119382
- },
119383
- {
119384
- name: "documents.updateOne",
119385
- class: "mutation",
119386
- description: "Update a single document matching a filter.",
119387
- parameters: {
119388
- type: "object",
119389
- properties: {
119390
- appId: { type: "string", description: "MongoDB Data API application ID." },
119391
- dataSourceName: { type: "string", description: "Data source name." },
119392
- databaseName: { type: "string", description: "Database name." },
119393
- collectionName: { type: "string", description: "Collection name." },
119394
- filter: { type: "object", description: "Query filter." },
119395
- update: { type: "object", description: 'Update operations (e.g., { "$set": { "status": "inactive" } }).' },
119396
- upsert: { type: "boolean", description: "Insert if no match found." }
119397
- },
119398
- required: ["appId", "dataSourceName", "databaseName", "collectionName", "filter", "update"]
119399
- },
119400
- request: {
119401
- method: "POST",
119402
- path: "/{appId}/endpoint/data/v1/action/updateOne",
119403
- body: {
119404
- dataSource: "{dataSourceName}",
119405
- database: "{databaseName}",
119406
- collection: "{collectionName}",
119407
- filter: "{filter}",
119408
- update: "{update}",
119409
- upsert: "{upsert}"
119410
- }
119411
- },
119412
- cas: "optimistic-read-verify"
119413
- },
119414
- {
119415
- name: "documents.updateMany",
119416
- class: "mutation",
119417
- description: "Update multiple documents matching a filter.",
119418
- parameters: {
119419
- type: "object",
119420
- properties: {
119421
- appId: { type: "string", description: "MongoDB Data API application ID." },
119422
- dataSourceName: { type: "string", description: "Data source name." },
119423
- databaseName: { type: "string", description: "Database name." },
119424
- collectionName: { type: "string", description: "Collection name." },
119425
- filter: { type: "object", description: "Query filter." },
119426
- update: { type: "object", description: "Update operations." },
119427
- upsert: { type: "boolean", description: "Insert if no match found." }
119428
- },
119429
- required: ["appId", "dataSourceName", "databaseName", "collectionName", "filter", "update"]
119430
- },
119431
- request: {
119432
- method: "POST",
119433
- path: "/{appId}/endpoint/data/v1/action/updateMany",
119434
- body: {
119435
- dataSource: "{dataSourceName}",
119436
- database: "{databaseName}",
119437
- collection: "{collectionName}",
119438
- filter: "{filter}",
119439
- update: "{update}",
119440
- upsert: "{upsert}"
119441
- }
119442
- },
119443
- cas: "optimistic-read-verify"
119444
- },
119445
- {
119446
- name: "documents.replaceOne",
119447
- class: "mutation",
119448
- description: "Replace a single document entirely.",
119449
- parameters: {
119450
- type: "object",
119451
- properties: {
119452
- appId: { type: "string", description: "MongoDB Data API application ID." },
119453
- dataSourceName: { type: "string", description: "Data source name." },
119454
- databaseName: { type: "string", description: "Database name." },
119455
- collectionName: { type: "string", description: "Collection name." },
119456
- filter: { type: "object", description: "Query filter." },
119457
- replacement: { type: "object", description: "Replacement document." },
119458
- upsert: { type: "boolean", description: "Insert if no match found." }
119459
- },
119460
- required: ["appId", "dataSourceName", "databaseName", "collectionName", "filter", "replacement"]
119461
- },
119462
- request: {
119463
- method: "POST",
119464
- path: "/{appId}/endpoint/data/v1/action/replaceOne",
119465
- body: {
119466
- dataSource: "{dataSourceName}",
119467
- database: "{databaseName}",
119468
- collection: "{collectionName}",
119469
- filter: "{filter}",
119470
- replacement: "{replacement}",
119471
- upsert: "{upsert}"
119472
- }
119473
- },
119474
- cas: "etag-if-match"
119475
- },
119476
- {
119477
- name: "documents.deleteOne",
119478
- class: "mutation",
119479
- description: "Delete a single document matching a filter.",
119480
- parameters: {
119481
- type: "object",
119482
- properties: {
119483
- appId: { type: "string", description: "MongoDB Data API application ID." },
119484
- dataSourceName: { type: "string", description: "Data source name." },
119485
- databaseName: { type: "string", description: "Database name." },
119486
- collectionName: { type: "string", description: "Collection name." },
119487
- filter: { type: "object", description: "Query filter." }
119488
- },
119489
- required: ["appId", "dataSourceName", "databaseName", "collectionName", "filter"]
119490
- },
119491
- request: {
119492
- method: "POST",
119493
- path: "/{appId}/endpoint/data/v1/action/deleteOne",
119494
- body: {
119495
- dataSource: "{dataSourceName}",
119496
- database: "{databaseName}",
119497
- collection: "{collectionName}",
119498
- filter: "{filter}"
119499
- }
119500
- },
119501
- cas: "native-idempotency"
119502
- },
119503
- {
119504
- name: "documents.deleteMany",
119505
- class: "mutation",
119506
- description: "Delete multiple documents matching a filter.",
119507
- parameters: {
119508
- type: "object",
119509
- properties: {
119510
- appId: { type: "string", description: "MongoDB Data API application ID." },
119511
- dataSourceName: { type: "string", description: "Data source name." },
119512
- databaseName: { type: "string", description: "Database name." },
119513
- collectionName: { type: "string", description: "Collection name." },
119514
- filter: { type: "object", description: "Query filter." }
119515
- },
119516
- required: ["appId", "dataSourceName", "databaseName", "collectionName", "filter"]
119517
- },
119518
- request: {
119519
- method: "POST",
119520
- path: "/{appId}/endpoint/data/v1/action/deleteMany",
119521
- body: {
119522
- dataSource: "{dataSourceName}",
119523
- database: "{databaseName}",
119524
- collection: "{collectionName}",
119525
- filter: "{filter}"
119526
- }
119527
- },
119528
- cas: "native-idempotency"
119529
- },
119530
- {
119531
- name: "documents.aggregate",
119532
- class: "read",
119533
- description: "Run an aggregation pipeline over a collection.",
119534
- parameters: {
119535
- type: "object",
119536
- properties: {
119537
- appId: { type: "string", description: "MongoDB Data API application ID." },
119538
- dataSourceName: { type: "string", description: "Data source name." },
119539
- databaseName: { type: "string", description: "Database name." },
119540
- collectionName: { type: "string", description: "Collection name." },
119541
- pipeline: { type: "array", items: { type: "object" }, description: "Aggregation stages." }
119542
- },
119543
- required: ["appId", "dataSourceName", "databaseName", "collectionName", "pipeline"]
119544
- },
119545
- request: {
119546
- method: "POST",
119547
- path: "/{appId}/endpoint/data/v1/action/aggregate",
119548
- body: {
119549
- dataSource: "{dataSourceName}",
119550
- database: "{databaseName}",
119551
- collection: "{collectionName}",
119552
- pipeline: "{pipeline}"
119553
- }
119554
- }
119555
- }
119556
- ]
119557
- });
119558
-
119559
121575
  // src/connectors/adapters/nifty.ts
119560
121576
  var niftyConnector = declarativeRestConnector({
119561
121577
  kind: "nifty",
@@ -124137,45 +126153,6 @@ var pollybotAiConnector = declarativeRestConnector({
124137
126153
  ]
124138
126154
  });
124139
126155
 
124140
- // src/connectors/adapters/postgres.ts
124141
- var postgresConnector = declarativeRestConnector({
124142
- kind: "postgres",
124143
- displayName: "PostgreSQL",
124144
- description: "Execute queries and monitor PostgreSQL databases.",
124145
- auth: { kind: "api-key", hint: "PostgreSQL connection credentials." },
124146
- category: "database",
124147
- defaultConsistencyModel: "authoritative",
124148
- baseUrl: "postgresql://",
124149
- test: { method: "GET", path: "/" },
124150
- capabilities: [
124151
- {
124152
- name: "query.execute",
124153
- class: "read",
124154
- description: "Execute a SQL query against the database.",
124155
- parameters: {
124156
- type: "object",
124157
- properties: {
124158
- host: { type: "string", description: "PostgreSQL server hostname" },
124159
- port: { type: "integer", description: "PostgreSQL server port" },
124160
- user: { type: "string", description: "Database user" },
124161
- password: { type: "string", description: "Database password" },
124162
- database: { type: "string", description: "Database name" },
124163
- query: { type: "string", description: "SQL query to execute" },
124164
- args: { type: "array", description: "Query arguments for parameterized queries" },
124165
- query_timeout: { type: "integer", description: "Query timeout in milliseconds" },
124166
- connection_timeout_ms: { type: "integer", description: "Connection timeout in milliseconds" },
124167
- application_name: { type: "string", description: "Application name for the connection" },
124168
- enable_ssl: { type: "boolean", description: "Enable SSL connection" },
124169
- reject_unauthorized: { type: "boolean", description: "Verify server certificate" },
124170
- certificate: { type: "string", description: "CA certificate for SSL verification" }
124171
- },
124172
- required: ["host", "port", "user", "password", "database", "query"]
124173
- },
124174
- request: { method: "POST", path: "/query", body: "{query}" }
124175
- }
124176
- ]
124177
- });
124178
-
124179
126156
  // src/connectors/adapters/postiz.ts
124180
126157
  var postizConnector = declarativeRestConnector({
124181
126158
  kind: "postiz",
@@ -144139,6 +146116,7 @@ export {
144139
146116
  deepgramConnector,
144140
146117
  detectingAiConnector,
144141
146118
  digitalPilotConnector,
146119
+ duckdbConnector,
144142
146120
  docsbotConnector,
144143
146121
  dripConnector,
144144
146122
  echowinConnector,
@@ -144269,7 +146247,10 @@ export {
144269
146247
  mastodonConnector,
144270
146248
  meetgeekAiConnector,
144271
146249
  mollieConnector,
146250
+ miroConnector,
144272
146251
  mondayConnector,
146252
+ createMongoDbConnector,
146253
+ mongodbConnector,
144273
146254
  mycaseConnector,
144274
146255
  notionConnector,
144275
146256
  notion,
@@ -144287,6 +146268,14 @@ export {
144287
146268
  pipedriveConnector,
144288
146269
  parquetFilesConnector,
144289
146270
  quickbooksConnector,
146271
+ createRabbitMqConnector,
146272
+ rabbitMqConnector,
146273
+ createRedisConnector,
146274
+ redisConnector,
146275
+ createRedshiftConnector,
146276
+ redshiftConnector,
146277
+ createPostgresConnector,
146278
+ postgresConnector,
144290
146279
  recallAiConnector,
144291
146280
  rampConnector,
144292
146281
  ringcentralConnector,
@@ -144354,11 +146343,14 @@ export {
144354
146343
  googleBigqueryConnector,
144355
146344
  hightouchConnector,
144356
146345
  metabaseConnector,
146346
+ createMySqlConnector,
146347
+ mysqlConnector,
144357
146348
  segmentConnector,
144358
146349
  supabaseConnector,
144359
146350
  builtwithConnector,
144360
146351
  fullenrichConnector,
144361
146352
  hunterConnector,
146353
+ neverbounceConnector,
144362
146354
  theirstackConnector,
144363
146355
  zerobounceConnector,
144364
146356
  CONNECTOR_ADAPTER_FACTORIES,
@@ -144384,7 +146376,6 @@ export {
144384
146376
  sanityConnector,
144385
146377
  figmaConnector,
144386
146378
  figjamConnector,
144387
- miroConnector,
144388
146379
  canvaConnector,
144389
146380
  adobeCreativeCloudConnector,
144390
146381
  clioConnector,
@@ -144604,7 +146595,6 @@ export {
144604
146595
  mailchainConnector,
144605
146596
  medullarConnector,
144606
146597
  mindStudioConnector,
144607
- mongodbConnector,
144608
146598
  niftyConnector,
144609
146599
  nocodbConnector,
144610
146600
  ntfyConnector,
@@ -144630,7 +146620,6 @@ export {
144630
146620
  plausibleConnector,
144631
146621
  pocketbaseConnector,
144632
146622
  pollybotAiConnector,
144633
- postgresConnector,
144634
146623
  postizConnector,
144635
146624
  posthogConnector,
144636
146625
  predictLeadsConnector,
@@ -144745,4 +146734,4 @@ export {
144745
146734
  demandbaseConnector,
144746
146735
  adapters_exports
144747
146736
  };
144748
- //# sourceMappingURL=chunk-5LDZLVKP.js.map
146737
+ //# sourceMappingURL=chunk-R5GQB3SQ.js.map