@squadbase/connectors 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -52,6 +52,12 @@ interface ProxyPolicyRule {
52
52
  interface ProxyPolicy {
53
53
  allowlist: ProxyPolicyRule[];
54
54
  }
55
+ type ConnectionCheckResult = {
56
+ success: true;
57
+ } | {
58
+ success: false;
59
+ error: string;
60
+ };
55
61
  interface ConnectorToolsConfig {
56
62
  oauthProxy: {
57
63
  appApiKey: string;
@@ -97,6 +103,9 @@ declare class ConnectorPlugin<P extends Record<string, ParameterDefinition> = Re
97
103
  }) => Promise<{
98
104
  rows: Record<string, unknown>[];
99
105
  }>;
106
+ readonly checkConnection?: (params: Record<string, string>, config: {
107
+ proxyFetch: typeof fetch;
108
+ }) => Promise<ConnectionCheckResult>;
100
109
  constructor(config: {
101
110
  slug: string;
102
111
  authType: string | null;
@@ -115,6 +124,9 @@ declare class ConnectorPlugin<P extends Record<string, ParameterDefinition> = Re
115
124
  }) => Promise<{
116
125
  rows: Record<string, unknown>[];
117
126
  }>;
127
+ checkConnection?: (params: Record<string, string>, config: {
128
+ proxyFetch: typeof fetch;
129
+ }) => Promise<ConnectionCheckResult>;
118
130
  });
119
131
  get connectorKey(): string;
120
132
  /**
@@ -790,4 +802,4 @@ declare const squadbaseDbConnector: ConnectorPlugin<{
790
802
  }>;
791
803
  }>;
792
804
 
793
- export { AUTH_TYPES, ConnectorPlugin, ConnectorSetup, ConnectorTool, type ConnectorToolsConfig, ParameterDefinition, type ProxyPolicy, type ProxyPolicyRule, type ReleaseFlag, type SetupLanguage, airtableConnector, awsAthenaConnector, bigqueryConnector, bigqueryOauthConnector, connectors, databricksConnector, dbtConnector, googleAnalyticsConnector, kintoneConnector, mysqlConnector, postgresqlConnector, redshiftConnector, snowflakeConnector, snowflakePatConnector, squadbaseDbConnector, wixStoreConnector };
805
+ export { AUTH_TYPES, type ConnectionCheckResult, ConnectorPlugin, ConnectorSetup, ConnectorTool, type ConnectorToolsConfig, ParameterDefinition, type ProxyPolicy, type ProxyPolicyRule, type ReleaseFlag, type SetupLanguage, airtableConnector, awsAthenaConnector, bigqueryConnector, bigqueryOauthConnector, connectors, databricksConnector, dbtConnector, googleAnalyticsConnector, kintoneConnector, mysqlConnector, postgresqlConnector, redshiftConnector, snowflakeConnector, snowflakePatConnector, squadbaseDbConnector, wixStoreConnector };
package/dist/index.js CHANGED
@@ -92,6 +92,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
92
92
  systemPrompt;
93
93
  tools;
94
94
  query;
95
+ checkConnection;
95
96
  constructor(config) {
96
97
  this.slug = config.slug;
97
98
  this.authType = config.authType;
@@ -106,6 +107,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
106
107
  this.systemPrompt = config.systemPrompt;
107
108
  this.tools = config.tools;
108
109
  this.query = config.query;
110
+ this.checkConnection = config.checkConnection;
109
111
  }
110
112
  get connectorKey() {
111
113
  return _ConnectorPlugin.deriveKey(this.slug, this.authType);
@@ -439,6 +441,45 @@ var snowflakeConnector = new ConnectorPlugin({
439
441
  - List columns: \`DESCRIBE TABLE db_name.schema_name.table_name\`
440
442
  - INFORMATION_SCHEMA is also available: \`SELECT * FROM db_name.INFORMATION_SCHEMA.TABLES\``,
441
443
  tools,
444
+ async checkConnection(params, _config) {
445
+ try {
446
+ const snowflake = (await import("snowflake-sdk")).default;
447
+ snowflake.configure({ logLevel: "ERROR" });
448
+ const privateKey = Buffer.from(
449
+ params[parameters.privateKeyBase64.slug],
450
+ "base64"
451
+ ).toString("utf-8");
452
+ const conn = snowflake.createConnection({
453
+ account: params[parameters.account.slug],
454
+ username: params[parameters.user.slug],
455
+ role: params[parameters.role.slug],
456
+ warehouse: params[parameters.warehouse.slug],
457
+ authenticator: "SNOWFLAKE_JWT",
458
+ privateKey
459
+ });
460
+ await new Promise((resolve, reject) => {
461
+ conn.connect((err) => {
462
+ if (err) reject(new Error(`Snowflake connect failed: ${err.message}`));
463
+ else resolve();
464
+ });
465
+ });
466
+ await new Promise((resolve, reject) => {
467
+ conn.execute({
468
+ sqlText: "SELECT 1",
469
+ complete: (err) => {
470
+ if (err) reject(new Error(`Snowflake query failed: ${err.message}`));
471
+ else resolve();
472
+ }
473
+ });
474
+ });
475
+ conn.destroy((err) => {
476
+ if (err) console.warn(`[connector-client] Snowflake destroy error: ${err.message}`);
477
+ });
478
+ return { success: true };
479
+ } catch (e) {
480
+ return { success: false, error: e instanceof Error ? e.message : String(e) };
481
+ }
482
+ },
442
483
  async query(params, sql, namedParams) {
443
484
  const resolvedSql = replaceLiteralParams(sql, namedParams);
444
485
  const snowflake = (await import("snowflake-sdk")).default;
@@ -653,6 +694,45 @@ var snowflakePatConnector = new ConnectorPlugin({
653
694
  - List columns: \`DESCRIBE TABLE db_name.schema_name.table_name\`
654
695
  - INFORMATION_SCHEMA is also available: \`SELECT * FROM db_name.INFORMATION_SCHEMA.TABLES\``,
655
696
  tools: tools2,
697
+ async checkConnection(params, _config) {
698
+ try {
699
+ const snowflake = (await import("snowflake-sdk")).default;
700
+ snowflake.configure({ logLevel: "ERROR" });
701
+ const conn = snowflake.createConnection({
702
+ account: params[parameters2.account.slug],
703
+ username: params[parameters2.user.slug],
704
+ role: params[parameters2.role.slug],
705
+ warehouse: params[parameters2.warehouse.slug],
706
+ password: params[parameters2.pat.slug]
707
+ });
708
+ await new Promise((resolve, reject) => {
709
+ conn.connect((err) => {
710
+ if (err)
711
+ reject(new Error(`Snowflake connect failed: ${err.message}`));
712
+ else resolve();
713
+ });
714
+ });
715
+ await new Promise((resolve, reject) => {
716
+ conn.execute({
717
+ sqlText: "SELECT 1",
718
+ complete: (err) => {
719
+ if (err)
720
+ reject(new Error(`Snowflake query failed: ${err.message}`));
721
+ else resolve();
722
+ }
723
+ });
724
+ });
725
+ conn.destroy((err) => {
726
+ if (err)
727
+ console.warn(
728
+ `[connector-client] Snowflake destroy error: ${err.message}`
729
+ );
730
+ });
731
+ return { success: true };
732
+ } catch (e) {
733
+ return { success: false, error: e instanceof Error ? e.message : String(e) };
734
+ }
735
+ },
656
736
  async query(params, sql, namedParams) {
657
737
  const resolvedSql = replaceLiteralParams(sql, namedParams);
658
738
  const snowflake = (await import("snowflake-sdk")).default;
@@ -797,6 +877,22 @@ var postgresqlConnector = new ConnectorPlugin({
797
877
  - List columns: \`SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'xxx'\`
798
878
  - Always include LIMIT in queries`,
799
879
  tools: tools3,
880
+ async checkConnection(params, _config) {
881
+ const { Pool } = await import("pg");
882
+ const pool = new Pool({
883
+ connectionString: params[parameters3.connectionUrl.slug],
884
+ ssl: { rejectUnauthorized: false },
885
+ connectionTimeoutMillis: 1e4
886
+ });
887
+ try {
888
+ await pool.query("SELECT 1");
889
+ return { success: true };
890
+ } catch (error) {
891
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
892
+ } finally {
893
+ await pool.end();
894
+ }
895
+ },
800
896
  async query(params, sql, namedParams) {
801
897
  const { Pool } = await import("pg");
802
898
  const { text, values } = buildPositionalParams(sql, namedParams);
@@ -921,6 +1017,21 @@ var mysqlConnector = new ConnectorPlugin({
921
1017
  - List columns: \`SELECT COLUMN_NAME, DATA_TYPE FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'xxx'\`
922
1018
  - Always include LIMIT in queries`,
923
1019
  tools: tools4,
1020
+ async checkConnection(params, _config) {
1021
+ const mysql = await import("mysql2/promise");
1022
+ const pool = mysql.createPool({
1023
+ uri: params[parameters4.connectionUrl.slug],
1024
+ connectTimeout: 1e4
1025
+ });
1026
+ try {
1027
+ await pool.query("SELECT 1");
1028
+ return { success: true };
1029
+ } catch (e) {
1030
+ return { success: false, error: e instanceof Error ? e.message : String(e) };
1031
+ } finally {
1032
+ await pool.end();
1033
+ }
1034
+ },
924
1035
  async query(params, sql, namedParams) {
925
1036
  const mysql = await import("mysql2/promise");
926
1037
  const { text, values } = buildQuestionmarkParams(sql, namedParams);
@@ -1039,14 +1150,10 @@ var bigquerySetup = new ConnectorSetup({
1039
1150
 
1040
1151
  #### \u30B9\u30C6\u30C3\u30D71: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u9078\u629E
1041
1152
  1. \`${listProjectsToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u304C\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306AGCP\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
1042
- 2. \u7D50\u679C\u306B\u5FDC\u3058\u3066\u5206\u5C90:
1043
- - **\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u304C2\u3064\u4EE5\u4E0A**: \`askUserQuestion\`\uFF08multiSelect: false\uFF09\u3067\u30E6\u30FC\u30B6\u30FC\u306B\u63D0\u793A\u3057\u3001\u4F7F\u7528\u3059\u308B\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u9078\u629E\u3055\u305B\u308B\u3002\u9078\u629E\u80A2\u306E label \u306F \`\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u540D (id: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8ID)\` \u306E\u5F62\u5F0F\u306B\u3059\u308B
1044
- - **\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u304C1\u3064\u3060\u3051**: askUserQuestion \u306F\u4F7F\u308F\u305A\u81EA\u52D5\u63A1\u7528\u3002\u300C\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8 X \u3092\u81EA\u52D5\u9078\u629E\u3057\u307E\u3057\u305F\u300D\u30681\u6587\u3060\u3051\u66F8\u304F
1045
- 3. \`updateConnectionParameters\` \u3067\u9078\u629E\u3055\u308C\u305F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u4FDD\u5B58\u3059\u308B:
1153
+ 2. \`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
1046
1154
  - \`parameterSlug\`: \`"project-id"\`
1047
- - \`value\`: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8ID
1048
- - \`displayValue\`: \`"\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u540D (id: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8ID)"\`
1049
- 4. \u7D9A\u884C\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u53D7\u3051\u53D6\u3063\u305F\u3089\u3001\u30B9\u30C6\u30C3\u30D72\u306B\u9032\u3080
1155
+ - \`options\`: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u4E00\u89A7\u3002\u5404 option \u306E \`label\` \u306F \`\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u540D (id: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8ID)\` \u306E\u5F62\u5F0F\u3001\`value\` \u306F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8ID
1156
+ 3. \u30E6\u30FC\u30B6\u30FC\u304C\u9078\u629E\u3057\u305F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E \`label\` \u304C\u30E1\u30C3\u30BB\u30FC\u30B8\u3068\u3057\u3066\u5C4A\u304F\u306E\u3067\u3001\u30B9\u30C6\u30C3\u30D72\u306B\u9032\u3080
1050
1157
 
1051
1158
  #### \u30B9\u30C6\u30C3\u30D72: \u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u9078\u629E
1052
1159
  1. \`SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA\` \u3092\u5B9F\u884C\u3057\u3066\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
@@ -1060,14 +1167,13 @@ var bigquerySetup = new ConnectorSetup({
1060
1167
  - **\u30C6\u30FC\u30D6\u30EB\u304C2\u3064\u4EE5\u4E0A**: \`askUserQuestion\`\uFF08multiSelect: true\uFF09\u3067\u30E6\u30FC\u30B6\u30FC\u306B\u63D0\u793A\u3057\u3001\u4F7F\u7528\u3059\u308B\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u629E\u3055\u305B\u308B\u3002description \u306B\u306F\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u540D\u3092\u8A18\u8F09\u3059\u308B
1061
1168
  - **\u30C6\u30FC\u30D6\u30EB\u304C1\u3064\u3060\u3051**: askUserQuestion \u306F\u4F7F\u308F\u305A\u81EA\u52D5\u63A1\u7528
1062
1169
 
1063
- #### \u30B9\u30C6\u30C3\u30D74: \u4FDD\u5B58
1064
- 5. \`updateConnectionContext\` \u3067\u4EE5\u4E0B\u3092\u4FDD\u5B58\u3059\u308B:
1170
+ #### \u30B9\u30C6\u30C3\u30D74: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5B8C\u4E86
1171
+ 5. \`updateConnectionContext\` \u3092\u547C\u3073\u51FA\u3059:
1065
1172
  - \`dataset\`: \u9078\u629E\u3055\u308C\u305F\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u540D\uFF08\u8907\u6570\u306E\u5834\u5408\u306F\u30AB\u30F3\u30DE\u533A\u5207\u308A\uFF09
1066
1173
  - \`tables\`: \u9078\u629E\u3055\u308C\u305F\u30C6\u30FC\u30D6\u30EB\u540D\uFF08\u8907\u6570\u306E\u5834\u5408\u306F\u30AB\u30F3\u30DE\u533A\u5207\u308A\uFF09
1067
1174
  - \`note\`: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5185\u5BB9\u306E\u7C21\u5358\u306A\u8AAC\u660E
1068
1175
 
1069
1176
  ### \u91CD\u8981\u306A\u5236\u7D04
1070
- - askUserQuestion \u306E options \u306B\u306F\u6700\u4F4E2\u4EF6\u5FC5\u8981\u30021\u4EF6\u3057\u304B\u306A\u3044\u5834\u5408\u306F askUserQuestion \u3092\u547C\u3070\u305A\u6B21\u306E\u30B9\u30C6\u30C3\u30D7\u306B\u9032\u3080\u3053\u3068
1071
1177
  - **\u30C6\u30FC\u30D6\u30EB\u306E\u884C\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\u30AF\u30A8\u30EA\u306E\u307F\u3002\u305D\u308C\u4EE5\u5916\u306E\u30AF\u30A8\u30EA\u306F\u5B9F\u884C\u7981\u6B62
1072
1178
 
1073
1179
  ### \u5B9F\u884C\u65B9\u91DD
@@ -1081,14 +1187,10 @@ Follow these steps to set up the BigQuery connection.
1081
1187
 
1082
1188
  #### Step 1: Project Selection
1083
1189
  1. Call \`${listProjectsToolName}\` to get the list of GCP projects accessible with the service account credentials
1084
- 2. Branch based on results:
1085
- - **2 or more projects**: Present them to the user via \`askUserQuestion\` (multiSelect: false) and let them select a project. Format option labels as \`Project Name (id: project-id)\`
1086
- - **Exactly 1 project**: Do NOT call askUserQuestion. Auto-select it. Just write "Auto-selected project X" in one sentence
1087
- 3. Call \`updateConnectionParameters\` to save the selected project:
1190
+ 2. Call \`updateConnectionParameters\`:
1088
1191
  - \`parameterSlug\`: \`"project-id"\`
1089
- - \`value\`: the project ID
1090
- - \`displayValue\`: \`"Project Name (id: project-id)"\`
1091
- 4. After receiving the continuation message, proceed to Step 2
1192
+ - \`options\`: The project list. Each option's \`label\` should be \`Project Name (id: project-id)\`, \`value\` should be the project ID
1193
+ 3. The \`label\` of the user's selected project will arrive as a message. Proceed to Step 2
1092
1194
 
1093
1195
  #### Step 2: Dataset Selection
1094
1196
  1. Run \`SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA\` to get the list of datasets
@@ -1102,14 +1204,13 @@ Follow these steps to set up the BigQuery connection.
1102
1204
  - **2 or more tables**: Present them to the user via \`askUserQuestion\` (multiSelect: true) and let them select which tables to use. Include the dataset name in the description
1103
1205
  - **Exactly 1 table**: Do NOT call askUserQuestion. Auto-select it
1104
1206
 
1105
- #### Step 4: Save
1106
- 5. Call \`updateConnectionContext\` to save:
1207
+ #### Step 4: Complete Setup
1208
+ 5. Call \`updateConnectionContext\`:
1107
1209
  - \`dataset\`: Selected dataset name(s) (comma-separated if multiple)
1108
1210
  - \`tables\`: Selected table name(s) (comma-separated if multiple)
1109
1211
  - \`note\`: Brief description of the setup
1110
1212
 
1111
1213
  ### Important Constraints
1112
- - askUserQuestion options requires at least 2 items. If there is only 1 item, do NOT call askUserQuestion \u2014 proceed to the next step directly
1113
1214
  - **Do NOT read table row data**. Only the metadata queries specified in the steps above are allowed. All other queries are forbidden
1114
1215
 
1115
1216
  ### Execution Policy
@@ -1203,6 +1304,23 @@ var bigqueryConnector = new ConnectorPlugin({
1203
1304
  - List columns: \`SELECT column_name, data_type FROM \\\`project_id.dataset\\\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'xxx'\`
1204
1305
  - Always specify project_id explicitly in queries`,
1205
1306
  tools: tools5,
1307
+ async checkConnection(params, _config) {
1308
+ const { BigQuery } = await import("@google-cloud/bigquery");
1309
+ const credentials = JSON.parse(
1310
+ Buffer.from(params[parameters5.serviceAccountKeyJsonBase64.slug], "base64").toString("utf-8")
1311
+ );
1312
+ const bq = new BigQuery({
1313
+ projectId: params[parameters5.projectId.slug],
1314
+ credentials
1315
+ });
1316
+ try {
1317
+ const [job] = await bq.createQueryJob({ query: "SELECT 1" });
1318
+ await job.getQueryResults();
1319
+ return { success: true };
1320
+ } catch (error) {
1321
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
1322
+ }
1323
+ },
1206
1324
  async query(params, sql, namedParams) {
1207
1325
  const { BigQuery } = await import("@google-cloud/bigquery");
1208
1326
  const resolvedSql = replaceLiteralParams(sql, namedParams);
@@ -1337,14 +1455,10 @@ var bigquerySetup2 = new ConnectorSetup({
1337
1455
 
1338
1456
  #### \u30B9\u30C6\u30C3\u30D71: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u9078\u629E
1339
1457
  1. \`${listProjectsToolName2}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001OAuth\u3067\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306AGCP\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
1340
- 2. \u7D50\u679C\u306B\u5FDC\u3058\u3066\u5206\u5C90:
1341
- - **\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u304C2\u3064\u4EE5\u4E0A**: \`askUserQuestion\`\uFF08multiSelect: false\uFF09\u3067\u30E6\u30FC\u30B6\u30FC\u306B\u63D0\u793A\u3057\u3001\u4F7F\u7528\u3059\u308B\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u9078\u629E\u3055\u305B\u308B\u3002\u9078\u629E\u80A2\u306E label \u306F \`\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u540D (id: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8ID)\` \u306E\u5F62\u5F0F\u306B\u3059\u308B
1342
- - **\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u304C1\u3064\u3060\u3051**: askUserQuestion \u306F\u4F7F\u308F\u305A\u81EA\u52D5\u63A1\u7528\u3002\u300C\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8 X \u3092\u81EA\u52D5\u9078\u629E\u3057\u307E\u3057\u305F\u300D\u30681\u6587\u3060\u3051\u66F8\u304F
1343
- 3. \`updateConnectionParameters\` \u3067\u9078\u629E\u3055\u308C\u305F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u4FDD\u5B58\u3059\u308B:
1458
+ 2. \`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
1344
1459
  - \`parameterSlug\`: \`"project-id"\`
1345
- - \`value\`: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8ID
1346
- - \`displayValue\`: \`"\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u540D (id: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8ID)"\`
1347
- 4. \u7D9A\u884C\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u53D7\u3051\u53D6\u3063\u305F\u3089\u3001\u30B9\u30C6\u30C3\u30D72\u306B\u9032\u3080
1460
+ - \`options\`: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u4E00\u89A7\u3002\u5404 option \u306E \`label\` \u306F \`\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u540D (id: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8ID)\` \u306E\u5F62\u5F0F\u3001\`value\` \u306F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8ID
1461
+ 3. \u30E6\u30FC\u30B6\u30FC\u304C\u9078\u629E\u3057\u305F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E \`label\` \u304C\u30E1\u30C3\u30BB\u30FC\u30B8\u3068\u3057\u3066\u5C4A\u304F\u306E\u3067\u3001\u30B9\u30C6\u30C3\u30D72\u306B\u9032\u3080
1348
1462
 
1349
1463
  #### \u30B9\u30C6\u30C3\u30D72: \u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u9078\u629E
1350
1464
  1. \`SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA\` \u3092\u5B9F\u884C\u3057\u3066\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
@@ -1358,14 +1472,13 @@ var bigquerySetup2 = new ConnectorSetup({
1358
1472
  - **\u30C6\u30FC\u30D6\u30EB\u304C2\u3064\u4EE5\u4E0A**: \`askUserQuestion\`\uFF08multiSelect: true\uFF09\u3067\u30E6\u30FC\u30B6\u30FC\u306B\u63D0\u793A\u3057\u3001\u4F7F\u7528\u3059\u308B\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u629E\u3055\u305B\u308B\u3002description \u306B\u306F\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u540D\u3092\u8A18\u8F09\u3059\u308B
1359
1473
  - **\u30C6\u30FC\u30D6\u30EB\u304C1\u3064\u3060\u3051**: askUserQuestion \u306F\u4F7F\u308F\u305A\u81EA\u52D5\u63A1\u7528
1360
1474
 
1361
- #### \u30B9\u30C6\u30C3\u30D74: \u4FDD\u5B58
1362
- 5. \`updateConnectionContext\` \u3067\u4EE5\u4E0B\u3092\u4FDD\u5B58\u3059\u308B:
1475
+ #### \u30B9\u30C6\u30C3\u30D74: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5B8C\u4E86
1476
+ 5. \`updateConnectionContext\` \u3092\u547C\u3073\u51FA\u3059:
1363
1477
  - \`dataset\`: \u9078\u629E\u3055\u308C\u305F\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u540D\uFF08\u8907\u6570\u306E\u5834\u5408\u306F\u30AB\u30F3\u30DE\u533A\u5207\u308A\uFF09
1364
1478
  - \`tables\`: \u9078\u629E\u3055\u308C\u305F\u30C6\u30FC\u30D6\u30EB\u540D\uFF08\u8907\u6570\u306E\u5834\u5408\u306F\u30AB\u30F3\u30DE\u533A\u5207\u308A\uFF09
1365
1479
  - \`note\`: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5185\u5BB9\u306E\u7C21\u5358\u306A\u8AAC\u660E
1366
1480
 
1367
1481
  ### \u91CD\u8981\u306A\u5236\u7D04
1368
- - askUserQuestion \u306E options \u306B\u306F\u6700\u4F4E2\u4EF6\u5FC5\u8981\u30021\u4EF6\u3057\u304B\u306A\u3044\u5834\u5408\u306F askUserQuestion \u3092\u547C\u3070\u305A\u6B21\u306E\u30B9\u30C6\u30C3\u30D7\u306B\u9032\u3080\u3053\u3068
1369
1482
  - **\u30C6\u30FC\u30D6\u30EB\u306E\u884C\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\u30AF\u30A8\u30EA\u306E\u307F\u3002\u305D\u308C\u4EE5\u5916\u306E\u30AF\u30A8\u30EA\u306F\u5B9F\u884C\u7981\u6B62
1370
1483
 
1371
1484
  ### \u5B9F\u884C\u65B9\u91DD
@@ -1379,14 +1492,10 @@ Follow these steps to set up the BigQuery connection.
1379
1492
 
1380
1493
  #### Step 1: Project Selection
1381
1494
  1. Call \`${listProjectsToolName2}\` to get the list of GCP projects accessible with the OAuth credentials
1382
- 2. Branch based on results:
1383
- - **2 or more projects**: Present them to the user via \`askUserQuestion\` (multiSelect: false) and let them select a project. Format option labels as \`Project Name (id: project-id)\`
1384
- - **Exactly 1 project**: Do NOT call askUserQuestion. Auto-select it. Just write "Auto-selected project X" in one sentence
1385
- 3. Call \`updateConnectionParameters\` to save the selected project:
1495
+ 2. Call \`updateConnectionParameters\`:
1386
1496
  - \`parameterSlug\`: \`"project-id"\`
1387
- - \`value\`: the project ID
1388
- - \`displayValue\`: \`"Project Name (id: project-id)"\`
1389
- 4. After receiving the continuation message, proceed to Step 2
1497
+ - \`options\`: The project list. Each option's \`label\` should be \`Project Name (id: project-id)\`, \`value\` should be the project ID
1498
+ 3. The \`label\` of the user's selected project will arrive as a message. Proceed to Step 2
1390
1499
 
1391
1500
  #### Step 2: Dataset Selection
1392
1501
  1. Run \`SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA\` to get the list of datasets
@@ -1400,14 +1509,13 @@ Follow these steps to set up the BigQuery connection.
1400
1509
  - **2 or more tables**: Present them to the user via \`askUserQuestion\` (multiSelect: true) and let them select which tables to use. Include the dataset name in the description
1401
1510
  - **Exactly 1 table**: Do NOT call askUserQuestion. Auto-select it
1402
1511
 
1403
- #### Step 4: Save
1404
- 5. Call \`updateConnectionContext\` to save:
1512
+ #### Step 4: Complete Setup
1513
+ 5. Call \`updateConnectionContext\`:
1405
1514
  - \`dataset\`: Selected dataset name(s) (comma-separated if multiple)
1406
1515
  - \`tables\`: Selected table name(s) (comma-separated if multiple)
1407
1516
  - \`note\`: Brief description of the setup
1408
1517
 
1409
1518
  ### Important Constraints
1410
- - askUserQuestion options requires at least 2 items. If there is only 1 item, do NOT call askUserQuestion \u2014 proceed to the next step directly
1411
1519
  - **Do NOT read table row data**. Only the metadata queries specified in the steps above are allowed. All other queries are forbidden
1412
1520
 
1413
1521
  ### Execution Policy
@@ -1594,6 +1702,25 @@ var bigqueryOauthConnector = new ConnectorPlugin({
1594
1702
  - List columns: \`SELECT column_name, data_type FROM \\\`project_id.dataset\\\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'xxx'\`
1595
1703
  - Always specify project_id explicitly in queries`,
1596
1704
  tools: tools6,
1705
+ async checkConnection(params, config) {
1706
+ const { proxyFetch } = config;
1707
+ const projectId = params[parameters6.projectId.slug];
1708
+ const url = `https://bigquery.googleapis.com/bigquery/v2/projects/${projectId}/queries`;
1709
+ try {
1710
+ const res = await proxyFetch(url, {
1711
+ method: "POST",
1712
+ headers: { "Content-Type": "application/json" },
1713
+ body: JSON.stringify({ query: "SELECT 1", useLegacySql: false })
1714
+ });
1715
+ if (!res.ok) {
1716
+ const errorText = await res.text().catch(() => res.statusText);
1717
+ return { success: false, error: `BigQuery query failed: HTTP ${res.status} ${errorText}` };
1718
+ }
1719
+ return { success: true };
1720
+ } catch (error) {
1721
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
1722
+ }
1723
+ },
1597
1724
  async query(params, sql, namedParams, context) {
1598
1725
  const { proxyFetch } = context;
1599
1726
  const projectId = params[parameters6.projectId.slug];
@@ -1798,6 +1925,62 @@ var awsAthenaConnector = new ConnectorPlugin({
1798
1925
  - Always include LIMIT in queries
1799
1926
  - Query execution is asynchronous and results may take time to retrieve`,
1800
1927
  tools: tools7,
1928
+ async checkConnection(params, _config) {
1929
+ try {
1930
+ const {
1931
+ AthenaClient,
1932
+ StartQueryExecutionCommand,
1933
+ GetQueryExecutionCommand
1934
+ } = await import("@aws-sdk/client-athena");
1935
+ const workgroup = params[parameters7.workgroup.slug];
1936
+ const outputLocation = params[parameters7.outputLocation.slug];
1937
+ if (!workgroup && !outputLocation) {
1938
+ return {
1939
+ success: false,
1940
+ error: "Either workgroup or output-location is required"
1941
+ };
1942
+ }
1943
+ const client = new AthenaClient({
1944
+ region: params[parameters7.awsRegion.slug],
1945
+ credentials: {
1946
+ accessKeyId: params[parameters7.awsAccessKeyId.slug],
1947
+ secretAccessKey: params[parameters7.awsSecretAccessKey.slug]
1948
+ }
1949
+ });
1950
+ const startParams = { QueryString: "SELECT 1" };
1951
+ if (workgroup) startParams.WorkGroup = workgroup;
1952
+ if (outputLocation) {
1953
+ startParams.ResultConfiguration = { OutputLocation: outputLocation };
1954
+ }
1955
+ const { QueryExecutionId } = await client.send(
1956
+ new StartQueryExecutionCommand(startParams)
1957
+ );
1958
+ const startTime = Date.now();
1959
+ while (true) {
1960
+ const exec = await client.send(
1961
+ new GetQueryExecutionCommand({ QueryExecutionId })
1962
+ );
1963
+ const state = exec.QueryExecution?.Status?.State;
1964
+ if (state === "SUCCEEDED") break;
1965
+ if (state === "FAILED" || state === "CANCELLED") {
1966
+ return {
1967
+ success: false,
1968
+ error: exec.QueryExecution?.Status?.StateChangeReason || `Query ${state}`
1969
+ };
1970
+ }
1971
+ if (Date.now() - startTime > 12e4) {
1972
+ return { success: false, error: "Query timed out after 120 seconds" };
1973
+ }
1974
+ await new Promise((r) => setTimeout(r, 1e3));
1975
+ }
1976
+ return { success: true };
1977
+ } catch (error) {
1978
+ return {
1979
+ success: false,
1980
+ error: error instanceof Error ? error.message : String(error)
1981
+ };
1982
+ }
1983
+ },
1801
1984
  async query(params, sql, namedParams) {
1802
1985
  const {
1803
1986
  AthenaClient,
@@ -2075,6 +2258,65 @@ var redshiftConnector = new ConnectorPlugin({
2075
2258
  - Always include LIMIT in queries
2076
2259
  - Query execution is asynchronous and results may take time to retrieve`,
2077
2260
  tools: tools8,
2261
+ async checkConnection(params, _config) {
2262
+ try {
2263
+ const {
2264
+ RedshiftDataClient,
2265
+ ExecuteStatementCommand,
2266
+ DescribeStatementCommand
2267
+ } = await import("@aws-sdk/client-redshift-data");
2268
+ const clusterIdentifier = params[parameters8.clusterIdentifier.slug];
2269
+ const workgroupName = params[parameters8.workgroupName.slug];
2270
+ const secretArn = params[parameters8.secretArn.slug];
2271
+ const dbUser = params[parameters8.dbUser.slug];
2272
+ if (!clusterIdentifier && !workgroupName) {
2273
+ return {
2274
+ success: false,
2275
+ error: "Either cluster-identifier or workgroup-name is required"
2276
+ };
2277
+ }
2278
+ const client = new RedshiftDataClient({
2279
+ region: params[parameters8.awsRegion.slug],
2280
+ credentials: {
2281
+ accessKeyId: params[parameters8.awsAccessKeyId.slug],
2282
+ secretAccessKey: params[parameters8.awsSecretAccessKey.slug]
2283
+ }
2284
+ });
2285
+ const { Id: statementId } = await client.send(
2286
+ new ExecuteStatementCommand({
2287
+ Database: params[parameters8.database.slug],
2288
+ Sql: "SELECT 1",
2289
+ ...clusterIdentifier && { ClusterIdentifier: clusterIdentifier },
2290
+ ...workgroupName && { WorkgroupName: workgroupName },
2291
+ ...secretArn && { SecretArn: secretArn },
2292
+ ...dbUser && { DbUser: dbUser }
2293
+ })
2294
+ );
2295
+ const startTime = Date.now();
2296
+ while (true) {
2297
+ const desc = await client.send(
2298
+ new DescribeStatementCommand({ Id: statementId })
2299
+ );
2300
+ if (desc.Status === "FINISHED") break;
2301
+ if (desc.Status === "FAILED" || desc.Status === "ABORTED") {
2302
+ return {
2303
+ success: false,
2304
+ error: desc.Error || `Statement ${desc.Status}`
2305
+ };
2306
+ }
2307
+ if (Date.now() - startTime > 12e4) {
2308
+ return { success: false, error: "Query timed out after 120 seconds" };
2309
+ }
2310
+ await new Promise((r) => setTimeout(r, 1e3));
2311
+ }
2312
+ return { success: true };
2313
+ } catch (error) {
2314
+ return {
2315
+ success: false,
2316
+ error: error instanceof Error ? error.message : String(error)
2317
+ };
2318
+ }
2319
+ },
2078
2320
  async query(params, sql, namedParams) {
2079
2321
  const {
2080
2322
  RedshiftDataClient,
@@ -2263,6 +2505,34 @@ var databricksConnector = new ConnectorPlugin({
2263
2505
  - List columns: \`DESCRIBE TABLE table_name\`
2264
2506
  - Always include LIMIT in queries`,
2265
2507
  tools: tools9,
2508
+ async checkConnection(params, _config) {
2509
+ const { DBSQLClient } = await import("@databricks/sql");
2510
+ const client = new DBSQLClient();
2511
+ await client.connect({
2512
+ host: params[parameters9.host.slug],
2513
+ path: params[parameters9.httpPath.slug],
2514
+ token: params[parameters9.token.slug]
2515
+ });
2516
+ let session;
2517
+ let operation;
2518
+ try {
2519
+ session = await client.openSession();
2520
+ operation = await session.executeStatement("SELECT 1", {
2521
+ runAsync: true
2522
+ });
2523
+ await operation.fetchAll();
2524
+ return { success: true };
2525
+ } catch (e) {
2526
+ return { success: false, error: e instanceof Error ? e.message : String(e) };
2527
+ } finally {
2528
+ if (operation) await operation.close().catch(() => {
2529
+ });
2530
+ if (session) await session.close().catch(() => {
2531
+ });
2532
+ await client.close().catch(() => {
2533
+ });
2534
+ }
2535
+ },
2266
2536
  async query(params, sql, namedParams) {
2267
2537
  const { DBSQLClient } = await import("@databricks/sql");
2268
2538
  const resolvedSql = replaceLiteralParams(sql, namedParams);
@@ -3124,6 +3394,22 @@ var squadbaseDbConnector = new ConnectorPlugin({
3124
3394
  - List columns: \`SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'xxx'\`
3125
3395
  - Always include LIMIT in queries`,
3126
3396
  tools: tools15,
3397
+ async checkConnection(params, _config) {
3398
+ const { Pool } = await import("pg");
3399
+ const pool = new Pool({
3400
+ connectionString: params[parameters15.connectionUrl.slug],
3401
+ ssl: { rejectUnauthorized: false },
3402
+ connectionTimeoutMillis: 1e4
3403
+ });
3404
+ try {
3405
+ await pool.query("SELECT 1");
3406
+ return { success: true };
3407
+ } catch (error) {
3408
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
3409
+ } finally {
3410
+ await pool.end();
3411
+ }
3412
+ },
3127
3413
  async query(params, sql, namedParams) {
3128
3414
  const { Pool } = await import("pg");
3129
3415
  const { text, values } = buildPositionalParams(sql, namedParams);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squadbase/connectors",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "Squadbase Connectors",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",