@squadbase/vite-server 0.1.9-dev.87dd3f7 → 0.1.9-dev.a120137
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 +73157 -60061
- 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 +923 -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 +73218 -60122
- package/dist/main.js +73212 -60116
- package/dist/vite-plugin.js +73118 -60022
- package/package.json +60 -2
|
@@ -0,0 +1,582 @@
|
|
|
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/supabase/parameters.ts
|
|
46
|
+
var parameters = {
|
|
47
|
+
connectionUrl: new ParameterDefinition({
|
|
48
|
+
slug: "connection-url",
|
|
49
|
+
name: "Supabase Connection URL",
|
|
50
|
+
description: "The Supabase Postgres connection string. Copy it from the Supabase dashboard (Project Settings \u2192 Database \u2192 Connection string). Use the Transaction pooler (port 6543) URL for serverless workloads, e.g. `postgresql://postgres.<project-ref>:<password>@aws-0-<region>.pooler.supabase.com:6543/postgres`.",
|
|
51
|
+
envVarBaseKey: "SUPABASE_DB_URL",
|
|
52
|
+
type: "text",
|
|
53
|
+
secret: true,
|
|
54
|
+
required: true
|
|
55
|
+
})
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// ../connectors/src/connectors/supabase/sdk/index.ts
|
|
59
|
+
function createClient(params) {
|
|
60
|
+
const connectionUrl = params[parameters.connectionUrl.slug];
|
|
61
|
+
if (!connectionUrl) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`supabase: missing required parameter: ${parameters.connectionUrl.slug}`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
async function runQuery(sql, queryParams) {
|
|
67
|
+
try {
|
|
68
|
+
const { Pool } = await import("pg");
|
|
69
|
+
const pool = new Pool({
|
|
70
|
+
connectionString: connectionUrl,
|
|
71
|
+
ssl: { rejectUnauthorized: false },
|
|
72
|
+
connectionTimeoutMillis: 1e4,
|
|
73
|
+
statement_timeout: 6e4
|
|
74
|
+
});
|
|
75
|
+
try {
|
|
76
|
+
const result = await pool.query(sql, queryParams);
|
|
77
|
+
return result.rows;
|
|
78
|
+
} finally {
|
|
79
|
+
await pool.end();
|
|
80
|
+
}
|
|
81
|
+
} catch (err) {
|
|
82
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
83
|
+
throw new Error(msg.replaceAll(connectionUrl, "***"));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
query: runQuery
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ../connectors/src/connector-onboarding.ts
|
|
92
|
+
var ConnectorOnboarding = class {
|
|
93
|
+
/** Phase 1: Connection setup instructions (optional — some connectors don't need this) */
|
|
94
|
+
connectionSetupInstructions;
|
|
95
|
+
/** Phase 2: Data overview instructions */
|
|
96
|
+
dataOverviewInstructions;
|
|
97
|
+
constructor(config) {
|
|
98
|
+
this.connectionSetupInstructions = config.connectionSetupInstructions;
|
|
99
|
+
this.dataOverviewInstructions = config.dataOverviewInstructions;
|
|
100
|
+
}
|
|
101
|
+
getConnectionSetupPrompt(language) {
|
|
102
|
+
return this.connectionSetupInstructions?.[language] ?? null;
|
|
103
|
+
}
|
|
104
|
+
getDataOverviewInstructions(language) {
|
|
105
|
+
return this.dataOverviewInstructions[language];
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// ../connectors/src/connector-tool.ts
|
|
110
|
+
var ConnectorTool = class {
|
|
111
|
+
name;
|
|
112
|
+
description;
|
|
113
|
+
inputSchema;
|
|
114
|
+
outputSchema;
|
|
115
|
+
_execute;
|
|
116
|
+
constructor(config) {
|
|
117
|
+
this.name = config.name;
|
|
118
|
+
this.description = config.description;
|
|
119
|
+
this.inputSchema = config.inputSchema;
|
|
120
|
+
this.outputSchema = config.outputSchema;
|
|
121
|
+
this._execute = config.execute;
|
|
122
|
+
}
|
|
123
|
+
createTool(connections, config) {
|
|
124
|
+
return {
|
|
125
|
+
description: this.description,
|
|
126
|
+
inputSchema: this.inputSchema,
|
|
127
|
+
outputSchema: this.outputSchema,
|
|
128
|
+
execute: (input) => this._execute(input, connections, config)
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// ../connectors/src/connector-plugin.ts
|
|
134
|
+
var ConnectorPlugin = class _ConnectorPlugin {
|
|
135
|
+
slug;
|
|
136
|
+
authType;
|
|
137
|
+
name;
|
|
138
|
+
description;
|
|
139
|
+
iconUrl;
|
|
140
|
+
parameters;
|
|
141
|
+
releaseFlag;
|
|
142
|
+
proxyPolicy;
|
|
143
|
+
experimentalAttributes;
|
|
144
|
+
categories;
|
|
145
|
+
onboarding;
|
|
146
|
+
systemPrompt;
|
|
147
|
+
tools;
|
|
148
|
+
query;
|
|
149
|
+
checkConnection;
|
|
150
|
+
constructor(config) {
|
|
151
|
+
this.slug = config.slug;
|
|
152
|
+
this.authType = config.authType;
|
|
153
|
+
this.name = config.name;
|
|
154
|
+
this.description = config.description;
|
|
155
|
+
this.iconUrl = config.iconUrl;
|
|
156
|
+
this.parameters = config.parameters;
|
|
157
|
+
this.releaseFlag = config.releaseFlag;
|
|
158
|
+
this.proxyPolicy = config.proxyPolicy;
|
|
159
|
+
this.experimentalAttributes = config.experimentalAttributes;
|
|
160
|
+
this.categories = config.categories ?? [];
|
|
161
|
+
this.onboarding = config.onboarding;
|
|
162
|
+
this.systemPrompt = config.systemPrompt;
|
|
163
|
+
this.tools = config.tools;
|
|
164
|
+
this.query = config.query;
|
|
165
|
+
this.checkConnection = config.checkConnection;
|
|
166
|
+
}
|
|
167
|
+
get connectorKey() {
|
|
168
|
+
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Create tools for connections that belong to this connector.
|
|
172
|
+
* Filters connections by connectorKey internally.
|
|
173
|
+
* Returns tools keyed as `${connectorKey}_${toolName}`.
|
|
174
|
+
*/
|
|
175
|
+
createTools(connections, config, opts) {
|
|
176
|
+
const myConnections = connections.filter(
|
|
177
|
+
(c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
|
|
178
|
+
);
|
|
179
|
+
const result = {};
|
|
180
|
+
for (const t of Object.values(this.tools)) {
|
|
181
|
+
const tool = t.createTool(myConnections, config);
|
|
182
|
+
const originalToModelOutput = tool.toModelOutput;
|
|
183
|
+
result[`${this.connectorKey}_${t.name}`] = {
|
|
184
|
+
...tool,
|
|
185
|
+
toModelOutput: async (options) => {
|
|
186
|
+
if (!originalToModelOutput) {
|
|
187
|
+
return opts.truncateOutput(options.output);
|
|
188
|
+
}
|
|
189
|
+
const modelOutput = await originalToModelOutput(options);
|
|
190
|
+
if (modelOutput.type === "text" || modelOutput.type === "json") {
|
|
191
|
+
return opts.truncateOutput(modelOutput.value);
|
|
192
|
+
}
|
|
193
|
+
return modelOutput;
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
return result;
|
|
198
|
+
}
|
|
199
|
+
static deriveKey(slug, authType) {
|
|
200
|
+
if (authType) return `${slug}-${authType}`;
|
|
201
|
+
const LEGACY_NULL_AUTH_TYPE_MAP = {
|
|
202
|
+
// user-password
|
|
203
|
+
"postgresql": "user-password",
|
|
204
|
+
"mysql": "user-password",
|
|
205
|
+
"clickhouse": "user-password",
|
|
206
|
+
"kintone": "user-password",
|
|
207
|
+
"squadbase-db": "user-password",
|
|
208
|
+
// service-account
|
|
209
|
+
"snowflake": "service-account",
|
|
210
|
+
"bigquery": "service-account",
|
|
211
|
+
"google-analytics": "service-account",
|
|
212
|
+
"google-calendar": "service-account",
|
|
213
|
+
"aws-athena": "service-account",
|
|
214
|
+
"redshift": "service-account",
|
|
215
|
+
// api-key
|
|
216
|
+
"databricks": "api-key",
|
|
217
|
+
"dbt": "api-key",
|
|
218
|
+
"airtable": "api-key",
|
|
219
|
+
"openai": "api-key",
|
|
220
|
+
"gemini": "api-key",
|
|
221
|
+
"anthropic": "api-key",
|
|
222
|
+
"wix-store": "api-key"
|
|
223
|
+
};
|
|
224
|
+
const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
|
|
225
|
+
if (fallbackAuthType) return `${slug}-${fallbackAuthType}`;
|
|
226
|
+
return slug;
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// ../connectors/src/auth-types.ts
|
|
231
|
+
var AUTH_TYPES = {
|
|
232
|
+
OAUTH: "oauth",
|
|
233
|
+
API_KEY: "api-key",
|
|
234
|
+
JWT: "jwt",
|
|
235
|
+
SERVICE_ACCOUNT: "service-account",
|
|
236
|
+
PAT: "pat",
|
|
237
|
+
USER_PASSWORD: "user-password"
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// ../connectors/src/lib/query-utils.ts
|
|
241
|
+
function buildPositionalParams(sql, namedParams) {
|
|
242
|
+
if (!namedParams) return { text: sql, values: [] };
|
|
243
|
+
const values = [];
|
|
244
|
+
const nameToIndex = /* @__PURE__ */ new Map();
|
|
245
|
+
const text = sql.replace(/\{\{(\w+)\}\}/g, (_match, name) => {
|
|
246
|
+
if (!nameToIndex.has(name)) {
|
|
247
|
+
values.push(namedParams[name] ?? null);
|
|
248
|
+
nameToIndex.set(name, values.length);
|
|
249
|
+
}
|
|
250
|
+
return `$${nameToIndex.get(name)}`;
|
|
251
|
+
});
|
|
252
|
+
return { text, values };
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// ../connectors/src/connectors/supabase/setup.ts
|
|
256
|
+
var supabaseOnboarding = new ConnectorOnboarding({
|
|
257
|
+
dataOverviewInstructions: {
|
|
258
|
+
en: `1. Use executeQuery to list tables in the \`public\` schema: \`SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'\`
|
|
259
|
+
2. Most Supabase projects also expose Auth/Storage tables in dedicated schemas (\`auth\`, \`storage\`). Inspect them with \`SELECT table_schema, table_name FROM information_schema.tables WHERE table_schema IN ('auth', 'storage')\` only when the user explicitly needs them
|
|
260
|
+
3. For key tables, fetch column info: \`SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'xxx'\`
|
|
261
|
+
4. Sample up to 3 tables with \`SELECT * FROM <table_name> LIMIT 5\` if column info alone is insufficient`,
|
|
262
|
+
ja: `1. executeQuery \u3067 \`public\` \u30B9\u30AD\u30FC\u30DE\u306E\u30C6\u30FC\u30D6\u30EB\u4E00\u89A7\u3092\u53D6\u5F97: \`SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'\`
|
|
263
|
+
2. Supabase\u306F Auth / Storage \u7528\u306E\u30C6\u30FC\u30D6\u30EB\u3092 \`auth\` / \`storage\` \u30B9\u30AD\u30FC\u30DE\u306B\u6301\u3061\u307E\u3059\u3002\u30E6\u30FC\u30B6\u30FC\u304C\u660E\u793A\u7684\u306B\u5FC5\u8981\u3068\u3057\u3066\u3044\u308B\u5834\u5408\u306E\u307F \`SELECT table_schema, table_name FROM information_schema.tables WHERE table_schema IN ('auth', 'storage')\` \u3067\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044
|
|
264
|
+
3. \u4E3B\u8981\u30C6\u30FC\u30D6\u30EB\u306E\u30AB\u30E9\u30E0\u60C5\u5831\u3092\u53D6\u5F97: \`SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'xxx'\`
|
|
265
|
+
4. \u30AB\u30E9\u30E0\u60C5\u5831\u3060\u3051\u3067\u306F\u4E0D\u5341\u5206\u306A\u5834\u5408\u3001\u6700\u59273\u30C6\u30FC\u30D6\u30EB\u3092 \`SELECT * FROM <table_name> LIMIT 5\` \u3067\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0`
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// ../connectors/src/connectors/supabase/tools/execute-query.ts
|
|
270
|
+
import { z } from "zod";
|
|
271
|
+
var MAX_ROWS = 500;
|
|
272
|
+
var CONNECT_TIMEOUT_MS = 1e4;
|
|
273
|
+
var STATEMENT_TIMEOUT_MS = 6e4;
|
|
274
|
+
var inputSchema = z.object({
|
|
275
|
+
toolUseIntent: z.string().optional().describe(
|
|
276
|
+
"Brief description of what you intend to accomplish with this tool call"
|
|
277
|
+
),
|
|
278
|
+
connectionId: z.string().describe("ID of the Supabase connection to use"),
|
|
279
|
+
sql: z.string().describe(
|
|
280
|
+
"PostgreSQL SQL query targeting the Supabase project. Use the `public` schema unless the user explicitly references Supabase Auth (`auth.*`) or Storage (`storage.*`). Always include LIMIT."
|
|
281
|
+
)
|
|
282
|
+
});
|
|
283
|
+
var outputSchema = z.discriminatedUnion("success", [
|
|
284
|
+
z.object({
|
|
285
|
+
success: z.literal(true),
|
|
286
|
+
rowCount: z.number(),
|
|
287
|
+
truncated: z.boolean(),
|
|
288
|
+
rows: z.array(z.record(z.string(), z.unknown()))
|
|
289
|
+
}),
|
|
290
|
+
z.object({
|
|
291
|
+
success: z.literal(false),
|
|
292
|
+
error: z.string()
|
|
293
|
+
})
|
|
294
|
+
]);
|
|
295
|
+
var executeQueryTool = new ConnectorTool({
|
|
296
|
+
name: "executeQuery",
|
|
297
|
+
description: `Execute SQL against a Supabase Postgres database. Returns up to ${MAX_ROWS} rows.
|
|
298
|
+
Use for: schema exploration (information_schema), data sampling, and analytical queries against Supabase tables.
|
|
299
|
+
User tables live in the \`public\` schema by default; Supabase-managed metadata lives in \`auth\` and \`storage\`.
|
|
300
|
+
Avoid loading large amounts of data; always include LIMIT in queries.`,
|
|
301
|
+
inputSchema,
|
|
302
|
+
outputSchema,
|
|
303
|
+
async execute({ connectionId, sql }, connections) {
|
|
304
|
+
const connection2 = connections.find((c) => c.id === connectionId);
|
|
305
|
+
if (!connection2) {
|
|
306
|
+
return {
|
|
307
|
+
success: false,
|
|
308
|
+
error: `Connection ${connectionId} not found`
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
console.log(
|
|
312
|
+
`[connector-query] supabase/${connection2.name}: ${sql}`
|
|
313
|
+
);
|
|
314
|
+
let connectionUrl;
|
|
315
|
+
try {
|
|
316
|
+
const { Pool } = await import("pg");
|
|
317
|
+
connectionUrl = parameters.connectionUrl.getValue(connection2);
|
|
318
|
+
const pool = new Pool({
|
|
319
|
+
connectionString: connectionUrl,
|
|
320
|
+
ssl: { rejectUnauthorized: false },
|
|
321
|
+
connectionTimeoutMillis: CONNECT_TIMEOUT_MS,
|
|
322
|
+
statement_timeout: STATEMENT_TIMEOUT_MS
|
|
323
|
+
});
|
|
324
|
+
try {
|
|
325
|
+
const result = await pool.query(sql);
|
|
326
|
+
const rows = result.rows;
|
|
327
|
+
const truncated = rows.length > MAX_ROWS;
|
|
328
|
+
return {
|
|
329
|
+
success: true,
|
|
330
|
+
rowCount: Math.min(rows.length, MAX_ROWS),
|
|
331
|
+
truncated,
|
|
332
|
+
rows: rows.slice(0, MAX_ROWS)
|
|
333
|
+
};
|
|
334
|
+
} finally {
|
|
335
|
+
await pool.end();
|
|
336
|
+
}
|
|
337
|
+
} catch (err) {
|
|
338
|
+
let msg = err instanceof Error ? err.message : String(err);
|
|
339
|
+
if (connectionUrl) {
|
|
340
|
+
msg = msg.replaceAll(connectionUrl, "***");
|
|
341
|
+
}
|
|
342
|
+
return { success: false, error: msg };
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
// ../connectors/src/connectors/supabase/index.ts
|
|
348
|
+
var tools = { executeQuery: executeQueryTool };
|
|
349
|
+
var supabaseConnector = new ConnectorPlugin({
|
|
350
|
+
slug: "supabase",
|
|
351
|
+
authType: AUTH_TYPES.USER_PASSWORD,
|
|
352
|
+
name: "Supabase",
|
|
353
|
+
description: "Connect to a Supabase project's Postgres database to query application tables and Supabase-managed schemas (auth, storage).",
|
|
354
|
+
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/14k0U6F9PVovVjYjWyNzKb/2c4ff53adbe9334a63fee0a13d9f050a/supabase-icon.webp",
|
|
355
|
+
parameters,
|
|
356
|
+
releaseFlag: { dev1: true, dev2: false, prod: false },
|
|
357
|
+
categories: ["database"],
|
|
358
|
+
onboarding: supabaseOnboarding,
|
|
359
|
+
systemPrompt: {
|
|
360
|
+
en: `### Tools
|
|
361
|
+
|
|
362
|
+
- \`supabase_executeQuery\`: Executes a PostgreSQL query against the Supabase project's database and returns rows. Use this for schema exploration via \`information_schema.tables\`/\`columns\` and for sampling data. See the SQL Reference below for syntax notes and Supabase-specific schemas.
|
|
363
|
+
|
|
364
|
+
### Business Logic
|
|
365
|
+
|
|
366
|
+
The business logic type for this connector is "sql".
|
|
367
|
+
|
|
368
|
+
### SQL Reference
|
|
369
|
+
- Schema layout:
|
|
370
|
+
- User tables live in the \`public\` schema by default.
|
|
371
|
+
- Supabase Auth tables live in the \`auth\` schema (e.g. \`auth.users\`).
|
|
372
|
+
- Supabase Storage tables live in the \`storage\` schema (e.g. \`storage.objects\`, \`storage.buckets\`).
|
|
373
|
+
- Schema exploration:
|
|
374
|
+
- List user tables: \`SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'\`
|
|
375
|
+
- List columns: \`SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'xxx'\`
|
|
376
|
+
- Always include LIMIT in queries`,
|
|
377
|
+
ja: `### \u30C4\u30FC\u30EB
|
|
378
|
+
|
|
379
|
+
- \`supabase_executeQuery\`: Supabase\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E Postgres \u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306B\u5BFE\u3057\u3066\u30AF\u30A8\u30EA\u3092\u5B9F\u884C\u3057\u3001\u884C\u30C7\u30FC\u30BF\u3092\u8FD4\u3057\u307E\u3059\u3002\`information_schema.tables\`/\`columns\` \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\u3002\u69CB\u6587\u306E\u6CE8\u610F\u70B9\u3068 Supabase \u56FA\u6709\u306E\u30B9\u30AD\u30FC\u30DE\u306F\u4E0B\u90E8\u306E\u300CSQL \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9\u300D\u3092\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
|
380
|
+
|
|
381
|
+
### Business Logic
|
|
382
|
+
|
|
383
|
+
\u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "sql" \u3067\u3059\u3002
|
|
384
|
+
|
|
385
|
+
### SQL \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
|
|
386
|
+
- \u30B9\u30AD\u30FC\u30DE\u69CB\u6210:
|
|
387
|
+
- \u30E6\u30FC\u30B6\u30FC\u306E\u30C6\u30FC\u30D6\u30EB\u306F\u30C7\u30D5\u30A9\u30EB\u30C8\u3067 \`public\` \u30B9\u30AD\u30FC\u30DE\u306B\u5B58\u5728\u3057\u307E\u3059\u3002
|
|
388
|
+
- Supabase Auth \u306E\u30C6\u30FC\u30D6\u30EB\u306F \`auth\` \u30B9\u30AD\u30FC\u30DE\u306B\u5B58\u5728\u3057\u307E\u3059\uFF08\u4F8B: \`auth.users\`\uFF09\u3002
|
|
389
|
+
- Supabase Storage \u306E\u30C6\u30FC\u30D6\u30EB\u306F \`storage\` \u30B9\u30AD\u30FC\u30DE\u306B\u5B58\u5728\u3057\u307E\u3059\uFF08\u4F8B: \`storage.objects\`, \`storage.buckets\`\uFF09\u3002
|
|
390
|
+
- \u30B9\u30AD\u30FC\u30DE\u63A2\u7D22:
|
|
391
|
+
- \u30E6\u30FC\u30B6\u30FC\u30C6\u30FC\u30D6\u30EB\u4E00\u89A7: \`SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'\`
|
|
392
|
+
- \u30AB\u30E9\u30E0\u4E00\u89A7: \`SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'xxx'\`
|
|
393
|
+
- \u30AF\u30A8\u30EA\u306B\u306F\u5FC5\u305A LIMIT \u3092\u542B\u3081\u3066\u304F\u3060\u3055\u3044`
|
|
394
|
+
},
|
|
395
|
+
tools,
|
|
396
|
+
async checkConnection(params, _config) {
|
|
397
|
+
const { Pool } = await import("pg");
|
|
398
|
+
const connectionUrl = params[parameters.connectionUrl.slug];
|
|
399
|
+
const pool = new Pool({
|
|
400
|
+
connectionString: connectionUrl,
|
|
401
|
+
ssl: { rejectUnauthorized: false },
|
|
402
|
+
connectionTimeoutMillis: 1e4
|
|
403
|
+
});
|
|
404
|
+
try {
|
|
405
|
+
await pool.query("SELECT 1");
|
|
406
|
+
return { success: true };
|
|
407
|
+
} catch (error) {
|
|
408
|
+
return {
|
|
409
|
+
success: false,
|
|
410
|
+
error: error instanceof Error ? error.message : String(error)
|
|
411
|
+
};
|
|
412
|
+
} finally {
|
|
413
|
+
await pool.end();
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
async query(params, sql, namedParams) {
|
|
417
|
+
const { Pool } = await import("pg");
|
|
418
|
+
const cleanSql = sql.replace(/;\s*$/, "");
|
|
419
|
+
const { text, values } = buildPositionalParams(cleanSql, namedParams);
|
|
420
|
+
const connectionUrl = params[parameters.connectionUrl.slug];
|
|
421
|
+
const pool = new Pool({
|
|
422
|
+
connectionString: connectionUrl,
|
|
423
|
+
ssl: { rejectUnauthorized: false },
|
|
424
|
+
connectionTimeoutMillis: 1e4,
|
|
425
|
+
statement_timeout: 6e4
|
|
426
|
+
});
|
|
427
|
+
try {
|
|
428
|
+
const result = await pool.query(text, values);
|
|
429
|
+
return { rows: result.rows };
|
|
430
|
+
} finally {
|
|
431
|
+
await pool.end();
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
// src/connectors/create-connector-sdk.ts
|
|
437
|
+
import { readFileSync } from "fs";
|
|
438
|
+
import path from "path";
|
|
439
|
+
|
|
440
|
+
// src/connector-client/env.ts
|
|
441
|
+
function resolveEnvVar(entry, key, connectionId) {
|
|
442
|
+
const envVarName = entry.envVars[key];
|
|
443
|
+
if (!envVarName) {
|
|
444
|
+
throw new Error(`Connection "${connectionId}" is missing envVars mapping for key "${key}"`);
|
|
445
|
+
}
|
|
446
|
+
const value = process.env[envVarName];
|
|
447
|
+
if (!value) {
|
|
448
|
+
throw new Error(`Environment variable "${envVarName}" (for connection "${connectionId}", key "${key}") is not set`);
|
|
449
|
+
}
|
|
450
|
+
return value;
|
|
451
|
+
}
|
|
452
|
+
function resolveEnvVarOptional(entry, key) {
|
|
453
|
+
const envVarName = entry.envVars[key];
|
|
454
|
+
if (!envVarName) return void 0;
|
|
455
|
+
return process.env[envVarName] || void 0;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// src/connector-client/proxy-fetch.ts
|
|
459
|
+
import { getContext } from "hono/context-storage";
|
|
460
|
+
import { getCookie } from "hono/cookie";
|
|
461
|
+
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
462
|
+
function normalizeHeaders(input) {
|
|
463
|
+
const out = {};
|
|
464
|
+
if (!input) return out;
|
|
465
|
+
new Headers(input).forEach((value, key) => {
|
|
466
|
+
out[key] = value;
|
|
467
|
+
});
|
|
468
|
+
return out;
|
|
469
|
+
}
|
|
470
|
+
function createSandboxProxyFetch(connectionId) {
|
|
471
|
+
return async (input, init) => {
|
|
472
|
+
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
473
|
+
const sandboxId = process.env.INTERNAL_SQUADBASE_SANDBOX_ID;
|
|
474
|
+
if (!token || !sandboxId) {
|
|
475
|
+
throw new Error(
|
|
476
|
+
"Connection proxy is not configured. Please check your deployment settings."
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
480
|
+
const originalMethod = init?.method ?? "GET";
|
|
481
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
482
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
483
|
+
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
484
|
+
return fetch(proxyUrl, {
|
|
485
|
+
method: "POST",
|
|
486
|
+
headers: {
|
|
487
|
+
"Content-Type": "application/json",
|
|
488
|
+
Authorization: `Bearer ${token}`
|
|
489
|
+
},
|
|
490
|
+
body: JSON.stringify({
|
|
491
|
+
url: originalUrl,
|
|
492
|
+
method: originalMethod,
|
|
493
|
+
headers: normalizeHeaders(init?.headers),
|
|
494
|
+
body: originalBody
|
|
495
|
+
})
|
|
496
|
+
});
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
function createDeployedAppProxyFetch(connectionId) {
|
|
500
|
+
const projectId = process.env["SQUADBASE_PROJECT_ID"];
|
|
501
|
+
if (!projectId) {
|
|
502
|
+
throw new Error(
|
|
503
|
+
"Connection proxy is not configured. Please check your deployment settings."
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
507
|
+
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
508
|
+
return async (input, init) => {
|
|
509
|
+
const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
510
|
+
const originalMethod = init?.method ?? "GET";
|
|
511
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
512
|
+
const c = getContext();
|
|
513
|
+
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
514
|
+
if (!appSession) {
|
|
515
|
+
throw new Error(
|
|
516
|
+
"No authentication method available for connection proxy."
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
return fetch(proxyUrl, {
|
|
520
|
+
method: "POST",
|
|
521
|
+
headers: {
|
|
522
|
+
"Content-Type": "application/json",
|
|
523
|
+
Authorization: `Bearer ${appSession}`
|
|
524
|
+
},
|
|
525
|
+
body: JSON.stringify({
|
|
526
|
+
url: originalUrl,
|
|
527
|
+
method: originalMethod,
|
|
528
|
+
headers: normalizeHeaders(init?.headers),
|
|
529
|
+
body: originalBody
|
|
530
|
+
})
|
|
531
|
+
});
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
function createProxyFetch(connectionId) {
|
|
535
|
+
if (process.env.INTERNAL_SQUADBASE_SANDBOX_ID) {
|
|
536
|
+
return createSandboxProxyFetch(connectionId);
|
|
537
|
+
}
|
|
538
|
+
return createDeployedAppProxyFetch(connectionId);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// src/connectors/create-connector-sdk.ts
|
|
542
|
+
function loadConnectionsSync() {
|
|
543
|
+
const filePath = process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), ".squadbase/connections.json");
|
|
544
|
+
try {
|
|
545
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
546
|
+
return JSON.parse(raw);
|
|
547
|
+
} catch {
|
|
548
|
+
return {};
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
function createConnectorSdk(plugin, createClient2) {
|
|
552
|
+
return (connectionId) => {
|
|
553
|
+
const connections = loadConnectionsSync();
|
|
554
|
+
const entry = connections[connectionId];
|
|
555
|
+
if (!entry) {
|
|
556
|
+
throw new Error(
|
|
557
|
+
`Connection "${connectionId}" not found in .squadbase/connections.json`
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
if (entry.connector.slug !== plugin.slug) {
|
|
561
|
+
throw new Error(
|
|
562
|
+
`Connection "${connectionId}" is not a ${plugin.slug} connection (got "${entry.connector.slug}")`
|
|
563
|
+
);
|
|
564
|
+
}
|
|
565
|
+
const params = {};
|
|
566
|
+
for (const param of Object.values(plugin.parameters)) {
|
|
567
|
+
if (param.required) {
|
|
568
|
+
params[param.slug] = resolveEnvVar(entry, param.slug, connectionId);
|
|
569
|
+
} else {
|
|
570
|
+
const val = resolveEnvVarOptional(entry, param.slug);
|
|
571
|
+
if (val !== void 0) params[param.slug] = val;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
return createClient2(params, createProxyFetch(connectionId));
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// src/connectors/entries/supabase.ts
|
|
579
|
+
var connection = createConnectorSdk(supabaseConnector, createClient);
|
|
580
|
+
export {
|
|
581
|
+
connection
|
|
582
|
+
};
|
|
@@ -201,6 +201,16 @@ var AUTH_TYPES = {
|
|
|
201
201
|
USER_PASSWORD: "user-password"
|
|
202
202
|
};
|
|
203
203
|
|
|
204
|
+
// ../connectors/src/lib/normalize-path.ts
|
|
205
|
+
function normalizeRequestPath(path2, basePathSegment) {
|
|
206
|
+
let p = path2.trim();
|
|
207
|
+
if (!p.startsWith("/")) p = "/" + p;
|
|
208
|
+
if (p === basePathSegment || p.startsWith(basePathSegment + "/")) {
|
|
209
|
+
p = p.slice(basePathSegment.length) || "/";
|
|
210
|
+
}
|
|
211
|
+
return p;
|
|
212
|
+
}
|
|
213
|
+
|
|
204
214
|
// ../connectors/src/connectors/tiktok-ads/tools/list-advertisers.ts
|
|
205
215
|
import { z } from "zod";
|
|
206
216
|
var BASE_URL2 = "https://business-api.tiktok.com/open_api/v1.3/";
|
|
@@ -375,7 +385,9 @@ var parameters = {
|
|
|
375
385
|
|
|
376
386
|
// ../connectors/src/connectors/tiktok-ads/tools/request.ts
|
|
377
387
|
import { z as z2 } from "zod";
|
|
378
|
-
var
|
|
388
|
+
var BASE_HOST = "https://business-api.tiktok.com";
|
|
389
|
+
var BASE_PATH_SEGMENT = "/open_api/v1.3";
|
|
390
|
+
var BASE_URL3 = `${BASE_HOST}${BASE_PATH_SEGMENT}`;
|
|
379
391
|
var REQUEST_TIMEOUT_MS2 = 6e4;
|
|
380
392
|
var cachedToken2 = null;
|
|
381
393
|
async function getProxyToken2(config) {
|
|
@@ -451,7 +463,8 @@ The advertiser_id is automatically injected if configured.`,
|
|
|
451
463
|
);
|
|
452
464
|
try {
|
|
453
465
|
const advertiserId = parameters.advertiserId.tryGetValue(connection2) ?? "";
|
|
454
|
-
|
|
466
|
+
const normalizedPath = normalizeRequestPath(path2, BASE_PATH_SEGMENT);
|
|
467
|
+
let url = `${BASE_URL3}${normalizedPath}`;
|
|
455
468
|
if (method === "GET") {
|
|
456
469
|
const params = new URLSearchParams(queryParams ?? {});
|
|
457
470
|
if (advertiserId && !params.has("advertiser_id")) {
|