@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/{chunk-4K4NERCT.js → chunk-LB7J6VXK.js} +57 -6
- package/dist/index.d.ts +196 -1
- package/dist/index.js +1594 -337
- package/dist/sdk.d.ts +216 -5
- package/dist/sdk.js +260 -34
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,8 +5,11 @@ import {
|
|
|
5
5
|
parameters3,
|
|
6
6
|
parameters4,
|
|
7
7
|
parameters5,
|
|
8
|
-
parameters6
|
|
9
|
-
|
|
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
|
|
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 =
|
|
352
|
-
const user =
|
|
353
|
-
const role =
|
|
354
|
-
const warehouse =
|
|
355
|
-
const privateKeyBase64 =
|
|
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 =
|
|
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:
|
|
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[
|
|
444
|
+
params[parameters10.privateKeyBase64.slug],
|
|
442
445
|
"base64"
|
|
443
446
|
).toString("utf-8");
|
|
444
|
-
const privateKeyPass = params[
|
|
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[
|
|
448
|
-
username: params[
|
|
449
|
-
role: params[
|
|
450
|
-
warehouse: params[
|
|
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[
|
|
485
|
+
params[parameters10.privateKeyBase64.slug],
|
|
483
486
|
"base64"
|
|
484
487
|
).toString("utf-8");
|
|
485
|
-
const privateKeyPass = params[
|
|
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[
|
|
489
|
-
username: params[
|
|
490
|
-
role: params[
|
|
491
|
-
warehouse: params[
|
|
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
|
|
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 =
|
|
615
|
-
const user =
|
|
616
|
-
const role =
|
|
617
|
-
const warehouse =
|
|
618
|
-
const password =
|
|
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:
|
|
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[
|
|
699
|
-
username: params[
|
|
700
|
-
role: params[
|
|
701
|
-
warehouse: params[
|
|
702
|
-
password: params[
|
|
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[
|
|
738
|
-
username: params[
|
|
739
|
-
role: params[
|
|
740
|
-
warehouse: params[
|
|
741
|
-
password: params[
|
|
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
|
|
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 =
|
|
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:
|
|
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[
|
|
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[
|
|
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
|
|
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 =
|
|
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:
|
|
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[
|
|
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[
|
|
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
|
|
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 =
|
|
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 =
|
|
1178
|
-
const serviceAccountJsonBase64 =
|
|
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 =
|
|
1340
|
-
const serviceAccountJsonBase64 =
|
|
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:
|
|
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[
|
|
1387
|
+
Buffer.from(params[parameters14.serviceAccountKeyJsonBase64.slug], "base64").toString("utf-8")
|
|
1385
1388
|
);
|
|
1386
1389
|
const bq = new BigQuery({
|
|
1387
|
-
projectId: params[
|
|
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[
|
|
1405
|
+
Buffer.from(params[parameters14.serviceAccountKeyJsonBase64.slug], "base64").toString("utf-8")
|
|
1403
1406
|
);
|
|
1404
1407
|
const bq = new BigQuery({
|
|
1405
|
-
projectId: params[
|
|
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
|
|
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 =
|
|
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 =
|
|
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:
|
|
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[
|
|
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[
|
|
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
|
|
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 =
|
|
2047
|
-
const outputLocation =
|
|
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:
|
|
2058
|
+
region: parameters16.awsRegion.getValue(connection),
|
|
2056
2059
|
credentials: {
|
|
2057
|
-
accessKeyId:
|
|
2058
|
-
secretAccessKey:
|
|
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:
|
|
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[
|
|
2141
|
-
const outputLocation = params[
|
|
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[
|
|
2152
|
+
region: params[parameters16.awsRegion.slug],
|
|
2150
2153
|
credentials: {
|
|
2151
|
-
accessKeyId: params[
|
|
2152
|
-
secretAccessKey: params[
|
|
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[
|
|
2198
|
-
const outputLocation = params[
|
|
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[
|
|
2206
|
+
region: params[parameters16.awsRegion.slug],
|
|
2204
2207
|
credentials: {
|
|
2205
|
-
accessKeyId: params[
|
|
2206
|
-
secretAccessKey: params[
|
|
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
|
|
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 =
|
|
2378
|
-
const awsSecretAccessKey =
|
|
2379
|
-
const awsRegion =
|
|
2380
|
-
const database =
|
|
2381
|
-
const clusterIdentifier =
|
|
2382
|
-
const workgroupName =
|
|
2383
|
-
const secretArn =
|
|
2384
|
-
const dbUser =
|
|
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:
|
|
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[
|
|
2474
|
-
const workgroupName = params[
|
|
2475
|
-
const secretArn = params[
|
|
2476
|
-
const dbUser = params[
|
|
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[
|
|
2487
|
+
region: params[parameters17.awsRegion.slug],
|
|
2485
2488
|
credentials: {
|
|
2486
|
-
accessKeyId: params[
|
|
2487
|
-
secretAccessKey: params[
|
|
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[
|
|
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[
|
|
2534
|
-
const workgroupName = params[
|
|
2535
|
-
const secretArn = params[
|
|
2536
|
-
const dbUser = params[
|
|
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[
|
|
2544
|
+
region: params[parameters17.awsRegion.slug],
|
|
2542
2545
|
credentials: {
|
|
2543
|
-
accessKeyId: params[
|
|
2544
|
-
secretAccessKey: params[
|
|
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[
|
|
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
|
|
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 =
|
|
2660
|
-
const token =
|
|
2661
|
-
const httpPath =
|
|
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:
|
|
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[
|
|
2718
|
-
path: params[
|
|
2719
|
-
token: params[
|
|
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[
|
|
2747
|
-
path: params[
|
|
2748
|
-
token: params[
|
|
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-
|
|
2904
|
+
// src/connectors/google-ads-oauth/tools/list-customers.ts
|
|
2902
2905
|
import { z as z15 } from "zod";
|
|
2903
|
-
var BASE_URL2 = "https://
|
|
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(
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
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
|
-
|
|
2916
|
-
|
|
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
|
|
2924
|
-
name: "
|
|
2925
|
-
description:
|
|
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
|
|
2965
|
+
async execute({ connectionId }, connections, config) {
|
|
2931
2966
|
const connection = connections.find((c) => c.id === connectionId);
|
|
2932
2967
|
if (!connection) {
|
|
2933
|
-
return {
|
|
2968
|
+
return {
|
|
2969
|
+
success: false,
|
|
2970
|
+
error: `Connection ${connectionId} not found`
|
|
2971
|
+
};
|
|
2934
2972
|
}
|
|
2935
|
-
console.log(
|
|
2973
|
+
console.log(
|
|
2974
|
+
`[connector-request] google-ads-oauth/${connection.name}: listCustomers`
|
|
2975
|
+
);
|
|
2936
2976
|
try {
|
|
2937
|
-
const
|
|
2938
|
-
const
|
|
2939
|
-
const
|
|
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(
|
|
2957
|
-
method,
|
|
2983
|
+
const response = await fetch(proxyUrl, {
|
|
2984
|
+
method: "POST",
|
|
2958
2985
|
headers: {
|
|
2959
|
-
|
|
2960
|
-
|
|
2986
|
+
"Content-Type": "application/json",
|
|
2987
|
+
Authorization: `Bearer ${token}`
|
|
2961
2988
|
},
|
|
2962
|
-
body:
|
|
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
|
|
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
|
-
|
|
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-
|
|
2985
|
-
var
|
|
2986
|
-
var
|
|
2987
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
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
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
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
|
-
|
|
3020
|
-
|
|
3021
|
-
-
|
|
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
|
-
|
|
3024
|
-
|
|
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
|
-
|
|
3027
|
-
|
|
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
|
-
|
|
3096
|
+
Follow these steps to set up the Google Ads (OAuth) connection.
|
|
3030
3097
|
|
|
3031
|
-
|
|
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
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
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/
|
|
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(
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
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.
|
|
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
|
|
3184
|
+
var requestTool2 = new ConnectorTool({
|
|
3076
3185
|
name: "request",
|
|
3077
|
-
description: `Send authenticated requests to the
|
|
3078
|
-
Authentication is handled automatically
|
|
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 {
|
|
3194
|
+
return {
|
|
3195
|
+
success: false,
|
|
3196
|
+
error: `Connection ${connectionId} not found`
|
|
3197
|
+
};
|
|
3085
3198
|
}
|
|
3086
|
-
console.log(
|
|
3199
|
+
console.log(
|
|
3200
|
+
`[connector-request] google-ads-oauth/${connection.name}: ${method} ${path}`
|
|
3201
|
+
);
|
|
3087
3202
|
try {
|
|
3088
|
-
const
|
|
3089
|
-
const
|
|
3090
|
-
const
|
|
3091
|
-
const
|
|
3092
|
-
const
|
|
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
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
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
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
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/
|
|
3127
|
-
var
|
|
3128
|
-
|
|
3129
|
-
|
|
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:
|
|
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:
|
|
4438
|
+
tools: tools15
|
|
3188
4439
|
});
|
|
3189
4440
|
|
|
3190
4441
|
// src/connectors/wix-store/tools/request.ts
|
|
3191
|
-
import { z as
|
|
3192
|
-
var
|
|
3193
|
-
var
|
|
3194
|
-
var
|
|
3195
|
-
toolUseIntent:
|
|
3196
|
-
connectionId:
|
|
3197
|
-
method:
|
|
3198
|
-
path:
|
|
3199
|
-
body:
|
|
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
|
|
3202
|
-
|
|
3203
|
-
success:
|
|
3204
|
-
status:
|
|
3205
|
-
data:
|
|
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
|
-
|
|
3208
|
-
success:
|
|
3209
|
-
error:
|
|
4458
|
+
z23.object({
|
|
4459
|
+
success: z23.literal(false),
|
|
4460
|
+
error: z23.string()
|
|
3210
4461
|
})
|
|
3211
4462
|
]);
|
|
3212
|
-
var
|
|
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:
|
|
3217
|
-
outputSchema:
|
|
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 =
|
|
3226
|
-
const siteId =
|
|
3227
|
-
const url = `${
|
|
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(),
|
|
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
|
|
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:
|
|
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:
|
|
4574
|
+
tools: tools16
|
|
3324
4575
|
});
|
|
3325
4576
|
|
|
3326
4577
|
// src/connectors/dbt/tools/request.ts
|
|
3327
|
-
import { z as
|
|
3328
|
-
var
|
|
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
|
|
3335
|
-
toolUseIntent:
|
|
3336
|
-
connectionId:
|
|
3337
|
-
query:
|
|
3338
|
-
variables:
|
|
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
|
|
3341
|
-
|
|
3342
|
-
success:
|
|
3343
|
-
data:
|
|
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
|
-
|
|
3346
|
-
success:
|
|
3347
|
-
error:
|
|
4596
|
+
z24.object({
|
|
4597
|
+
success: z24.literal(false),
|
|
4598
|
+
error: z24.string()
|
|
3348
4599
|
})
|
|
3349
4600
|
]);
|
|
3350
|
-
var
|
|
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:
|
|
3356
|
-
outputSchema:
|
|
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 =
|
|
3365
|
-
const token =
|
|
3366
|
-
const environmentId =
|
|
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(),
|
|
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
|
|
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:
|
|
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:
|
|
4749
|
+
tools: tools17
|
|
3499
4750
|
});
|
|
3500
4751
|
|
|
3501
4752
|
// src/connectors/squadbase-db/parameters.ts
|
|
3502
|
-
var
|
|
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
|
|
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
|
|
3520
|
-
toolUseIntent:
|
|
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:
|
|
3524
|
-
sql:
|
|
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
|
|
3527
|
-
|
|
3528
|
-
success:
|
|
3529
|
-
rowCount:
|
|
3530
|
-
truncated:
|
|
3531
|
-
rows:
|
|
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
|
-
|
|
3534
|
-
success:
|
|
3535
|
-
error:
|
|
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:
|
|
3544
|
-
outputSchema:
|
|
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 =
|
|
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
|
|
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:
|
|
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:
|
|
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[
|
|
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[
|
|
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
|
|
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:
|
|
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:
|
|
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,
|