@squadbase/connectors 0.1.1 → 0.1.2-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5,8 +5,11 @@ import {
5
5
  parameters3,
6
6
  parameters4,
7
7
  parameters5,
8
- parameters6
9
- } from "./chunk-4K4NERCT.js";
8
+ parameters6,
9
+ parameters7,
10
+ parameters8,
11
+ parameters9
12
+ } from "./chunk-LB7J6VXK.js";
10
13
 
11
14
  // src/connector-setup.ts
12
15
  var ConnectorSetup = class {
@@ -232,7 +235,7 @@ Follow these steps to set up the Snowflake connection.
232
235
  });
233
236
 
234
237
  // src/connectors/snowflake/parameters.ts
235
- var parameters7 = {
238
+ var parameters10 = {
236
239
  account: new ParameterDefinition({
237
240
  slug: "account",
238
241
  name: "Snowflake Account",
@@ -348,15 +351,15 @@ Avoid loading large amounts of data; always include LIMIT in queries.`,
348
351
  try {
349
352
  const snowflake = (await import("snowflake-sdk")).default;
350
353
  snowflake.configure({ logLevel: "ERROR" });
351
- const account = parameters7.account.getValue(connection);
352
- const user = parameters7.user.getValue(connection);
353
- const role = parameters7.role.getValue(connection);
354
- const warehouse = parameters7.warehouse.getValue(connection);
355
- const privateKeyBase64 = parameters7.privateKeyBase64.getValue(connection);
354
+ const account = parameters10.account.getValue(connection);
355
+ const user = parameters10.user.getValue(connection);
356
+ const role = parameters10.role.getValue(connection);
357
+ const warehouse = parameters10.warehouse.getValue(connection);
358
+ const privateKeyBase64 = parameters10.privateKeyBase64.getValue(connection);
356
359
  const privateKeyPem = Buffer.from(privateKeyBase64, "base64").toString(
357
360
  "utf-8"
358
361
  );
359
- const privateKeyPass = parameters7.privateKeyPassphrase.tryGetValue(connection);
362
+ const privateKeyPass = parameters10.privateKeyPassphrase.tryGetValue(connection);
360
363
  const privateKey = decryptPrivateKey(privateKeyPem, privateKeyPass ?? void 0);
361
364
  const conn = snowflake.createConnection({
362
365
  account,
@@ -421,7 +424,7 @@ var snowflakeConnector = new ConnectorPlugin({
421
424
  name: "Snowflake",
422
425
  description: "Connect to Snowflake for cloud data warehousing and analytics.",
423
426
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/6oyVtAcP3pMlXaOrts9unk/b7a9dc25d15c388b66e983041b855447/snowflake.svg",
424
- parameters: parameters7,
427
+ parameters: parameters10,
425
428
  releaseFlag: { dev1: true, dev2: true, prod: true },
426
429
  setup: snowflakeSetup,
427
430
  systemPrompt: `## Snowflake SQL Notes
@@ -438,16 +441,16 @@ var snowflakeConnector = new ConnectorPlugin({
438
441
  const snowflake = (await import("snowflake-sdk")).default;
439
442
  snowflake.configure({ logLevel: "ERROR" });
440
443
  const privateKeyPem = Buffer.from(
441
- params[parameters7.privateKeyBase64.slug],
444
+ params[parameters10.privateKeyBase64.slug],
442
445
  "base64"
443
446
  ).toString("utf-8");
444
- const privateKeyPass = params[parameters7.privateKeyPassphrase.slug] || void 0;
447
+ const privateKeyPass = params[parameters10.privateKeyPassphrase.slug] || void 0;
445
448
  const privateKey = decryptPrivateKey(privateKeyPem, privateKeyPass);
446
449
  const conn = snowflake.createConnection({
447
- account: params[parameters7.account.slug],
448
- username: params[parameters7.user.slug],
449
- role: params[parameters7.role.slug],
450
- warehouse: params[parameters7.warehouse.slug],
450
+ account: params[parameters10.account.slug],
451
+ username: params[parameters10.user.slug],
452
+ role: params[parameters10.role.slug],
453
+ warehouse: params[parameters10.warehouse.slug],
451
454
  authenticator: "SNOWFLAKE_JWT",
452
455
  privateKey
453
456
  });
@@ -479,16 +482,16 @@ var snowflakeConnector = new ConnectorPlugin({
479
482
  const snowflake = (await import("snowflake-sdk")).default;
480
483
  snowflake.configure({ logLevel: "ERROR" });
481
484
  const privateKeyPem = Buffer.from(
482
- params[parameters7.privateKeyBase64.slug],
485
+ params[parameters10.privateKeyBase64.slug],
483
486
  "base64"
484
487
  ).toString("utf-8");
485
- const privateKeyPass = params[parameters7.privateKeyPassphrase.slug] || void 0;
488
+ const privateKeyPass = params[parameters10.privateKeyPassphrase.slug] || void 0;
486
489
  const privateKey = decryptPrivateKey(privateKeyPem, privateKeyPass);
487
490
  const conn = snowflake.createConnection({
488
- account: params[parameters7.account.slug],
489
- username: params[parameters7.user.slug],
490
- role: params[parameters7.role.slug],
491
- warehouse: params[parameters7.warehouse.slug],
491
+ account: params[parameters10.account.slug],
492
+ username: params[parameters10.user.slug],
493
+ role: params[parameters10.role.slug],
494
+ warehouse: params[parameters10.warehouse.slug],
492
495
  authenticator: "SNOWFLAKE_JWT",
493
496
  privateKey
494
497
  });
@@ -517,7 +520,7 @@ var snowflakeConnector = new ConnectorPlugin({
517
520
  });
518
521
 
519
522
  // src/connectors/snowflake-pat/parameters.ts
520
- var parameters8 = {
523
+ var parameters11 = {
521
524
  account: new ParameterDefinition({
522
525
  slug: "account",
523
526
  name: "Snowflake Account",
@@ -611,11 +614,11 @@ Avoid loading large amounts of data; always include LIMIT in queries.`,
611
614
  try {
612
615
  const snowflake = (await import("snowflake-sdk")).default;
613
616
  snowflake.configure({ logLevel: "ERROR" });
614
- const account = parameters8.account.getValue(connection);
615
- const user = parameters8.user.getValue(connection);
616
- const role = parameters8.role.getValue(connection);
617
- const warehouse = parameters8.warehouse.getValue(connection);
618
- const password = parameters8.pat.getValue(connection);
617
+ const account = parameters11.account.getValue(connection);
618
+ const user = parameters11.user.getValue(connection);
619
+ const role = parameters11.role.getValue(connection);
620
+ const warehouse = parameters11.warehouse.getValue(connection);
621
+ const password = parameters11.pat.getValue(connection);
619
622
  const conn = snowflake.createConnection({
620
623
  account,
621
624
  username: user,
@@ -678,7 +681,7 @@ var snowflakePatConnector = new ConnectorPlugin({
678
681
  name: "Snowflake (PAT)",
679
682
  description: "Connect to Snowflake using a Personal Access Token (PAT).",
680
683
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/6oyVtAcP3pMlXaOrts9unk/b7a9dc25d15c388b66e983041b855447/snowflake.svg",
681
- parameters: parameters8,
684
+ parameters: parameters11,
682
685
  releaseFlag: { dev1: true, dev2: true, prod: true },
683
686
  setup: snowflakeSetup,
684
687
  systemPrompt: `## Snowflake SQL Notes
@@ -695,11 +698,11 @@ var snowflakePatConnector = new ConnectorPlugin({
695
698
  const snowflake = (await import("snowflake-sdk")).default;
696
699
  snowflake.configure({ logLevel: "ERROR" });
697
700
  const conn = snowflake.createConnection({
698
- account: params[parameters8.account.slug],
699
- username: params[parameters8.user.slug],
700
- role: params[parameters8.role.slug],
701
- warehouse: params[parameters8.warehouse.slug],
702
- password: params[parameters8.pat.slug]
701
+ account: params[parameters11.account.slug],
702
+ username: params[parameters11.user.slug],
703
+ role: params[parameters11.role.slug],
704
+ warehouse: params[parameters11.warehouse.slug],
705
+ password: params[parameters11.pat.slug]
703
706
  });
704
707
  await new Promise((resolve, reject) => {
705
708
  conn.connect((err) => {
@@ -734,11 +737,11 @@ var snowflakePatConnector = new ConnectorPlugin({
734
737
  const snowflake = (await import("snowflake-sdk")).default;
735
738
  snowflake.configure({ logLevel: "ERROR" });
736
739
  const conn = snowflake.createConnection({
737
- account: params[parameters8.account.slug],
738
- username: params[parameters8.user.slug],
739
- role: params[parameters8.role.slug],
740
- warehouse: params[parameters8.warehouse.slug],
741
- password: params[parameters8.pat.slug]
740
+ account: params[parameters11.account.slug],
741
+ username: params[parameters11.user.slug],
742
+ role: params[parameters11.role.slug],
743
+ warehouse: params[parameters11.warehouse.slug],
744
+ password: params[parameters11.pat.slug]
742
745
  });
743
746
  await new Promise((resolve, reject) => {
744
747
  conn.connect((err) => {
@@ -770,7 +773,7 @@ var snowflakePatConnector = new ConnectorPlugin({
770
773
  });
771
774
 
772
775
  // src/connectors/postgresql/parameters.ts
773
- var parameters9 = {
776
+ var parameters12 = {
774
777
  connectionUrl: new ParameterDefinition({
775
778
  slug: "connection-url",
776
779
  name: "PostgreSQL Connection URL",
@@ -827,7 +830,7 @@ Avoid loading large amounts of data; always include LIMIT in queries.`,
827
830
  let connectionUrl;
828
831
  try {
829
832
  const { Pool } = await import("pg");
830
- connectionUrl = parameters9.connectionUrl.getValue(connection);
833
+ connectionUrl = parameters12.connectionUrl.getValue(connection);
831
834
  const pool = new Pool({
832
835
  connectionString: connectionUrl,
833
836
  ssl: { rejectUnauthorized: false },
@@ -865,7 +868,7 @@ var postgresqlConnector = new ConnectorPlugin({
865
868
  name: "PostgreSQL",
866
869
  description: "Connect to PostgreSQL databases for relational data storage and querying.",
867
870
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/42AHi2uqteUn65MyqdN6V7/a0f68f12af6aac96bbcda5980f43de07/elephant.png",
868
- parameters: parameters9,
871
+ parameters: parameters12,
869
872
  releaseFlag: { dev1: true, dev2: true, prod: true },
870
873
  systemPrompt: `## PostgreSQL SQL Notes
871
874
  - Schema exploration:
@@ -876,7 +879,7 @@ var postgresqlConnector = new ConnectorPlugin({
876
879
  async checkConnection(params, _config) {
877
880
  const { Pool } = await import("pg");
878
881
  const pool = new Pool({
879
- connectionString: params[parameters9.connectionUrl.slug],
882
+ connectionString: params[parameters12.connectionUrl.slug],
880
883
  ssl: { rejectUnauthorized: false },
881
884
  connectionTimeoutMillis: 1e4
882
885
  });
@@ -893,7 +896,7 @@ var postgresqlConnector = new ConnectorPlugin({
893
896
  const { Pool } = await import("pg");
894
897
  const { text, values } = buildPositionalParams(sql, namedParams);
895
898
  const pool = new Pool({
896
- connectionString: params[parameters9.connectionUrl.slug],
899
+ connectionString: params[parameters12.connectionUrl.slug],
897
900
  ssl: { rejectUnauthorized: false },
898
901
  connectionTimeoutMillis: 1e4,
899
902
  statement_timeout: 6e4
@@ -908,7 +911,7 @@ var postgresqlConnector = new ConnectorPlugin({
908
911
  });
909
912
 
910
913
  // src/connectors/mysql/parameters.ts
911
- var parameters10 = {
914
+ var parameters13 = {
912
915
  connectionUrl: new ParameterDefinition({
913
916
  slug: "connection-url",
914
917
  name: "MySQL Connection URL",
@@ -965,7 +968,7 @@ Avoid loading large amounts of data; always include LIMIT in queries.`,
965
968
  let connectionUrl;
966
969
  try {
967
970
  const mysql = await import("mysql2/promise");
968
- connectionUrl = parameters10.connectionUrl.getValue(connection);
971
+ connectionUrl = parameters13.connectionUrl.getValue(connection);
969
972
  const pool = mysql.createPool({
970
973
  uri: connectionUrl,
971
974
  connectTimeout: CONNECT_TIMEOUT_MS2
@@ -1005,7 +1008,7 @@ var mysqlConnector = new ConnectorPlugin({
1005
1008
  name: "MySQL",
1006
1009
  description: "Connect to MySQL databases for relational data storage and querying.",
1007
1010
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/6ghPFeGgl7uBs5NHH1a4L/512c9433beec5b595caa41f04921c1f9/logo-mysql-170x115.png",
1008
- parameters: parameters10,
1011
+ parameters: parameters13,
1009
1012
  releaseFlag: { dev1: true, dev2: true, prod: true },
1010
1013
  systemPrompt: `## MySQL SQL Notes
1011
1014
  - Schema exploration:
@@ -1016,7 +1019,7 @@ var mysqlConnector = new ConnectorPlugin({
1016
1019
  async checkConnection(params, _config) {
1017
1020
  const mysql = await import("mysql2/promise");
1018
1021
  const pool = mysql.createPool({
1019
- uri: params[parameters10.connectionUrl.slug],
1022
+ uri: params[parameters13.connectionUrl.slug],
1020
1023
  connectTimeout: 1e4
1021
1024
  });
1022
1025
  try {
@@ -1032,7 +1035,7 @@ var mysqlConnector = new ConnectorPlugin({
1032
1035
  const mysql = await import("mysql2/promise");
1033
1036
  const { text, values } = buildQuestionmarkParams(sql, namedParams);
1034
1037
  const pool = mysql.createPool({
1035
- uri: params[parameters10.connectionUrl.slug],
1038
+ uri: params[parameters13.connectionUrl.slug],
1036
1039
  connectTimeout: 1e4
1037
1040
  });
1038
1041
  try {
@@ -1053,7 +1056,7 @@ var mysqlConnector = new ConnectorPlugin({
1053
1056
  import { z as z5 } from "zod";
1054
1057
 
1055
1058
  // src/connectors/bigquery/parameters.ts
1056
- var parameters11 = {
1059
+ var parameters14 = {
1057
1060
  serviceAccountKeyJsonBase64: new ParameterDefinition({
1058
1061
  slug: "service-account-key-json-base64",
1059
1062
  name: "Google Cloud Service Account JSON",
@@ -1110,7 +1113,7 @@ var listProjectsTool = new ConnectorTool({
1110
1113
  };
1111
1114
  }
1112
1115
  try {
1113
- const serviceAccountJsonBase64 = parameters11.serviceAccountKeyJsonBase64.getValue(connection);
1116
+ const serviceAccountJsonBase64 = parameters14.serviceAccountKeyJsonBase64.getValue(connection);
1114
1117
  const credentials = JSON.parse(
1115
1118
  Buffer.from(serviceAccountJsonBase64, "base64").toString("utf-8")
1116
1119
  );
@@ -1174,8 +1177,8 @@ var listDatasetsTool = new ConnectorTool({
1174
1177
  }
1175
1178
  try {
1176
1179
  const { BigQuery } = await import("@google-cloud/bigquery");
1177
- const projectId = parameters11.projectId.getValue(connection);
1178
- const serviceAccountJsonBase64 = parameters11.serviceAccountKeyJsonBase64.getValue(connection);
1180
+ const projectId = parameters14.projectId.getValue(connection);
1181
+ const serviceAccountJsonBase64 = parameters14.serviceAccountKeyJsonBase64.getValue(connection);
1179
1182
  const credentials = JSON.parse(
1180
1183
  Buffer.from(serviceAccountJsonBase64, "base64").toString("utf-8")
1181
1184
  );
@@ -1336,8 +1339,8 @@ Avoid loading large amounts of data; always include LIMIT in queries.`,
1336
1339
  );
1337
1340
  try {
1338
1341
  const { BigQuery } = await import("@google-cloud/bigquery");
1339
- const projectId = parameters11.projectId.getValue(connection);
1340
- const serviceAccountJsonBase64 = parameters11.serviceAccountKeyJsonBase64.getValue(connection);
1342
+ const projectId = parameters14.projectId.getValue(connection);
1343
+ const serviceAccountJsonBase64 = parameters14.serviceAccountKeyJsonBase64.getValue(connection);
1341
1344
  const credentials = JSON.parse(
1342
1345
  Buffer.from(serviceAccountJsonBase64, "base64").toString("utf-8")
1343
1346
  );
@@ -1367,7 +1370,7 @@ var bigqueryConnector = new ConnectorPlugin({
1367
1370
  name: "BigQuery",
1368
1371
  description: "Connect to Google BigQuery for data warehouse and analytics.",
1369
1372
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/6nlehQyOmdbktG5hOYkYMr/6ca559140d5ddc7dadc5eac88858a563/bigquery.svg",
1370
- parameters: parameters11,
1373
+ parameters: parameters14,
1371
1374
  releaseFlag: { dev1: true, dev2: true, prod: true },
1372
1375
  setup: bigquerySetup,
1373
1376
  systemPrompt: `## BigQuery SQL Notes
@@ -1381,10 +1384,10 @@ var bigqueryConnector = new ConnectorPlugin({
1381
1384
  async checkConnection(params, _config) {
1382
1385
  const { BigQuery } = await import("@google-cloud/bigquery");
1383
1386
  const credentials = JSON.parse(
1384
- Buffer.from(params[parameters11.serviceAccountKeyJsonBase64.slug], "base64").toString("utf-8")
1387
+ Buffer.from(params[parameters14.serviceAccountKeyJsonBase64.slug], "base64").toString("utf-8")
1385
1388
  );
1386
1389
  const bq = new BigQuery({
1387
- projectId: params[parameters11.projectId.slug],
1390
+ projectId: params[parameters14.projectId.slug],
1388
1391
  credentials
1389
1392
  });
1390
1393
  try {
@@ -1399,10 +1402,10 @@ var bigqueryConnector = new ConnectorPlugin({
1399
1402
  const { BigQuery } = await import("@google-cloud/bigquery");
1400
1403
  const resolvedSql = replaceLiteralParams(sql, namedParams);
1401
1404
  const credentials = JSON.parse(
1402
- Buffer.from(params[parameters11.serviceAccountKeyJsonBase64.slug], "base64").toString("utf-8")
1405
+ Buffer.from(params[parameters14.serviceAccountKeyJsonBase64.slug], "base64").toString("utf-8")
1403
1406
  );
1404
1407
  const bq = new BigQuery({
1405
- projectId: params[parameters11.projectId.slug],
1408
+ projectId: params[parameters14.projectId.slug],
1406
1409
  credentials
1407
1410
  });
1408
1411
  const [job] = await bq.createQueryJob({ query: resolvedSql });
@@ -1522,7 +1525,7 @@ var listProjectsTool2 = new ConnectorTool({
1522
1525
  import { z as z9 } from "zod";
1523
1526
 
1524
1527
  // src/connectors/bigquery-oauth/parameters.ts
1525
- var parameters12 = {
1528
+ var parameters15 = {
1526
1529
  projectId: new ParameterDefinition({
1527
1530
  slug: "project-id",
1528
1531
  name: "Google Cloud Project ID",
@@ -1600,7 +1603,7 @@ var listDatasetsTool2 = new ConnectorTool({
1600
1603
  error: `Connection ${connectionId} not found`
1601
1604
  };
1602
1605
  }
1603
- const gcpProjectId = parameters12.projectId.getValue(connection);
1606
+ const gcpProjectId = parameters15.projectId.getValue(connection);
1604
1607
  console.log(
1605
1608
  `[connector-query] bigquery-oauth/${connection.name}: listDatasets`
1606
1609
  );
@@ -1823,7 +1826,7 @@ Avoid loading large amounts of data; always include LIMIT in queries.`,
1823
1826
  error: `Connection ${connectionId} not found`
1824
1827
  };
1825
1828
  }
1826
- const gcpProjectId = parameters12.projectId.getValue(connection);
1829
+ const gcpProjectId = parameters15.projectId.getValue(connection);
1827
1830
  console.log(
1828
1831
  `[connector-query] bigquery-oauth/${connection.name}: ${sql}`
1829
1832
  );
@@ -1890,7 +1893,7 @@ var bigqueryOauthConnector = new ConnectorPlugin({
1890
1893
  name: "BigQuery (OAuth)",
1891
1894
  description: "Connect to Google BigQuery for data warehouse and analytics using OAuth.",
1892
1895
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/6nlehQyOmdbktG5hOYkYMr/6ca559140d5ddc7dadc5eac88858a563/bigquery.svg",
1893
- parameters: parameters12,
1896
+ parameters: parameters15,
1894
1897
  releaseFlag: { dev1: true, dev2: true, prod: true },
1895
1898
  setup: bigquerySetup2,
1896
1899
  proxyPolicy: {
@@ -1909,7 +1912,7 @@ var bigqueryOauthConnector = new ConnectorPlugin({
1909
1912
  tools: tools6,
1910
1913
  async checkConnection(params, config) {
1911
1914
  const { proxyFetch } = config;
1912
- const projectId = params[parameters12.projectId.slug];
1915
+ const projectId = params[parameters15.projectId.slug];
1913
1916
  const url = `https://bigquery.googleapis.com/bigquery/v2/projects/${projectId}/queries`;
1914
1917
  try {
1915
1918
  const res = await proxyFetch(url, {
@@ -1928,7 +1931,7 @@ var bigqueryOauthConnector = new ConnectorPlugin({
1928
1931
  },
1929
1932
  async query(params, sql, namedParams, context) {
1930
1933
  const { proxyFetch } = context;
1931
- const projectId = params[parameters12.projectId.slug];
1934
+ const projectId = params[parameters15.projectId.slug];
1932
1935
  const resolvedSql = replaceLiteralParams(sql, namedParams);
1933
1936
  const url = `https://bigquery.googleapis.com/bigquery/v2/projects/${projectId}/queries`;
1934
1937
  const res = await proxyFetch(url, {
@@ -1946,7 +1949,7 @@ var bigqueryOauthConnector = new ConnectorPlugin({
1946
1949
  });
1947
1950
 
1948
1951
  // src/connectors/aws-athena/parameters.ts
1949
- var parameters13 = {
1952
+ var parameters16 = {
1950
1953
  awsAccessKeyId: new ParameterDefinition({
1951
1954
  slug: "aws-access-key-id",
1952
1955
  name: "AWS Access Key ID",
@@ -2043,8 +2046,8 @@ Avoid loading large amounts of data; always include LIMIT in queries.`,
2043
2046
  GetQueryExecutionCommand,
2044
2047
  GetQueryResultsCommand
2045
2048
  } = await import("@aws-sdk/client-athena");
2046
- const workgroup = parameters13.workgroup.tryGetValue(connection);
2047
- const outputLocation = parameters13.outputLocation.tryGetValue(connection);
2049
+ const workgroup = parameters16.workgroup.tryGetValue(connection);
2050
+ const outputLocation = parameters16.outputLocation.tryGetValue(connection);
2048
2051
  if (!workgroup && !outputLocation) {
2049
2052
  return {
2050
2053
  success: false,
@@ -2052,10 +2055,10 @@ Avoid loading large amounts of data; always include LIMIT in queries.`,
2052
2055
  };
2053
2056
  }
2054
2057
  const client = new AthenaClient({
2055
- region: parameters13.awsRegion.getValue(connection),
2058
+ region: parameters16.awsRegion.getValue(connection),
2056
2059
  credentials: {
2057
- accessKeyId: parameters13.awsAccessKeyId.getValue(connection),
2058
- secretAccessKey: parameters13.awsSecretAccessKey.getValue(connection)
2060
+ accessKeyId: parameters16.awsAccessKeyId.getValue(connection),
2061
+ secretAccessKey: parameters16.awsSecretAccessKey.getValue(connection)
2059
2062
  }
2060
2063
  });
2061
2064
  const startParams = { QueryString: sql };
@@ -2119,7 +2122,7 @@ var awsAthenaConnector = new ConnectorPlugin({
2119
2122
  name: "AWS Athena",
2120
2123
  description: "Connect to AWS Athena for serverless SQL queries on S3 data.",
2121
2124
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/5x0vIHtUHfJJMZUv4RFOYZ/5059bac389f0169542f39cdb4b387d2c/Athena.svg",
2122
- parameters: parameters13,
2125
+ parameters: parameters16,
2123
2126
  releaseFlag: { dev1: true, dev2: true, prod: true },
2124
2127
  systemPrompt: `## AWS Athena SQL Notes
2125
2128
  - Uses Presto/Trino based SQL syntax
@@ -2137,8 +2140,8 @@ var awsAthenaConnector = new ConnectorPlugin({
2137
2140
  StartQueryExecutionCommand,
2138
2141
  GetQueryExecutionCommand
2139
2142
  } = await import("@aws-sdk/client-athena");
2140
- const workgroup = params[parameters13.workgroup.slug];
2141
- const outputLocation = params[parameters13.outputLocation.slug];
2143
+ const workgroup = params[parameters16.workgroup.slug];
2144
+ const outputLocation = params[parameters16.outputLocation.slug];
2142
2145
  if (!workgroup && !outputLocation) {
2143
2146
  return {
2144
2147
  success: false,
@@ -2146,10 +2149,10 @@ var awsAthenaConnector = new ConnectorPlugin({
2146
2149
  };
2147
2150
  }
2148
2151
  const client = new AthenaClient({
2149
- region: params[parameters13.awsRegion.slug],
2152
+ region: params[parameters16.awsRegion.slug],
2150
2153
  credentials: {
2151
- accessKeyId: params[parameters13.awsAccessKeyId.slug],
2152
- secretAccessKey: params[parameters13.awsSecretAccessKey.slug]
2154
+ accessKeyId: params[parameters16.awsAccessKeyId.slug],
2155
+ secretAccessKey: params[parameters16.awsSecretAccessKey.slug]
2153
2156
  }
2154
2157
  });
2155
2158
  const startParams = { QueryString: "SELECT 1" };
@@ -2194,16 +2197,16 @@ var awsAthenaConnector = new ConnectorPlugin({
2194
2197
  GetQueryResultsCommand
2195
2198
  } = await import("@aws-sdk/client-athena");
2196
2199
  const resolvedSql = replaceLiteralParams(sql, namedParams);
2197
- const workgroup = params[parameters13.workgroup.slug];
2198
- const outputLocation = params[parameters13.outputLocation.slug];
2200
+ const workgroup = params[parameters16.workgroup.slug];
2201
+ const outputLocation = params[parameters16.outputLocation.slug];
2199
2202
  if (!workgroup && !outputLocation) {
2200
2203
  throw new Error("Either workgroup or output-location is required");
2201
2204
  }
2202
2205
  const client = new AthenaClient({
2203
- region: params[parameters13.awsRegion.slug],
2206
+ region: params[parameters16.awsRegion.slug],
2204
2207
  credentials: {
2205
- accessKeyId: params[parameters13.awsAccessKeyId.slug],
2206
- secretAccessKey: params[parameters13.awsSecretAccessKey.slug]
2208
+ accessKeyId: params[parameters16.awsAccessKeyId.slug],
2209
+ secretAccessKey: params[parameters16.awsSecretAccessKey.slug]
2207
2210
  }
2208
2211
  });
2209
2212
  const startParams = { QueryString: resolvedSql };
@@ -2248,7 +2251,7 @@ var awsAthenaConnector = new ConnectorPlugin({
2248
2251
  });
2249
2252
 
2250
2253
  // src/connectors/redshift/parameters.ts
2251
- var parameters14 = {
2254
+ var parameters17 = {
2252
2255
  awsAccessKeyId: new ParameterDefinition({
2253
2256
  slug: "aws-access-key-id",
2254
2257
  name: "AWS Access Key ID",
@@ -2374,14 +2377,14 @@ Avoid loading large amounts of data; always include LIMIT in queries.`,
2374
2377
  DescribeStatementCommand,
2375
2378
  GetStatementResultCommand
2376
2379
  } = await import("@aws-sdk/client-redshift-data");
2377
- const awsAccessKeyId = parameters14.awsAccessKeyId.getValue(connection);
2378
- const awsSecretAccessKey = parameters14.awsSecretAccessKey.getValue(connection);
2379
- const awsRegion = parameters14.awsRegion.getValue(connection);
2380
- const database = parameters14.database.getValue(connection);
2381
- const clusterIdentifier = parameters14.clusterIdentifier.tryGetValue(connection);
2382
- const workgroupName = parameters14.workgroupName.tryGetValue(connection);
2383
- const secretArn = parameters14.secretArn.tryGetValue(connection);
2384
- const dbUser = parameters14.dbUser.tryGetValue(connection);
2380
+ const awsAccessKeyId = parameters17.awsAccessKeyId.getValue(connection);
2381
+ const awsSecretAccessKey = parameters17.awsSecretAccessKey.getValue(connection);
2382
+ const awsRegion = parameters17.awsRegion.getValue(connection);
2383
+ const database = parameters17.database.getValue(connection);
2384
+ const clusterIdentifier = parameters17.clusterIdentifier.tryGetValue(connection);
2385
+ const workgroupName = parameters17.workgroupName.tryGetValue(connection);
2386
+ const secretArn = parameters17.secretArn.tryGetValue(connection);
2387
+ const dbUser = parameters17.dbUser.tryGetValue(connection);
2385
2388
  if (!clusterIdentifier && !workgroupName) {
2386
2389
  return {
2387
2390
  success: false,
@@ -2452,7 +2455,7 @@ var redshiftConnector = new ConnectorPlugin({
2452
2455
  name: "Redshift",
2453
2456
  description: "Connect to Amazon Redshift for data warehouse analytics.",
2454
2457
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/AEwW2psmrnZ7htTVsgA9t/a637e31707c5d760be73ce1d8ec75580/aws-redshift-logo.svg",
2455
- parameters: parameters14,
2458
+ parameters: parameters17,
2456
2459
  releaseFlag: { dev1: true, dev2: true, prod: true },
2457
2460
  systemPrompt: `## Redshift SQL Notes
2458
2461
  - Uses PostgreSQL based SQL syntax
@@ -2470,10 +2473,10 @@ var redshiftConnector = new ConnectorPlugin({
2470
2473
  ExecuteStatementCommand,
2471
2474
  DescribeStatementCommand
2472
2475
  } = await import("@aws-sdk/client-redshift-data");
2473
- const clusterIdentifier = params[parameters14.clusterIdentifier.slug];
2474
- const workgroupName = params[parameters14.workgroupName.slug];
2475
- const secretArn = params[parameters14.secretArn.slug];
2476
- const dbUser = params[parameters14.dbUser.slug];
2476
+ const clusterIdentifier = params[parameters17.clusterIdentifier.slug];
2477
+ const workgroupName = params[parameters17.workgroupName.slug];
2478
+ const secretArn = params[parameters17.secretArn.slug];
2479
+ const dbUser = params[parameters17.dbUser.slug];
2477
2480
  if (!clusterIdentifier && !workgroupName) {
2478
2481
  return {
2479
2482
  success: false,
@@ -2481,15 +2484,15 @@ var redshiftConnector = new ConnectorPlugin({
2481
2484
  };
2482
2485
  }
2483
2486
  const client = new RedshiftDataClient({
2484
- region: params[parameters14.awsRegion.slug],
2487
+ region: params[parameters17.awsRegion.slug],
2485
2488
  credentials: {
2486
- accessKeyId: params[parameters14.awsAccessKeyId.slug],
2487
- secretAccessKey: params[parameters14.awsSecretAccessKey.slug]
2489
+ accessKeyId: params[parameters17.awsAccessKeyId.slug],
2490
+ secretAccessKey: params[parameters17.awsSecretAccessKey.slug]
2488
2491
  }
2489
2492
  });
2490
2493
  const { Id: statementId } = await client.send(
2491
2494
  new ExecuteStatementCommand({
2492
- Database: params[parameters14.database.slug],
2495
+ Database: params[parameters17.database.slug],
2493
2496
  Sql: "SELECT 1",
2494
2497
  ...clusterIdentifier && { ClusterIdentifier: clusterIdentifier },
2495
2498
  ...workgroupName && { WorkgroupName: workgroupName },
@@ -2530,23 +2533,23 @@ var redshiftConnector = new ConnectorPlugin({
2530
2533
  GetStatementResultCommand
2531
2534
  } = await import("@aws-sdk/client-redshift-data");
2532
2535
  const resolvedSql = replaceLiteralParams(sql, namedParams);
2533
- const clusterIdentifier = params[parameters14.clusterIdentifier.slug];
2534
- const workgroupName = params[parameters14.workgroupName.slug];
2535
- const secretArn = params[parameters14.secretArn.slug];
2536
- const dbUser = params[parameters14.dbUser.slug];
2536
+ const clusterIdentifier = params[parameters17.clusterIdentifier.slug];
2537
+ const workgroupName = params[parameters17.workgroupName.slug];
2538
+ const secretArn = params[parameters17.secretArn.slug];
2539
+ const dbUser = params[parameters17.dbUser.slug];
2537
2540
  if (!clusterIdentifier && !workgroupName) {
2538
2541
  throw new Error("Either cluster-identifier or workgroup-name is required");
2539
2542
  }
2540
2543
  const client = new RedshiftDataClient({
2541
- region: params[parameters14.awsRegion.slug],
2544
+ region: params[parameters17.awsRegion.slug],
2542
2545
  credentials: {
2543
- accessKeyId: params[parameters14.awsAccessKeyId.slug],
2544
- secretAccessKey: params[parameters14.awsSecretAccessKey.slug]
2546
+ accessKeyId: params[parameters17.awsAccessKeyId.slug],
2547
+ secretAccessKey: params[parameters17.awsSecretAccessKey.slug]
2545
2548
  }
2546
2549
  });
2547
2550
  const { Id: statementId } = await client.send(
2548
2551
  new ExecuteStatementCommand({
2549
- Database: params[parameters14.database.slug],
2552
+ Database: params[parameters17.database.slug],
2550
2553
  Sql: resolvedSql,
2551
2554
  ...clusterIdentifier && { ClusterIdentifier: clusterIdentifier },
2552
2555
  ...workgroupName && { WorkgroupName: workgroupName },
@@ -2584,7 +2587,7 @@ var redshiftConnector = new ConnectorPlugin({
2584
2587
  });
2585
2588
 
2586
2589
  // src/connectors/databricks/parameters.ts
2587
- var parameters15 = {
2590
+ var parameters18 = {
2588
2591
  host: new ParameterDefinition({
2589
2592
  slug: "host",
2590
2593
  name: "Databricks Workspace Host",
@@ -2656,9 +2659,9 @@ Avoid loading large amounts of data; always include LIMIT in queries.`,
2656
2659
  );
2657
2660
  try {
2658
2661
  const { DBSQLClient } = await import("@databricks/sql");
2659
- const host = parameters15.host.getValue(connection);
2660
- const token = parameters15.token.getValue(connection);
2661
- const httpPath = parameters15.httpPath.getValue(connection);
2662
+ const host = parameters18.host.getValue(connection);
2663
+ const token = parameters18.token.getValue(connection);
2664
+ const httpPath = parameters18.httpPath.getValue(connection);
2662
2665
  const client = new DBSQLClient();
2663
2666
  await client.connect({ host, path: httpPath, token });
2664
2667
  let session;
@@ -2699,7 +2702,7 @@ var databricksConnector = new ConnectorPlugin({
2699
2702
  name: "Databricks",
2700
2703
  description: "Connect to Databricks for data lakehouse and SQL analytics.",
2701
2704
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/6QgcrfpQOKg18P7DdgKerd/af55bf0d871339049824dd167b97a29f/databricks-icon.svg",
2702
- parameters: parameters15,
2705
+ parameters: parameters18,
2703
2706
  releaseFlag: { dev1: true, dev2: true, prod: true },
2704
2707
  systemPrompt: `## Databricks SQL Notes
2705
2708
  - Uses Spark SQL / Databricks SQL syntax
@@ -2714,9 +2717,9 @@ var databricksConnector = new ConnectorPlugin({
2714
2717
  const { DBSQLClient } = await import("@databricks/sql");
2715
2718
  const client = new DBSQLClient();
2716
2719
  await client.connect({
2717
- host: params[parameters15.host.slug],
2718
- path: params[parameters15.httpPath.slug],
2719
- token: params[parameters15.token.slug]
2720
+ host: params[parameters18.host.slug],
2721
+ path: params[parameters18.httpPath.slug],
2722
+ token: params[parameters18.token.slug]
2720
2723
  });
2721
2724
  let session;
2722
2725
  let operation;
@@ -2743,9 +2746,9 @@ var databricksConnector = new ConnectorPlugin({
2743
2746
  const resolvedSql = replaceLiteralParams(sql, namedParams);
2744
2747
  const client = new DBSQLClient();
2745
2748
  await client.connect({
2746
- host: params[parameters15.host.slug],
2747
- path: params[parameters15.httpPath.slug],
2748
- token: params[parameters15.token.slug]
2749
+ host: params[parameters18.host.slug],
2750
+ path: params[parameters18.httpPath.slug],
2751
+ token: params[parameters18.token.slug]
2749
2752
  });
2750
2753
  let session;
2751
2754
  let operation;
@@ -2898,79 +2901,152 @@ await airtable.updateRecords("Tasks", [
2898
2901
  tools: tools10
2899
2902
  });
2900
2903
 
2901
- // src/connectors/google-analytics/tools/request.ts
2904
+ // src/connectors/google-ads-oauth/tools/list-customers.ts
2902
2905
  import { z as z15 } from "zod";
2903
- var BASE_URL2 = "https://analyticsdata.googleapis.com/v1beta/";
2906
+ var BASE_URL2 = "https://googleads.googleapis.com/v18/";
2904
2907
  var REQUEST_TIMEOUT_MS5 = 6e4;
2908
+ var cachedToken4 = null;
2909
+ async function getProxyToken4(config) {
2910
+ if (cachedToken4 && cachedToken4.expiresAt > Date.now() + 6e4) {
2911
+ return cachedToken4.token;
2912
+ }
2913
+ const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
2914
+ const res = await fetch(url, {
2915
+ method: "POST",
2916
+ headers: {
2917
+ "Content-Type": "application/json",
2918
+ "x-api-key": config.appApiKey,
2919
+ "project-id": config.projectId
2920
+ },
2921
+ body: JSON.stringify({
2922
+ sandboxId: config.sandboxId,
2923
+ issuedBy: "coding-agent"
2924
+ })
2925
+ });
2926
+ if (!res.ok) {
2927
+ const errorText = await res.text().catch(() => res.statusText);
2928
+ throw new Error(
2929
+ `Failed to get proxy token: HTTP ${res.status} ${errorText}`
2930
+ );
2931
+ }
2932
+ const data = await res.json();
2933
+ cachedToken4 = {
2934
+ token: data.token,
2935
+ expiresAt: new Date(data.expiresAt).getTime()
2936
+ };
2937
+ return data.token;
2938
+ }
2905
2939
  var inputSchema15 = z15.object({
2906
- toolUseIntent: z15.string().optional().describe("Brief description of what you intend to accomplish with this tool call"),
2907
- connectionId: z15.string().describe("ID of the Google Analytics connection to use"),
2908
- method: z15.enum(["GET", "POST"]).describe("HTTP method"),
2909
- path: z15.string().describe("API path (e.g., 'properties/{propertyId}:runReport'). {propertyId} is automatically replaced."),
2910
- body: z15.record(z15.string(), z15.unknown()).optional().describe("POST request body (JSON)")
2940
+ toolUseIntent: z15.string().optional().describe(
2941
+ "Brief description of what you intend to accomplish with this tool call"
2942
+ ),
2943
+ connectionId: z15.string().describe("ID of the Google Ads OAuth connection to use")
2911
2944
  });
2912
2945
  var outputSchema15 = z15.discriminatedUnion("success", [
2913
2946
  z15.object({
2914
2947
  success: z15.literal(true),
2915
- status: z15.number(),
2916
- data: z15.record(z15.string(), z15.unknown())
2948
+ customers: z15.array(
2949
+ z15.object({
2950
+ customerId: z15.string(),
2951
+ descriptiveName: z15.string()
2952
+ })
2953
+ )
2917
2954
  }),
2918
2955
  z15.object({
2919
2956
  success: z15.literal(false),
2920
2957
  error: z15.string()
2921
2958
  })
2922
2959
  ]);
2923
- var requestTool2 = new ConnectorTool({
2924
- name: "request",
2925
- description: `Send authenticated requests to the Google Analytics Data API.
2926
- Authentication is handled automatically using a service account.
2927
- {propertyId} in the path is automatically replaced with the connection's property-id.`,
2960
+ var listCustomersTool = new ConnectorTool({
2961
+ name: "listCustomers",
2962
+ description: "List Google Ads customer accounts accessible with the current OAuth credentials.",
2928
2963
  inputSchema: inputSchema15,
2929
2964
  outputSchema: outputSchema15,
2930
- async execute({ connectionId, method, path, body }, connections) {
2965
+ async execute({ connectionId }, connections, config) {
2931
2966
  const connection = connections.find((c) => c.id === connectionId);
2932
2967
  if (!connection) {
2933
- return { success: false, error: `Connection ${connectionId} not found` };
2968
+ return {
2969
+ success: false,
2970
+ error: `Connection ${connectionId} not found`
2971
+ };
2934
2972
  }
2935
- console.log(`[connector-request] google-analytics/${connection.name}: ${method} ${path}`);
2973
+ console.log(
2974
+ `[connector-request] google-ads-oauth/${connection.name}: listCustomers`
2975
+ );
2936
2976
  try {
2937
- const { GoogleAuth } = await import("google-auth-library");
2938
- const keyJsonBase64 = parameters2.serviceAccountKeyJsonBase64.getValue(connection);
2939
- const propertyId = parameters2.propertyId.getValue(connection);
2940
- const credentials = JSON.parse(
2941
- Buffer.from(keyJsonBase64, "base64").toString("utf-8")
2942
- );
2943
- const auth = new GoogleAuth({
2944
- credentials,
2945
- scopes: ["https://www.googleapis.com/auth/analytics.readonly"]
2946
- });
2947
- const token = await auth.getAccessToken();
2948
- if (!token) {
2949
- return { success: false, error: "Failed to obtain access token" };
2950
- }
2951
- const resolvedPath = path.replace(/\{propertyId\}/g, propertyId);
2952
- const url = `${BASE_URL2}${resolvedPath}`;
2977
+ const developerToken = parameters2.developerToken.getValue(connection);
2978
+ const token = await getProxyToken4(config.oauthProxy);
2979
+ const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
2953
2980
  const controller = new AbortController();
2954
2981
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS5);
2955
2982
  try {
2956
- const response = await fetch(url, {
2957
- method,
2983
+ const response = await fetch(proxyUrl, {
2984
+ method: "POST",
2958
2985
  headers: {
2959
- Authorization: `Bearer ${token}`,
2960
- "Content-Type": "application/json"
2986
+ "Content-Type": "application/json",
2987
+ Authorization: `Bearer ${token}`
2961
2988
  },
2962
- body: method === "POST" && body ? JSON.stringify(body) : void 0,
2989
+ body: JSON.stringify({
2990
+ url: `${BASE_URL2}customers:listAccessibleCustomers`,
2991
+ method: "GET",
2992
+ headers: {
2993
+ "developer-token": developerToken
2994
+ }
2995
+ }),
2963
2996
  signal: controller.signal
2964
2997
  });
2965
2998
  const data = await response.json();
2966
2999
  if (!response.ok) {
2967
- const errorObj = data?.error;
2968
- return {
2969
- success: false,
2970
- error: errorObj?.message ?? `HTTP ${response.status} ${response.statusText}`
2971
- };
3000
+ const errorMessage = typeof data?.error === "string" ? data.error : typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`;
3001
+ return { success: false, error: errorMessage };
2972
3002
  }
2973
- return { success: true, status: response.status, data };
3003
+ const customerIds = (data.resourceNames ?? []).map(
3004
+ (rn) => rn.replace(/^customers\//, "")
3005
+ );
3006
+ const customers = [];
3007
+ for (const cid of customerIds) {
3008
+ try {
3009
+ const detailResponse = await fetch(proxyUrl, {
3010
+ method: "POST",
3011
+ headers: {
3012
+ "Content-Type": "application/json",
3013
+ Authorization: `Bearer ${token}`
3014
+ },
3015
+ body: JSON.stringify({
3016
+ url: `${BASE_URL2}customers/${cid}/googleAds:searchStream`,
3017
+ method: "POST",
3018
+ headers: {
3019
+ "Content-Type": "application/json",
3020
+ "developer-token": developerToken,
3021
+ "login-customer-id": cid
3022
+ },
3023
+ body: JSON.stringify({
3024
+ query: "SELECT customer.id, customer.descriptive_name FROM customer LIMIT 1"
3025
+ })
3026
+ }),
3027
+ signal: controller.signal
3028
+ });
3029
+ if (detailResponse.ok) {
3030
+ const detailData = await detailResponse.json();
3031
+ const customer = detailData?.[0]?.results?.[0]?.customer;
3032
+ customers.push({
3033
+ customerId: cid,
3034
+ descriptiveName: customer?.descriptiveName ?? cid
3035
+ });
3036
+ } else {
3037
+ customers.push({
3038
+ customerId: cid,
3039
+ descriptiveName: cid
3040
+ });
3041
+ }
3042
+ } catch {
3043
+ customers.push({
3044
+ customerId: cid,
3045
+ descriptiveName: cid
3046
+ });
3047
+ }
3048
+ }
3049
+ return { success: true, customers };
2974
3050
  } finally {
2975
3051
  clearTimeout(timeout);
2976
3052
  }
@@ -2981,136 +3057,182 @@ Authentication is handled automatically using a service account.
2981
3057
  }
2982
3058
  });
2983
3059
 
2984
- // src/connectors/google-analytics/index.ts
2985
- var tools11 = { request: requestTool2 };
2986
- var googleAnalyticsConnector = new ConnectorPlugin({
2987
- slug: "google-analytics",
2988
- authType: null,
2989
- name: "Google Analytics",
2990
- description: "Connect to Google Analytics for web analytics and reporting.",
2991
- iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/7fs0ipzxuD9mACDzBATtxX/3c53ed90d15c96483e4f78cb29dab5e9/google-analytics.svg",
2992
- parameters: parameters2,
2993
- releaseFlag: { dev1: true, dev2: true, prod: true },
2994
- systemPrompt: `## Google Analytics Data API
2995
- - Call the GA4 Data API using the authenticated request tool
2996
- - {propertyId} in the path is automatically replaced
3060
+ // src/connectors/google-ads-oauth/setup.ts
3061
+ var listCustomersToolName = `google-ads-oauth_${listCustomersTool.name}`;
3062
+ var googleAdsSetup = new ConnectorSetup({
3063
+ ja: `## Google Ads \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u624B\u9806
2997
3064
 
2998
- ### Get Metadata (Check available dimensions and metrics)
2999
- - GET properties/{propertyId}/metadata
3065
+ \u4EE5\u4E0B\u306E\u624B\u9806\u3067Google Ads (OAuth) \u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044\u3002
3000
3066
 
3001
- ### Get Report
3002
- - POST properties/{propertyId}:runReport
3003
- - Body example:
3004
- {
3005
- "dateRanges": [{"startDate": "7daysAgo", "endDate": "today"}],
3006
- "dimensions": [{"name": "date"}],
3007
- "metrics": [{"name": "activeUsers"}],
3008
- "limit": 100
3009
- }
3067
+ ### \u624B\u9806
3010
3068
 
3011
- ### Common Dimensions
3012
- date, country, city, deviceCategory, browser, pagePath, pageTitle,
3013
- sessionSource, sessionMedium, eventName
3069
+ #### \u30B9\u30C6\u30C3\u30D71: Developer Token \u8A2D\u5B9A
3070
+ 1. \u30E6\u30FC\u30B6\u30FC\u306B\u300CGoogle Ads API \u306E Developer Token \u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\uFF08Google Ads \u7BA1\u7406\u753B\u9762 > \u30C4\u30FC\u30EB\u3068\u8A2D\u5B9A > API \u30BB\u30F3\u30BF\u30FC\u3067\u53D6\u5F97\u3067\u304D\u307E\u3059\uFF09\u300D\u3068\u4F1D\u3048\u308B
3071
+ 2. \`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
3072
+ - \`parameterSlug\`: \`"developer-token"\`
3073
+ - \`value\`: \u30E6\u30FC\u30B6\u30FC\u304C\u63D0\u4F9B\u3057\u305F Developer Token
3014
3074
 
3015
- ### Common Metrics
3016
- activeUsers, sessions, screenPageViews, bounceRate,
3017
- averageSessionDuration, conversions, totalRevenue
3075
+ #### \u30B9\u30C6\u30C3\u30D72: \u30AB\u30B9\u30BF\u30DE\u30FC\u9078\u629E
3076
+ 1. \`${listCustomersToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001OAuth\u3067\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306AGoogle Ads\u30AB\u30B9\u30BF\u30DE\u30FC\u30A2\u30AB\u30A6\u30F3\u30C8\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
3077
+ 2. \`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
3078
+ - \`parameterSlug\`: \`"customer-id"\`
3079
+ - \`options\`: \u30AB\u30B9\u30BF\u30DE\u30FC\u4E00\u89A7\u3002\u5404 option \u306E \`label\` \u306F \`\u30A2\u30AB\u30A6\u30F3\u30C8\u540D (id: \u30AB\u30B9\u30BF\u30DE\u30FCID)\` \u306E\u5F62\u5F0F\u3001\`value\` \u306F\u30AB\u30B9\u30BF\u30DE\u30FCID
3080
+ 3. \u30E6\u30FC\u30B6\u30FC\u304C\u9078\u629E\u3057\u305F\u30AB\u30B9\u30BF\u30DE\u30FC\u306E \`label\` \u304C\u30E1\u30C3\u30BB\u30FC\u30B8\u3068\u3057\u3066\u5C4A\u304F\u306E\u3067\u3001\u30B9\u30C6\u30C3\u30D73\u306B\u9032\u3080
3018
3081
 
3019
- ### Date Specification
3020
- - Absolute: "2024-01-01"
3021
- - Relative: "today", "yesterday", "7daysAgo", "30daysAgo"
3082
+ #### \u30B9\u30C6\u30C3\u30D73: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5B8C\u4E86
3083
+ 1. \`updateConnectionContext\` \u3092\u547C\u3073\u51FA\u3059:
3084
+ - \`customer\`: \u9078\u629E\u3055\u308C\u305F\u30AB\u30B9\u30BF\u30DE\u30FC\u306E\u8868\u793A\u540D
3085
+ - \`customerId\`: \u9078\u629E\u3055\u308C\u305F\u30AB\u30B9\u30BF\u30DE\u30FCID
3086
+ - \`note\`: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5185\u5BB9\u306E\u7C21\u5358\u306A\u8AAC\u660E
3022
3087
 
3023
- ## Google Analytics SDK (TypeScript handler)
3024
- Non-SQL connectors like Google Analytics can also be used via the SDK in TypeScript handlers:
3088
+ ### \u91CD\u8981\u306A\u5236\u7D04
3089
+ - **\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u4E2D\u306B\u30EC\u30DD\u30FC\u30C8\u30C7\u30FC\u30BF\u3092\u53D6\u5F97\u3057\u306A\u3044\u3053\u3068**\u3002\u5B9F\u884C\u3057\u3066\u3088\u3044\u306E\u306F\u4E0A\u8A18\u624B\u9806\u3067\u6307\u5B9A\u3055\u308C\u305F\u30E1\u30BF\u30C7\u30FC\u30BF\u53D6\u5F97\u306E\u307F
3025
3090
 
3026
- \`\`\`ts
3027
- import { connection } from "@squadbase/vite-server/connectors/google-analytics";
3091
+ ### \u5B9F\u884C\u65B9\u91DD
3092
+ - \u30C4\u30FC\u30EB\u9593\u306F1\u6587\u3060\u3051\u66F8\u3044\u3066\u5373\u6B21\u306E\u30C4\u30FC\u30EB\u547C\u3073\u51FA\u3057
3093
+ - \u4E0D\u8981\u306A\u8AAC\u660E\u306F\u7701\u7565\u3057\u3001\u52B9\u7387\u7684\u306B\u9032\u3081\u308B`,
3094
+ en: `## Google Ads Setup Instructions
3028
3095
 
3029
- const ga = connection("<connectionId>");
3096
+ Follow these steps to set up the Google Ads (OAuth) connection.
3030
3097
 
3031
- // Authenticated fetch (returns standard Response)
3032
- const res = await ga.request("properties/{propertyId}:runReport", {
3033
- method: "POST",
3034
- body: JSON.stringify({ dateRanges: [{ startDate: "7daysAgo", endDate: "today" }], metrics: [{ name: "activeUsers" }] }),
3035
- });
3036
- const data = await res.json();
3098
+ ### Steps
3037
3099
 
3038
- // Convenience methods
3039
- const { rows, rowCount } = await ga.runReport({
3040
- dateRanges: [{ startDate: "7daysAgo", endDate: "today" }],
3041
- dimensions: [{ name: "date" }],
3042
- metrics: [{ name: "activeUsers" }, { name: "sessions" }],
3043
- limit: 100,
3044
- });
3045
- const metadata = await ga.getMetadata();
3046
- const realtime = await ga.runRealtimeReport({
3047
- metrics: [{ name: "activeUsers" }],
3048
- dimensions: [{ name: "country" }],
3049
- });
3050
- \`\`\``,
3051
- tools: tools11
3100
+ #### Step 1: Developer Token Setup
3101
+ 1. Ask the user to provide their Google Ads API Developer Token (available in Google Ads UI > Tools & Settings > API Center)
3102
+ 2. Call \`updateConnectionParameters\`:
3103
+ - \`parameterSlug\`: \`"developer-token"\`
3104
+ - \`value\`: The Developer Token provided by the user
3105
+
3106
+ #### Step 2: Customer Selection
3107
+ 1. Call \`${listCustomersToolName}\` to get the list of Google Ads customer accounts accessible with the OAuth credentials
3108
+ 2. Call \`updateConnectionParameters\`:
3109
+ - \`parameterSlug\`: \`"customer-id"\`
3110
+ - \`options\`: The customer list. Each option's \`label\` should be \`Account Name (id: customerId)\`, \`value\` should be the customer ID
3111
+ 3. The \`label\` of the user's selected customer will arrive as a message. Proceed to Step 3
3112
+
3113
+ #### Step 3: Complete Setup
3114
+ 1. Call \`updateConnectionContext\`:
3115
+ - \`customer\`: The selected customer's display name
3116
+ - \`customerId\`: The selected customer ID
3117
+ - \`note\`: Brief description of the setup
3118
+
3119
+ ### Important Constraints
3120
+ - **Do NOT fetch report data during setup**. Only the metadata requests specified in the steps above are allowed
3121
+
3122
+ ### Execution Policy
3123
+ - Write only 1 sentence between tool calls, then immediately call the next tool
3124
+ - Skip unnecessary explanations and proceed efficiently`
3052
3125
  });
3053
3126
 
3054
- // src/connectors/kintone/tools/request.ts
3127
+ // src/connectors/google-ads-oauth/tools/request.ts
3055
3128
  import { z as z16 } from "zod";
3129
+ var BASE_URL3 = "https://googleads.googleapis.com/v18/";
3056
3130
  var REQUEST_TIMEOUT_MS6 = 6e4;
3131
+ var cachedToken5 = null;
3132
+ async function getProxyToken5(config) {
3133
+ if (cachedToken5 && cachedToken5.expiresAt > Date.now() + 6e4) {
3134
+ return cachedToken5.token;
3135
+ }
3136
+ const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
3137
+ const res = await fetch(url, {
3138
+ method: "POST",
3139
+ headers: {
3140
+ "Content-Type": "application/json",
3141
+ "x-api-key": config.appApiKey,
3142
+ "project-id": config.projectId
3143
+ },
3144
+ body: JSON.stringify({
3145
+ sandboxId: config.sandboxId,
3146
+ issuedBy: "coding-agent"
3147
+ })
3148
+ });
3149
+ if (!res.ok) {
3150
+ const errorText = await res.text().catch(() => res.statusText);
3151
+ throw new Error(
3152
+ `Failed to get proxy token: HTTP ${res.status} ${errorText}`
3153
+ );
3154
+ }
3155
+ const data = await res.json();
3156
+ cachedToken5 = {
3157
+ token: data.token,
3158
+ expiresAt: new Date(data.expiresAt).getTime()
3159
+ };
3160
+ return data.token;
3161
+ }
3057
3162
  var inputSchema16 = z16.object({
3058
- toolUseIntent: z16.string().optional().describe("Brief description of what you intend to accomplish with this tool call"),
3059
- connectionId: z16.string().describe("ID of the kintone connection to use"),
3060
- method: z16.enum(["GET", "POST", "PUT", "DELETE"]).describe("HTTP method"),
3061
- path: z16.string().describe("API path (e.g., 'apps.json', 'records.json?app=1&query=...')"),
3062
- body: z16.record(z16.string(), z16.unknown()).optional().describe("Request body (JSON)")
3163
+ toolUseIntent: z16.string().optional().describe(
3164
+ "Brief description of what you intend to accomplish with this tool call"
3165
+ ),
3166
+ connectionId: z16.string().describe("ID of the Google Ads OAuth connection to use"),
3167
+ method: z16.enum(["GET", "POST"]).describe("HTTP method"),
3168
+ path: z16.string().describe(
3169
+ "API path appended to https://googleads.googleapis.com/v18/ (e.g., 'customers/{customerId}/googleAds:searchStream'). {customerId} is automatically replaced."
3170
+ ),
3171
+ body: z16.record(z16.string(), z16.unknown()).optional().describe("POST request body (JSON)")
3063
3172
  });
3064
3173
  var outputSchema16 = z16.discriminatedUnion("success", [
3065
3174
  z16.object({
3066
3175
  success: z16.literal(true),
3067
3176
  status: z16.number(),
3068
- data: z16.record(z16.string(), z16.unknown())
3177
+ data: z16.unknown()
3069
3178
  }),
3070
3179
  z16.object({
3071
3180
  success: z16.literal(false),
3072
3181
  error: z16.string()
3073
3182
  })
3074
3183
  ]);
3075
- var requestTool3 = new ConnectorTool({
3184
+ var requestTool2 = new ConnectorTool({
3076
3185
  name: "request",
3077
- description: `Send authenticated requests to the kintone REST API.
3078
- Authentication is handled automatically using username and password.`,
3186
+ description: `Send authenticated requests to the Google Ads API v18.
3187
+ Authentication is handled automatically via OAuth proxy.
3188
+ {customerId} in the path is automatically replaced with the connection's customer ID (hyphens removed).`,
3079
3189
  inputSchema: inputSchema16,
3080
3190
  outputSchema: outputSchema16,
3081
- async execute({ connectionId, method, path, body }, connections) {
3191
+ async execute({ connectionId, method, path, body }, connections, config) {
3082
3192
  const connection = connections.find((c) => c.id === connectionId);
3083
3193
  if (!connection) {
3084
- return { success: false, error: `Connection ${connectionId} not found` };
3194
+ return {
3195
+ success: false,
3196
+ error: `Connection ${connectionId} not found`
3197
+ };
3085
3198
  }
3086
- console.log(`[connector-request] kintone/${connection.name}: ${method} ${path}`);
3199
+ console.log(
3200
+ `[connector-request] google-ads-oauth/${connection.name}: ${method} ${path}`
3201
+ );
3087
3202
  try {
3088
- const baseUrl = parameters3.baseUrl.getValue(connection);
3089
- const username = parameters3.username.getValue(connection);
3090
- const password = parameters3.password.getValue(connection);
3091
- const authToken = Buffer.from(`${username}:${password}`).toString("base64");
3092
- const url = `${baseUrl.replace(/\/+$/, "")}/k/v1/${path}`;
3203
+ const rawCustomerId = parameters2.customerId.tryGetValue(connection);
3204
+ const customerId = rawCustomerId?.replace(/-/g, "") ?? "";
3205
+ const resolvedPath = customerId ? path.replace(/\{customerId\}/g, customerId) : path;
3206
+ const url = `${BASE_URL3}${resolvedPath}`;
3207
+ const token = await getProxyToken5(config.oauthProxy);
3208
+ const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
3093
3209
  const controller = new AbortController();
3094
3210
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS6);
3095
3211
  try {
3096
- const headers = {
3097
- "X-Cybozu-Authorization": authToken
3098
- };
3099
- if (body) {
3100
- headers["Content-Type"] = "application/json";
3101
- }
3102
- const response = await fetch(url, {
3103
- method,
3104
- headers,
3105
- body: body ? JSON.stringify(body) : void 0,
3212
+ const developerToken = parameters2.developerToken.getValue(connection);
3213
+ const response = await fetch(proxyUrl, {
3214
+ method: "POST",
3215
+ headers: {
3216
+ "Content-Type": "application/json",
3217
+ Authorization: `Bearer ${token}`
3218
+ },
3219
+ body: JSON.stringify({
3220
+ url,
3221
+ method,
3222
+ headers: {
3223
+ "Content-Type": "application/json",
3224
+ "developer-token": developerToken,
3225
+ ...customerId ? { "login-customer-id": customerId } : {}
3226
+ },
3227
+ ...method === "POST" && body ? { body: JSON.stringify(body) } : {}
3228
+ }),
3106
3229
  signal: controller.signal
3107
3230
  });
3108
3231
  const data = await response.json();
3109
3232
  if (!response.ok) {
3110
- return {
3111
- success: false,
3112
- error: data?.message ?? `HTTP ${response.status} ${response.statusText}`
3113
- };
3233
+ const dataObj = data;
3234
+ const errorMessage = typeof dataObj?.error === "string" ? dataObj.error : typeof dataObj?.message === "string" ? dataObj.message : `HTTP ${response.status} ${response.statusText}`;
3235
+ return { success: false, error: errorMessage };
3114
3236
  }
3115
3237
  return { success: true, status: response.status, data };
3116
3238
  } finally {
@@ -3123,15 +3245,1144 @@ Authentication is handled automatically using username and password.`,
3123
3245
  }
3124
3246
  });
3125
3247
 
3126
- // src/connectors/kintone/index.ts
3127
- var tools12 = { request: requestTool3 };
3128
- var kintoneConnector = new ConnectorPlugin({
3129
- slug: "kintone",
3248
+ // src/connectors/google-ads-oauth/index.ts
3249
+ var tools11 = {
3250
+ request: requestTool2,
3251
+ listCustomers: listCustomersTool
3252
+ };
3253
+ var googleAdsOauthConnector = new ConnectorPlugin({
3254
+ slug: "google-ads",
3255
+ authType: AUTH_TYPES.OAUTH,
3256
+ name: "Google Ads (OAuth)",
3257
+ description: "Connect to Google Ads for advertising campaign data and reporting using OAuth.",
3258
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/1NGvmgvCxX7Tn11EST2N3N/a745fe7c63d360ed40a27ddaad3af168/google-ads.svg",
3259
+ parameters: parameters2,
3260
+ releaseFlag: { dev1: true, dev2: false, prod: false },
3261
+ setup: googleAdsSetup,
3262
+ proxyPolicy: {
3263
+ allowlist: [
3264
+ {
3265
+ host: "googleads.googleapis.com",
3266
+ methods: ["GET", "POST"]
3267
+ }
3268
+ ]
3269
+ },
3270
+ systemPrompt: `## Google Ads API (OAuth, Read-Only)
3271
+ - Use GAQL (Google Ads Query Language) to query campaign data
3272
+ - {customerId} in the path is automatically replaced (hyphens removed)
3273
+
3274
+ ### Query Data (searchStream)
3275
+ - POST customers/{customerId}/googleAds:searchStream
3276
+ - Body: { "query": "SELECT campaign.id, campaign.name, metrics.impressions FROM campaign WHERE segments.date DURING LAST_30_DAYS" }
3277
+
3278
+ ### Common GAQL Resources
3279
+ - \`campaign\`: Campaign data (campaign.id, campaign.name, campaign.status)
3280
+ - \`ad_group\`: Ad group data (ad_group.id, ad_group.name, ad_group.status)
3281
+ - \`ad_group_ad\`: Ad data (ad_group_ad.ad.id, ad_group_ad.status)
3282
+ - \`keyword_view\`: Keyword performance data
3283
+
3284
+ ### Common Metrics
3285
+ metrics.impressions, metrics.clicks, metrics.cost_micros, metrics.conversions,
3286
+ metrics.ctr, metrics.average_cpc, metrics.conversions_value
3287
+
3288
+ ### Common Segments
3289
+ segments.date, segments.device, segments.ad_network_type
3290
+
3291
+ ### Date Filters
3292
+ - \`DURING LAST_7_DAYS\`, \`DURING LAST_30_DAYS\`, \`DURING THIS_MONTH\`
3293
+ - \`WHERE segments.date BETWEEN '2024-01-01' AND '2024-01-31'\`
3294
+
3295
+ ### Tips
3296
+ - cost_micros is in micros (divide by 1,000,000 for actual currency)
3297
+ - Use LIMIT to restrict result count
3298
+ - Always include relevant WHERE clauses to filter data
3299
+
3300
+ ## Google Ads SDK (TypeScript handler)
3301
+
3302
+ \`\`\`ts
3303
+ import { connection } from "@squadbase/vite-server/connectors/google-ads-oauth";
3304
+
3305
+ const ads = connection("<connectionId>");
3306
+
3307
+ // Execute a GAQL query
3308
+ const rows = await ads.search(
3309
+ "SELECT campaign.name, metrics.impressions, metrics.clicks FROM campaign WHERE segments.date DURING LAST_7_DAYS"
3310
+ );
3311
+ rows.forEach(row => console.log(row));
3312
+
3313
+ // List accessible customer accounts
3314
+ const customerIds = await ads.listAccessibleCustomers();
3315
+ \`\`\``,
3316
+ tools: tools11,
3317
+ async checkConnection(params, config) {
3318
+ const { proxyFetch } = config;
3319
+ const rawCustomerId = params[parameters2.customerId.slug];
3320
+ const customerId = rawCustomerId?.replace(/-/g, "");
3321
+ if (!customerId) {
3322
+ return { success: true };
3323
+ }
3324
+ const developerToken = params[parameters2.developerToken.slug];
3325
+ if (!developerToken) {
3326
+ return {
3327
+ success: false,
3328
+ error: "Developer token is required"
3329
+ };
3330
+ }
3331
+ const url = `https://googleads.googleapis.com/v18/customers/${customerId}/googleAds:searchStream`;
3332
+ try {
3333
+ const res = await proxyFetch(url, {
3334
+ method: "POST",
3335
+ headers: {
3336
+ "Content-Type": "application/json",
3337
+ "developer-token": developerToken,
3338
+ "login-customer-id": customerId
3339
+ },
3340
+ body: JSON.stringify({
3341
+ query: "SELECT customer.id FROM customer LIMIT 1"
3342
+ })
3343
+ });
3344
+ if (!res.ok) {
3345
+ const errorText = await res.text().catch(() => res.statusText);
3346
+ return {
3347
+ success: false,
3348
+ error: `Google Ads API failed: HTTP ${res.status} ${errorText}`
3349
+ };
3350
+ }
3351
+ return { success: true };
3352
+ } catch (error) {
3353
+ return {
3354
+ success: false,
3355
+ error: error instanceof Error ? error.message : String(error)
3356
+ };
3357
+ }
3358
+ }
3359
+ });
3360
+
3361
+ // src/connectors/google-analytics/tools/request.ts
3362
+ import { z as z17 } from "zod";
3363
+ var BASE_URL4 = "https://analyticsdata.googleapis.com/v1beta/";
3364
+ var REQUEST_TIMEOUT_MS7 = 6e4;
3365
+ var inputSchema17 = z17.object({
3366
+ toolUseIntent: z17.string().optional().describe("Brief description of what you intend to accomplish with this tool call"),
3367
+ connectionId: z17.string().describe("ID of the Google Analytics connection to use"),
3368
+ method: z17.enum(["GET", "POST"]).describe("HTTP method"),
3369
+ path: z17.string().describe("API path (e.g., 'properties/{propertyId}:runReport'). {propertyId} is automatically replaced."),
3370
+ body: z17.record(z17.string(), z17.unknown()).optional().describe("POST request body (JSON)")
3371
+ });
3372
+ var outputSchema17 = z17.discriminatedUnion("success", [
3373
+ z17.object({
3374
+ success: z17.literal(true),
3375
+ status: z17.number(),
3376
+ data: z17.record(z17.string(), z17.unknown())
3377
+ }),
3378
+ z17.object({
3379
+ success: z17.literal(false),
3380
+ error: z17.string()
3381
+ })
3382
+ ]);
3383
+ var requestTool3 = new ConnectorTool({
3384
+ name: "request",
3385
+ description: `Send authenticated requests to the Google Analytics Data API.
3386
+ Authentication is handled automatically using a service account.
3387
+ {propertyId} in the path is automatically replaced with the connection's property-id.`,
3388
+ inputSchema: inputSchema17,
3389
+ outputSchema: outputSchema17,
3390
+ async execute({ connectionId, method, path, body }, connections) {
3391
+ const connection = connections.find((c) => c.id === connectionId);
3392
+ if (!connection) {
3393
+ return { success: false, error: `Connection ${connectionId} not found` };
3394
+ }
3395
+ console.log(`[connector-request] google-analytics/${connection.name}: ${method} ${path}`);
3396
+ try {
3397
+ const { GoogleAuth } = await import("google-auth-library");
3398
+ const keyJsonBase64 = parameters3.serviceAccountKeyJsonBase64.getValue(connection);
3399
+ const propertyId = parameters3.propertyId.getValue(connection);
3400
+ const credentials = JSON.parse(
3401
+ Buffer.from(keyJsonBase64, "base64").toString("utf-8")
3402
+ );
3403
+ const auth = new GoogleAuth({
3404
+ credentials,
3405
+ scopes: ["https://www.googleapis.com/auth/analytics.readonly"]
3406
+ });
3407
+ const token = await auth.getAccessToken();
3408
+ if (!token) {
3409
+ return { success: false, error: "Failed to obtain access token" };
3410
+ }
3411
+ const resolvedPath = path.replace(/\{propertyId\}/g, propertyId);
3412
+ const url = `${BASE_URL4}${resolvedPath}`;
3413
+ const controller = new AbortController();
3414
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS7);
3415
+ try {
3416
+ const response = await fetch(url, {
3417
+ method,
3418
+ headers: {
3419
+ Authorization: `Bearer ${token}`,
3420
+ "Content-Type": "application/json"
3421
+ },
3422
+ body: method === "POST" && body ? JSON.stringify(body) : void 0,
3423
+ signal: controller.signal
3424
+ });
3425
+ const data = await response.json();
3426
+ if (!response.ok) {
3427
+ const errorObj = data?.error;
3428
+ return {
3429
+ success: false,
3430
+ error: errorObj?.message ?? `HTTP ${response.status} ${response.statusText}`
3431
+ };
3432
+ }
3433
+ return { success: true, status: response.status, data };
3434
+ } finally {
3435
+ clearTimeout(timeout);
3436
+ }
3437
+ } catch (err) {
3438
+ const msg = err instanceof Error ? err.message : String(err);
3439
+ return { success: false, error: msg };
3440
+ }
3441
+ }
3442
+ });
3443
+
3444
+ // src/connectors/google-analytics/index.ts
3445
+ var tools12 = { request: requestTool3 };
3446
+ var googleAnalyticsConnector = new ConnectorPlugin({
3447
+ slug: "google-analytics",
3448
+ authType: null,
3449
+ name: "Google Analytics",
3450
+ description: "Connect to Google Analytics for web analytics and reporting.",
3451
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/7fs0ipzxuD9mACDzBATtxX/3c53ed90d15c96483e4f78cb29dab5e9/google-analytics.svg",
3452
+ parameters: parameters3,
3453
+ releaseFlag: { dev1: true, dev2: true, prod: true },
3454
+ systemPrompt: `## Google Analytics Data API
3455
+ - Call the GA4 Data API using the authenticated request tool
3456
+ - {propertyId} in the path is automatically replaced
3457
+
3458
+ ### Get Metadata (Check available dimensions and metrics)
3459
+ - GET properties/{propertyId}/metadata
3460
+
3461
+ ### Get Report
3462
+ - POST properties/{propertyId}:runReport
3463
+ - Body example:
3464
+ {
3465
+ "dateRanges": [{"startDate": "7daysAgo", "endDate": "today"}],
3466
+ "dimensions": [{"name": "date"}],
3467
+ "metrics": [{"name": "activeUsers"}],
3468
+ "limit": 100
3469
+ }
3470
+
3471
+ ### Common Dimensions
3472
+ date, country, city, deviceCategory, browser, pagePath, pageTitle,
3473
+ sessionSource, sessionMedium, eventName
3474
+
3475
+ ### Common Metrics
3476
+ activeUsers, sessions, screenPageViews, bounceRate,
3477
+ averageSessionDuration, conversions, totalRevenue
3478
+
3479
+ ### Date Specification
3480
+ - Absolute: "2024-01-01"
3481
+ - Relative: "today", "yesterday", "7daysAgo", "30daysAgo"
3482
+
3483
+ ## Google Analytics SDK (TypeScript handler)
3484
+ Non-SQL connectors like Google Analytics can also be used via the SDK in TypeScript handlers:
3485
+
3486
+ \`\`\`ts
3487
+ import { connection } from "@squadbase/vite-server/connectors/google-analytics";
3488
+
3489
+ const ga = connection("<connectionId>");
3490
+
3491
+ // Authenticated fetch (returns standard Response)
3492
+ const res = await ga.request("properties/{propertyId}:runReport", {
3493
+ method: "POST",
3494
+ body: JSON.stringify({ dateRanges: [{ startDate: "7daysAgo", endDate: "today" }], metrics: [{ name: "activeUsers" }] }),
3495
+ });
3496
+ const data = await res.json();
3497
+
3498
+ // Convenience methods
3499
+ const { rows, rowCount } = await ga.runReport({
3500
+ dateRanges: [{ startDate: "7daysAgo", endDate: "today" }],
3501
+ dimensions: [{ name: "date" }],
3502
+ metrics: [{ name: "activeUsers" }, { name: "sessions" }],
3503
+ limit: 100,
3504
+ });
3505
+ const metadata = await ga.getMetadata();
3506
+ const realtime = await ga.runRealtimeReport({
3507
+ metrics: [{ name: "activeUsers" }],
3508
+ dimensions: [{ name: "country" }],
3509
+ });
3510
+ \`\`\``,
3511
+ tools: tools12
3512
+ });
3513
+
3514
+ // src/connectors/google-analytics-oauth/tools/list-accounts.ts
3515
+ import { z as z18 } from "zod";
3516
+ var ADMIN_BASE_URL = "https://analyticsadmin.googleapis.com/v1beta/";
3517
+ var REQUEST_TIMEOUT_MS8 = 6e4;
3518
+ var cachedToken6 = null;
3519
+ async function getProxyToken6(config) {
3520
+ if (cachedToken6 && cachedToken6.expiresAt > Date.now() + 6e4) {
3521
+ return cachedToken6.token;
3522
+ }
3523
+ const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
3524
+ const res = await fetch(url, {
3525
+ method: "POST",
3526
+ headers: {
3527
+ "Content-Type": "application/json",
3528
+ "x-api-key": config.appApiKey,
3529
+ "project-id": config.projectId
3530
+ },
3531
+ body: JSON.stringify({
3532
+ sandboxId: config.sandboxId,
3533
+ issuedBy: "coding-agent"
3534
+ })
3535
+ });
3536
+ if (!res.ok) {
3537
+ const errorText = await res.text().catch(() => res.statusText);
3538
+ throw new Error(
3539
+ `Failed to get proxy token: HTTP ${res.status} ${errorText}`
3540
+ );
3541
+ }
3542
+ const data = await res.json();
3543
+ cachedToken6 = {
3544
+ token: data.token,
3545
+ expiresAt: new Date(data.expiresAt).getTime()
3546
+ };
3547
+ return data.token;
3548
+ }
3549
+ var inputSchema18 = z18.object({
3550
+ toolUseIntent: z18.string().optional().describe(
3551
+ "Brief description of what you intend to accomplish with this tool call"
3552
+ ),
3553
+ connectionId: z18.string().describe("ID of the Google Analytics OAuth connection to use")
3554
+ });
3555
+ var outputSchema18 = z18.discriminatedUnion("success", [
3556
+ z18.object({
3557
+ success: z18.literal(true),
3558
+ accounts: z18.array(
3559
+ z18.object({
3560
+ name: z18.string(),
3561
+ displayName: z18.string()
3562
+ })
3563
+ )
3564
+ }),
3565
+ z18.object({
3566
+ success: z18.literal(false),
3567
+ error: z18.string()
3568
+ })
3569
+ ]);
3570
+ var listAccountsTool = new ConnectorTool({
3571
+ name: "listAccounts",
3572
+ description: "List Google Analytics accounts accessible with the current OAuth credentials. Returns account names and display names.",
3573
+ inputSchema: inputSchema18,
3574
+ outputSchema: outputSchema18,
3575
+ async execute({ connectionId }, connections, config) {
3576
+ const connection = connections.find((c) => c.id === connectionId);
3577
+ if (!connection) {
3578
+ return {
3579
+ success: false,
3580
+ error: `Connection ${connectionId} not found`
3581
+ };
3582
+ }
3583
+ console.log(
3584
+ `[connector-request] google-analytics-oauth/${connection.name}: listAccounts`
3585
+ );
3586
+ try {
3587
+ const token = await getProxyToken6(config.oauthProxy);
3588
+ const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
3589
+ const controller = new AbortController();
3590
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS8);
3591
+ try {
3592
+ const response = await fetch(proxyUrl, {
3593
+ method: "POST",
3594
+ headers: {
3595
+ "Content-Type": "application/json",
3596
+ Authorization: `Bearer ${token}`
3597
+ },
3598
+ body: JSON.stringify({
3599
+ url: `${ADMIN_BASE_URL}accounts`,
3600
+ method: "GET"
3601
+ }),
3602
+ signal: controller.signal
3603
+ });
3604
+ const data = await response.json();
3605
+ if (!response.ok) {
3606
+ const errorMessage = typeof data?.error === "string" ? data.error : typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`;
3607
+ return { success: false, error: errorMessage };
3608
+ }
3609
+ const accounts = (data.accounts ?? []).map((a) => ({
3610
+ name: a.name ?? "",
3611
+ displayName: a.displayName ?? ""
3612
+ }));
3613
+ return { success: true, accounts };
3614
+ } finally {
3615
+ clearTimeout(timeout);
3616
+ }
3617
+ } catch (err) {
3618
+ const msg = err instanceof Error ? err.message : String(err);
3619
+ return { success: false, error: msg };
3620
+ }
3621
+ }
3622
+ });
3623
+
3624
+ // src/connectors/google-analytics-oauth/tools/list-properties.ts
3625
+ import { z as z19 } from "zod";
3626
+ var ADMIN_BASE_URL2 = "https://analyticsadmin.googleapis.com/v1beta/";
3627
+ var REQUEST_TIMEOUT_MS9 = 6e4;
3628
+ var cachedToken7 = null;
3629
+ async function getProxyToken7(config) {
3630
+ if (cachedToken7 && cachedToken7.expiresAt > Date.now() + 6e4) {
3631
+ return cachedToken7.token;
3632
+ }
3633
+ const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
3634
+ const res = await fetch(url, {
3635
+ method: "POST",
3636
+ headers: {
3637
+ "Content-Type": "application/json",
3638
+ "x-api-key": config.appApiKey,
3639
+ "project-id": config.projectId
3640
+ },
3641
+ body: JSON.stringify({
3642
+ sandboxId: config.sandboxId,
3643
+ issuedBy: "coding-agent"
3644
+ })
3645
+ });
3646
+ if (!res.ok) {
3647
+ const errorText = await res.text().catch(() => res.statusText);
3648
+ throw new Error(
3649
+ `Failed to get proxy token: HTTP ${res.status} ${errorText}`
3650
+ );
3651
+ }
3652
+ const data = await res.json();
3653
+ cachedToken7 = {
3654
+ token: data.token,
3655
+ expiresAt: new Date(data.expiresAt).getTime()
3656
+ };
3657
+ return data.token;
3658
+ }
3659
+ var inputSchema19 = z19.object({
3660
+ toolUseIntent: z19.string().optional().describe(
3661
+ "Brief description of what you intend to accomplish with this tool call"
3662
+ ),
3663
+ connectionId: z19.string().describe("ID of the Google Analytics OAuth connection to use"),
3664
+ accountName: z19.string().describe(
3665
+ "The account resource name (e.g., 'accounts/123456'). Obtained from the listAccounts tool."
3666
+ )
3667
+ });
3668
+ var outputSchema19 = z19.discriminatedUnion("success", [
3669
+ z19.object({
3670
+ success: z19.literal(true),
3671
+ properties: z19.array(
3672
+ z19.object({
3673
+ name: z19.string(),
3674
+ displayName: z19.string(),
3675
+ propertyId: z19.string()
3676
+ })
3677
+ )
3678
+ }),
3679
+ z19.object({
3680
+ success: z19.literal(false),
3681
+ error: z19.string()
3682
+ })
3683
+ ]);
3684
+ var listPropertiesTool = new ConnectorTool({
3685
+ name: "listProperties",
3686
+ description: "List GA4 properties for a given Google Analytics account. Returns property names, display names, and property IDs.",
3687
+ inputSchema: inputSchema19,
3688
+ outputSchema: outputSchema19,
3689
+ async execute({ connectionId, accountName }, connections, config) {
3690
+ const connection = connections.find((c) => c.id === connectionId);
3691
+ if (!connection) {
3692
+ return {
3693
+ success: false,
3694
+ error: `Connection ${connectionId} not found`
3695
+ };
3696
+ }
3697
+ console.log(
3698
+ `[connector-request] google-analytics-oauth/${connection.name}: listProperties for ${accountName}`
3699
+ );
3700
+ try {
3701
+ const token = await getProxyToken7(config.oauthProxy);
3702
+ const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
3703
+ const controller = new AbortController();
3704
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS9);
3705
+ try {
3706
+ const filter = encodeURIComponent(`parent:${accountName}`);
3707
+ const response = await fetch(proxyUrl, {
3708
+ method: "POST",
3709
+ headers: {
3710
+ "Content-Type": "application/json",
3711
+ Authorization: `Bearer ${token}`
3712
+ },
3713
+ body: JSON.stringify({
3714
+ url: `${ADMIN_BASE_URL2}properties?filter=${filter}`,
3715
+ method: "GET"
3716
+ }),
3717
+ signal: controller.signal
3718
+ });
3719
+ const data = await response.json();
3720
+ if (!response.ok) {
3721
+ const errorMessage = typeof data?.error === "string" ? data.error : typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`;
3722
+ return { success: false, error: errorMessage };
3723
+ }
3724
+ const properties = (data.properties ?? []).map((p) => {
3725
+ const name = p.name ?? "";
3726
+ const propertyId = name.replace(/^properties\//, "");
3727
+ return {
3728
+ name,
3729
+ displayName: p.displayName ?? "",
3730
+ propertyId
3731
+ };
3732
+ });
3733
+ return { success: true, properties };
3734
+ } finally {
3735
+ clearTimeout(timeout);
3736
+ }
3737
+ } catch (err) {
3738
+ const msg = err instanceof Error ? err.message : String(err);
3739
+ return { success: false, error: msg };
3740
+ }
3741
+ }
3742
+ });
3743
+
3744
+ // src/connectors/google-analytics-oauth/setup.ts
3745
+ var listAccountsToolName = `google-analytics-oauth_${listAccountsTool.name}`;
3746
+ var listPropertiesToolName = `google-analytics-oauth_${listPropertiesTool.name}`;
3747
+ var googleAnalyticsOauthSetup = new ConnectorSetup({
3748
+ ja: `## Google Analytics \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u624B\u9806
3749
+
3750
+ \u4EE5\u4E0B\u306E\u624B\u9806\u3067Google Analytics (OAuth) \u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044\u3002
3751
+
3752
+ ### \u624B\u9806
3753
+
3754
+ #### \u30B9\u30C6\u30C3\u30D71: \u30A2\u30AB\u30A6\u30F3\u30C8\u9078\u629E
3755
+ 1. \`${listAccountsToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001OAuth\u3067\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306AGoogle Analytics\u30A2\u30AB\u30A6\u30F3\u30C8\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
3756
+ 2. \u300C\u4F7F\u7528\u3059\u308B\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u300D\u3068\u30E6\u30FC\u30B6\u30FC\u306B\u4F1D\u3048\u305F\u4E0A\u3067\u3001\`askUserQuestion\` \u3092\u547C\u3073\u51FA\u3059:
3757
+ - \`options\`: \u30A2\u30AB\u30A6\u30F3\u30C8\u4E00\u89A7\u3002\u5404 option \u306E \`label\` \u306F \`\u8868\u793A\u540D (name)\` \u306E\u5F62\u5F0F
3758
+
3759
+ #### \u30B9\u30C6\u30C3\u30D72: \u30D7\u30ED\u30D1\u30C6\u30A3\u9078\u629E
3760
+ 1. \`${listPropertiesToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001\u9078\u629E\u3055\u308C\u305F\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
3761
+ 2. \`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
3762
+ - \`parameterSlug\`: \`"property-id"\`
3763
+ - \`options\`: \u30D7\u30ED\u30D1\u30C6\u30A3\u4E00\u89A7\u3002\u5404 option \u306E \`label\` \u306F \`\u8868\u793A\u540D (id: \u30D7\u30ED\u30D1\u30C6\u30A3ID)\` \u306E\u5F62\u5F0F\u3001\`value\` \u306F\u30D7\u30ED\u30D1\u30C6\u30A3ID
3764
+ 3. \u30E6\u30FC\u30B6\u30FC\u304C\u9078\u629E\u3057\u305F\u30D7\u30ED\u30D1\u30C6\u30A3\u306E \`label\` \u304C\u30E1\u30C3\u30BB\u30FC\u30B8\u3068\u3057\u3066\u5C4A\u304F\u306E\u3067\u3001\u30B9\u30C6\u30C3\u30D73\u306B\u9032\u3080
3765
+
3766
+ #### \u30B9\u30C6\u30C3\u30D73: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5B8C\u4E86
3767
+ 1. \`updateConnectionContext\` \u3092\u547C\u3073\u51FA\u3059:
3768
+ - \`property\`: \u9078\u629E\u3055\u308C\u305F\u30D7\u30ED\u30D1\u30C6\u30A3\u306E\u8868\u793A\u540D
3769
+ - \`propertyId\`: \u9078\u629E\u3055\u308C\u305F\u30D7\u30ED\u30D1\u30C6\u30A3ID
3770
+ - \`note\`: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5185\u5BB9\u306E\u7C21\u5358\u306A\u8AAC\u660E
3771
+
3772
+ ### \u91CD\u8981\u306A\u5236\u7D04
3773
+ - **\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u4E2D\u306B\u30EC\u30DD\u30FC\u30C8\u30C7\u30FC\u30BF\u3092\u53D6\u5F97\u3057\u306A\u3044\u3053\u3068**\u3002\u5B9F\u884C\u3057\u3066\u3088\u3044\u306E\u306F\u4E0A\u8A18\u624B\u9806\u3067\u6307\u5B9A\u3055\u308C\u305F\u30E1\u30BF\u30C7\u30FC\u30BF\u53D6\u5F97\u306E\u307F
3774
+
3775
+ ### \u5B9F\u884C\u65B9\u91DD
3776
+ - \u30C4\u30FC\u30EB\u9593\u306F1\u6587\u3060\u3051\u66F8\u3044\u3066\u5373\u6B21\u306E\u30C4\u30FC\u30EB\u547C\u3073\u51FA\u3057
3777
+ - \u4E0D\u8981\u306A\u8AAC\u660E\u306F\u7701\u7565\u3057\u3001\u52B9\u7387\u7684\u306B\u9032\u3081\u308B`,
3778
+ en: `## Google Analytics Setup Instructions
3779
+
3780
+ Follow these steps to set up the Google Analytics (OAuth) connection.
3781
+
3782
+ ### Steps
3783
+
3784
+ #### Step 1: Account Selection
3785
+ 1. Call \`${listAccountsToolName}\` to get the list of Google Analytics accounts accessible with the OAuth credentials
3786
+ 2. Tell the user "Please select an account.", then call \`askUserQuestion\`:
3787
+ - \`options\`: The account list. Each option's \`label\` should be \`Display Name (name)\`
3788
+
3789
+ #### Step 2: Property Selection
3790
+ 1. Call \`${listPropertiesToolName}\` to get the list of properties for the selected account
3791
+ 2. Call \`updateConnectionParameters\`:
3792
+ - \`parameterSlug\`: \`"property-id"\`
3793
+ - \`options\`: The property list. Each option's \`label\` should be \`Display Name (id: propertyId)\`, \`value\` should be the property ID
3794
+ 3. The \`label\` of the user's selected property will arrive as a message. Proceed to Step 3
3795
+
3796
+ #### Step 3: Complete Setup
3797
+ 1. Call \`updateConnectionContext\`:
3798
+ - \`property\`: The selected property's display name
3799
+ - \`propertyId\`: The selected property ID
3800
+ - \`note\`: Brief description of the setup
3801
+
3802
+ ### Important Constraints
3803
+ - **Do NOT fetch report data during setup**. Only the metadata requests specified in the steps above are allowed
3804
+
3805
+ ### Execution Policy
3806
+ - Write only 1 sentence between tool calls, then immediately call the next tool
3807
+ - Skip unnecessary explanations and proceed efficiently`
3808
+ });
3809
+
3810
+ // src/connectors/google-analytics-oauth/tools/request.ts
3811
+ import { z as z20 } from "zod";
3812
+ var BASE_URL5 = "https://analyticsdata.googleapis.com/v1beta/";
3813
+ var REQUEST_TIMEOUT_MS10 = 6e4;
3814
+ var cachedToken8 = null;
3815
+ async function getProxyToken8(config) {
3816
+ if (cachedToken8 && cachedToken8.expiresAt > Date.now() + 6e4) {
3817
+ return cachedToken8.token;
3818
+ }
3819
+ const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
3820
+ const res = await fetch(url, {
3821
+ method: "POST",
3822
+ headers: {
3823
+ "Content-Type": "application/json",
3824
+ "x-api-key": config.appApiKey,
3825
+ "project-id": config.projectId
3826
+ },
3827
+ body: JSON.stringify({
3828
+ sandboxId: config.sandboxId,
3829
+ issuedBy: "coding-agent"
3830
+ })
3831
+ });
3832
+ if (!res.ok) {
3833
+ const errorText = await res.text().catch(() => res.statusText);
3834
+ throw new Error(
3835
+ `Failed to get proxy token: HTTP ${res.status} ${errorText}`
3836
+ );
3837
+ }
3838
+ const data = await res.json();
3839
+ cachedToken8 = {
3840
+ token: data.token,
3841
+ expiresAt: new Date(data.expiresAt).getTime()
3842
+ };
3843
+ return data.token;
3844
+ }
3845
+ var inputSchema20 = z20.object({
3846
+ toolUseIntent: z20.string().optional().describe(
3847
+ "Brief description of what you intend to accomplish with this tool call"
3848
+ ),
3849
+ connectionId: z20.string().describe("ID of the Google Analytics OAuth connection to use"),
3850
+ method: z20.enum(["GET", "POST"]).describe("HTTP method"),
3851
+ path: z20.string().describe(
3852
+ "API path appended to https://analyticsdata.googleapis.com/v1beta/ (e.g., 'properties/{propertyId}:runReport'). {propertyId} is automatically replaced."
3853
+ ),
3854
+ body: z20.record(z20.string(), z20.unknown()).optional().describe("POST request body (JSON)")
3855
+ });
3856
+ var outputSchema20 = z20.discriminatedUnion("success", [
3857
+ z20.object({
3858
+ success: z20.literal(true),
3859
+ status: z20.number(),
3860
+ data: z20.record(z20.string(), z20.unknown())
3861
+ }),
3862
+ z20.object({
3863
+ success: z20.literal(false),
3864
+ error: z20.string()
3865
+ })
3866
+ ]);
3867
+ var requestTool4 = new ConnectorTool({
3868
+ name: "request",
3869
+ description: `Send authenticated requests to the Google Analytics Data API v1beta.
3870
+ Authentication is handled automatically via OAuth proxy.
3871
+ {propertyId} in the path is automatically replaced with the connection's property ID.`,
3872
+ inputSchema: inputSchema20,
3873
+ outputSchema: outputSchema20,
3874
+ async execute({ connectionId, method, path, body }, connections, config) {
3875
+ const connection = connections.find((c) => c.id === connectionId);
3876
+ if (!connection) {
3877
+ return {
3878
+ success: false,
3879
+ error: `Connection ${connectionId} not found`
3880
+ };
3881
+ }
3882
+ console.log(
3883
+ `[connector-request] google-analytics-oauth/${connection.name}: ${method} ${path}`
3884
+ );
3885
+ try {
3886
+ const propertyId = parameters4.propertyId.tryGetValue(connection);
3887
+ const resolvedPath = propertyId ? path.replace(/\{propertyId\}/g, propertyId) : path;
3888
+ const url = `${BASE_URL5}${resolvedPath}`;
3889
+ const token = await getProxyToken8(config.oauthProxy);
3890
+ const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
3891
+ const controller = new AbortController();
3892
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS10);
3893
+ try {
3894
+ const response = await fetch(proxyUrl, {
3895
+ method: "POST",
3896
+ headers: {
3897
+ "Content-Type": "application/json",
3898
+ Authorization: `Bearer ${token}`
3899
+ },
3900
+ body: JSON.stringify({
3901
+ url,
3902
+ method,
3903
+ ...method === "POST" && body ? {
3904
+ headers: { "Content-Type": "application/json" },
3905
+ body: JSON.stringify(body)
3906
+ } : {}
3907
+ }),
3908
+ signal: controller.signal
3909
+ });
3910
+ const data = await response.json();
3911
+ if (!response.ok) {
3912
+ const errorMessage = typeof data?.error === "string" ? data.error : typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`;
3913
+ return { success: false, error: errorMessage };
3914
+ }
3915
+ return { success: true, status: response.status, data };
3916
+ } finally {
3917
+ clearTimeout(timeout);
3918
+ }
3919
+ } catch (err) {
3920
+ const msg = err instanceof Error ? err.message : String(err);
3921
+ return { success: false, error: msg };
3922
+ }
3923
+ }
3924
+ });
3925
+
3926
+ // src/connectors/google-analytics-oauth/index.ts
3927
+ var tools13 = {
3928
+ request: requestTool4,
3929
+ listAccounts: listAccountsTool,
3930
+ listProperties: listPropertiesTool
3931
+ };
3932
+ var googleAnalyticsOauthConnector = new ConnectorPlugin({
3933
+ slug: "google-analytics",
3934
+ authType: AUTH_TYPES.OAUTH,
3935
+ name: "Google Analytics (OAuth)",
3936
+ description: "Connect to Google Analytics for web analytics and reporting using OAuth.",
3937
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/7fs0ipzxuD9mACDzBATtxX/3c53ed90d15c96483e4f78cb29dab5e9/google-analytics.svg",
3938
+ parameters: parameters4,
3939
+ releaseFlag: { dev1: true, dev2: false, prod: false },
3940
+ setup: googleAnalyticsOauthSetup,
3941
+ proxyPolicy: {
3942
+ allowlist: [
3943
+ {
3944
+ host: "analyticsdata.googleapis.com",
3945
+ methods: ["GET", "POST"]
3946
+ },
3947
+ {
3948
+ host: "analyticsadmin.googleapis.com",
3949
+ methods: ["GET"]
3950
+ }
3951
+ ]
3952
+ },
3953
+ systemPrompt: `## Google Analytics Data API (OAuth, Read-Only)
3954
+ - Call the GA4 Data API using the authenticated request tool
3955
+ - {propertyId} in the path is automatically replaced
3956
+
3957
+ ### Get Metadata (Check available dimensions and metrics)
3958
+ - GET properties/{propertyId}/metadata
3959
+
3960
+ ### Get Report
3961
+ - POST properties/{propertyId}:runReport
3962
+ - Body example:
3963
+ {
3964
+ "dateRanges": [{"startDate": "7daysAgo", "endDate": "today"}],
3965
+ "dimensions": [{"name": "date"}],
3966
+ "metrics": [{"name": "activeUsers"}],
3967
+ "limit": 100
3968
+ }
3969
+
3970
+ ### Common Dimensions
3971
+ date, country, city, deviceCategory, browser, pagePath, pageTitle,
3972
+ sessionSource, sessionMedium, eventName
3973
+
3974
+ ### Common Metrics
3975
+ activeUsers, sessions, screenPageViews, bounceRate,
3976
+ averageSessionDuration, conversions, totalRevenue
3977
+
3978
+ ### Date Specification
3979
+ - Absolute: "2024-01-01"
3980
+ - Relative: "today", "yesterday", "7daysAgo", "30daysAgo"
3981
+
3982
+ ## Google Analytics SDK (TypeScript handler)
3983
+
3984
+ \`\`\`ts
3985
+ import { connection } from "@squadbase/vite-server/connectors/google-analytics-oauth";
3986
+
3987
+ const ga = connection("<connectionId>");
3988
+
3989
+ // Authenticated fetch (returns standard Response)
3990
+ const res = await ga.request("properties/{propertyId}:runReport", {
3991
+ method: "POST",
3992
+ body: JSON.stringify({ dateRanges: [{ startDate: "7daysAgo", endDate: "today" }], metrics: [{ name: "activeUsers" }] }),
3993
+ });
3994
+ const data = await res.json();
3995
+
3996
+ // Convenience methods
3997
+ const { rows, rowCount } = await ga.runReport({
3998
+ dateRanges: [{ startDate: "7daysAgo", endDate: "today" }],
3999
+ dimensions: [{ name: "date" }],
4000
+ metrics: [{ name: "activeUsers" }, { name: "sessions" }],
4001
+ limit: 100,
4002
+ });
4003
+ const metadata = await ga.getMetadata();
4004
+ const realtime = await ga.runRealtimeReport({
4005
+ metrics: [{ name: "activeUsers" }],
4006
+ dimensions: [{ name: "country" }],
4007
+ });
4008
+ \`\`\``,
4009
+ tools: tools13,
4010
+ async checkConnection(params, config) {
4011
+ const { proxyFetch } = config;
4012
+ const propertyId = params[parameters4.propertyId.slug];
4013
+ if (!propertyId) {
4014
+ return { success: true };
4015
+ }
4016
+ const url = `https://analyticsdata.googleapis.com/v1beta/properties/${propertyId}/metadata`;
4017
+ try {
4018
+ const res = await proxyFetch(url, { method: "GET" });
4019
+ if (!res.ok) {
4020
+ const errorText = await res.text().catch(() => res.statusText);
4021
+ return {
4022
+ success: false,
4023
+ error: `Google Analytics API failed: HTTP ${res.status} ${errorText}`
4024
+ };
4025
+ }
4026
+ return { success: true };
4027
+ } catch (error) {
4028
+ return {
4029
+ success: false,
4030
+ error: error instanceof Error ? error.message : String(error)
4031
+ };
4032
+ }
4033
+ }
4034
+ });
4035
+
4036
+ // src/connectors/google-sheets-oauth/tools/request.ts
4037
+ import { z as z21 } from "zod";
4038
+ var BASE_URL6 = "https://sheets.googleapis.com/v4/spreadsheets";
4039
+ var REQUEST_TIMEOUT_MS11 = 6e4;
4040
+ var cachedToken9 = null;
4041
+ async function getProxyToken9(config) {
4042
+ if (cachedToken9 && cachedToken9.expiresAt > Date.now() + 6e4) {
4043
+ return cachedToken9.token;
4044
+ }
4045
+ const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
4046
+ const res = await fetch(url, {
4047
+ method: "POST",
4048
+ headers: {
4049
+ "Content-Type": "application/json",
4050
+ "x-api-key": config.appApiKey,
4051
+ "project-id": config.projectId
4052
+ },
4053
+ body: JSON.stringify({
4054
+ sandboxId: config.sandboxId,
4055
+ issuedBy: "coding-agent"
4056
+ })
4057
+ });
4058
+ if (!res.ok) {
4059
+ const errorText = await res.text().catch(() => res.statusText);
4060
+ throw new Error(
4061
+ `Failed to get proxy token: HTTP ${res.status} ${errorText}`
4062
+ );
4063
+ }
4064
+ const data = await res.json();
4065
+ cachedToken9 = {
4066
+ token: data.token,
4067
+ expiresAt: new Date(data.expiresAt).getTime()
4068
+ };
4069
+ return data.token;
4070
+ }
4071
+ var inputSchema21 = z21.object({
4072
+ toolUseIntent: z21.string().optional().describe(
4073
+ "Brief description of what you intend to accomplish with this tool call"
4074
+ ),
4075
+ connectionId: z21.string().describe("ID of the Google Sheets OAuth connection to use"),
4076
+ method: z21.enum(["GET"]).describe("HTTP method (read-only, GET only)"),
4077
+ path: z21.string().describe(
4078
+ "API path appended to https://sheets.googleapis.com/v4/spreadsheets (e.g., '/{spreadsheetId}', '/{spreadsheetId}/values/Sheet1!A1:D10'). {spreadsheetId} is automatically replaced if a default is configured."
4079
+ ),
4080
+ queryParams: z21.record(z21.string(), z21.string()).optional().describe("Query parameters to append to the URL")
4081
+ });
4082
+ var outputSchema21 = z21.discriminatedUnion("success", [
4083
+ z21.object({
4084
+ success: z21.literal(true),
4085
+ status: z21.number(),
4086
+ data: z21.record(z21.string(), z21.unknown())
4087
+ }),
4088
+ z21.object({
4089
+ success: z21.literal(false),
4090
+ error: z21.string()
4091
+ })
4092
+ ]);
4093
+ var requestTool5 = new ConnectorTool({
4094
+ name: "request",
4095
+ description: `Send authenticated GET requests to the Google Sheets API v4.
4096
+ Authentication is handled automatically via OAuth proxy.
4097
+ {spreadsheetId} in the path is automatically replaced with the connection's default spreadsheet ID if configured.`,
4098
+ inputSchema: inputSchema21,
4099
+ outputSchema: outputSchema21,
4100
+ async execute({ connectionId, method, path, queryParams }, connections, config) {
4101
+ const connection = connections.find((c) => c.id === connectionId);
4102
+ if (!connection) {
4103
+ return {
4104
+ success: false,
4105
+ error: `Connection ${connectionId} not found`
4106
+ };
4107
+ }
4108
+ console.log(
4109
+ `[connector-request] google-sheets-oauth/${connection.name}: ${method} ${path}`
4110
+ );
4111
+ try {
4112
+ const spreadsheetId = parameters5.spreadsheetId.tryGetValue(connection);
4113
+ const resolvedPath = spreadsheetId ? path.replace(/\{spreadsheetId\}/g, spreadsheetId) : path;
4114
+ let url = `${BASE_URL6}${resolvedPath.startsWith("/") ? "" : "/"}${resolvedPath}`;
4115
+ if (queryParams) {
4116
+ const searchParams = new URLSearchParams(queryParams);
4117
+ url += `?${searchParams.toString()}`;
4118
+ }
4119
+ const token = await getProxyToken9(config.oauthProxy);
4120
+ const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
4121
+ const controller = new AbortController();
4122
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS11);
4123
+ try {
4124
+ const response = await fetch(proxyUrl, {
4125
+ method: "POST",
4126
+ headers: {
4127
+ "Content-Type": "application/json",
4128
+ Authorization: `Bearer ${token}`
4129
+ },
4130
+ body: JSON.stringify({
4131
+ url,
4132
+ method
4133
+ }),
4134
+ signal: controller.signal
4135
+ });
4136
+ const data = await response.json();
4137
+ if (!response.ok) {
4138
+ const errorMessage = typeof data?.error === "string" ? data.error : typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`;
4139
+ return { success: false, error: errorMessage };
4140
+ }
4141
+ return { success: true, status: response.status, data };
4142
+ } finally {
4143
+ clearTimeout(timeout);
4144
+ }
4145
+ } catch (err) {
4146
+ const msg = err instanceof Error ? err.message : String(err);
4147
+ return { success: false, error: msg };
4148
+ }
4149
+ }
4150
+ });
4151
+
4152
+ // src/connectors/google-sheets-oauth/setup.ts
4153
+ var requestToolName = `google-sheets-oauth_${requestTool5.name}`;
4154
+ var googleSheetsSetup = new ConnectorSetup({
4155
+ ja: `## Google Sheets \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u624B\u9806
4156
+
4157
+ \u4EE5\u4E0B\u306E\u624B\u9806\u3067Google Sheets\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044\u3002
4158
+
4159
+ ### \u624B\u9806
4160
+
4161
+ #### \u30B9\u30C6\u30C3\u30D71: \u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u9078\u629E
4162
+ 1. \u30E6\u30FC\u30B6\u30FC\u306B\u300C\u4F7F\u7528\u3059\u308BGoogle Sheets\u306EURL\u3092\u8CBC\u308A\u4ED8\u3051\u3066\u304F\u3060\u3055\u3044\uFF08\u4F8B: https://docs.google.com/spreadsheets/d/xxxxx/edit\uFF09\u300D\u3068\u4F1D\u3048\u308B
4163
+ 2. \u30E6\u30FC\u30B6\u30FC\u304CURL\u307E\u305F\u306F\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8ID\u3092\u63D0\u4F9B\u3057\u305F\u3089\u3001URL\u304B\u3089ID\u3092\u62BD\u51FA\u3059\u308B\uFF08\`/d/\` \u3068 \`/edit\` \u306E\u9593\u306E\u6587\u5B57\u5217\uFF09
4164
+ 3. \`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
4165
+ - \`parameterSlug\`: \`"spreadsheet-id"\`
4166
+ - \`value\`: \u62BD\u51FA\u3057\u305F\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8ID
4167
+
4168
+ #### \u30B9\u30C6\u30C3\u30D72: \u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u691C\u8A3C
4169
+ 1. \`${requestToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u53D6\u5F97\u3059\u308B:
4170
+ - \`method\`: \`"GET"\`
4171
+ - \`path\`: \`"/{spreadsheetId}?fields=spreadsheetId,properties.title,sheets.properties.title"\`
4172
+ 2. \u30A8\u30E9\u30FC\u304C\u8FD4\u3055\u308C\u305F\u5834\u5408\u3001\u30E6\u30FC\u30B6\u30FC\u306B\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306E\u5171\u6709\u8A2D\u5B9A\u3092\u78BA\u8A8D\u3059\u308B\u3088\u3046\u4F1D\u3048\u308B
4173
+
4174
+ #### \u30B9\u30C6\u30C3\u30D73: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5B8C\u4E86
4175
+ 1. \`updateConnectionContext\` \u3092\u547C\u3073\u51FA\u3059:
4176
+ - \`spreadsheet\`: \u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306E\u30BF\u30A4\u30C8\u30EB
4177
+ - \`sheets\`: \u30B7\u30FC\u30C8\u540D\u4E00\u89A7\uFF08\u30AB\u30F3\u30DE\u533A\u5207\u308A\uFF09
4178
+ - \`note\`: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5185\u5BB9\u306E\u7C21\u5358\u306A\u8AAC\u660E
4179
+
4180
+ ### \u91CD\u8981\u306A\u5236\u7D04
4181
+ - **\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u4E2D\u306B\u30B7\u30FC\u30C8\u306E\u30C7\u30FC\u30BF\u3092\u8AAD\u307F\u53D6\u3089\u306A\u3044\u3053\u3068**\u3002\u5B9F\u884C\u3057\u3066\u3088\u3044\u306E\u306F\u4E0A\u8A18\u624B\u9806\u3067\u6307\u5B9A\u3055\u308C\u305F\u30E1\u30BF\u30C7\u30FC\u30BF\u53D6\u5F97\u30EA\u30AF\u30A8\u30B9\u30C8\u306E\u307F
4182
+
4183
+ ### \u5B9F\u884C\u65B9\u91DD
4184
+ - \u30C4\u30FC\u30EB\u9593\u306F1\u6587\u3060\u3051\u66F8\u3044\u3066\u5373\u6B21\u306E\u30C4\u30FC\u30EB\u547C\u3073\u51FA\u3057
4185
+ - \u4E0D\u8981\u306A\u8AAC\u660E\u306F\u7701\u7565\u3057\u3001\u52B9\u7387\u7684\u306B\u9032\u3081\u308B`,
4186
+ en: `## Google Sheets Setup Instructions
4187
+
4188
+ Follow these steps to set up the Google Sheets connection.
4189
+
4190
+ ### Steps
4191
+
4192
+ #### Step 1: Spreadsheet Selection
4193
+ 1. Ask the user to paste the Google Sheets URL (e.g., https://docs.google.com/spreadsheets/d/xxxxx/edit)
4194
+ 2. When the user provides a URL or spreadsheet ID, extract the ID from the URL (the string between \`/d/\` and \`/edit\`)
4195
+ 3. Call \`updateConnectionParameters\`:
4196
+ - \`parameterSlug\`: \`"spreadsheet-id"\`
4197
+ - \`value\`: The extracted spreadsheet ID
4198
+
4199
+ #### Step 2: Spreadsheet Validation
4200
+ 1. Call \`${requestToolName}\` to fetch spreadsheet metadata:
4201
+ - \`method\`: \`"GET"\`
4202
+ - \`path\`: \`"/{spreadsheetId}?fields=spreadsheetId,properties.title,sheets.properties.title"\`
4203
+ 2. If an error is returned, ask the user to check the spreadsheet sharing settings
4204
+
4205
+ #### Step 3: Complete Setup
4206
+ 1. Call \`updateConnectionContext\`:
4207
+ - \`spreadsheet\`: The spreadsheet title
4208
+ - \`sheets\`: Sheet names (comma-separated)
4209
+ - \`note\`: Brief description of the setup
4210
+
4211
+ ### Important Constraints
4212
+ - **Do NOT read sheet data during setup**. Only the metadata request specified in the steps above is allowed
4213
+
4214
+ ### Execution Policy
4215
+ - Write only 1 sentence between tool calls, then immediately call the next tool
4216
+ - Skip unnecessary explanations and proceed efficiently`
4217
+ });
4218
+
4219
+ // src/connectors/google-sheets-oauth/index.ts
4220
+ var tools14 = { request: requestTool5 };
4221
+ var googleSheetsOauthConnector = new ConnectorPlugin({
4222
+ slug: "google-sheets",
4223
+ authType: AUTH_TYPES.OAUTH,
4224
+ name: "Google Sheets (OAuth)",
4225
+ description: "Connect to Google Sheets for spreadsheet data access using OAuth.",
4226
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/1UPQuggyiZmbb26CuaSr2h/032770e8739b183fa00b7625f024e536/google-sheets.svg",
4227
+ parameters: parameters5,
4228
+ releaseFlag: { dev1: true, dev2: false, prod: false },
4229
+ setup: googleSheetsSetup,
4230
+ proxyPolicy: {
4231
+ allowlist: [
4232
+ {
4233
+ host: "sheets.googleapis.com",
4234
+ methods: ["GET"]
4235
+ }
4236
+ ]
4237
+ },
4238
+ systemPrompt: `## Google Sheets API (OAuth, Read-Only)
4239
+
4240
+ ### Available Endpoints
4241
+ - GET \`/{spreadsheetId}\` \u2014 Get spreadsheet metadata (title, sheets, properties)
4242
+ - GET \`/{spreadsheetId}/values/{range}\` \u2014 Get cell values for a range
4243
+ - GET \`/{spreadsheetId}/values:batchGet?ranges={range1}&ranges={range2}\` \u2014 Get values for multiple ranges
4244
+
4245
+ ### Range Notation (A1 notation)
4246
+ - \`Sheet1!A1:D10\` \u2014 Specific range on Sheet1
4247
+ - \`Sheet1!A:A\` \u2014 Entire column A on Sheet1
4248
+ - \`Sheet1!1:3\` \u2014 Rows 1 to 3 on Sheet1
4249
+ - \`Sheet1\` \u2014 All data on Sheet1
4250
+ - \`A1:D10\` \u2014 Range on the first sheet (when only one sheet exists)
4251
+
4252
+ ### Tips
4253
+ - Use \`{spreadsheetId}\` placeholder in paths \u2014 it is automatically replaced with the configured default spreadsheet ID
4254
+ - To explore a spreadsheet, first get metadata to see available sheet names
4255
+ - Use \`valueRenderOption=FORMATTED_VALUE\` query param to get display values
4256
+ - Use \`valueRenderOption=UNFORMATTED_VALUE\` for raw numeric values
4257
+ - Use \`majorDimension=COLUMNS\` to get data organized by columns instead of rows
4258
+
4259
+ ## Google Sheets SDK (TypeScript handler)
4260
+
4261
+ \`\`\`ts
4262
+ import { connection } from "@squadbase/vite-server/connectors/google-sheets-oauth";
4263
+
4264
+ const sheets = connection("<connectionId>");
4265
+
4266
+ // Get spreadsheet metadata
4267
+ const metadata = await sheets.getSpreadsheet();
4268
+ console.log(metadata.properties.title, metadata.sheets.map(s => s.properties.title));
4269
+
4270
+ // Get cell values
4271
+ const values = await sheets.getValues("Sheet1!A1:D10");
4272
+ console.log(values.values); // 2D array
4273
+
4274
+ // Get multiple ranges at once
4275
+ const batch = await sheets.batchGetValues(["Sheet1!A1:B5", "Sheet2!A1:C3"]);
4276
+ batch.valueRanges.forEach(vr => console.log(vr.range, vr.values));
4277
+ \`\`\``,
4278
+ tools: tools14,
4279
+ async checkConnection(params, config) {
4280
+ const { proxyFetch } = config;
4281
+ const spreadsheetId = params[parameters5.spreadsheetId.slug];
4282
+ if (!spreadsheetId) {
4283
+ return { success: true };
4284
+ }
4285
+ const url = `https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}?fields=spreadsheetId,properties.title`;
4286
+ try {
4287
+ const res = await proxyFetch(url, { method: "GET" });
4288
+ if (!res.ok) {
4289
+ const errorText = await res.text().catch(() => res.statusText);
4290
+ return {
4291
+ success: false,
4292
+ error: `Google Sheets API failed: HTTP ${res.status} ${errorText}`
4293
+ };
4294
+ }
4295
+ return { success: true };
4296
+ } catch (error) {
4297
+ return {
4298
+ success: false,
4299
+ error: error instanceof Error ? error.message : String(error)
4300
+ };
4301
+ }
4302
+ }
4303
+ });
4304
+
4305
+ // src/connectors/kintone/tools/request.ts
4306
+ import { z as z22 } from "zod";
4307
+ var REQUEST_TIMEOUT_MS12 = 6e4;
4308
+ var inputSchema22 = z22.object({
4309
+ toolUseIntent: z22.string().optional().describe("Brief description of what you intend to accomplish with this tool call"),
4310
+ connectionId: z22.string().describe("ID of the kintone connection to use"),
4311
+ method: z22.enum(["GET", "POST", "PUT", "DELETE"]).describe("HTTP method"),
4312
+ path: z22.string().describe("API path (e.g., 'apps.json', 'records.json?app=1&query=...')"),
4313
+ body: z22.record(z22.string(), z22.unknown()).optional().describe("Request body (JSON)")
4314
+ });
4315
+ var outputSchema22 = z22.discriminatedUnion("success", [
4316
+ z22.object({
4317
+ success: z22.literal(true),
4318
+ status: z22.number(),
4319
+ data: z22.record(z22.string(), z22.unknown())
4320
+ }),
4321
+ z22.object({
4322
+ success: z22.literal(false),
4323
+ error: z22.string()
4324
+ })
4325
+ ]);
4326
+ var requestTool6 = new ConnectorTool({
4327
+ name: "request",
4328
+ description: `Send authenticated requests to the kintone REST API.
4329
+ Authentication is handled automatically using username and password.`,
4330
+ inputSchema: inputSchema22,
4331
+ outputSchema: outputSchema22,
4332
+ async execute({ connectionId, method, path, body }, connections) {
4333
+ const connection = connections.find((c) => c.id === connectionId);
4334
+ if (!connection) {
4335
+ return { success: false, error: `Connection ${connectionId} not found` };
4336
+ }
4337
+ console.log(`[connector-request] kintone/${connection.name}: ${method} ${path}`);
4338
+ try {
4339
+ const baseUrl = parameters6.baseUrl.getValue(connection);
4340
+ const username = parameters6.username.getValue(connection);
4341
+ const password = parameters6.password.getValue(connection);
4342
+ const authToken = Buffer.from(`${username}:${password}`).toString("base64");
4343
+ const url = `${baseUrl.replace(/\/+$/, "")}/k/v1/${path}`;
4344
+ const controller = new AbortController();
4345
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS12);
4346
+ try {
4347
+ const headers = {
4348
+ "X-Cybozu-Authorization": authToken
4349
+ };
4350
+ if (body) {
4351
+ headers["Content-Type"] = "application/json";
4352
+ }
4353
+ const response = await fetch(url, {
4354
+ method,
4355
+ headers,
4356
+ body: body ? JSON.stringify(body) : void 0,
4357
+ signal: controller.signal
4358
+ });
4359
+ const data = await response.json();
4360
+ if (!response.ok) {
4361
+ return {
4362
+ success: false,
4363
+ error: data?.message ?? `HTTP ${response.status} ${response.statusText}`
4364
+ };
4365
+ }
4366
+ return { success: true, status: response.status, data };
4367
+ } finally {
4368
+ clearTimeout(timeout);
4369
+ }
4370
+ } catch (err) {
4371
+ const msg = err instanceof Error ? err.message : String(err);
4372
+ return { success: false, error: msg };
4373
+ }
4374
+ }
4375
+ });
4376
+
4377
+ // src/connectors/kintone/index.ts
4378
+ var tools15 = { request: requestTool6 };
4379
+ var kintoneConnector = new ConnectorPlugin({
4380
+ slug: "kintone",
3130
4381
  authType: null,
3131
4382
  name: "kintone",
3132
4383
  description: "Connect to kintone for business application data retrieval and analytics.",
3133
4384
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/76nPGMJFZkMFE3UQNo2JFy/e71dc5f5d5cec1306ce0e17aafbfd9f0/kintone.png",
3134
- parameters: parameters3,
4385
+ parameters: parameters6,
3135
4386
  releaseFlag: { dev1: true, dev2: true, prod: true },
3136
4387
  systemPrompt: `## kintone REST API
3137
4388
  - Call the kintone REST API using the authenticated request tool
@@ -3184,37 +4435,37 @@ const { records, totalCount } = await kintone.getRecords(1, {
3184
4435
  const { record } = await kintone.getRecord(1, 100);
3185
4436
  const { apps } = await kintone.listApps();
3186
4437
  \`\`\``,
3187
- tools: tools12
4438
+ tools: tools15
3188
4439
  });
3189
4440
 
3190
4441
  // src/connectors/wix-store/tools/request.ts
3191
- import { z as z17 } from "zod";
3192
- var BASE_URL3 = "https://www.wixapis.com/";
3193
- var REQUEST_TIMEOUT_MS7 = 6e4;
3194
- var inputSchema17 = z17.object({
3195
- toolUseIntent: z17.string().optional().describe("Brief description of what you intend to accomplish with this tool call"),
3196
- connectionId: z17.string().describe("ID of the Wix Store connection to use"),
3197
- method: z17.enum(["GET", "POST"]).describe("HTTP method"),
3198
- path: z17.string().describe("API path (e.g., 'stores/v1/products/query', 'stores/v2/orders/query')"),
3199
- body: z17.record(z17.string(), z17.unknown()).optional().describe("Request body (JSON)")
4442
+ import { z as z23 } from "zod";
4443
+ var BASE_URL7 = "https://www.wixapis.com/";
4444
+ var REQUEST_TIMEOUT_MS13 = 6e4;
4445
+ var inputSchema23 = z23.object({
4446
+ toolUseIntent: z23.string().optional().describe("Brief description of what you intend to accomplish with this tool call"),
4447
+ connectionId: z23.string().describe("ID of the Wix Store connection to use"),
4448
+ method: z23.enum(["GET", "POST"]).describe("HTTP method"),
4449
+ path: z23.string().describe("API path (e.g., 'stores/v1/products/query', 'stores/v2/orders/query')"),
4450
+ body: z23.record(z23.string(), z23.unknown()).optional().describe("Request body (JSON)")
3200
4451
  });
3201
- var outputSchema17 = z17.discriminatedUnion("success", [
3202
- z17.object({
3203
- success: z17.literal(true),
3204
- status: z17.number(),
3205
- data: z17.record(z17.string(), z17.unknown())
4452
+ var outputSchema23 = z23.discriminatedUnion("success", [
4453
+ z23.object({
4454
+ success: z23.literal(true),
4455
+ status: z23.number(),
4456
+ data: z23.record(z23.string(), z23.unknown())
3206
4457
  }),
3207
- z17.object({
3208
- success: z17.literal(false),
3209
- error: z17.string()
4458
+ z23.object({
4459
+ success: z23.literal(false),
4460
+ error: z23.string()
3210
4461
  })
3211
4462
  ]);
3212
- var requestTool4 = new ConnectorTool({
4463
+ var requestTool7 = new ConnectorTool({
3213
4464
  name: "request",
3214
4465
  description: `Send authenticated requests to the Wix Store API.
3215
4466
  Authentication is handled automatically using the API Key and Site ID.`,
3216
- inputSchema: inputSchema17,
3217
- outputSchema: outputSchema17,
4467
+ inputSchema: inputSchema23,
4468
+ outputSchema: outputSchema23,
3218
4469
  async execute({ connectionId, method, path, body }, connections) {
3219
4470
  const connection = connections.find((c) => c.id === connectionId);
3220
4471
  if (!connection) {
@@ -3222,11 +4473,11 @@ Authentication is handled automatically using the API Key and Site ID.`,
3222
4473
  }
3223
4474
  console.log(`[connector-request] wix-store/${connection.name}: ${method} ${path}`);
3224
4475
  try {
3225
- const apiKey = parameters4.apiKey.getValue(connection);
3226
- const siteId = parameters4.siteId.getValue(connection);
3227
- const url = `${BASE_URL3}${path}`;
4476
+ const apiKey = parameters7.apiKey.getValue(connection);
4477
+ const siteId = parameters7.siteId.getValue(connection);
4478
+ const url = `${BASE_URL7}${path}`;
3228
4479
  const controller = new AbortController();
3229
- const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS7);
4480
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS13);
3230
4481
  try {
3231
4482
  const response = await fetch(url, {
3232
4483
  method,
@@ -3258,14 +4509,14 @@ Authentication is handled automatically using the API Key and Site ID.`,
3258
4509
  });
3259
4510
 
3260
4511
  // src/connectors/wix-store/index.ts
3261
- var tools13 = { request: requestTool4 };
4512
+ var tools16 = { request: requestTool7 };
3262
4513
  var wixStoreConnector = new ConnectorPlugin({
3263
4514
  slug: "wix-store",
3264
4515
  authType: null,
3265
4516
  name: "Wix Store",
3266
4517
  description: "Connect to Wix Store.",
3267
4518
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/YyFxclQFzROIYpFam6vRK/e7e75d3feac49a1cc5e433c147216d23/Wix_logo_black.svg",
3268
- parameters: parameters4,
4519
+ parameters: parameters7,
3269
4520
  releaseFlag: { dev1: true, dev2: true, prod: true },
3270
4521
  systemPrompt: `## Wix Store API
3271
4522
  - Call the Wix Store REST API using the authenticated request tool
@@ -3320,40 +4571,40 @@ const { order } = await wix.getOrder("order-id");
3320
4571
  const { inventoryItems } = await wix.queryInventory({ paging: { limit: 50 } });
3321
4572
  const { collections } = await wix.queryCollections({ paging: { limit: 50 } });
3322
4573
  \`\`\``,
3323
- tools: tools13
4574
+ tools: tools16
3324
4575
  });
3325
4576
 
3326
4577
  // src/connectors/dbt/tools/request.ts
3327
- import { z as z18 } from "zod";
3328
- var REQUEST_TIMEOUT_MS8 = 6e4;
4578
+ import { z as z24 } from "zod";
4579
+ var REQUEST_TIMEOUT_MS14 = 6e4;
3329
4580
  function resolveGraphqlEndpoint(host) {
3330
4581
  if (host.includes("emea")) return "https://metadata.emea.dbt.com/graphql";
3331
4582
  if (host.includes(".au.")) return "https://metadata.au.dbt.com/graphql";
3332
4583
  return "https://metadata.cloud.getdbt.com/graphql";
3333
4584
  }
3334
- var inputSchema18 = z18.object({
3335
- toolUseIntent: z18.string().optional().describe("Brief description of what you intend to accomplish with this tool call"),
3336
- connectionId: z18.string().describe("ID of the dbt Cloud connection to use"),
3337
- query: z18.string().describe("GraphQL query"),
3338
- variables: z18.record(z18.string(), z18.unknown()).optional().describe("GraphQL variables (JSON)")
4585
+ var inputSchema24 = z24.object({
4586
+ toolUseIntent: z24.string().optional().describe("Brief description of what you intend to accomplish with this tool call"),
4587
+ connectionId: z24.string().describe("ID of the dbt Cloud connection to use"),
4588
+ query: z24.string().describe("GraphQL query"),
4589
+ variables: z24.record(z24.string(), z24.unknown()).optional().describe("GraphQL variables (JSON)")
3339
4590
  });
3340
- var outputSchema18 = z18.discriminatedUnion("success", [
3341
- z18.object({
3342
- success: z18.literal(true),
3343
- data: z18.record(z18.string(), z18.unknown())
4591
+ var outputSchema24 = z24.discriminatedUnion("success", [
4592
+ z24.object({
4593
+ success: z24.literal(true),
4594
+ data: z24.record(z24.string(), z24.unknown())
3344
4595
  }),
3345
- z18.object({
3346
- success: z18.literal(false),
3347
- error: z18.string()
4596
+ z24.object({
4597
+ success: z24.literal(false),
4598
+ error: z24.string()
3348
4599
  })
3349
4600
  ]);
3350
- var requestTool5 = new ConnectorTool({
4601
+ var requestTool8 = new ConnectorTool({
3351
4602
  name: "request",
3352
4603
  description: `Send authenticated requests to the dbt Cloud Discovery API (GraphQL).
3353
4604
  Authentication is handled automatically using the API token.
3354
4605
  {environmentId} in GraphQL variables is automatically replaced with the prod-env-id.`,
3355
- inputSchema: inputSchema18,
3356
- outputSchema: outputSchema18,
4606
+ inputSchema: inputSchema24,
4607
+ outputSchema: outputSchema24,
3357
4608
  async execute({ connectionId, query, variables }, connections) {
3358
4609
  const connection = connections.find((c) => c.id === connectionId);
3359
4610
  if (!connection) {
@@ -3361,15 +4612,15 @@ Authentication is handled automatically using the API token.
3361
4612
  }
3362
4613
  console.log(`[connector-request] dbt/${connection.name}: GraphQL query`);
3363
4614
  try {
3364
- const host = parameters5.host.getValue(connection);
3365
- const token = parameters5.token.getValue(connection);
3366
- const environmentId = parameters5.prodEnvId.getValue(connection);
4615
+ const host = parameters8.host.getValue(connection);
4616
+ const token = parameters8.token.getValue(connection);
4617
+ const environmentId = parameters8.prodEnvId.getValue(connection);
3367
4618
  const resolvedVariables = variables ? JSON.parse(
3368
4619
  JSON.stringify(variables).replace(/\{environmentId\}/g, environmentId)
3369
4620
  ) : void 0;
3370
4621
  const endpoint = resolveGraphqlEndpoint(host);
3371
4622
  const controller = new AbortController();
3372
- const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS8);
4623
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS14);
3373
4624
  try {
3374
4625
  const response = await fetch(endpoint, {
3375
4626
  method: "POST",
@@ -3406,14 +4657,14 @@ Authentication is handled automatically using the API token.
3406
4657
  });
3407
4658
 
3408
4659
  // src/connectors/dbt/index.ts
3409
- var tools14 = { request: requestTool5 };
4660
+ var tools17 = { request: requestTool8 };
3410
4661
  var dbtConnector = new ConnectorPlugin({
3411
4662
  slug: "dbt",
3412
4663
  authType: null,
3413
4664
  name: "dbt",
3414
4665
  description: "Connect to dbt Cloud for data transformation and analytics engineering.",
3415
4666
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/4iT6ncXtdtHdkXexU0WgfZ/0367a38d245f2568eab5eb511f9ee692/dbt.png",
3416
- parameters: parameters5,
4667
+ parameters: parameters8,
3417
4668
  releaseFlag: { dev1: true, dev2: true, prod: true },
3418
4669
  systemPrompt: `## dbt Cloud Discovery API (GraphQL)
3419
4670
  - Call the dbt Cloud Discovery API using the authenticated request tool
@@ -3495,11 +4746,11 @@ const sources = await dbt.getSources({ limit: 100 });
3495
4746
  const tests = await dbt.getTests({ limit: 100 });
3496
4747
  const metrics = await dbt.getMetrics({ limit: 100 });
3497
4748
  \`\`\``,
3498
- tools: tools14
4749
+ tools: tools17
3499
4750
  });
3500
4751
 
3501
4752
  // src/connectors/squadbase-db/parameters.ts
3502
- var parameters16 = {
4753
+ var parameters19 = {
3503
4754
  connectionUrl: new ParameterDefinition({
3504
4755
  slug: "connection-url",
3505
4756
  name: "Connection URL",
@@ -3512,27 +4763,27 @@ var parameters16 = {
3512
4763
  };
3513
4764
 
3514
4765
  // src/connectors/squadbase-db/tools/execute-query.ts
3515
- import { z as z19 } from "zod";
4766
+ import { z as z25 } from "zod";
3516
4767
  var MAX_ROWS10 = 500;
3517
4768
  var CONNECT_TIMEOUT_MS3 = 1e4;
3518
4769
  var STATEMENT_TIMEOUT_MS2 = 6e4;
3519
- var inputSchema19 = z19.object({
3520
- toolUseIntent: z19.string().optional().describe(
4770
+ var inputSchema25 = z25.object({
4771
+ toolUseIntent: z25.string().optional().describe(
3521
4772
  "Brief description of what you intend to accomplish with this tool call"
3522
4773
  ),
3523
- connectionId: z19.string().describe("ID of the Squadbase DB connection to use"),
3524
- sql: z19.string().describe("PostgreSQL SQL query. Always include LIMIT in queries.")
4774
+ connectionId: z25.string().describe("ID of the Squadbase DB connection to use"),
4775
+ sql: z25.string().describe("PostgreSQL SQL query. Always include LIMIT in queries.")
3525
4776
  });
3526
- var outputSchema19 = z19.discriminatedUnion("success", [
3527
- z19.object({
3528
- success: z19.literal(true),
3529
- rowCount: z19.number(),
3530
- truncated: z19.boolean(),
3531
- rows: z19.array(z19.record(z19.string(), z19.unknown()))
4777
+ var outputSchema25 = z25.discriminatedUnion("success", [
4778
+ z25.object({
4779
+ success: z25.literal(true),
4780
+ rowCount: z25.number(),
4781
+ truncated: z25.boolean(),
4782
+ rows: z25.array(z25.record(z25.string(), z25.unknown()))
3532
4783
  }),
3533
- z19.object({
3534
- success: z19.literal(false),
3535
- error: z19.string()
4784
+ z25.object({
4785
+ success: z25.literal(false),
4786
+ error: z25.string()
3536
4787
  })
3537
4788
  ]);
3538
4789
  var executeQueryTool10 = new ConnectorTool({
@@ -3540,8 +4791,8 @@ var executeQueryTool10 = new ConnectorTool({
3540
4791
  description: `Execute SQL against Squadbase DB (PostgreSQL). Returns up to ${MAX_ROWS10} rows.
3541
4792
  Use for: schema exploration (information_schema), data sampling, analytical queries.
3542
4793
  Avoid loading large amounts of data; always include LIMIT in queries.`,
3543
- inputSchema: inputSchema19,
3544
- outputSchema: outputSchema19,
4794
+ inputSchema: inputSchema25,
4795
+ outputSchema: outputSchema25,
3545
4796
  async execute({ connectionId, sql }, connections) {
3546
4797
  const connection = connections.find((c) => c.id === connectionId);
3547
4798
  if (!connection) {
@@ -3556,7 +4807,7 @@ Avoid loading large amounts of data; always include LIMIT in queries.`,
3556
4807
  let connectionUrl;
3557
4808
  try {
3558
4809
  const { Pool } = await import("pg");
3559
- connectionUrl = parameters16.connectionUrl.getValue(connection);
4810
+ connectionUrl = parameters19.connectionUrl.getValue(connection);
3560
4811
  const pool = new Pool({
3561
4812
  connectionString: connectionUrl,
3562
4813
  ssl: { rejectUnauthorized: false },
@@ -3587,14 +4838,14 @@ Avoid loading large amounts of data; always include LIMIT in queries.`,
3587
4838
  });
3588
4839
 
3589
4840
  // src/connectors/squadbase-db/index.ts
3590
- var tools15 = { executeQuery: executeQueryTool10 };
4841
+ var tools18 = { executeQuery: executeQueryTool10 };
3591
4842
  var squadbaseDbConnector = new ConnectorPlugin({
3592
4843
  slug: "squadbase-db",
3593
4844
  authType: null,
3594
4845
  name: "Squadbase DB",
3595
4846
  description: "Connect to Squadbase DB (PostgreSQL).",
3596
4847
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/25y0XqMxIufeD3egWH3bEl/659b4ade405890654cfaf91c03a4b458/icon.svg",
3597
- parameters: parameters16,
4848
+ parameters: parameters19,
3598
4849
  releaseFlag: { dev1: true, dev2: true, prod: true },
3599
4850
  systemPrompt: `## Squadbase DB SQL Notes
3600
4851
  - Uses PostgreSQL based SQL syntax
@@ -3602,11 +4853,11 @@ var squadbaseDbConnector = new ConnectorPlugin({
3602
4853
  - List tables: \`SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'\`
3603
4854
  - List columns: \`SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'xxx'\`
3604
4855
  - Always include LIMIT in queries`,
3605
- tools: tools15,
4856
+ tools: tools18,
3606
4857
  async checkConnection(params, _config) {
3607
4858
  const { Pool } = await import("pg");
3608
4859
  const pool = new Pool({
3609
- connectionString: params[parameters16.connectionUrl.slug],
4860
+ connectionString: params[parameters19.connectionUrl.slug],
3610
4861
  ssl: { rejectUnauthorized: false },
3611
4862
  connectionTimeoutMillis: 1e4
3612
4863
  });
@@ -3623,7 +4874,7 @@ var squadbaseDbConnector = new ConnectorPlugin({
3623
4874
  const { Pool } = await import("pg");
3624
4875
  const { text, values } = buildPositionalParams(sql, namedParams);
3625
4876
  const pool = new Pool({
3626
- connectionString: params[parameters16.connectionUrl.slug],
4877
+ connectionString: params[parameters19.connectionUrl.slug],
3627
4878
  ssl: { rejectUnauthorized: false },
3628
4879
  connectionTimeoutMillis: 1e4,
3629
4880
  statement_timeout: 6e4
@@ -3638,14 +4889,14 @@ var squadbaseDbConnector = new ConnectorPlugin({
3638
4889
  });
3639
4890
 
3640
4891
  // src/connectors/openai/index.ts
3641
- var tools16 = {};
4892
+ var tools19 = {};
3642
4893
  var openaiConnector = new ConnectorPlugin({
3643
4894
  slug: "openai",
3644
4895
  authType: null,
3645
4896
  name: "OpenAI",
3646
4897
  description: "Connect to OpenAI for AI model inference, embeddings, and image generation.",
3647
4898
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/53XJtCgUlW10x6i1X8xpxM/0bfd634069f1d74241296543cb20427a/openai.svg",
3648
- parameters: parameters6,
4899
+ parameters: parameters9,
3649
4900
  releaseFlag: { dev1: true, dev2: true, prod: true },
3650
4901
  systemPrompt: `## OpenAI SDK (TypeScript handler)
3651
4902
  Use the OpenAI connector via the SDK in TypeScript handlers:
@@ -3662,7 +4913,7 @@ const response = await client.chat.completions.create({
3662
4913
  messages: [{ role: "user", content: "Hello" }],
3663
4914
  });
3664
4915
  \`\`\``,
3665
- tools: tools16
4916
+ tools: tools19
3666
4917
  });
3667
4918
 
3668
4919
  // src/connectors/registry.ts
@@ -3677,7 +4928,10 @@ var plugins = {
3677
4928
  awsAthena: awsAthenaConnector,
3678
4929
  postgresql: postgresqlConnector,
3679
4930
  mysql: mysqlConnector,
4931
+ googleAdsOauth: googleAdsOauthConnector,
3680
4932
  googleAnalytics: googleAnalyticsConnector,
4933
+ googleAnalyticsOauth: googleAnalyticsOauthConnector,
4934
+ googleSheetsOauth: googleSheetsOauthConnector,
3681
4935
  airtable: airtableConnector,
3682
4936
  squadbaseDb: squadbaseDbConnector,
3683
4937
  kintone: kintoneConnector,
@@ -3718,7 +4972,10 @@ export {
3718
4972
  connectors,
3719
4973
  databricksConnector,
3720
4974
  dbtConnector,
4975
+ googleAdsOauthConnector,
3721
4976
  googleAnalyticsConnector,
4977
+ googleAnalyticsOauthConnector,
4978
+ googleSheetsOauthConnector,
3722
4979
  kintoneConnector,
3723
4980
  mysqlConnector,
3724
4981
  openaiConnector,