@squadbase/connectors 0.1.1 → 0.1.2-dev.0
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-Q5TIPE53.js} +52 -1
- package/dist/index.d.ts +196 -1
- package/dist/index.js +1371 -126
- package/dist/sdk.d.ts +218 -7
- package/dist/sdk.js +228 -2
- 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-Q5TIPE53.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;
|
|
@@ -3499,7 +3502,7 @@ const metrics = await dbt.getMetrics({ limit: 100 });
|
|
|
3499
3502
|
});
|
|
3500
3503
|
|
|
3501
3504
|
// src/connectors/squadbase-db/parameters.ts
|
|
3502
|
-
var
|
|
3505
|
+
var parameters19 = {
|
|
3503
3506
|
connectionUrl: new ParameterDefinition({
|
|
3504
3507
|
slug: "connection-url",
|
|
3505
3508
|
name: "Connection URL",
|
|
@@ -3556,7 +3559,7 @@ Avoid loading large amounts of data; always include LIMIT in queries.`,
|
|
|
3556
3559
|
let connectionUrl;
|
|
3557
3560
|
try {
|
|
3558
3561
|
const { Pool } = await import("pg");
|
|
3559
|
-
connectionUrl =
|
|
3562
|
+
connectionUrl = parameters19.connectionUrl.getValue(connection);
|
|
3560
3563
|
const pool = new Pool({
|
|
3561
3564
|
connectionString: connectionUrl,
|
|
3562
3565
|
ssl: { rejectUnauthorized: false },
|
|
@@ -3594,7 +3597,7 @@ var squadbaseDbConnector = new ConnectorPlugin({
|
|
|
3594
3597
|
name: "Squadbase DB",
|
|
3595
3598
|
description: "Connect to Squadbase DB (PostgreSQL).",
|
|
3596
3599
|
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/25y0XqMxIufeD3egWH3bEl/659b4ade405890654cfaf91c03a4b458/icon.svg",
|
|
3597
|
-
parameters:
|
|
3600
|
+
parameters: parameters19,
|
|
3598
3601
|
releaseFlag: { dev1: true, dev2: true, prod: true },
|
|
3599
3602
|
systemPrompt: `## Squadbase DB SQL Notes
|
|
3600
3603
|
- Uses PostgreSQL based SQL syntax
|
|
@@ -3606,7 +3609,7 @@ var squadbaseDbConnector = new ConnectorPlugin({
|
|
|
3606
3609
|
async checkConnection(params, _config) {
|
|
3607
3610
|
const { Pool } = await import("pg");
|
|
3608
3611
|
const pool = new Pool({
|
|
3609
|
-
connectionString: params[
|
|
3612
|
+
connectionString: params[parameters19.connectionUrl.slug],
|
|
3610
3613
|
ssl: { rejectUnauthorized: false },
|
|
3611
3614
|
connectionTimeoutMillis: 1e4
|
|
3612
3615
|
});
|
|
@@ -3623,7 +3626,7 @@ var squadbaseDbConnector = new ConnectorPlugin({
|
|
|
3623
3626
|
const { Pool } = await import("pg");
|
|
3624
3627
|
const { text, values } = buildPositionalParams(sql, namedParams);
|
|
3625
3628
|
const pool = new Pool({
|
|
3626
|
-
connectionString: params[
|
|
3629
|
+
connectionString: params[parameters19.connectionUrl.slug],
|
|
3627
3630
|
ssl: { rejectUnauthorized: false },
|
|
3628
3631
|
connectionTimeoutMillis: 1e4,
|
|
3629
3632
|
statement_timeout: 6e4
|
|
@@ -3665,6 +3668,1242 @@ const response = await client.chat.completions.create({
|
|
|
3665
3668
|
tools: tools16
|
|
3666
3669
|
});
|
|
3667
3670
|
|
|
3671
|
+
// src/connectors/google-sheets-oauth/tools/request.ts
|
|
3672
|
+
import { z as z20 } from "zod";
|
|
3673
|
+
var BASE_URL4 = "https://sheets.googleapis.com/v4/spreadsheets";
|
|
3674
|
+
var REQUEST_TIMEOUT_MS9 = 6e4;
|
|
3675
|
+
var cachedToken4 = null;
|
|
3676
|
+
async function getProxyToken4(config) {
|
|
3677
|
+
if (cachedToken4 && cachedToken4.expiresAt > Date.now() + 6e4) {
|
|
3678
|
+
return cachedToken4.token;
|
|
3679
|
+
}
|
|
3680
|
+
const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
|
|
3681
|
+
const res = await fetch(url, {
|
|
3682
|
+
method: "POST",
|
|
3683
|
+
headers: {
|
|
3684
|
+
"Content-Type": "application/json",
|
|
3685
|
+
"x-api-key": config.appApiKey,
|
|
3686
|
+
"project-id": config.projectId
|
|
3687
|
+
},
|
|
3688
|
+
body: JSON.stringify({
|
|
3689
|
+
sandboxId: config.sandboxId,
|
|
3690
|
+
issuedBy: "coding-agent"
|
|
3691
|
+
})
|
|
3692
|
+
});
|
|
3693
|
+
if (!res.ok) {
|
|
3694
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
3695
|
+
throw new Error(
|
|
3696
|
+
`Failed to get proxy token: HTTP ${res.status} ${errorText}`
|
|
3697
|
+
);
|
|
3698
|
+
}
|
|
3699
|
+
const data = await res.json();
|
|
3700
|
+
cachedToken4 = {
|
|
3701
|
+
token: data.token,
|
|
3702
|
+
expiresAt: new Date(data.expiresAt).getTime()
|
|
3703
|
+
};
|
|
3704
|
+
return data.token;
|
|
3705
|
+
}
|
|
3706
|
+
var inputSchema20 = z20.object({
|
|
3707
|
+
toolUseIntent: z20.string().optional().describe(
|
|
3708
|
+
"Brief description of what you intend to accomplish with this tool call"
|
|
3709
|
+
),
|
|
3710
|
+
connectionId: z20.string().describe("ID of the Google Sheets OAuth connection to use"),
|
|
3711
|
+
method: z20.enum(["GET"]).describe("HTTP method (read-only, GET only)"),
|
|
3712
|
+
path: z20.string().describe(
|
|
3713
|
+
"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."
|
|
3714
|
+
),
|
|
3715
|
+
queryParams: z20.record(z20.string(), z20.string()).optional().describe("Query parameters to append to the URL")
|
|
3716
|
+
});
|
|
3717
|
+
var outputSchema20 = z20.discriminatedUnion("success", [
|
|
3718
|
+
z20.object({
|
|
3719
|
+
success: z20.literal(true),
|
|
3720
|
+
status: z20.number(),
|
|
3721
|
+
data: z20.record(z20.string(), z20.unknown())
|
|
3722
|
+
}),
|
|
3723
|
+
z20.object({
|
|
3724
|
+
success: z20.literal(false),
|
|
3725
|
+
error: z20.string()
|
|
3726
|
+
})
|
|
3727
|
+
]);
|
|
3728
|
+
var requestTool6 = new ConnectorTool({
|
|
3729
|
+
name: "request",
|
|
3730
|
+
description: `Send authenticated GET requests to the Google Sheets API v4.
|
|
3731
|
+
Authentication is handled automatically via OAuth proxy.
|
|
3732
|
+
{spreadsheetId} in the path is automatically replaced with the connection's default spreadsheet ID if configured.`,
|
|
3733
|
+
inputSchema: inputSchema20,
|
|
3734
|
+
outputSchema: outputSchema20,
|
|
3735
|
+
async execute({ connectionId, method, path, queryParams }, connections, config) {
|
|
3736
|
+
const connection = connections.find((c) => c.id === connectionId);
|
|
3737
|
+
if (!connection) {
|
|
3738
|
+
return {
|
|
3739
|
+
success: false,
|
|
3740
|
+
error: `Connection ${connectionId} not found`
|
|
3741
|
+
};
|
|
3742
|
+
}
|
|
3743
|
+
console.log(
|
|
3744
|
+
`[connector-request] google-sheets-oauth/${connection.name}: ${method} ${path}`
|
|
3745
|
+
);
|
|
3746
|
+
try {
|
|
3747
|
+
const spreadsheetId = parameters7.spreadsheetId.tryGetValue(connection);
|
|
3748
|
+
const resolvedPath = spreadsheetId ? path.replace(/\{spreadsheetId\}/g, spreadsheetId) : path;
|
|
3749
|
+
let url = `${BASE_URL4}${resolvedPath.startsWith("/") ? "" : "/"}${resolvedPath}`;
|
|
3750
|
+
if (queryParams) {
|
|
3751
|
+
const searchParams = new URLSearchParams(queryParams);
|
|
3752
|
+
url += `?${searchParams.toString()}`;
|
|
3753
|
+
}
|
|
3754
|
+
const token = await getProxyToken4(config.oauthProxy);
|
|
3755
|
+
const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
3756
|
+
const controller = new AbortController();
|
|
3757
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS9);
|
|
3758
|
+
try {
|
|
3759
|
+
const response = await fetch(proxyUrl, {
|
|
3760
|
+
method: "POST",
|
|
3761
|
+
headers: {
|
|
3762
|
+
"Content-Type": "application/json",
|
|
3763
|
+
Authorization: `Bearer ${token}`
|
|
3764
|
+
},
|
|
3765
|
+
body: JSON.stringify({
|
|
3766
|
+
url,
|
|
3767
|
+
method
|
|
3768
|
+
}),
|
|
3769
|
+
signal: controller.signal
|
|
3770
|
+
});
|
|
3771
|
+
const data = await response.json();
|
|
3772
|
+
if (!response.ok) {
|
|
3773
|
+
const errorMessage = typeof data?.error === "string" ? data.error : typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`;
|
|
3774
|
+
return { success: false, error: errorMessage };
|
|
3775
|
+
}
|
|
3776
|
+
return { success: true, status: response.status, data };
|
|
3777
|
+
} finally {
|
|
3778
|
+
clearTimeout(timeout);
|
|
3779
|
+
}
|
|
3780
|
+
} catch (err) {
|
|
3781
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3782
|
+
return { success: false, error: msg };
|
|
3783
|
+
}
|
|
3784
|
+
}
|
|
3785
|
+
});
|
|
3786
|
+
|
|
3787
|
+
// src/connectors/google-sheets-oauth/setup.ts
|
|
3788
|
+
var requestToolName = `google-sheets-oauth_${requestTool6.name}`;
|
|
3789
|
+
var googleSheetsSetup = new ConnectorSetup({
|
|
3790
|
+
ja: `## Google Sheets \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u624B\u9806
|
|
3791
|
+
|
|
3792
|
+
\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
|
|
3793
|
+
|
|
3794
|
+
### \u624B\u9806
|
|
3795
|
+
|
|
3796
|
+
#### \u30B9\u30C6\u30C3\u30D71: \u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u9078\u629E
|
|
3797
|
+
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
|
|
3798
|
+
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
|
|
3799
|
+
3. \`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
|
|
3800
|
+
- \`parameterSlug\`: \`"spreadsheet-id"\`
|
|
3801
|
+
- \`value\`: \u62BD\u51FA\u3057\u305F\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8ID
|
|
3802
|
+
|
|
3803
|
+
#### \u30B9\u30C6\u30C3\u30D72: \u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u691C\u8A3C
|
|
3804
|
+
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:
|
|
3805
|
+
- \`method\`: \`"GET"\`
|
|
3806
|
+
- \`path\`: \`"/{spreadsheetId}?fields=spreadsheetId,properties.title,sheets.properties.title"\`
|
|
3807
|
+
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
|
|
3808
|
+
|
|
3809
|
+
#### \u30B9\u30C6\u30C3\u30D73: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5B8C\u4E86
|
|
3810
|
+
1. \`updateConnectionContext\` \u3092\u547C\u3073\u51FA\u3059:
|
|
3811
|
+
- \`spreadsheet\`: \u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306E\u30BF\u30A4\u30C8\u30EB
|
|
3812
|
+
- \`sheets\`: \u30B7\u30FC\u30C8\u540D\u4E00\u89A7\uFF08\u30AB\u30F3\u30DE\u533A\u5207\u308A\uFF09
|
|
3813
|
+
- \`note\`: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5185\u5BB9\u306E\u7C21\u5358\u306A\u8AAC\u660E
|
|
3814
|
+
|
|
3815
|
+
### \u91CD\u8981\u306A\u5236\u7D04
|
|
3816
|
+
- **\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
|
|
3817
|
+
|
|
3818
|
+
### \u5B9F\u884C\u65B9\u91DD
|
|
3819
|
+
- \u30C4\u30FC\u30EB\u9593\u306F1\u6587\u3060\u3051\u66F8\u3044\u3066\u5373\u6B21\u306E\u30C4\u30FC\u30EB\u547C\u3073\u51FA\u3057
|
|
3820
|
+
- \u4E0D\u8981\u306A\u8AAC\u660E\u306F\u7701\u7565\u3057\u3001\u52B9\u7387\u7684\u306B\u9032\u3081\u308B`,
|
|
3821
|
+
en: `## Google Sheets Setup Instructions
|
|
3822
|
+
|
|
3823
|
+
Follow these steps to set up the Google Sheets connection.
|
|
3824
|
+
|
|
3825
|
+
### Steps
|
|
3826
|
+
|
|
3827
|
+
#### Step 1: Spreadsheet Selection
|
|
3828
|
+
1. Ask the user to paste the Google Sheets URL (e.g., https://docs.google.com/spreadsheets/d/xxxxx/edit)
|
|
3829
|
+
2. When the user provides a URL or spreadsheet ID, extract the ID from the URL (the string between \`/d/\` and \`/edit\`)
|
|
3830
|
+
3. Call \`updateConnectionParameters\`:
|
|
3831
|
+
- \`parameterSlug\`: \`"spreadsheet-id"\`
|
|
3832
|
+
- \`value\`: The extracted spreadsheet ID
|
|
3833
|
+
|
|
3834
|
+
#### Step 2: Spreadsheet Validation
|
|
3835
|
+
1. Call \`${requestToolName}\` to fetch spreadsheet metadata:
|
|
3836
|
+
- \`method\`: \`"GET"\`
|
|
3837
|
+
- \`path\`: \`"/{spreadsheetId}?fields=spreadsheetId,properties.title,sheets.properties.title"\`
|
|
3838
|
+
2. If an error is returned, ask the user to check the spreadsheet sharing settings
|
|
3839
|
+
|
|
3840
|
+
#### Step 3: Complete Setup
|
|
3841
|
+
1. Call \`updateConnectionContext\`:
|
|
3842
|
+
- \`spreadsheet\`: The spreadsheet title
|
|
3843
|
+
- \`sheets\`: Sheet names (comma-separated)
|
|
3844
|
+
- \`note\`: Brief description of the setup
|
|
3845
|
+
|
|
3846
|
+
### Important Constraints
|
|
3847
|
+
- **Do NOT read sheet data during setup**. Only the metadata request specified in the steps above is allowed
|
|
3848
|
+
|
|
3849
|
+
### Execution Policy
|
|
3850
|
+
- Write only 1 sentence between tool calls, then immediately call the next tool
|
|
3851
|
+
- Skip unnecessary explanations and proceed efficiently`
|
|
3852
|
+
});
|
|
3853
|
+
|
|
3854
|
+
// src/connectors/google-sheets-oauth/index.ts
|
|
3855
|
+
var tools17 = { request: requestTool6 };
|
|
3856
|
+
var googleSheetsOauthConnector = new ConnectorPlugin({
|
|
3857
|
+
slug: "google-sheets",
|
|
3858
|
+
authType: AUTH_TYPES.OAUTH,
|
|
3859
|
+
name: "Google Sheets (OAuth)",
|
|
3860
|
+
description: "Connect to Google Sheets for spreadsheet data access using OAuth.",
|
|
3861
|
+
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/5lJMKlzv5lYbsBQbXGqacn/f56205b34e55c37d1dc69b34dcbbc379/google-sheets.svg",
|
|
3862
|
+
parameters: parameters7,
|
|
3863
|
+
releaseFlag: { dev1: true, dev2: true, prod: false },
|
|
3864
|
+
setup: googleSheetsSetup,
|
|
3865
|
+
proxyPolicy: {
|
|
3866
|
+
allowlist: [
|
|
3867
|
+
{
|
|
3868
|
+
host: "sheets.googleapis.com",
|
|
3869
|
+
methods: ["GET"]
|
|
3870
|
+
}
|
|
3871
|
+
]
|
|
3872
|
+
},
|
|
3873
|
+
systemPrompt: `## Google Sheets API (OAuth, Read-Only)
|
|
3874
|
+
|
|
3875
|
+
### Available Endpoints
|
|
3876
|
+
- GET \`/{spreadsheetId}\` \u2014 Get spreadsheet metadata (title, sheets, properties)
|
|
3877
|
+
- GET \`/{spreadsheetId}/values/{range}\` \u2014 Get cell values for a range
|
|
3878
|
+
- GET \`/{spreadsheetId}/values:batchGet?ranges={range1}&ranges={range2}\` \u2014 Get values for multiple ranges
|
|
3879
|
+
|
|
3880
|
+
### Range Notation (A1 notation)
|
|
3881
|
+
- \`Sheet1!A1:D10\` \u2014 Specific range on Sheet1
|
|
3882
|
+
- \`Sheet1!A:A\` \u2014 Entire column A on Sheet1
|
|
3883
|
+
- \`Sheet1!1:3\` \u2014 Rows 1 to 3 on Sheet1
|
|
3884
|
+
- \`Sheet1\` \u2014 All data on Sheet1
|
|
3885
|
+
- \`A1:D10\` \u2014 Range on the first sheet (when only one sheet exists)
|
|
3886
|
+
|
|
3887
|
+
### Tips
|
|
3888
|
+
- Use \`{spreadsheetId}\` placeholder in paths \u2014 it is automatically replaced with the configured default spreadsheet ID
|
|
3889
|
+
- To explore a spreadsheet, first get metadata to see available sheet names
|
|
3890
|
+
- Use \`valueRenderOption=FORMATTED_VALUE\` query param to get display values
|
|
3891
|
+
- Use \`valueRenderOption=UNFORMATTED_VALUE\` for raw numeric values
|
|
3892
|
+
- Use \`majorDimension=COLUMNS\` to get data organized by columns instead of rows
|
|
3893
|
+
|
|
3894
|
+
## Google Sheets SDK (TypeScript handler)
|
|
3895
|
+
|
|
3896
|
+
\`\`\`ts
|
|
3897
|
+
import { connection } from "@squadbase/vite-server/connectors/google-sheets-oauth";
|
|
3898
|
+
|
|
3899
|
+
const sheets = connection("<connectionId>");
|
|
3900
|
+
|
|
3901
|
+
// Get spreadsheet metadata
|
|
3902
|
+
const metadata = await sheets.getSpreadsheet();
|
|
3903
|
+
console.log(metadata.properties.title, metadata.sheets.map(s => s.properties.title));
|
|
3904
|
+
|
|
3905
|
+
// Get cell values
|
|
3906
|
+
const values = await sheets.getValues("Sheet1!A1:D10");
|
|
3907
|
+
console.log(values.values); // 2D array
|
|
3908
|
+
|
|
3909
|
+
// Get multiple ranges at once
|
|
3910
|
+
const batch = await sheets.batchGetValues(["Sheet1!A1:B5", "Sheet2!A1:C3"]);
|
|
3911
|
+
batch.valueRanges.forEach(vr => console.log(vr.range, vr.values));
|
|
3912
|
+
\`\`\``,
|
|
3913
|
+
tools: tools17,
|
|
3914
|
+
async checkConnection(params, config) {
|
|
3915
|
+
const { proxyFetch } = config;
|
|
3916
|
+
const spreadsheetId = params[parameters7.spreadsheetId.slug];
|
|
3917
|
+
if (!spreadsheetId) {
|
|
3918
|
+
return { success: true };
|
|
3919
|
+
}
|
|
3920
|
+
const url = `https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}?fields=spreadsheetId,properties.title`;
|
|
3921
|
+
try {
|
|
3922
|
+
const res = await proxyFetch(url, { method: "GET" });
|
|
3923
|
+
if (!res.ok) {
|
|
3924
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
3925
|
+
return {
|
|
3926
|
+
success: false,
|
|
3927
|
+
error: `Google Sheets API failed: HTTP ${res.status} ${errorText}`
|
|
3928
|
+
};
|
|
3929
|
+
}
|
|
3930
|
+
return { success: true };
|
|
3931
|
+
} catch (error) {
|
|
3932
|
+
return {
|
|
3933
|
+
success: false,
|
|
3934
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3935
|
+
};
|
|
3936
|
+
}
|
|
3937
|
+
}
|
|
3938
|
+
});
|
|
3939
|
+
|
|
3940
|
+
// src/connectors/google-analytics-oauth/tools/list-accounts.ts
|
|
3941
|
+
import { z as z21 } from "zod";
|
|
3942
|
+
var ADMIN_BASE_URL = "https://analyticsadmin.googleapis.com/v1beta/";
|
|
3943
|
+
var REQUEST_TIMEOUT_MS10 = 6e4;
|
|
3944
|
+
var cachedToken5 = null;
|
|
3945
|
+
async function getProxyToken5(config) {
|
|
3946
|
+
if (cachedToken5 && cachedToken5.expiresAt > Date.now() + 6e4) {
|
|
3947
|
+
return cachedToken5.token;
|
|
3948
|
+
}
|
|
3949
|
+
const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
|
|
3950
|
+
const res = await fetch(url, {
|
|
3951
|
+
method: "POST",
|
|
3952
|
+
headers: {
|
|
3953
|
+
"Content-Type": "application/json",
|
|
3954
|
+
"x-api-key": config.appApiKey,
|
|
3955
|
+
"project-id": config.projectId
|
|
3956
|
+
},
|
|
3957
|
+
body: JSON.stringify({
|
|
3958
|
+
sandboxId: config.sandboxId,
|
|
3959
|
+
issuedBy: "coding-agent"
|
|
3960
|
+
})
|
|
3961
|
+
});
|
|
3962
|
+
if (!res.ok) {
|
|
3963
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
3964
|
+
throw new Error(
|
|
3965
|
+
`Failed to get proxy token: HTTP ${res.status} ${errorText}`
|
|
3966
|
+
);
|
|
3967
|
+
}
|
|
3968
|
+
const data = await res.json();
|
|
3969
|
+
cachedToken5 = {
|
|
3970
|
+
token: data.token,
|
|
3971
|
+
expiresAt: new Date(data.expiresAt).getTime()
|
|
3972
|
+
};
|
|
3973
|
+
return data.token;
|
|
3974
|
+
}
|
|
3975
|
+
var inputSchema21 = z21.object({
|
|
3976
|
+
toolUseIntent: z21.string().optional().describe(
|
|
3977
|
+
"Brief description of what you intend to accomplish with this tool call"
|
|
3978
|
+
),
|
|
3979
|
+
connectionId: z21.string().describe("ID of the Google Analytics OAuth connection to use")
|
|
3980
|
+
});
|
|
3981
|
+
var outputSchema21 = z21.discriminatedUnion("success", [
|
|
3982
|
+
z21.object({
|
|
3983
|
+
success: z21.literal(true),
|
|
3984
|
+
accounts: z21.array(
|
|
3985
|
+
z21.object({
|
|
3986
|
+
name: z21.string(),
|
|
3987
|
+
displayName: z21.string()
|
|
3988
|
+
})
|
|
3989
|
+
)
|
|
3990
|
+
}),
|
|
3991
|
+
z21.object({
|
|
3992
|
+
success: z21.literal(false),
|
|
3993
|
+
error: z21.string()
|
|
3994
|
+
})
|
|
3995
|
+
]);
|
|
3996
|
+
var listAccountsTool = new ConnectorTool({
|
|
3997
|
+
name: "listAccounts",
|
|
3998
|
+
description: "List Google Analytics accounts accessible with the current OAuth credentials. Returns account names and display names.",
|
|
3999
|
+
inputSchema: inputSchema21,
|
|
4000
|
+
outputSchema: outputSchema21,
|
|
4001
|
+
async execute({ connectionId }, connections, config) {
|
|
4002
|
+
const connection = connections.find((c) => c.id === connectionId);
|
|
4003
|
+
if (!connection) {
|
|
4004
|
+
return {
|
|
4005
|
+
success: false,
|
|
4006
|
+
error: `Connection ${connectionId} not found`
|
|
4007
|
+
};
|
|
4008
|
+
}
|
|
4009
|
+
console.log(
|
|
4010
|
+
`[connector-request] google-analytics-oauth/${connection.name}: listAccounts`
|
|
4011
|
+
);
|
|
4012
|
+
try {
|
|
4013
|
+
const token = await getProxyToken5(config.oauthProxy);
|
|
4014
|
+
const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
4015
|
+
const controller = new AbortController();
|
|
4016
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS10);
|
|
4017
|
+
try {
|
|
4018
|
+
const response = await fetch(proxyUrl, {
|
|
4019
|
+
method: "POST",
|
|
4020
|
+
headers: {
|
|
4021
|
+
"Content-Type": "application/json",
|
|
4022
|
+
Authorization: `Bearer ${token}`
|
|
4023
|
+
},
|
|
4024
|
+
body: JSON.stringify({
|
|
4025
|
+
url: `${ADMIN_BASE_URL}accounts`,
|
|
4026
|
+
method: "GET"
|
|
4027
|
+
}),
|
|
4028
|
+
signal: controller.signal
|
|
4029
|
+
});
|
|
4030
|
+
const data = await response.json();
|
|
4031
|
+
if (!response.ok) {
|
|
4032
|
+
const errorMessage = typeof data?.error === "string" ? data.error : typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`;
|
|
4033
|
+
return { success: false, error: errorMessage };
|
|
4034
|
+
}
|
|
4035
|
+
const accounts = (data.accounts ?? []).map((a) => ({
|
|
4036
|
+
name: a.name ?? "",
|
|
4037
|
+
displayName: a.displayName ?? ""
|
|
4038
|
+
}));
|
|
4039
|
+
return { success: true, accounts };
|
|
4040
|
+
} finally {
|
|
4041
|
+
clearTimeout(timeout);
|
|
4042
|
+
}
|
|
4043
|
+
} catch (err) {
|
|
4044
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4045
|
+
return { success: false, error: msg };
|
|
4046
|
+
}
|
|
4047
|
+
}
|
|
4048
|
+
});
|
|
4049
|
+
|
|
4050
|
+
// src/connectors/google-analytics-oauth/tools/list-properties.ts
|
|
4051
|
+
import { z as z22 } from "zod";
|
|
4052
|
+
var ADMIN_BASE_URL2 = "https://analyticsadmin.googleapis.com/v1beta/";
|
|
4053
|
+
var REQUEST_TIMEOUT_MS11 = 6e4;
|
|
4054
|
+
var cachedToken6 = null;
|
|
4055
|
+
async function getProxyToken6(config) {
|
|
4056
|
+
if (cachedToken6 && cachedToken6.expiresAt > Date.now() + 6e4) {
|
|
4057
|
+
return cachedToken6.token;
|
|
4058
|
+
}
|
|
4059
|
+
const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
|
|
4060
|
+
const res = await fetch(url, {
|
|
4061
|
+
method: "POST",
|
|
4062
|
+
headers: {
|
|
4063
|
+
"Content-Type": "application/json",
|
|
4064
|
+
"x-api-key": config.appApiKey,
|
|
4065
|
+
"project-id": config.projectId
|
|
4066
|
+
},
|
|
4067
|
+
body: JSON.stringify({
|
|
4068
|
+
sandboxId: config.sandboxId,
|
|
4069
|
+
issuedBy: "coding-agent"
|
|
4070
|
+
})
|
|
4071
|
+
});
|
|
4072
|
+
if (!res.ok) {
|
|
4073
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
4074
|
+
throw new Error(
|
|
4075
|
+
`Failed to get proxy token: HTTP ${res.status} ${errorText}`
|
|
4076
|
+
);
|
|
4077
|
+
}
|
|
4078
|
+
const data = await res.json();
|
|
4079
|
+
cachedToken6 = {
|
|
4080
|
+
token: data.token,
|
|
4081
|
+
expiresAt: new Date(data.expiresAt).getTime()
|
|
4082
|
+
};
|
|
4083
|
+
return data.token;
|
|
4084
|
+
}
|
|
4085
|
+
var inputSchema22 = z22.object({
|
|
4086
|
+
toolUseIntent: z22.string().optional().describe(
|
|
4087
|
+
"Brief description of what you intend to accomplish with this tool call"
|
|
4088
|
+
),
|
|
4089
|
+
connectionId: z22.string().describe("ID of the Google Analytics OAuth connection to use"),
|
|
4090
|
+
accountName: z22.string().describe(
|
|
4091
|
+
"The account resource name (e.g., 'accounts/123456'). Obtained from the listAccounts tool."
|
|
4092
|
+
)
|
|
4093
|
+
});
|
|
4094
|
+
var outputSchema22 = z22.discriminatedUnion("success", [
|
|
4095
|
+
z22.object({
|
|
4096
|
+
success: z22.literal(true),
|
|
4097
|
+
properties: z22.array(
|
|
4098
|
+
z22.object({
|
|
4099
|
+
name: z22.string(),
|
|
4100
|
+
displayName: z22.string(),
|
|
4101
|
+
propertyId: z22.string()
|
|
4102
|
+
})
|
|
4103
|
+
)
|
|
4104
|
+
}),
|
|
4105
|
+
z22.object({
|
|
4106
|
+
success: z22.literal(false),
|
|
4107
|
+
error: z22.string()
|
|
4108
|
+
})
|
|
4109
|
+
]);
|
|
4110
|
+
var listPropertiesTool = new ConnectorTool({
|
|
4111
|
+
name: "listProperties",
|
|
4112
|
+
description: "List GA4 properties for a given Google Analytics account. Returns property names, display names, and property IDs.",
|
|
4113
|
+
inputSchema: inputSchema22,
|
|
4114
|
+
outputSchema: outputSchema22,
|
|
4115
|
+
async execute({ connectionId, accountName }, connections, config) {
|
|
4116
|
+
const connection = connections.find((c) => c.id === connectionId);
|
|
4117
|
+
if (!connection) {
|
|
4118
|
+
return {
|
|
4119
|
+
success: false,
|
|
4120
|
+
error: `Connection ${connectionId} not found`
|
|
4121
|
+
};
|
|
4122
|
+
}
|
|
4123
|
+
console.log(
|
|
4124
|
+
`[connector-request] google-analytics-oauth/${connection.name}: listProperties for ${accountName}`
|
|
4125
|
+
);
|
|
4126
|
+
try {
|
|
4127
|
+
const token = await getProxyToken6(config.oauthProxy);
|
|
4128
|
+
const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
4129
|
+
const controller = new AbortController();
|
|
4130
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS11);
|
|
4131
|
+
try {
|
|
4132
|
+
const filter = encodeURIComponent(`parent:${accountName}`);
|
|
4133
|
+
const response = await fetch(proxyUrl, {
|
|
4134
|
+
method: "POST",
|
|
4135
|
+
headers: {
|
|
4136
|
+
"Content-Type": "application/json",
|
|
4137
|
+
Authorization: `Bearer ${token}`
|
|
4138
|
+
},
|
|
4139
|
+
body: JSON.stringify({
|
|
4140
|
+
url: `${ADMIN_BASE_URL2}properties?filter=${filter}`,
|
|
4141
|
+
method: "GET"
|
|
4142
|
+
}),
|
|
4143
|
+
signal: controller.signal
|
|
4144
|
+
});
|
|
4145
|
+
const data = await response.json();
|
|
4146
|
+
if (!response.ok) {
|
|
4147
|
+
const errorMessage = typeof data?.error === "string" ? data.error : typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`;
|
|
4148
|
+
return { success: false, error: errorMessage };
|
|
4149
|
+
}
|
|
4150
|
+
const properties = (data.properties ?? []).map((p) => {
|
|
4151
|
+
const name = p.name ?? "";
|
|
4152
|
+
const propertyId = name.replace(/^properties\//, "");
|
|
4153
|
+
return {
|
|
4154
|
+
name,
|
|
4155
|
+
displayName: p.displayName ?? "",
|
|
4156
|
+
propertyId
|
|
4157
|
+
};
|
|
4158
|
+
});
|
|
4159
|
+
return { success: true, properties };
|
|
4160
|
+
} finally {
|
|
4161
|
+
clearTimeout(timeout);
|
|
4162
|
+
}
|
|
4163
|
+
} catch (err) {
|
|
4164
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4165
|
+
return { success: false, error: msg };
|
|
4166
|
+
}
|
|
4167
|
+
}
|
|
4168
|
+
});
|
|
4169
|
+
|
|
4170
|
+
// src/connectors/google-analytics-oauth/setup.ts
|
|
4171
|
+
var listAccountsToolName = `google-analytics-oauth_${listAccountsTool.name}`;
|
|
4172
|
+
var listPropertiesToolName = `google-analytics-oauth_${listPropertiesTool.name}`;
|
|
4173
|
+
var googleAnalyticsOauthSetup = new ConnectorSetup({
|
|
4174
|
+
ja: `## Google Analytics \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u624B\u9806
|
|
4175
|
+
|
|
4176
|
+
\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
|
|
4177
|
+
|
|
4178
|
+
### \u624B\u9806
|
|
4179
|
+
|
|
4180
|
+
#### \u30B9\u30C6\u30C3\u30D71: \u30A2\u30AB\u30A6\u30F3\u30C8\u9078\u629E
|
|
4181
|
+
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
|
|
4182
|
+
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:
|
|
4183
|
+
- \`options\`: \u30A2\u30AB\u30A6\u30F3\u30C8\u4E00\u89A7\u3002\u5404 option \u306E \`label\` \u306F \`\u8868\u793A\u540D (name)\` \u306E\u5F62\u5F0F
|
|
4184
|
+
|
|
4185
|
+
#### \u30B9\u30C6\u30C3\u30D72: \u30D7\u30ED\u30D1\u30C6\u30A3\u9078\u629E
|
|
4186
|
+
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
|
|
4187
|
+
2. \`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
|
|
4188
|
+
- \`parameterSlug\`: \`"property-id"\`
|
|
4189
|
+
- \`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
|
|
4190
|
+
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
|
|
4191
|
+
|
|
4192
|
+
#### \u30B9\u30C6\u30C3\u30D73: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5B8C\u4E86
|
|
4193
|
+
1. \`updateConnectionContext\` \u3092\u547C\u3073\u51FA\u3059:
|
|
4194
|
+
- \`property\`: \u9078\u629E\u3055\u308C\u305F\u30D7\u30ED\u30D1\u30C6\u30A3\u306E\u8868\u793A\u540D
|
|
4195
|
+
- \`propertyId\`: \u9078\u629E\u3055\u308C\u305F\u30D7\u30ED\u30D1\u30C6\u30A3ID
|
|
4196
|
+
- \`note\`: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5185\u5BB9\u306E\u7C21\u5358\u306A\u8AAC\u660E
|
|
4197
|
+
|
|
4198
|
+
### \u91CD\u8981\u306A\u5236\u7D04
|
|
4199
|
+
- **\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
|
|
4200
|
+
|
|
4201
|
+
### \u5B9F\u884C\u65B9\u91DD
|
|
4202
|
+
- \u30C4\u30FC\u30EB\u9593\u306F1\u6587\u3060\u3051\u66F8\u3044\u3066\u5373\u6B21\u306E\u30C4\u30FC\u30EB\u547C\u3073\u51FA\u3057
|
|
4203
|
+
- \u4E0D\u8981\u306A\u8AAC\u660E\u306F\u7701\u7565\u3057\u3001\u52B9\u7387\u7684\u306B\u9032\u3081\u308B`,
|
|
4204
|
+
en: `## Google Analytics Setup Instructions
|
|
4205
|
+
|
|
4206
|
+
Follow these steps to set up the Google Analytics (OAuth) connection.
|
|
4207
|
+
|
|
4208
|
+
### Steps
|
|
4209
|
+
|
|
4210
|
+
#### Step 1: Account Selection
|
|
4211
|
+
1. Call \`${listAccountsToolName}\` to get the list of Google Analytics accounts accessible with the OAuth credentials
|
|
4212
|
+
2. Tell the user "Please select an account.", then call \`askUserQuestion\`:
|
|
4213
|
+
- \`options\`: The account list. Each option's \`label\` should be \`Display Name (name)\`
|
|
4214
|
+
|
|
4215
|
+
#### Step 2: Property Selection
|
|
4216
|
+
1. Call \`${listPropertiesToolName}\` to get the list of properties for the selected account
|
|
4217
|
+
2. Call \`updateConnectionParameters\`:
|
|
4218
|
+
- \`parameterSlug\`: \`"property-id"\`
|
|
4219
|
+
- \`options\`: The property list. Each option's \`label\` should be \`Display Name (id: propertyId)\`, \`value\` should be the property ID
|
|
4220
|
+
3. The \`label\` of the user's selected property will arrive as a message. Proceed to Step 3
|
|
4221
|
+
|
|
4222
|
+
#### Step 3: Complete Setup
|
|
4223
|
+
1. Call \`updateConnectionContext\`:
|
|
4224
|
+
- \`property\`: The selected property's display name
|
|
4225
|
+
- \`propertyId\`: The selected property ID
|
|
4226
|
+
- \`note\`: Brief description of the setup
|
|
4227
|
+
|
|
4228
|
+
### Important Constraints
|
|
4229
|
+
- **Do NOT fetch report data during setup**. Only the metadata requests specified in the steps above are allowed
|
|
4230
|
+
|
|
4231
|
+
### Execution Policy
|
|
4232
|
+
- Write only 1 sentence between tool calls, then immediately call the next tool
|
|
4233
|
+
- Skip unnecessary explanations and proceed efficiently`
|
|
4234
|
+
});
|
|
4235
|
+
|
|
4236
|
+
// src/connectors/google-analytics-oauth/tools/request.ts
|
|
4237
|
+
import { z as z23 } from "zod";
|
|
4238
|
+
var BASE_URL5 = "https://analyticsdata.googleapis.com/v1beta/";
|
|
4239
|
+
var REQUEST_TIMEOUT_MS12 = 6e4;
|
|
4240
|
+
var cachedToken7 = null;
|
|
4241
|
+
async function getProxyToken7(config) {
|
|
4242
|
+
if (cachedToken7 && cachedToken7.expiresAt > Date.now() + 6e4) {
|
|
4243
|
+
return cachedToken7.token;
|
|
4244
|
+
}
|
|
4245
|
+
const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
|
|
4246
|
+
const res = await fetch(url, {
|
|
4247
|
+
method: "POST",
|
|
4248
|
+
headers: {
|
|
4249
|
+
"Content-Type": "application/json",
|
|
4250
|
+
"x-api-key": config.appApiKey,
|
|
4251
|
+
"project-id": config.projectId
|
|
4252
|
+
},
|
|
4253
|
+
body: JSON.stringify({
|
|
4254
|
+
sandboxId: config.sandboxId,
|
|
4255
|
+
issuedBy: "coding-agent"
|
|
4256
|
+
})
|
|
4257
|
+
});
|
|
4258
|
+
if (!res.ok) {
|
|
4259
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
4260
|
+
throw new Error(
|
|
4261
|
+
`Failed to get proxy token: HTTP ${res.status} ${errorText}`
|
|
4262
|
+
);
|
|
4263
|
+
}
|
|
4264
|
+
const data = await res.json();
|
|
4265
|
+
cachedToken7 = {
|
|
4266
|
+
token: data.token,
|
|
4267
|
+
expiresAt: new Date(data.expiresAt).getTime()
|
|
4268
|
+
};
|
|
4269
|
+
return data.token;
|
|
4270
|
+
}
|
|
4271
|
+
var inputSchema23 = z23.object({
|
|
4272
|
+
toolUseIntent: z23.string().optional().describe(
|
|
4273
|
+
"Brief description of what you intend to accomplish with this tool call"
|
|
4274
|
+
),
|
|
4275
|
+
connectionId: z23.string().describe("ID of the Google Analytics OAuth connection to use"),
|
|
4276
|
+
method: z23.enum(["GET", "POST"]).describe("HTTP method"),
|
|
4277
|
+
path: z23.string().describe(
|
|
4278
|
+
"API path appended to https://analyticsdata.googleapis.com/v1beta/ (e.g., 'properties/{propertyId}:runReport'). {propertyId} is automatically replaced."
|
|
4279
|
+
),
|
|
4280
|
+
body: z23.record(z23.string(), z23.unknown()).optional().describe("POST request body (JSON)")
|
|
4281
|
+
});
|
|
4282
|
+
var outputSchema23 = z23.discriminatedUnion("success", [
|
|
4283
|
+
z23.object({
|
|
4284
|
+
success: z23.literal(true),
|
|
4285
|
+
status: z23.number(),
|
|
4286
|
+
data: z23.record(z23.string(), z23.unknown())
|
|
4287
|
+
}),
|
|
4288
|
+
z23.object({
|
|
4289
|
+
success: z23.literal(false),
|
|
4290
|
+
error: z23.string()
|
|
4291
|
+
})
|
|
4292
|
+
]);
|
|
4293
|
+
var requestTool7 = new ConnectorTool({
|
|
4294
|
+
name: "request",
|
|
4295
|
+
description: `Send authenticated requests to the Google Analytics Data API v1beta.
|
|
4296
|
+
Authentication is handled automatically via OAuth proxy.
|
|
4297
|
+
{propertyId} in the path is automatically replaced with the connection's property ID.`,
|
|
4298
|
+
inputSchema: inputSchema23,
|
|
4299
|
+
outputSchema: outputSchema23,
|
|
4300
|
+
async execute({ connectionId, method, path, body }, connections, config) {
|
|
4301
|
+
const connection = connections.find((c) => c.id === connectionId);
|
|
4302
|
+
if (!connection) {
|
|
4303
|
+
return {
|
|
4304
|
+
success: false,
|
|
4305
|
+
error: `Connection ${connectionId} not found`
|
|
4306
|
+
};
|
|
4307
|
+
}
|
|
4308
|
+
console.log(
|
|
4309
|
+
`[connector-request] google-analytics-oauth/${connection.name}: ${method} ${path}`
|
|
4310
|
+
);
|
|
4311
|
+
try {
|
|
4312
|
+
const propertyId = parameters8.propertyId.tryGetValue(connection);
|
|
4313
|
+
const resolvedPath = propertyId ? path.replace(/\{propertyId\}/g, propertyId) : path;
|
|
4314
|
+
const url = `${BASE_URL5}${resolvedPath}`;
|
|
4315
|
+
const token = await getProxyToken7(config.oauthProxy);
|
|
4316
|
+
const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
4317
|
+
const controller = new AbortController();
|
|
4318
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS12);
|
|
4319
|
+
try {
|
|
4320
|
+
const response = await fetch(proxyUrl, {
|
|
4321
|
+
method: "POST",
|
|
4322
|
+
headers: {
|
|
4323
|
+
"Content-Type": "application/json",
|
|
4324
|
+
Authorization: `Bearer ${token}`
|
|
4325
|
+
},
|
|
4326
|
+
body: JSON.stringify({
|
|
4327
|
+
url,
|
|
4328
|
+
method,
|
|
4329
|
+
...method === "POST" && body ? {
|
|
4330
|
+
headers: { "Content-Type": "application/json" },
|
|
4331
|
+
body: JSON.stringify(body)
|
|
4332
|
+
} : {}
|
|
4333
|
+
}),
|
|
4334
|
+
signal: controller.signal
|
|
4335
|
+
});
|
|
4336
|
+
const data = await response.json();
|
|
4337
|
+
if (!response.ok) {
|
|
4338
|
+
const errorMessage = typeof data?.error === "string" ? data.error : typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`;
|
|
4339
|
+
return { success: false, error: errorMessage };
|
|
4340
|
+
}
|
|
4341
|
+
return { success: true, status: response.status, data };
|
|
4342
|
+
} finally {
|
|
4343
|
+
clearTimeout(timeout);
|
|
4344
|
+
}
|
|
4345
|
+
} catch (err) {
|
|
4346
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4347
|
+
return { success: false, error: msg };
|
|
4348
|
+
}
|
|
4349
|
+
}
|
|
4350
|
+
});
|
|
4351
|
+
|
|
4352
|
+
// src/connectors/google-analytics-oauth/index.ts
|
|
4353
|
+
var tools18 = {
|
|
4354
|
+
request: requestTool7,
|
|
4355
|
+
listAccounts: listAccountsTool,
|
|
4356
|
+
listProperties: listPropertiesTool
|
|
4357
|
+
};
|
|
4358
|
+
var googleAnalyticsOauthConnector = new ConnectorPlugin({
|
|
4359
|
+
slug: "google-analytics",
|
|
4360
|
+
authType: AUTH_TYPES.OAUTH,
|
|
4361
|
+
name: "Google Analytics (OAuth)",
|
|
4362
|
+
description: "Connect to Google Analytics for web analytics and reporting using OAuth.",
|
|
4363
|
+
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/7fs0ipzxuD9mACDzBATtxX/3c53ed90d15c96483e4f78cb29dab5e9/google-analytics.svg",
|
|
4364
|
+
parameters: parameters8,
|
|
4365
|
+
releaseFlag: { dev1: true, dev2: true, prod: false },
|
|
4366
|
+
setup: googleAnalyticsOauthSetup,
|
|
4367
|
+
proxyPolicy: {
|
|
4368
|
+
allowlist: [
|
|
4369
|
+
{
|
|
4370
|
+
host: "analyticsdata.googleapis.com",
|
|
4371
|
+
methods: ["GET", "POST"]
|
|
4372
|
+
},
|
|
4373
|
+
{
|
|
4374
|
+
host: "analyticsadmin.googleapis.com",
|
|
4375
|
+
methods: ["GET"]
|
|
4376
|
+
}
|
|
4377
|
+
]
|
|
4378
|
+
},
|
|
4379
|
+
systemPrompt: `## Google Analytics Data API (OAuth, Read-Only)
|
|
4380
|
+
- Call the GA4 Data API using the authenticated request tool
|
|
4381
|
+
- {propertyId} in the path is automatically replaced
|
|
4382
|
+
|
|
4383
|
+
### Get Metadata (Check available dimensions and metrics)
|
|
4384
|
+
- GET properties/{propertyId}/metadata
|
|
4385
|
+
|
|
4386
|
+
### Get Report
|
|
4387
|
+
- POST properties/{propertyId}:runReport
|
|
4388
|
+
- Body example:
|
|
4389
|
+
{
|
|
4390
|
+
"dateRanges": [{"startDate": "7daysAgo", "endDate": "today"}],
|
|
4391
|
+
"dimensions": [{"name": "date"}],
|
|
4392
|
+
"metrics": [{"name": "activeUsers"}],
|
|
4393
|
+
"limit": 100
|
|
4394
|
+
}
|
|
4395
|
+
|
|
4396
|
+
### Common Dimensions
|
|
4397
|
+
date, country, city, deviceCategory, browser, pagePath, pageTitle,
|
|
4398
|
+
sessionSource, sessionMedium, eventName
|
|
4399
|
+
|
|
4400
|
+
### Common Metrics
|
|
4401
|
+
activeUsers, sessions, screenPageViews, bounceRate,
|
|
4402
|
+
averageSessionDuration, conversions, totalRevenue
|
|
4403
|
+
|
|
4404
|
+
### Date Specification
|
|
4405
|
+
- Absolute: "2024-01-01"
|
|
4406
|
+
- Relative: "today", "yesterday", "7daysAgo", "30daysAgo"
|
|
4407
|
+
|
|
4408
|
+
## Google Analytics SDK (TypeScript handler)
|
|
4409
|
+
|
|
4410
|
+
\`\`\`ts
|
|
4411
|
+
import { connection } from "@squadbase/vite-server/connectors/google-analytics-oauth";
|
|
4412
|
+
|
|
4413
|
+
const ga = connection("<connectionId>");
|
|
4414
|
+
|
|
4415
|
+
// Authenticated fetch (returns standard Response)
|
|
4416
|
+
const res = await ga.request("properties/{propertyId}:runReport", {
|
|
4417
|
+
method: "POST",
|
|
4418
|
+
body: JSON.stringify({ dateRanges: [{ startDate: "7daysAgo", endDate: "today" }], metrics: [{ name: "activeUsers" }] }),
|
|
4419
|
+
});
|
|
4420
|
+
const data = await res.json();
|
|
4421
|
+
|
|
4422
|
+
// Convenience methods
|
|
4423
|
+
const { rows, rowCount } = await ga.runReport({
|
|
4424
|
+
dateRanges: [{ startDate: "7daysAgo", endDate: "today" }],
|
|
4425
|
+
dimensions: [{ name: "date" }],
|
|
4426
|
+
metrics: [{ name: "activeUsers" }, { name: "sessions" }],
|
|
4427
|
+
limit: 100,
|
|
4428
|
+
});
|
|
4429
|
+
const metadata = await ga.getMetadata();
|
|
4430
|
+
const realtime = await ga.runRealtimeReport({
|
|
4431
|
+
metrics: [{ name: "activeUsers" }],
|
|
4432
|
+
dimensions: [{ name: "country" }],
|
|
4433
|
+
});
|
|
4434
|
+
\`\`\``,
|
|
4435
|
+
tools: tools18,
|
|
4436
|
+
async checkConnection(params, config) {
|
|
4437
|
+
const { proxyFetch } = config;
|
|
4438
|
+
const propertyId = params[parameters8.propertyId.slug];
|
|
4439
|
+
if (!propertyId) {
|
|
4440
|
+
return { success: true };
|
|
4441
|
+
}
|
|
4442
|
+
const url = `https://analyticsdata.googleapis.com/v1beta/properties/${propertyId}/metadata`;
|
|
4443
|
+
try {
|
|
4444
|
+
const res = await proxyFetch(url, { method: "GET" });
|
|
4445
|
+
if (!res.ok) {
|
|
4446
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
4447
|
+
return {
|
|
4448
|
+
success: false,
|
|
4449
|
+
error: `Google Analytics API failed: HTTP ${res.status} ${errorText}`
|
|
4450
|
+
};
|
|
4451
|
+
}
|
|
4452
|
+
return { success: true };
|
|
4453
|
+
} catch (error) {
|
|
4454
|
+
return {
|
|
4455
|
+
success: false,
|
|
4456
|
+
error: error instanceof Error ? error.message : String(error)
|
|
4457
|
+
};
|
|
4458
|
+
}
|
|
4459
|
+
}
|
|
4460
|
+
});
|
|
4461
|
+
|
|
4462
|
+
// src/connectors/google-ads-oauth/tools/list-customers.ts
|
|
4463
|
+
import { z as z24 } from "zod";
|
|
4464
|
+
var BASE_URL6 = "https://googleads.googleapis.com/v18/";
|
|
4465
|
+
var REQUEST_TIMEOUT_MS13 = 6e4;
|
|
4466
|
+
var cachedToken8 = null;
|
|
4467
|
+
async function getProxyToken8(config) {
|
|
4468
|
+
if (cachedToken8 && cachedToken8.expiresAt > Date.now() + 6e4) {
|
|
4469
|
+
return cachedToken8.token;
|
|
4470
|
+
}
|
|
4471
|
+
const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
|
|
4472
|
+
const res = await fetch(url, {
|
|
4473
|
+
method: "POST",
|
|
4474
|
+
headers: {
|
|
4475
|
+
"Content-Type": "application/json",
|
|
4476
|
+
"x-api-key": config.appApiKey,
|
|
4477
|
+
"project-id": config.projectId
|
|
4478
|
+
},
|
|
4479
|
+
body: JSON.stringify({
|
|
4480
|
+
sandboxId: config.sandboxId,
|
|
4481
|
+
issuedBy: "coding-agent"
|
|
4482
|
+
})
|
|
4483
|
+
});
|
|
4484
|
+
if (!res.ok) {
|
|
4485
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
4486
|
+
throw new Error(
|
|
4487
|
+
`Failed to get proxy token: HTTP ${res.status} ${errorText}`
|
|
4488
|
+
);
|
|
4489
|
+
}
|
|
4490
|
+
const data = await res.json();
|
|
4491
|
+
cachedToken8 = {
|
|
4492
|
+
token: data.token,
|
|
4493
|
+
expiresAt: new Date(data.expiresAt).getTime()
|
|
4494
|
+
};
|
|
4495
|
+
return data.token;
|
|
4496
|
+
}
|
|
4497
|
+
var inputSchema24 = z24.object({
|
|
4498
|
+
toolUseIntent: z24.string().optional().describe(
|
|
4499
|
+
"Brief description of what you intend to accomplish with this tool call"
|
|
4500
|
+
),
|
|
4501
|
+
connectionId: z24.string().describe("ID of the Google Ads OAuth connection to use")
|
|
4502
|
+
});
|
|
4503
|
+
var outputSchema24 = z24.discriminatedUnion("success", [
|
|
4504
|
+
z24.object({
|
|
4505
|
+
success: z24.literal(true),
|
|
4506
|
+
customers: z24.array(
|
|
4507
|
+
z24.object({
|
|
4508
|
+
customerId: z24.string(),
|
|
4509
|
+
descriptiveName: z24.string()
|
|
4510
|
+
})
|
|
4511
|
+
)
|
|
4512
|
+
}),
|
|
4513
|
+
z24.object({
|
|
4514
|
+
success: z24.literal(false),
|
|
4515
|
+
error: z24.string()
|
|
4516
|
+
})
|
|
4517
|
+
]);
|
|
4518
|
+
var listCustomersTool = new ConnectorTool({
|
|
4519
|
+
name: "listCustomers",
|
|
4520
|
+
description: "List Google Ads customer accounts accessible with the current OAuth credentials.",
|
|
4521
|
+
inputSchema: inputSchema24,
|
|
4522
|
+
outputSchema: outputSchema24,
|
|
4523
|
+
async execute({ connectionId }, connections, config) {
|
|
4524
|
+
const connection = connections.find((c) => c.id === connectionId);
|
|
4525
|
+
if (!connection) {
|
|
4526
|
+
return {
|
|
4527
|
+
success: false,
|
|
4528
|
+
error: `Connection ${connectionId} not found`
|
|
4529
|
+
};
|
|
4530
|
+
}
|
|
4531
|
+
console.log(
|
|
4532
|
+
`[connector-request] google-ads-oauth/${connection.name}: listCustomers`
|
|
4533
|
+
);
|
|
4534
|
+
try {
|
|
4535
|
+
const developerToken = parameters9.developerToken.getValue(connection);
|
|
4536
|
+
const token = await getProxyToken8(config.oauthProxy);
|
|
4537
|
+
const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
4538
|
+
const controller = new AbortController();
|
|
4539
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS13);
|
|
4540
|
+
try {
|
|
4541
|
+
const response = await fetch(proxyUrl, {
|
|
4542
|
+
method: "POST",
|
|
4543
|
+
headers: {
|
|
4544
|
+
"Content-Type": "application/json",
|
|
4545
|
+
Authorization: `Bearer ${token}`
|
|
4546
|
+
},
|
|
4547
|
+
body: JSON.stringify({
|
|
4548
|
+
url: `${BASE_URL6}customers:listAccessibleCustomers`,
|
|
4549
|
+
method: "GET",
|
|
4550
|
+
headers: {
|
|
4551
|
+
"developer-token": developerToken
|
|
4552
|
+
}
|
|
4553
|
+
}),
|
|
4554
|
+
signal: controller.signal
|
|
4555
|
+
});
|
|
4556
|
+
const data = await response.json();
|
|
4557
|
+
if (!response.ok) {
|
|
4558
|
+
const errorMessage = typeof data?.error === "string" ? data.error : typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`;
|
|
4559
|
+
return { success: false, error: errorMessage };
|
|
4560
|
+
}
|
|
4561
|
+
const customerIds = (data.resourceNames ?? []).map(
|
|
4562
|
+
(rn) => rn.replace(/^customers\//, "")
|
|
4563
|
+
);
|
|
4564
|
+
const customers = [];
|
|
4565
|
+
for (const cid of customerIds) {
|
|
4566
|
+
try {
|
|
4567
|
+
const detailResponse = await fetch(proxyUrl, {
|
|
4568
|
+
method: "POST",
|
|
4569
|
+
headers: {
|
|
4570
|
+
"Content-Type": "application/json",
|
|
4571
|
+
Authorization: `Bearer ${token}`
|
|
4572
|
+
},
|
|
4573
|
+
body: JSON.stringify({
|
|
4574
|
+
url: `${BASE_URL6}customers/${cid}/googleAds:searchStream`,
|
|
4575
|
+
method: "POST",
|
|
4576
|
+
headers: {
|
|
4577
|
+
"Content-Type": "application/json",
|
|
4578
|
+
"developer-token": developerToken,
|
|
4579
|
+
"login-customer-id": cid
|
|
4580
|
+
},
|
|
4581
|
+
body: JSON.stringify({
|
|
4582
|
+
query: "SELECT customer.id, customer.descriptive_name FROM customer LIMIT 1"
|
|
4583
|
+
})
|
|
4584
|
+
}),
|
|
4585
|
+
signal: controller.signal
|
|
4586
|
+
});
|
|
4587
|
+
if (detailResponse.ok) {
|
|
4588
|
+
const detailData = await detailResponse.json();
|
|
4589
|
+
const customer = detailData?.[0]?.results?.[0]?.customer;
|
|
4590
|
+
customers.push({
|
|
4591
|
+
customerId: cid,
|
|
4592
|
+
descriptiveName: customer?.descriptiveName ?? cid
|
|
4593
|
+
});
|
|
4594
|
+
} else {
|
|
4595
|
+
customers.push({
|
|
4596
|
+
customerId: cid,
|
|
4597
|
+
descriptiveName: cid
|
|
4598
|
+
});
|
|
4599
|
+
}
|
|
4600
|
+
} catch {
|
|
4601
|
+
customers.push({
|
|
4602
|
+
customerId: cid,
|
|
4603
|
+
descriptiveName: cid
|
|
4604
|
+
});
|
|
4605
|
+
}
|
|
4606
|
+
}
|
|
4607
|
+
return { success: true, customers };
|
|
4608
|
+
} finally {
|
|
4609
|
+
clearTimeout(timeout);
|
|
4610
|
+
}
|
|
4611
|
+
} catch (err) {
|
|
4612
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4613
|
+
return { success: false, error: msg };
|
|
4614
|
+
}
|
|
4615
|
+
}
|
|
4616
|
+
});
|
|
4617
|
+
|
|
4618
|
+
// src/connectors/google-ads-oauth/setup.ts
|
|
4619
|
+
var listCustomersToolName = `google-ads-oauth_${listCustomersTool.name}`;
|
|
4620
|
+
var googleAdsSetup = new ConnectorSetup({
|
|
4621
|
+
ja: `## Google Ads \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u624B\u9806
|
|
4622
|
+
|
|
4623
|
+
\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
|
|
4624
|
+
|
|
4625
|
+
### \u624B\u9806
|
|
4626
|
+
|
|
4627
|
+
#### \u30B9\u30C6\u30C3\u30D71: \u30AB\u30B9\u30BF\u30DE\u30FC\u9078\u629E
|
|
4628
|
+
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
|
|
4629
|
+
2. \`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
|
|
4630
|
+
- \`parameterSlug\`: \`"customer-id"\`
|
|
4631
|
+
- \`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
|
|
4632
|
+
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\u30D72\u306B\u9032\u3080
|
|
4633
|
+
|
|
4634
|
+
#### \u30B9\u30C6\u30C3\u30D72: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5B8C\u4E86
|
|
4635
|
+
1. \`updateConnectionContext\` \u3092\u547C\u3073\u51FA\u3059:
|
|
4636
|
+
- \`customer\`: \u9078\u629E\u3055\u308C\u305F\u30AB\u30B9\u30BF\u30DE\u30FC\u306E\u8868\u793A\u540D
|
|
4637
|
+
- \`customerId\`: \u9078\u629E\u3055\u308C\u305F\u30AB\u30B9\u30BF\u30DE\u30FCID
|
|
4638
|
+
- \`note\`: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5185\u5BB9\u306E\u7C21\u5358\u306A\u8AAC\u660E
|
|
4639
|
+
|
|
4640
|
+
### \u91CD\u8981\u306A\u5236\u7D04
|
|
4641
|
+
- **\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
|
|
4642
|
+
|
|
4643
|
+
### \u5B9F\u884C\u65B9\u91DD
|
|
4644
|
+
- \u30C4\u30FC\u30EB\u9593\u306F1\u6587\u3060\u3051\u66F8\u3044\u3066\u5373\u6B21\u306E\u30C4\u30FC\u30EB\u547C\u3073\u51FA\u3057
|
|
4645
|
+
- \u4E0D\u8981\u306A\u8AAC\u660E\u306F\u7701\u7565\u3057\u3001\u52B9\u7387\u7684\u306B\u9032\u3081\u308B`,
|
|
4646
|
+
en: `## Google Ads Setup Instructions
|
|
4647
|
+
|
|
4648
|
+
Follow these steps to set up the Google Ads (OAuth) connection.
|
|
4649
|
+
|
|
4650
|
+
### Steps
|
|
4651
|
+
|
|
4652
|
+
#### Step 1: Customer Selection
|
|
4653
|
+
1. Call \`${listCustomersToolName}\` to get the list of Google Ads customer accounts accessible with the OAuth credentials
|
|
4654
|
+
2. Call \`updateConnectionParameters\`:
|
|
4655
|
+
- \`parameterSlug\`: \`"customer-id"\`
|
|
4656
|
+
- \`options\`: The customer list. Each option's \`label\` should be \`Account Name (id: customerId)\`, \`value\` should be the customer ID
|
|
4657
|
+
3. The \`label\` of the user's selected customer will arrive as a message. Proceed to Step 2
|
|
4658
|
+
|
|
4659
|
+
#### Step 2: Complete Setup
|
|
4660
|
+
1. Call \`updateConnectionContext\`:
|
|
4661
|
+
- \`customer\`: The selected customer's display name
|
|
4662
|
+
- \`customerId\`: The selected customer ID
|
|
4663
|
+
- \`note\`: Brief description of the setup
|
|
4664
|
+
|
|
4665
|
+
### Important Constraints
|
|
4666
|
+
- **Do NOT fetch report data during setup**. Only the metadata requests specified in the steps above are allowed
|
|
4667
|
+
|
|
4668
|
+
### Execution Policy
|
|
4669
|
+
- Write only 1 sentence between tool calls, then immediately call the next tool
|
|
4670
|
+
- Skip unnecessary explanations and proceed efficiently`
|
|
4671
|
+
});
|
|
4672
|
+
|
|
4673
|
+
// src/connectors/google-ads-oauth/tools/request.ts
|
|
4674
|
+
import { z as z25 } from "zod";
|
|
4675
|
+
var BASE_URL7 = "https://googleads.googleapis.com/v18/";
|
|
4676
|
+
var REQUEST_TIMEOUT_MS14 = 6e4;
|
|
4677
|
+
var cachedToken9 = null;
|
|
4678
|
+
async function getProxyToken9(config) {
|
|
4679
|
+
if (cachedToken9 && cachedToken9.expiresAt > Date.now() + 6e4) {
|
|
4680
|
+
return cachedToken9.token;
|
|
4681
|
+
}
|
|
4682
|
+
const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
|
|
4683
|
+
const res = await fetch(url, {
|
|
4684
|
+
method: "POST",
|
|
4685
|
+
headers: {
|
|
4686
|
+
"Content-Type": "application/json",
|
|
4687
|
+
"x-api-key": config.appApiKey,
|
|
4688
|
+
"project-id": config.projectId
|
|
4689
|
+
},
|
|
4690
|
+
body: JSON.stringify({
|
|
4691
|
+
sandboxId: config.sandboxId,
|
|
4692
|
+
issuedBy: "coding-agent"
|
|
4693
|
+
})
|
|
4694
|
+
});
|
|
4695
|
+
if (!res.ok) {
|
|
4696
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
4697
|
+
throw new Error(
|
|
4698
|
+
`Failed to get proxy token: HTTP ${res.status} ${errorText}`
|
|
4699
|
+
);
|
|
4700
|
+
}
|
|
4701
|
+
const data = await res.json();
|
|
4702
|
+
cachedToken9 = {
|
|
4703
|
+
token: data.token,
|
|
4704
|
+
expiresAt: new Date(data.expiresAt).getTime()
|
|
4705
|
+
};
|
|
4706
|
+
return data.token;
|
|
4707
|
+
}
|
|
4708
|
+
var inputSchema25 = z25.object({
|
|
4709
|
+
toolUseIntent: z25.string().optional().describe(
|
|
4710
|
+
"Brief description of what you intend to accomplish with this tool call"
|
|
4711
|
+
),
|
|
4712
|
+
connectionId: z25.string().describe("ID of the Google Ads OAuth connection to use"),
|
|
4713
|
+
method: z25.enum(["GET", "POST"]).describe("HTTP method"),
|
|
4714
|
+
path: z25.string().describe(
|
|
4715
|
+
"API path appended to https://googleads.googleapis.com/v18/ (e.g., 'customers/{customerId}/googleAds:searchStream'). {customerId} is automatically replaced."
|
|
4716
|
+
),
|
|
4717
|
+
body: z25.record(z25.string(), z25.unknown()).optional().describe("POST request body (JSON)")
|
|
4718
|
+
});
|
|
4719
|
+
var outputSchema25 = z25.discriminatedUnion("success", [
|
|
4720
|
+
z25.object({
|
|
4721
|
+
success: z25.literal(true),
|
|
4722
|
+
status: z25.number(),
|
|
4723
|
+
data: z25.unknown()
|
|
4724
|
+
}),
|
|
4725
|
+
z25.object({
|
|
4726
|
+
success: z25.literal(false),
|
|
4727
|
+
error: z25.string()
|
|
4728
|
+
})
|
|
4729
|
+
]);
|
|
4730
|
+
var requestTool8 = new ConnectorTool({
|
|
4731
|
+
name: "request",
|
|
4732
|
+
description: `Send authenticated requests to the Google Ads API v18.
|
|
4733
|
+
Authentication is handled automatically via OAuth proxy.
|
|
4734
|
+
{customerId} in the path is automatically replaced with the connection's customer ID (hyphens removed).`,
|
|
4735
|
+
inputSchema: inputSchema25,
|
|
4736
|
+
outputSchema: outputSchema25,
|
|
4737
|
+
async execute({ connectionId, method, path, body }, connections, config) {
|
|
4738
|
+
const connection = connections.find((c) => c.id === connectionId);
|
|
4739
|
+
if (!connection) {
|
|
4740
|
+
return {
|
|
4741
|
+
success: false,
|
|
4742
|
+
error: `Connection ${connectionId} not found`
|
|
4743
|
+
};
|
|
4744
|
+
}
|
|
4745
|
+
console.log(
|
|
4746
|
+
`[connector-request] google-ads-oauth/${connection.name}: ${method} ${path}`
|
|
4747
|
+
);
|
|
4748
|
+
try {
|
|
4749
|
+
const rawCustomerId = parameters9.customerId.tryGetValue(connection);
|
|
4750
|
+
const customerId = rawCustomerId?.replace(/-/g, "") ?? "";
|
|
4751
|
+
const resolvedPath = customerId ? path.replace(/\{customerId\}/g, customerId) : path;
|
|
4752
|
+
const url = `${BASE_URL7}${resolvedPath}`;
|
|
4753
|
+
const token = await getProxyToken9(config.oauthProxy);
|
|
4754
|
+
const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
4755
|
+
const controller = new AbortController();
|
|
4756
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS14);
|
|
4757
|
+
try {
|
|
4758
|
+
const developerToken = parameters9.developerToken.getValue(connection);
|
|
4759
|
+
const response = await fetch(proxyUrl, {
|
|
4760
|
+
method: "POST",
|
|
4761
|
+
headers: {
|
|
4762
|
+
"Content-Type": "application/json",
|
|
4763
|
+
Authorization: `Bearer ${token}`
|
|
4764
|
+
},
|
|
4765
|
+
body: JSON.stringify({
|
|
4766
|
+
url,
|
|
4767
|
+
method,
|
|
4768
|
+
headers: {
|
|
4769
|
+
"Content-Type": "application/json",
|
|
4770
|
+
"developer-token": developerToken,
|
|
4771
|
+
...customerId ? { "login-customer-id": customerId } : {}
|
|
4772
|
+
},
|
|
4773
|
+
...method === "POST" && body ? { body: JSON.stringify(body) } : {}
|
|
4774
|
+
}),
|
|
4775
|
+
signal: controller.signal
|
|
4776
|
+
});
|
|
4777
|
+
const data = await response.json();
|
|
4778
|
+
if (!response.ok) {
|
|
4779
|
+
const dataObj = data;
|
|
4780
|
+
const errorMessage = typeof dataObj?.error === "string" ? dataObj.error : typeof dataObj?.message === "string" ? dataObj.message : `HTTP ${response.status} ${response.statusText}`;
|
|
4781
|
+
return { success: false, error: errorMessage };
|
|
4782
|
+
}
|
|
4783
|
+
return { success: true, status: response.status, data };
|
|
4784
|
+
} finally {
|
|
4785
|
+
clearTimeout(timeout);
|
|
4786
|
+
}
|
|
4787
|
+
} catch (err) {
|
|
4788
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4789
|
+
return { success: false, error: msg };
|
|
4790
|
+
}
|
|
4791
|
+
}
|
|
4792
|
+
});
|
|
4793
|
+
|
|
4794
|
+
// src/connectors/google-ads-oauth/index.ts
|
|
4795
|
+
var tools19 = {
|
|
4796
|
+
request: requestTool8,
|
|
4797
|
+
listCustomers: listCustomersTool
|
|
4798
|
+
};
|
|
4799
|
+
var googleAdsOauthConnector = new ConnectorPlugin({
|
|
4800
|
+
slug: "google-ads",
|
|
4801
|
+
authType: AUTH_TYPES.OAUTH,
|
|
4802
|
+
name: "Google Ads (OAuth)",
|
|
4803
|
+
description: "Connect to Google Ads for advertising campaign data and reporting using OAuth.",
|
|
4804
|
+
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/6lQFddkMPLCzLJBPn1TiSe/4b22b78cd2a9cc91e9ee9283e5c80a51/google-ads.svg",
|
|
4805
|
+
parameters: parameters9,
|
|
4806
|
+
releaseFlag: { dev1: true, dev2: true, prod: false },
|
|
4807
|
+
setup: googleAdsSetup,
|
|
4808
|
+
proxyPolicy: {
|
|
4809
|
+
allowlist: [
|
|
4810
|
+
{
|
|
4811
|
+
host: "googleads.googleapis.com",
|
|
4812
|
+
methods: ["GET", "POST"]
|
|
4813
|
+
}
|
|
4814
|
+
]
|
|
4815
|
+
},
|
|
4816
|
+
systemPrompt: `## Google Ads API (OAuth, Read-Only)
|
|
4817
|
+
- Use GAQL (Google Ads Query Language) to query campaign data
|
|
4818
|
+
- {customerId} in the path is automatically replaced (hyphens removed)
|
|
4819
|
+
|
|
4820
|
+
### Query Data (searchStream)
|
|
4821
|
+
- POST customers/{customerId}/googleAds:searchStream
|
|
4822
|
+
- Body: { "query": "SELECT campaign.id, campaign.name, metrics.impressions FROM campaign WHERE segments.date DURING LAST_30_DAYS" }
|
|
4823
|
+
|
|
4824
|
+
### Common GAQL Resources
|
|
4825
|
+
- \`campaign\`: Campaign data (campaign.id, campaign.name, campaign.status)
|
|
4826
|
+
- \`ad_group\`: Ad group data (ad_group.id, ad_group.name, ad_group.status)
|
|
4827
|
+
- \`ad_group_ad\`: Ad data (ad_group_ad.ad.id, ad_group_ad.status)
|
|
4828
|
+
- \`keyword_view\`: Keyword performance data
|
|
4829
|
+
|
|
4830
|
+
### Common Metrics
|
|
4831
|
+
metrics.impressions, metrics.clicks, metrics.cost_micros, metrics.conversions,
|
|
4832
|
+
metrics.ctr, metrics.average_cpc, metrics.conversions_value
|
|
4833
|
+
|
|
4834
|
+
### Common Segments
|
|
4835
|
+
segments.date, segments.device, segments.ad_network_type
|
|
4836
|
+
|
|
4837
|
+
### Date Filters
|
|
4838
|
+
- \`DURING LAST_7_DAYS\`, \`DURING LAST_30_DAYS\`, \`DURING THIS_MONTH\`
|
|
4839
|
+
- \`WHERE segments.date BETWEEN '2024-01-01' AND '2024-01-31'\`
|
|
4840
|
+
|
|
4841
|
+
### Tips
|
|
4842
|
+
- cost_micros is in micros (divide by 1,000,000 for actual currency)
|
|
4843
|
+
- Use LIMIT to restrict result count
|
|
4844
|
+
- Always include relevant WHERE clauses to filter data
|
|
4845
|
+
|
|
4846
|
+
## Google Ads SDK (TypeScript handler)
|
|
4847
|
+
|
|
4848
|
+
\`\`\`ts
|
|
4849
|
+
import { connection } from "@squadbase/vite-server/connectors/google-ads-oauth";
|
|
4850
|
+
|
|
4851
|
+
const ads = connection("<connectionId>");
|
|
4852
|
+
|
|
4853
|
+
// Execute a GAQL query
|
|
4854
|
+
const rows = await ads.search(
|
|
4855
|
+
"SELECT campaign.name, metrics.impressions, metrics.clicks FROM campaign WHERE segments.date DURING LAST_7_DAYS"
|
|
4856
|
+
);
|
|
4857
|
+
rows.forEach(row => console.log(row));
|
|
4858
|
+
|
|
4859
|
+
// List accessible customer accounts
|
|
4860
|
+
const customerIds = await ads.listAccessibleCustomers();
|
|
4861
|
+
\`\`\``,
|
|
4862
|
+
tools: tools19,
|
|
4863
|
+
async checkConnection(params, config) {
|
|
4864
|
+
const { proxyFetch } = config;
|
|
4865
|
+
const rawCustomerId = params[parameters9.customerId.slug];
|
|
4866
|
+
const customerId = rawCustomerId?.replace(/-/g, "");
|
|
4867
|
+
if (!customerId) {
|
|
4868
|
+
return { success: true };
|
|
4869
|
+
}
|
|
4870
|
+
const developerToken = params[parameters9.developerToken.slug];
|
|
4871
|
+
if (!developerToken) {
|
|
4872
|
+
return {
|
|
4873
|
+
success: false,
|
|
4874
|
+
error: "Developer token is required"
|
|
4875
|
+
};
|
|
4876
|
+
}
|
|
4877
|
+
const url = `https://googleads.googleapis.com/v18/customers/${customerId}/googleAds:searchStream`;
|
|
4878
|
+
try {
|
|
4879
|
+
const res = await proxyFetch(url, {
|
|
4880
|
+
method: "POST",
|
|
4881
|
+
headers: {
|
|
4882
|
+
"Content-Type": "application/json",
|
|
4883
|
+
"developer-token": developerToken,
|
|
4884
|
+
"login-customer-id": customerId
|
|
4885
|
+
},
|
|
4886
|
+
body: JSON.stringify({
|
|
4887
|
+
query: "SELECT customer.id FROM customer LIMIT 1"
|
|
4888
|
+
})
|
|
4889
|
+
});
|
|
4890
|
+
if (!res.ok) {
|
|
4891
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
4892
|
+
return {
|
|
4893
|
+
success: false,
|
|
4894
|
+
error: `Google Ads API failed: HTTP ${res.status} ${errorText}`
|
|
4895
|
+
};
|
|
4896
|
+
}
|
|
4897
|
+
return { success: true };
|
|
4898
|
+
} catch (error) {
|
|
4899
|
+
return {
|
|
4900
|
+
success: false,
|
|
4901
|
+
error: error instanceof Error ? error.message : String(error)
|
|
4902
|
+
};
|
|
4903
|
+
}
|
|
4904
|
+
}
|
|
4905
|
+
});
|
|
4906
|
+
|
|
3668
4907
|
// src/connectors/registry.ts
|
|
3669
4908
|
var plugins = {
|
|
3670
4909
|
snowflake: snowflakeConnector,
|
|
@@ -3682,7 +4921,10 @@ var plugins = {
|
|
|
3682
4921
|
squadbaseDb: squadbaseDbConnector,
|
|
3683
4922
|
kintone: kintoneConnector,
|
|
3684
4923
|
wixStore: wixStoreConnector,
|
|
3685
|
-
openai: openaiConnector
|
|
4924
|
+
openai: openaiConnector,
|
|
4925
|
+
googleSheetsOauth: googleSheetsOauthConnector,
|
|
4926
|
+
googleAnalyticsOauth: googleAnalyticsOauthConnector,
|
|
4927
|
+
googleAdsOauth: googleAdsOauthConnector
|
|
3686
4928
|
};
|
|
3687
4929
|
var connectors = {
|
|
3688
4930
|
...plugins,
|
|
@@ -3718,7 +4960,10 @@ export {
|
|
|
3718
4960
|
connectors,
|
|
3719
4961
|
databricksConnector,
|
|
3720
4962
|
dbtConnector,
|
|
4963
|
+
googleAdsOauthConnector,
|
|
3721
4964
|
googleAnalyticsConnector,
|
|
4965
|
+
googleAnalyticsOauthConnector,
|
|
4966
|
+
googleSheetsOauthConnector,
|
|
3722
4967
|
kintoneConnector,
|
|
3723
4968
|
mysqlConnector,
|
|
3724
4969
|
openaiConnector,
|