@squadbase/vite-server 0.1.9-dev.87dd3f7 → 0.1.9-dev.a57a0ac
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/cli/index.js +74937 -61829
- package/dist/connectors/asana.js +15 -2
- package/dist/connectors/aws-billing.d.ts +5 -0
- package/dist/connectors/aws-billing.js +29843 -0
- package/dist/connectors/azure-sql.d.ts +5 -0
- package/dist/connectors/azure-sql.js +657 -0
- package/dist/connectors/clickup.d.ts +5 -0
- package/dist/connectors/clickup.js +850 -0
- package/dist/connectors/freshdesk.d.ts +5 -0
- package/dist/connectors/freshdesk.js +842 -0
- package/dist/connectors/freshsales.d.ts +5 -0
- package/dist/connectors/freshsales.js +867 -0
- package/dist/connectors/freshservice.d.ts +5 -0
- package/dist/connectors/freshservice.js +813 -0
- package/dist/connectors/github.d.ts +5 -0
- package/dist/connectors/github.js +963 -0
- package/dist/connectors/gmail-oauth.js +15 -2
- package/dist/connectors/gmail.js +23 -14
- package/dist/connectors/google-audit-log.js +25 -14
- package/dist/connectors/google-calendar-oauth.js +18 -2
- package/dist/connectors/google-calendar.js +40 -26
- package/dist/connectors/google-docs.js +18 -2
- package/dist/connectors/google-drive.js +15 -2
- package/dist/connectors/google-search-console-oauth.d.ts +5 -0
- package/dist/connectors/google-search-console-oauth.js +954 -0
- package/dist/connectors/google-sheets.js +18 -2
- package/dist/connectors/google-slides.js +18 -2
- package/dist/connectors/jdbc.d.ts +5 -0
- package/dist/connectors/jdbc.js +21097 -0
- package/dist/connectors/monday.d.ts +5 -0
- package/dist/connectors/monday.js +853 -0
- package/dist/connectors/oracle.d.ts +5 -0
- package/dist/connectors/oracle.js +665 -0
- package/dist/connectors/semrush.d.ts +5 -0
- package/dist/connectors/semrush.js +812 -0
- package/dist/connectors/sqlserver.d.ts +5 -0
- package/dist/connectors/sqlserver.js +656 -0
- package/dist/connectors/supabase.d.ts +5 -0
- package/dist/connectors/supabase.js +582 -0
- package/dist/connectors/tiktok-ads.js +15 -2
- package/dist/index.js +73506 -60398
- package/dist/main.js +73500 -60392
- package/dist/vite-plugin.js +73405 -60297
- package/package.json +60 -2
|
@@ -0,0 +1,657 @@
|
|
|
1
|
+
// ../connectors/src/parameter-definition.ts
|
|
2
|
+
var ParameterDefinition = class {
|
|
3
|
+
slug;
|
|
4
|
+
name;
|
|
5
|
+
description;
|
|
6
|
+
envVarBaseKey;
|
|
7
|
+
type;
|
|
8
|
+
secret;
|
|
9
|
+
required;
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this.slug = config.slug;
|
|
12
|
+
this.name = config.name;
|
|
13
|
+
this.description = config.description;
|
|
14
|
+
this.envVarBaseKey = config.envVarBaseKey;
|
|
15
|
+
this.type = config.type;
|
|
16
|
+
this.secret = config.secret;
|
|
17
|
+
this.required = config.required;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get the parameter value from a ConnectorConnectionObject.
|
|
21
|
+
*/
|
|
22
|
+
getValue(connection2) {
|
|
23
|
+
const param = connection2.parameters.find(
|
|
24
|
+
(p) => p.parameterSlug === this.slug
|
|
25
|
+
);
|
|
26
|
+
if (!param || param.value == null) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
`Parameter "${this.slug}" not found or has no value in connection "${connection2.id}"`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
return param.value;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Try to get the parameter value. Returns undefined if not found (for optional params).
|
|
35
|
+
*/
|
|
36
|
+
tryGetValue(connection2) {
|
|
37
|
+
const param = connection2.parameters.find(
|
|
38
|
+
(p) => p.parameterSlug === this.slug
|
|
39
|
+
);
|
|
40
|
+
if (!param || param.value == null) return void 0;
|
|
41
|
+
return param.value;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// ../connectors/src/connectors/sqlserver/utils.ts
|
|
46
|
+
var SQLSERVER_PREFIX_RE = /^(?:jdbc:)?sqlserver:\/\//i;
|
|
47
|
+
var TRUE_VALUES = /* @__PURE__ */ new Set(["true", "1", "yes"]);
|
|
48
|
+
var FALSE_VALUES = /* @__PURE__ */ new Set(["false", "0", "no"]);
|
|
49
|
+
function parseBoolean(value) {
|
|
50
|
+
if (value == null) return void 0;
|
|
51
|
+
const lower = value.toLowerCase();
|
|
52
|
+
if (TRUE_VALUES.has(lower)) return true;
|
|
53
|
+
if (FALSE_VALUES.has(lower)) return false;
|
|
54
|
+
return void 0;
|
|
55
|
+
}
|
|
56
|
+
function parseSqlServerJdbcUrl(jdbcUrl, options = {}) {
|
|
57
|
+
const trimmed = jdbcUrl.trim();
|
|
58
|
+
if (!SQLSERVER_PREFIX_RE.test(trimmed)) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`Unsupported SQL Server URL "${redactSqlServerUrl(trimmed)}". Expected prefix: jdbc:sqlserver:// or sqlserver://.`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
const withoutPrefix = trimmed.replace(SQLSERVER_PREFIX_RE, "");
|
|
64
|
+
const [hostAndPath, ...propertySegments] = withoutPrefix.split(";");
|
|
65
|
+
const props = {};
|
|
66
|
+
for (const segment of propertySegments) {
|
|
67
|
+
if (!segment) continue;
|
|
68
|
+
const eqIdx = segment.indexOf("=");
|
|
69
|
+
if (eqIdx === -1) continue;
|
|
70
|
+
const key = segment.slice(0, eqIdx).trim().toLowerCase();
|
|
71
|
+
const value = segment.slice(eqIdx + 1).trim();
|
|
72
|
+
if (key) props[key] = value;
|
|
73
|
+
}
|
|
74
|
+
const url = new URL(`mssql://${hostAndPath}`);
|
|
75
|
+
for (const [key, value] of url.searchParams.entries()) {
|
|
76
|
+
if (!(key.toLowerCase() in props)) {
|
|
77
|
+
props[key.toLowerCase()] = value;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const server = url.hostname;
|
|
81
|
+
const port = url.port ? Number(url.port) : 1433;
|
|
82
|
+
const pathname = url.pathname.replace(/^\//, "");
|
|
83
|
+
const database = pathname || props["database"] || props["databasename"];
|
|
84
|
+
const user = props["user"] || props["username"] || props["userid"] || options.username;
|
|
85
|
+
const password = props["password"] || options.password;
|
|
86
|
+
return {
|
|
87
|
+
server,
|
|
88
|
+
port,
|
|
89
|
+
database,
|
|
90
|
+
user,
|
|
91
|
+
password,
|
|
92
|
+
options: props
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function toMssqlConfig(parsed, defaults = {}) {
|
|
96
|
+
const encrypt = parseBoolean(parsed.options["encrypt"]) ?? defaults.encrypt ?? false;
|
|
97
|
+
const trustServerCertificate = parseBoolean(parsed.options["trustservercertificate"]) ?? !encrypt;
|
|
98
|
+
return {
|
|
99
|
+
server: parsed.server,
|
|
100
|
+
port: parsed.port,
|
|
101
|
+
database: parsed.database,
|
|
102
|
+
user: parsed.user,
|
|
103
|
+
password: parsed.password,
|
|
104
|
+
connectionTimeout: 1e4,
|
|
105
|
+
requestTimeout: 6e4,
|
|
106
|
+
options: {
|
|
107
|
+
encrypt,
|
|
108
|
+
trustServerCertificate
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function redactSqlServerUrl(jdbcUrl) {
|
|
113
|
+
return jdbcUrl.replace(/(:\/\/)([^@/;]+)@/, "$1***@").replace(/(password\s*=\s*)([^;]+)/gi, "$1***");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ../connectors/src/lib/mssql-runner.ts
|
|
117
|
+
async function importMssql() {
|
|
118
|
+
const mod = await import("mssql");
|
|
119
|
+
return mod.default ?? mod;
|
|
120
|
+
}
|
|
121
|
+
async function runMssqlQuery(parsed, sql, options = {}) {
|
|
122
|
+
const sqlMod = await importMssql();
|
|
123
|
+
const config = toMssqlConfig(parsed, {
|
|
124
|
+
encrypt: options.forceEncrypt
|
|
125
|
+
});
|
|
126
|
+
const pool = new sqlMod.ConnectionPool(config);
|
|
127
|
+
await pool.connect();
|
|
128
|
+
try {
|
|
129
|
+
const result = await pool.request().query(sql);
|
|
130
|
+
const recordset = result.recordset ?? [];
|
|
131
|
+
return { rows: recordset };
|
|
132
|
+
} finally {
|
|
133
|
+
await pool.close();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async function checkMssqlConnection(url, credentials, options = {}) {
|
|
137
|
+
let parsed;
|
|
138
|
+
try {
|
|
139
|
+
parsed = parseSqlServerJdbcUrl(url, credentials);
|
|
140
|
+
} catch (err) {
|
|
141
|
+
return {
|
|
142
|
+
success: false,
|
|
143
|
+
error: err instanceof Error ? err.message : String(err)
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
await runMssqlQuery(parsed, "SELECT 1 AS one", options);
|
|
148
|
+
return { success: true };
|
|
149
|
+
} catch (err) {
|
|
150
|
+
let msg = err instanceof Error ? err.message : String(err);
|
|
151
|
+
msg = msg.replaceAll(url, redactSqlServerUrl(url));
|
|
152
|
+
return { success: false, error: msg };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ../connectors/src/connectors/azure-sql/parameters.ts
|
|
157
|
+
var parameters = {
|
|
158
|
+
jdbcUrl: new ParameterDefinition({
|
|
159
|
+
slug: "jdbc-url",
|
|
160
|
+
name: "Azure SQL JDBC URL",
|
|
161
|
+
description: "JDBC-style connection URL for Azure SQL Database (e.g. `jdbc:sqlserver://<server>.database.windows.net:1433;database=<db>;encrypt=true`). Encryption is enforced by Azure SQL \u2014 the connector defaults `encrypt=true` even when the URL omits it. The `jdbc:` prefix may be omitted (`sqlserver://...`).",
|
|
162
|
+
envVarBaseKey: "AZURE_SQL_JDBC_URL",
|
|
163
|
+
type: "text",
|
|
164
|
+
secret: true,
|
|
165
|
+
required: true
|
|
166
|
+
}),
|
|
167
|
+
username: new ParameterDefinition({
|
|
168
|
+
slug: "username",
|
|
169
|
+
name: "Username",
|
|
170
|
+
description: "Azure SQL login (typically `<user>@<server>`). Optional when embedded in the JDBC URL via `user=...`.",
|
|
171
|
+
envVarBaseKey: "AZURE_SQL_USERNAME",
|
|
172
|
+
type: "text",
|
|
173
|
+
secret: false,
|
|
174
|
+
required: false
|
|
175
|
+
}),
|
|
176
|
+
password: new ParameterDefinition({
|
|
177
|
+
slug: "password",
|
|
178
|
+
name: "Password",
|
|
179
|
+
description: "Azure SQL password. Optional when embedded in the JDBC URL via `password=...`.",
|
|
180
|
+
envVarBaseKey: "AZURE_SQL_PASSWORD",
|
|
181
|
+
type: "text",
|
|
182
|
+
secret: true,
|
|
183
|
+
required: false
|
|
184
|
+
})
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
// ../connectors/src/connectors/azure-sql/sdk/index.ts
|
|
188
|
+
function createClient(params) {
|
|
189
|
+
const jdbcUrl = params[parameters.jdbcUrl.slug];
|
|
190
|
+
if (!jdbcUrl) {
|
|
191
|
+
throw new Error(
|
|
192
|
+
`azure-sql: missing required parameter: ${parameters.jdbcUrl.slug}`
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
const username = params[parameters.username.slug];
|
|
196
|
+
const password = params[parameters.password.slug];
|
|
197
|
+
const parsed = parseSqlServerJdbcUrl(jdbcUrl, { username, password });
|
|
198
|
+
async function runQuery(sql) {
|
|
199
|
+
try {
|
|
200
|
+
const { rows } = await runMssqlQuery(parsed, sql, { forceEncrypt: true });
|
|
201
|
+
return rows;
|
|
202
|
+
} catch (err) {
|
|
203
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
204
|
+
throw new Error(msg.replaceAll(jdbcUrl, redactSqlServerUrl(jdbcUrl)));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return { query: runQuery };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ../connectors/src/connector-onboarding.ts
|
|
211
|
+
var ConnectorOnboarding = class {
|
|
212
|
+
/** Phase 1: Connection setup instructions (optional — some connectors don't need this) */
|
|
213
|
+
connectionSetupInstructions;
|
|
214
|
+
/** Phase 2: Data overview instructions */
|
|
215
|
+
dataOverviewInstructions;
|
|
216
|
+
constructor(config) {
|
|
217
|
+
this.connectionSetupInstructions = config.connectionSetupInstructions;
|
|
218
|
+
this.dataOverviewInstructions = config.dataOverviewInstructions;
|
|
219
|
+
}
|
|
220
|
+
getConnectionSetupPrompt(language) {
|
|
221
|
+
return this.connectionSetupInstructions?.[language] ?? null;
|
|
222
|
+
}
|
|
223
|
+
getDataOverviewInstructions(language) {
|
|
224
|
+
return this.dataOverviewInstructions[language];
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// ../connectors/src/connector-tool.ts
|
|
229
|
+
var ConnectorTool = class {
|
|
230
|
+
name;
|
|
231
|
+
description;
|
|
232
|
+
inputSchema;
|
|
233
|
+
outputSchema;
|
|
234
|
+
_execute;
|
|
235
|
+
constructor(config) {
|
|
236
|
+
this.name = config.name;
|
|
237
|
+
this.description = config.description;
|
|
238
|
+
this.inputSchema = config.inputSchema;
|
|
239
|
+
this.outputSchema = config.outputSchema;
|
|
240
|
+
this._execute = config.execute;
|
|
241
|
+
}
|
|
242
|
+
createTool(connections, config) {
|
|
243
|
+
return {
|
|
244
|
+
description: this.description,
|
|
245
|
+
inputSchema: this.inputSchema,
|
|
246
|
+
outputSchema: this.outputSchema,
|
|
247
|
+
execute: (input) => this._execute(input, connections, config)
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// ../connectors/src/connector-plugin.ts
|
|
253
|
+
var ConnectorPlugin = class _ConnectorPlugin {
|
|
254
|
+
slug;
|
|
255
|
+
authType;
|
|
256
|
+
name;
|
|
257
|
+
description;
|
|
258
|
+
iconUrl;
|
|
259
|
+
parameters;
|
|
260
|
+
releaseFlag;
|
|
261
|
+
proxyPolicy;
|
|
262
|
+
experimentalAttributes;
|
|
263
|
+
categories;
|
|
264
|
+
onboarding;
|
|
265
|
+
systemPrompt;
|
|
266
|
+
tools;
|
|
267
|
+
query;
|
|
268
|
+
checkConnection;
|
|
269
|
+
constructor(config) {
|
|
270
|
+
this.slug = config.slug;
|
|
271
|
+
this.authType = config.authType;
|
|
272
|
+
this.name = config.name;
|
|
273
|
+
this.description = config.description;
|
|
274
|
+
this.iconUrl = config.iconUrl;
|
|
275
|
+
this.parameters = config.parameters;
|
|
276
|
+
this.releaseFlag = config.releaseFlag;
|
|
277
|
+
this.proxyPolicy = config.proxyPolicy;
|
|
278
|
+
this.experimentalAttributes = config.experimentalAttributes;
|
|
279
|
+
this.categories = config.categories ?? [];
|
|
280
|
+
this.onboarding = config.onboarding;
|
|
281
|
+
this.systemPrompt = config.systemPrompt;
|
|
282
|
+
this.tools = config.tools;
|
|
283
|
+
this.query = config.query;
|
|
284
|
+
this.checkConnection = config.checkConnection;
|
|
285
|
+
}
|
|
286
|
+
get connectorKey() {
|
|
287
|
+
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Create tools for connections that belong to this connector.
|
|
291
|
+
* Filters connections by connectorKey internally.
|
|
292
|
+
* Returns tools keyed as `${connectorKey}_${toolName}`.
|
|
293
|
+
*/
|
|
294
|
+
createTools(connections, config, opts) {
|
|
295
|
+
const myConnections = connections.filter(
|
|
296
|
+
(c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
|
|
297
|
+
);
|
|
298
|
+
const result = {};
|
|
299
|
+
for (const t of Object.values(this.tools)) {
|
|
300
|
+
const tool = t.createTool(myConnections, config);
|
|
301
|
+
const originalToModelOutput = tool.toModelOutput;
|
|
302
|
+
result[`${this.connectorKey}_${t.name}`] = {
|
|
303
|
+
...tool,
|
|
304
|
+
toModelOutput: async (options) => {
|
|
305
|
+
if (!originalToModelOutput) {
|
|
306
|
+
return opts.truncateOutput(options.output);
|
|
307
|
+
}
|
|
308
|
+
const modelOutput = await originalToModelOutput(options);
|
|
309
|
+
if (modelOutput.type === "text" || modelOutput.type === "json") {
|
|
310
|
+
return opts.truncateOutput(modelOutput.value);
|
|
311
|
+
}
|
|
312
|
+
return modelOutput;
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
return result;
|
|
317
|
+
}
|
|
318
|
+
static deriveKey(slug, authType) {
|
|
319
|
+
if (authType) return `${slug}-${authType}`;
|
|
320
|
+
const LEGACY_NULL_AUTH_TYPE_MAP = {
|
|
321
|
+
// user-password
|
|
322
|
+
"postgresql": "user-password",
|
|
323
|
+
"mysql": "user-password",
|
|
324
|
+
"clickhouse": "user-password",
|
|
325
|
+
"kintone": "user-password",
|
|
326
|
+
"squadbase-db": "user-password",
|
|
327
|
+
// service-account
|
|
328
|
+
"snowflake": "service-account",
|
|
329
|
+
"bigquery": "service-account",
|
|
330
|
+
"google-analytics": "service-account",
|
|
331
|
+
"google-calendar": "service-account",
|
|
332
|
+
"aws-athena": "service-account",
|
|
333
|
+
"redshift": "service-account",
|
|
334
|
+
// api-key
|
|
335
|
+
"databricks": "api-key",
|
|
336
|
+
"dbt": "api-key",
|
|
337
|
+
"airtable": "api-key",
|
|
338
|
+
"openai": "api-key",
|
|
339
|
+
"gemini": "api-key",
|
|
340
|
+
"anthropic": "api-key",
|
|
341
|
+
"wix-store": "api-key"
|
|
342
|
+
};
|
|
343
|
+
const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
|
|
344
|
+
if (fallbackAuthType) return `${slug}-${fallbackAuthType}`;
|
|
345
|
+
return slug;
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
// ../connectors/src/auth-types.ts
|
|
350
|
+
var AUTH_TYPES = {
|
|
351
|
+
OAUTH: "oauth",
|
|
352
|
+
API_KEY: "api-key",
|
|
353
|
+
JWT: "jwt",
|
|
354
|
+
SERVICE_ACCOUNT: "service-account",
|
|
355
|
+
PAT: "pat",
|
|
356
|
+
USER_PASSWORD: "user-password"
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
// ../connectors/src/connectors/azure-sql/setup.ts
|
|
360
|
+
var azureSqlOnboarding = new ConnectorOnboarding({
|
|
361
|
+
dataOverviewInstructions: {
|
|
362
|
+
en: `1. Use azure-sql_executeQuery to confirm the database flavor: \`SELECT @@VERSION\` (Azure SQL returns "Microsoft SQL Azure \u2026")
|
|
363
|
+
2. List user tables: \`SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA NOT IN ('sys', 'INFORMATION_SCHEMA')\`
|
|
364
|
+
3. For key tables, fetch column info: \`SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'dbo' AND TABLE_NAME = 'xxx'\`
|
|
365
|
+
4. Sample up to 3 tables. Azure SQL is T-SQL, so use \`TOP\` rather than \`LIMIT\`: \`SELECT TOP 5 * FROM <schema>.<table_name>\``,
|
|
366
|
+
ja: `1. azure-sql_executeQuery \u3067\u30D5\u30EC\u30FC\u30D0\u30FC\u3092\u78BA\u8A8D: \`SELECT @@VERSION\`\uFF08Azure SQL \u306F "Microsoft SQL Azure \u2026" \u3092\u8FD4\u3057\u307E\u3059\uFF09
|
|
367
|
+
2. \u30E6\u30FC\u30B6\u30FC\u30C6\u30FC\u30D6\u30EB\u4E00\u89A7: \`SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA NOT IN ('sys', 'INFORMATION_SCHEMA')\`
|
|
368
|
+
3. \u4E3B\u8981\u30C6\u30FC\u30D6\u30EB\u306E\u30AB\u30E9\u30E0\u60C5\u5831: \`SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'dbo' AND TABLE_NAME = 'xxx'\`
|
|
369
|
+
4. \u5FC5\u8981\u306B\u5FDC\u3058\u3066\u6700\u59273\u30C6\u30FC\u30D6\u30EB\u3092\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0\u3002Azure SQL \u306F T-SQL \u306E\u305F\u3081 \`LIMIT\` \u3067\u306F\u306A\u304F \`TOP\` \u3092\u4F7F\u7528: \`SELECT TOP 5 * FROM <schema>.<table_name>\``
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
// ../connectors/src/connectors/azure-sql/tools/execute-query.ts
|
|
374
|
+
import { z } from "zod";
|
|
375
|
+
var MAX_ROWS = 500;
|
|
376
|
+
var inputSchema = z.object({
|
|
377
|
+
toolUseIntent: z.string().optional().describe(
|
|
378
|
+
"Brief description of what you intend to accomplish with this tool call"
|
|
379
|
+
),
|
|
380
|
+
connectionId: z.string().describe("ID of the Azure SQL connection to use"),
|
|
381
|
+
sql: z.string().describe(
|
|
382
|
+
"T-SQL query to execute against Azure SQL. Use SQL Server syntax (e.g. `TOP n`, square-bracket identifiers). Always include `TOP` to bound result size."
|
|
383
|
+
)
|
|
384
|
+
});
|
|
385
|
+
var outputSchema = z.discriminatedUnion("success", [
|
|
386
|
+
z.object({
|
|
387
|
+
success: z.literal(true),
|
|
388
|
+
rowCount: z.number(),
|
|
389
|
+
truncated: z.boolean(),
|
|
390
|
+
rows: z.array(z.record(z.string(), z.unknown()))
|
|
391
|
+
}),
|
|
392
|
+
z.object({
|
|
393
|
+
success: z.literal(false),
|
|
394
|
+
error: z.string()
|
|
395
|
+
})
|
|
396
|
+
]);
|
|
397
|
+
var executeQueryTool = new ConnectorTool({
|
|
398
|
+
name: "executeQuery",
|
|
399
|
+
description: `Execute a T-SQL query against Azure SQL Database. Returns up to ${MAX_ROWS} rows.
|
|
400
|
+
Use for: schema exploration via \`INFORMATION_SCHEMA\`, data sampling, and analytical queries.
|
|
401
|
+
Azure SQL is T-SQL: use \`TOP n\` instead of \`LIMIT n\`. Identifiers can be wrapped in square brackets.
|
|
402
|
+
Avoid loading large amounts of data; always include \`TOP\` in queries.`,
|
|
403
|
+
inputSchema,
|
|
404
|
+
outputSchema,
|
|
405
|
+
async execute({ connectionId, sql }, connections) {
|
|
406
|
+
const connection2 = connections.find((c) => c.id === connectionId);
|
|
407
|
+
if (!connection2) {
|
|
408
|
+
return {
|
|
409
|
+
success: false,
|
|
410
|
+
error: `Connection ${connectionId} not found`
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
const jdbcUrl = parameters.jdbcUrl.getValue(connection2);
|
|
414
|
+
const username = parameters.username.tryGetValue(connection2);
|
|
415
|
+
const password = parameters.password.tryGetValue(connection2);
|
|
416
|
+
console.log(
|
|
417
|
+
`[connector-query] azure-sql/${connection2.name} (${redactSqlServerUrl(jdbcUrl)}): ${sql}`
|
|
418
|
+
);
|
|
419
|
+
let parsed;
|
|
420
|
+
try {
|
|
421
|
+
parsed = parseSqlServerJdbcUrl(jdbcUrl, { username, password });
|
|
422
|
+
} catch (err) {
|
|
423
|
+
return {
|
|
424
|
+
success: false,
|
|
425
|
+
error: err instanceof Error ? err.message : String(err)
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
try {
|
|
429
|
+
const { rows } = await runMssqlQuery(parsed, sql, { forceEncrypt: true });
|
|
430
|
+
const truncated = rows.length > MAX_ROWS;
|
|
431
|
+
return {
|
|
432
|
+
success: true,
|
|
433
|
+
rowCount: Math.min(rows.length, MAX_ROWS),
|
|
434
|
+
truncated,
|
|
435
|
+
rows: rows.slice(0, MAX_ROWS)
|
|
436
|
+
};
|
|
437
|
+
} catch (err) {
|
|
438
|
+
let msg = err instanceof Error ? err.message : String(err);
|
|
439
|
+
msg = msg.replaceAll(jdbcUrl, redactSqlServerUrl(jdbcUrl));
|
|
440
|
+
return { success: false, error: msg };
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
// ../connectors/src/connectors/azure-sql/index.ts
|
|
446
|
+
var tools = { executeQuery: executeQueryTool };
|
|
447
|
+
var azureSqlConnector = new ConnectorPlugin({
|
|
448
|
+
slug: "azure-sql",
|
|
449
|
+
authType: AUTH_TYPES.USER_PASSWORD,
|
|
450
|
+
name: "Azure SQL",
|
|
451
|
+
description: "Connect to Azure SQL Database (managed) using a JDBC-style URL. Encryption is enforced automatically.",
|
|
452
|
+
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/5TL0yBbxoLlk6jFZuiHl8w/55040f52d57bf0b77a2215c985c5a772/azure-sql-icon.png",
|
|
453
|
+
parameters,
|
|
454
|
+
releaseFlag: { dev1: true, dev2: false, prod: false },
|
|
455
|
+
categories: ["database"],
|
|
456
|
+
onboarding: azureSqlOnboarding,
|
|
457
|
+
systemPrompt: {
|
|
458
|
+
en: `### Tools
|
|
459
|
+
|
|
460
|
+
- \`azure-sql_executeQuery\`: Executes a T-SQL query against Azure SQL Database and returns rows. Use for schema exploration via \`INFORMATION_SCHEMA\` and data sampling. See the SQL Reference below for Azure SQL-specific notes.
|
|
461
|
+
|
|
462
|
+
### Business Logic
|
|
463
|
+
|
|
464
|
+
The business logic type for this connector is "sql".
|
|
465
|
+
|
|
466
|
+
### SQL Reference
|
|
467
|
+
- Dialect: T-SQL (same as on-premises SQL Server). Use \`TOP n\` instead of \`LIMIT n\`.
|
|
468
|
+
- Schema layout: user objects live in \`dbo\` by default; system objects in \`sys\` and \`INFORMATION_SCHEMA\`.
|
|
469
|
+
- Schema exploration:
|
|
470
|
+
- List user tables: \`SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA NOT IN ('sys', 'INFORMATION_SCHEMA')\`
|
|
471
|
+
- List columns: \`SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'dbo' AND TABLE_NAME = 'xxx'\`
|
|
472
|
+
- Cross-database queries are not supported on Azure SQL Database (single-DB scope per connection); always reference objects within the connected database.
|
|
473
|
+
- Always bound results with \`TOP\` in queries.`,
|
|
474
|
+
ja: `### \u30C4\u30FC\u30EB
|
|
475
|
+
|
|
476
|
+
- \`azure-sql_executeQuery\`: Azure SQL Database \u306B\u5BFE\u3057\u3066 T-SQL \u30AF\u30A8\u30EA\u3092\u5B9F\u884C\u3057\u3001\u884C\u30C7\u30FC\u30BF\u3092\u8FD4\u3057\u307E\u3059\u3002\`INFORMATION_SCHEMA\` \u3092\u4F7F\u3063\u305F\u30B9\u30AD\u30FC\u30DE\u63A2\u7D22\u3084\u30C7\u30FC\u30BF\u306E\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0\u306B\u4F7F\u3044\u307E\u3059\u3002Azure SQL \u56FA\u6709\u306E\u6CE8\u610F\u70B9\u306F\u4E0B\u90E8\u306E\u300CSQL \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9\u300D\u3092\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
|
477
|
+
|
|
478
|
+
### Business Logic
|
|
479
|
+
|
|
480
|
+
\u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "sql" \u3067\u3059\u3002
|
|
481
|
+
|
|
482
|
+
### SQL \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
|
|
483
|
+
- \u65B9\u8A00: T-SQL\uFF08\u30AA\u30F3\u30D7\u30EC SQL Server \u3068\u5171\u901A\uFF09\u3002\`LIMIT n\` \u3067\u306F\u306A\u304F \`TOP n\` \u3092\u4F7F\u7528\u3057\u307E\u3059\u3002
|
|
484
|
+
- \u30B9\u30AD\u30FC\u30DE\u69CB\u6210: \u30E6\u30FC\u30B6\u30FC\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u306F\u30C7\u30D5\u30A9\u30EB\u30C8\u3067 \`dbo\` \u306B\u914D\u7F6E\u3055\u308C\u307E\u3059\u3002\u30B7\u30B9\u30C6\u30E0\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u306F \`sys\` \u304A\u3088\u3073 \`INFORMATION_SCHEMA\` \u306B\u5B58\u5728\u3057\u307E\u3059\u3002
|
|
485
|
+
- \u30B9\u30AD\u30FC\u30DE\u63A2\u7D22:
|
|
486
|
+
- \u30E6\u30FC\u30B6\u30FC\u30C6\u30FC\u30D6\u30EB\u4E00\u89A7: \`SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA NOT IN ('sys', 'INFORMATION_SCHEMA')\`
|
|
487
|
+
- \u30AB\u30E9\u30E0\u4E00\u89A7: \`SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'dbo' AND TABLE_NAME = 'xxx'\`
|
|
488
|
+
- Azure SQL Database \u3067\u306F\u8907\u6570DB\u3092\u307E\u305F\u3044\u3060\u30AF\u30A8\u30EA\u306F\u3067\u304D\u307E\u305B\u3093\uFF08\u63A5\u7D9A\u5358\u4F4D\u30671DB\uFF09\u3002\u63A5\u7D9A\u4E2D\u306E\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u5185\u306E\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u306E\u307F\u3092\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
|
489
|
+
- \u7D50\u679C\u4EF6\u6570\u306F\u5FC5\u305A \`TOP\` \u3067\u5236\u9650\u3057\u3066\u304F\u3060\u3055\u3044\u3002`
|
|
490
|
+
},
|
|
491
|
+
tools,
|
|
492
|
+
async checkConnection(params, _config) {
|
|
493
|
+
return checkMssqlConnection(
|
|
494
|
+
params[parameters.jdbcUrl.slug],
|
|
495
|
+
{
|
|
496
|
+
username: params[parameters.username.slug],
|
|
497
|
+
password: params[parameters.password.slug]
|
|
498
|
+
},
|
|
499
|
+
{ forceEncrypt: true }
|
|
500
|
+
);
|
|
501
|
+
},
|
|
502
|
+
async query(params, sql, _namedParams) {
|
|
503
|
+
const parsed = parseSqlServerJdbcUrl(params[parameters.jdbcUrl.slug], {
|
|
504
|
+
username: params[parameters.username.slug],
|
|
505
|
+
password: params[parameters.password.slug]
|
|
506
|
+
});
|
|
507
|
+
return runMssqlQuery(parsed, sql, { forceEncrypt: true });
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
// src/connectors/create-connector-sdk.ts
|
|
512
|
+
import { readFileSync } from "fs";
|
|
513
|
+
import path from "path";
|
|
514
|
+
|
|
515
|
+
// src/connector-client/env.ts
|
|
516
|
+
function resolveEnvVar(entry, key, connectionId) {
|
|
517
|
+
const envVarName = entry.envVars[key];
|
|
518
|
+
if (!envVarName) {
|
|
519
|
+
throw new Error(`Connection "${connectionId}" is missing envVars mapping for key "${key}"`);
|
|
520
|
+
}
|
|
521
|
+
const value = process.env[envVarName];
|
|
522
|
+
if (!value) {
|
|
523
|
+
throw new Error(`Environment variable "${envVarName}" (for connection "${connectionId}", key "${key}") is not set`);
|
|
524
|
+
}
|
|
525
|
+
return value;
|
|
526
|
+
}
|
|
527
|
+
function resolveEnvVarOptional(entry, key) {
|
|
528
|
+
const envVarName = entry.envVars[key];
|
|
529
|
+
if (!envVarName) return void 0;
|
|
530
|
+
return process.env[envVarName] || void 0;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// src/connector-client/proxy-fetch.ts
|
|
534
|
+
import { getContext } from "hono/context-storage";
|
|
535
|
+
import { getCookie } from "hono/cookie";
|
|
536
|
+
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
537
|
+
function normalizeHeaders(input) {
|
|
538
|
+
const out = {};
|
|
539
|
+
if (!input) return out;
|
|
540
|
+
new Headers(input).forEach((value, key) => {
|
|
541
|
+
out[key] = value;
|
|
542
|
+
});
|
|
543
|
+
return out;
|
|
544
|
+
}
|
|
545
|
+
function createSandboxProxyFetch(connectionId) {
|
|
546
|
+
return async (input, init) => {
|
|
547
|
+
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
548
|
+
const sandboxId = process.env.INTERNAL_SQUADBASE_SANDBOX_ID;
|
|
549
|
+
if (!token || !sandboxId) {
|
|
550
|
+
throw new Error(
|
|
551
|
+
"Connection proxy is not configured. Please check your deployment settings."
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
555
|
+
const originalMethod = init?.method ?? "GET";
|
|
556
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
557
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
558
|
+
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
559
|
+
return fetch(proxyUrl, {
|
|
560
|
+
method: "POST",
|
|
561
|
+
headers: {
|
|
562
|
+
"Content-Type": "application/json",
|
|
563
|
+
Authorization: `Bearer ${token}`
|
|
564
|
+
},
|
|
565
|
+
body: JSON.stringify({
|
|
566
|
+
url: originalUrl,
|
|
567
|
+
method: originalMethod,
|
|
568
|
+
headers: normalizeHeaders(init?.headers),
|
|
569
|
+
body: originalBody
|
|
570
|
+
})
|
|
571
|
+
});
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
function createDeployedAppProxyFetch(connectionId) {
|
|
575
|
+
const projectId = process.env["SQUADBASE_PROJECT_ID"];
|
|
576
|
+
if (!projectId) {
|
|
577
|
+
throw new Error(
|
|
578
|
+
"Connection proxy is not configured. Please check your deployment settings."
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
582
|
+
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
583
|
+
return async (input, init) => {
|
|
584
|
+
const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
585
|
+
const originalMethod = init?.method ?? "GET";
|
|
586
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
587
|
+
const c = getContext();
|
|
588
|
+
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
589
|
+
if (!appSession) {
|
|
590
|
+
throw new Error(
|
|
591
|
+
"No authentication method available for connection proxy."
|
|
592
|
+
);
|
|
593
|
+
}
|
|
594
|
+
return fetch(proxyUrl, {
|
|
595
|
+
method: "POST",
|
|
596
|
+
headers: {
|
|
597
|
+
"Content-Type": "application/json",
|
|
598
|
+
Authorization: `Bearer ${appSession}`
|
|
599
|
+
},
|
|
600
|
+
body: JSON.stringify({
|
|
601
|
+
url: originalUrl,
|
|
602
|
+
method: originalMethod,
|
|
603
|
+
headers: normalizeHeaders(init?.headers),
|
|
604
|
+
body: originalBody
|
|
605
|
+
})
|
|
606
|
+
});
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
function createProxyFetch(connectionId) {
|
|
610
|
+
if (process.env.INTERNAL_SQUADBASE_SANDBOX_ID) {
|
|
611
|
+
return createSandboxProxyFetch(connectionId);
|
|
612
|
+
}
|
|
613
|
+
return createDeployedAppProxyFetch(connectionId);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// src/connectors/create-connector-sdk.ts
|
|
617
|
+
function loadConnectionsSync() {
|
|
618
|
+
const filePath = process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), ".squadbase/connections.json");
|
|
619
|
+
try {
|
|
620
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
621
|
+
return JSON.parse(raw);
|
|
622
|
+
} catch {
|
|
623
|
+
return {};
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
function createConnectorSdk(plugin, createClient2) {
|
|
627
|
+
return (connectionId) => {
|
|
628
|
+
const connections = loadConnectionsSync();
|
|
629
|
+
const entry = connections[connectionId];
|
|
630
|
+
if (!entry) {
|
|
631
|
+
throw new Error(
|
|
632
|
+
`Connection "${connectionId}" not found in .squadbase/connections.json`
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
if (entry.connector.slug !== plugin.slug) {
|
|
636
|
+
throw new Error(
|
|
637
|
+
`Connection "${connectionId}" is not a ${plugin.slug} connection (got "${entry.connector.slug}")`
|
|
638
|
+
);
|
|
639
|
+
}
|
|
640
|
+
const params = {};
|
|
641
|
+
for (const param of Object.values(plugin.parameters)) {
|
|
642
|
+
if (param.required) {
|
|
643
|
+
params[param.slug] = resolveEnvVar(entry, param.slug, connectionId);
|
|
644
|
+
} else {
|
|
645
|
+
const val = resolveEnvVarOptional(entry, param.slug);
|
|
646
|
+
if (val !== void 0) params[param.slug] = val;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
return createClient2(params, createProxyFetch(connectionId));
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// src/connectors/entries/azure-sql.ts
|
|
654
|
+
var connection = createConnectorSdk(azureSqlConnector, createClient);
|
|
655
|
+
export {
|
|
656
|
+
connection
|
|
657
|
+
};
|