@squadbase/vite-server 0.1.5-dev.0 → 0.1.5-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +411 -236
- package/dist/connectors/airtable-oauth.js +0 -8
- package/dist/connectors/gmail-oauth.js +0 -8
- package/dist/connectors/gmail.js +0 -8
- package/dist/connectors/google-ads.js +0 -8
- package/dist/connectors/google-analytics-oauth.js +0 -8
- package/dist/connectors/google-calendar-oauth.js +0 -8
- package/dist/connectors/google-calendar.js +0 -10
- package/dist/connectors/hubspot-oauth.js +0 -6
- package/dist/connectors/influxdb.d.ts +5 -0
- package/dist/connectors/influxdb.js +767 -0
- package/dist/connectors/intercom-oauth.js +0 -6
- package/dist/connectors/linear.d.ts +5 -0
- package/dist/connectors/linear.js +688 -0
- package/dist/connectors/linkedin-ads.js +0 -8
- package/dist/connectors/meta-ads-oauth.d.ts +5 -0
- package/dist/connectors/meta-ads-oauth.js +795 -0
- package/dist/connectors/meta-ads.d.ts +5 -0
- package/dist/connectors/meta-ads.js +780 -0
- package/dist/connectors/notion-oauth.js +0 -6
- package/dist/connectors/shopify-oauth.js +0 -6
- package/dist/connectors/stripe-api-key.js +0 -4
- package/dist/connectors/stripe-oauth.js +0 -6
- package/dist/connectors/tiktok-ads.d.ts +5 -0
- package/dist/connectors/tiktok-ads.js +840 -0
- package/dist/connectors/zendesk-oauth.js +0 -6
- package/dist/index.js +411 -236
- package/dist/main.js +411 -236
- package/dist/vite-plugin.js +411 -236
- package/package.json +21 -1
|
@@ -0,0 +1,767 @@
|
|
|
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/influxdb/parameters.ts
|
|
46
|
+
var parameters = {
|
|
47
|
+
url: new ParameterDefinition({
|
|
48
|
+
slug: "url",
|
|
49
|
+
name: "InfluxDB URL",
|
|
50
|
+
description: "The base URL of your InfluxDB instance (e.g., 'https://us-east-1-1.aws.cloud2.influxdata.com' for InfluxDB Cloud). Do not include a trailing slash.",
|
|
51
|
+
envVarBaseKey: "INFLUXDB_URL",
|
|
52
|
+
type: "text",
|
|
53
|
+
secret: false,
|
|
54
|
+
required: true
|
|
55
|
+
}),
|
|
56
|
+
token: new ParameterDefinition({
|
|
57
|
+
slug: "token",
|
|
58
|
+
name: "API Token",
|
|
59
|
+
description: "The API token used to authenticate against your InfluxDB instance. Generate one from the InfluxDB UI (Load Data \u2192 API Tokens).",
|
|
60
|
+
envVarBaseKey: "INFLUXDB_TOKEN",
|
|
61
|
+
type: "text",
|
|
62
|
+
secret: true,
|
|
63
|
+
required: true
|
|
64
|
+
}),
|
|
65
|
+
database: new ParameterDefinition({
|
|
66
|
+
slug: "database",
|
|
67
|
+
name: "Database",
|
|
68
|
+
description: "The default database to query. For InfluxDB 3 this is the database name; for InfluxDB 2 use the bucket name.",
|
|
69
|
+
envVarBaseKey: "INFLUXDB_DATABASE",
|
|
70
|
+
type: "text",
|
|
71
|
+
secret: false,
|
|
72
|
+
required: true
|
|
73
|
+
}),
|
|
74
|
+
org: new ParameterDefinition({
|
|
75
|
+
slug: "org",
|
|
76
|
+
name: "Organization",
|
|
77
|
+
description: "The InfluxDB organization name. Required for InfluxDB 2.x Flux queries and writes; optional for InfluxDB 3.",
|
|
78
|
+
envVarBaseKey: "INFLUXDB_ORG",
|
|
79
|
+
type: "text",
|
|
80
|
+
secret: false,
|
|
81
|
+
required: false
|
|
82
|
+
})
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// ../connectors/src/connectors/influxdb/sdk/index.ts
|
|
86
|
+
function createClient(params) {
|
|
87
|
+
const url = (params[parameters.url.slug] ?? "").replace(/\/$/, "");
|
|
88
|
+
const token = params[parameters.token.slug];
|
|
89
|
+
const database = params[parameters.database.slug];
|
|
90
|
+
const org = params[parameters.org.slug];
|
|
91
|
+
if (!url) {
|
|
92
|
+
throw new Error(
|
|
93
|
+
`influxdb: missing required parameter: ${parameters.url.slug}`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
if (!token) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
`influxdb: missing required parameter: ${parameters.token.slug}`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
if (!database) {
|
|
102
|
+
throw new Error(
|
|
103
|
+
`influxdb: missing required parameter: ${parameters.database.slug}`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
function authHeaders(extra) {
|
|
107
|
+
const headers = new Headers(extra);
|
|
108
|
+
headers.set("Authorization", `Token ${token}`);
|
|
109
|
+
if (!headers.has("Accept")) headers.set("Accept", "application/json");
|
|
110
|
+
return headers;
|
|
111
|
+
}
|
|
112
|
+
async function assertOk(res, label) {
|
|
113
|
+
if (!res.ok) {
|
|
114
|
+
const body = await res.text().catch(() => "(unreadable body)");
|
|
115
|
+
throw new Error(
|
|
116
|
+
`influxdb ${label}: ${res.status} ${res.statusText} \u2014 ${body}`
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
database,
|
|
122
|
+
org,
|
|
123
|
+
request(path2, init) {
|
|
124
|
+
const fullUrl = `${url}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
125
|
+
const headers = new Headers(init?.headers);
|
|
126
|
+
headers.set("Authorization", `Token ${token}`);
|
|
127
|
+
if (!headers.has("Accept")) headers.set("Accept", "application/json");
|
|
128
|
+
return fetch(fullUrl, { ...init, headers });
|
|
129
|
+
},
|
|
130
|
+
async querySql(sql, options) {
|
|
131
|
+
const res = await fetch(`${url}/api/v3/query_sql`, {
|
|
132
|
+
method: "POST",
|
|
133
|
+
headers: authHeaders({ "Content-Type": "application/json" }),
|
|
134
|
+
body: JSON.stringify({
|
|
135
|
+
db: options?.database ?? database,
|
|
136
|
+
q: sql
|
|
137
|
+
})
|
|
138
|
+
});
|
|
139
|
+
await assertOk(res, "querySql");
|
|
140
|
+
return await res.json();
|
|
141
|
+
},
|
|
142
|
+
async queryInfluxql(influxql, options) {
|
|
143
|
+
const res = await fetch(`${url}/api/v3/query_influxql`, {
|
|
144
|
+
method: "POST",
|
|
145
|
+
headers: authHeaders({ "Content-Type": "application/json" }),
|
|
146
|
+
body: JSON.stringify({
|
|
147
|
+
db: options?.database ?? database,
|
|
148
|
+
q: influxql
|
|
149
|
+
})
|
|
150
|
+
});
|
|
151
|
+
await assertOk(res, "queryInfluxql");
|
|
152
|
+
return await res.json();
|
|
153
|
+
},
|
|
154
|
+
async queryFlux(flux, options) {
|
|
155
|
+
const resolvedOrg = options?.org ?? org;
|
|
156
|
+
if (!resolvedOrg) {
|
|
157
|
+
throw new Error(
|
|
158
|
+
`influxdb queryFlux: 'org' parameter is required for Flux queries but was not configured`
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
const res = await fetch(
|
|
162
|
+
`${url}/api/v2/query?org=${encodeURIComponent(resolvedOrg)}`,
|
|
163
|
+
{
|
|
164
|
+
method: "POST",
|
|
165
|
+
headers: authHeaders({
|
|
166
|
+
"Content-Type": "application/vnd.flux",
|
|
167
|
+
Accept: "application/csv"
|
|
168
|
+
}),
|
|
169
|
+
body: flux
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
await assertOk(res, "queryFlux");
|
|
173
|
+
return await res.text();
|
|
174
|
+
},
|
|
175
|
+
async writeLineProtocol(lineProtocol, options) {
|
|
176
|
+
const resolvedDatabase = options?.database ?? database;
|
|
177
|
+
const resolvedOrg = options?.org ?? org;
|
|
178
|
+
const precision = options?.precision ?? "ns";
|
|
179
|
+
const endpoint = resolvedOrg ? `${url}/api/v2/write?org=${encodeURIComponent(resolvedOrg)}&bucket=${encodeURIComponent(resolvedDatabase)}&precision=${precision}` : `${url}/api/v3/write_lp?db=${encodeURIComponent(resolvedDatabase)}&precision=${precision}`;
|
|
180
|
+
const res = await fetch(endpoint, {
|
|
181
|
+
method: "POST",
|
|
182
|
+
headers: authHeaders({ "Content-Type": "text/plain; charset=utf-8" }),
|
|
183
|
+
body: lineProtocol
|
|
184
|
+
});
|
|
185
|
+
await assertOk(res, "writeLineProtocol");
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ../connectors/src/connector-onboarding.ts
|
|
191
|
+
var ConnectorOnboarding = class {
|
|
192
|
+
/** Phase 1: Connection setup instructions (optional — some connectors don't need this) */
|
|
193
|
+
connectionSetupInstructions;
|
|
194
|
+
/** Phase 2: Data overview instructions */
|
|
195
|
+
dataOverviewInstructions;
|
|
196
|
+
constructor(config) {
|
|
197
|
+
this.connectionSetupInstructions = config.connectionSetupInstructions;
|
|
198
|
+
this.dataOverviewInstructions = config.dataOverviewInstructions;
|
|
199
|
+
}
|
|
200
|
+
getConnectionSetupPrompt(language) {
|
|
201
|
+
return this.connectionSetupInstructions?.[language] ?? null;
|
|
202
|
+
}
|
|
203
|
+
getDataOverviewInstructions(language) {
|
|
204
|
+
return this.dataOverviewInstructions[language];
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// ../connectors/src/connector-tool.ts
|
|
209
|
+
var ConnectorTool = class {
|
|
210
|
+
name;
|
|
211
|
+
description;
|
|
212
|
+
inputSchema;
|
|
213
|
+
outputSchema;
|
|
214
|
+
_execute;
|
|
215
|
+
constructor(config) {
|
|
216
|
+
this.name = config.name;
|
|
217
|
+
this.description = config.description;
|
|
218
|
+
this.inputSchema = config.inputSchema;
|
|
219
|
+
this.outputSchema = config.outputSchema;
|
|
220
|
+
this._execute = config.execute;
|
|
221
|
+
}
|
|
222
|
+
createTool(connections, config) {
|
|
223
|
+
return {
|
|
224
|
+
description: this.description,
|
|
225
|
+
inputSchema: this.inputSchema,
|
|
226
|
+
outputSchema: this.outputSchema,
|
|
227
|
+
execute: (input) => this._execute(input, connections, config)
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// ../connectors/src/connector-plugin.ts
|
|
233
|
+
var ConnectorPlugin = class _ConnectorPlugin {
|
|
234
|
+
slug;
|
|
235
|
+
authType;
|
|
236
|
+
name;
|
|
237
|
+
description;
|
|
238
|
+
iconUrl;
|
|
239
|
+
parameters;
|
|
240
|
+
releaseFlag;
|
|
241
|
+
proxyPolicy;
|
|
242
|
+
experimentalAttributes;
|
|
243
|
+
onboarding;
|
|
244
|
+
systemPrompt;
|
|
245
|
+
tools;
|
|
246
|
+
query;
|
|
247
|
+
checkConnection;
|
|
248
|
+
constructor(config) {
|
|
249
|
+
this.slug = config.slug;
|
|
250
|
+
this.authType = config.authType;
|
|
251
|
+
this.name = config.name;
|
|
252
|
+
this.description = config.description;
|
|
253
|
+
this.iconUrl = config.iconUrl;
|
|
254
|
+
this.parameters = config.parameters;
|
|
255
|
+
this.releaseFlag = config.releaseFlag;
|
|
256
|
+
this.proxyPolicy = config.proxyPolicy;
|
|
257
|
+
this.experimentalAttributes = config.experimentalAttributes;
|
|
258
|
+
this.onboarding = config.onboarding;
|
|
259
|
+
this.systemPrompt = config.systemPrompt;
|
|
260
|
+
this.tools = config.tools;
|
|
261
|
+
this.query = config.query;
|
|
262
|
+
this.checkConnection = config.checkConnection;
|
|
263
|
+
}
|
|
264
|
+
get connectorKey() {
|
|
265
|
+
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Create tools for connections that belong to this connector.
|
|
269
|
+
* Filters connections by connectorKey internally.
|
|
270
|
+
* Returns tools keyed as `${connectorKey}_${toolName}`.
|
|
271
|
+
*/
|
|
272
|
+
createTools(connections, config, opts) {
|
|
273
|
+
const myConnections = connections.filter(
|
|
274
|
+
(c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
|
|
275
|
+
);
|
|
276
|
+
const result = {};
|
|
277
|
+
for (const t of Object.values(this.tools)) {
|
|
278
|
+
const tool = t.createTool(myConnections, config);
|
|
279
|
+
const originalToModelOutput = tool.toModelOutput;
|
|
280
|
+
result[`${this.connectorKey}_${t.name}`] = {
|
|
281
|
+
...tool,
|
|
282
|
+
toModelOutput: async (options) => {
|
|
283
|
+
if (!originalToModelOutput) {
|
|
284
|
+
return opts.truncateOutput(options.output);
|
|
285
|
+
}
|
|
286
|
+
const modelOutput = await originalToModelOutput(options);
|
|
287
|
+
if (modelOutput.type === "text" || modelOutput.type === "json") {
|
|
288
|
+
return opts.truncateOutput(modelOutput.value);
|
|
289
|
+
}
|
|
290
|
+
return modelOutput;
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
return result;
|
|
295
|
+
}
|
|
296
|
+
static deriveKey(slug, authType) {
|
|
297
|
+
if (authType) return `${slug}-${authType}`;
|
|
298
|
+
const LEGACY_NULL_AUTH_TYPE_MAP = {
|
|
299
|
+
// user-password
|
|
300
|
+
"postgresql": "user-password",
|
|
301
|
+
"mysql": "user-password",
|
|
302
|
+
"clickhouse": "user-password",
|
|
303
|
+
"kintone": "user-password",
|
|
304
|
+
"squadbase-db": "user-password",
|
|
305
|
+
// service-account
|
|
306
|
+
"snowflake": "service-account",
|
|
307
|
+
"bigquery": "service-account",
|
|
308
|
+
"google-analytics": "service-account",
|
|
309
|
+
"google-calendar": "service-account",
|
|
310
|
+
"aws-athena": "service-account",
|
|
311
|
+
"redshift": "service-account",
|
|
312
|
+
// api-key
|
|
313
|
+
"databricks": "api-key",
|
|
314
|
+
"dbt": "api-key",
|
|
315
|
+
"airtable": "api-key",
|
|
316
|
+
"openai": "api-key",
|
|
317
|
+
"gemini": "api-key",
|
|
318
|
+
"anthropic": "api-key",
|
|
319
|
+
"wix-store": "api-key"
|
|
320
|
+
};
|
|
321
|
+
const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
|
|
322
|
+
if (fallbackAuthType) return `${slug}-${fallbackAuthType}`;
|
|
323
|
+
return slug;
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
// ../connectors/src/auth-types.ts
|
|
328
|
+
var AUTH_TYPES = {
|
|
329
|
+
OAUTH: "oauth",
|
|
330
|
+
API_KEY: "api-key",
|
|
331
|
+
JWT: "jwt",
|
|
332
|
+
SERVICE_ACCOUNT: "service-account",
|
|
333
|
+
PAT: "pat",
|
|
334
|
+
USER_PASSWORD: "user-password"
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
// ../connectors/src/connectors/influxdb/setup.ts
|
|
338
|
+
var influxdbOnboarding = new ConnectorOnboarding({
|
|
339
|
+
connectionSetupInstructions: {
|
|
340
|
+
en: `#### Generate an API Token
|
|
341
|
+
1. Sign in to your InfluxDB Cloud / OSS instance
|
|
342
|
+
2. Go to Load Data \u2192 API Tokens \u2192 Generate API Token
|
|
343
|
+
3. Create an All-Access or Custom token with at least read permission on your target database/bucket
|
|
344
|
+
4. Copy the token into the API Token parameter
|
|
345
|
+
|
|
346
|
+
#### Confirm the Database (or Bucket) Name
|
|
347
|
+
- InfluxDB 3: use the database name
|
|
348
|
+
- InfluxDB 2: use the bucket name (buckets act as databases in the v1/v3 compatibility endpoints)
|
|
349
|
+
|
|
350
|
+
#### Organization (InfluxDB 2 only)
|
|
351
|
+
- If you are on InfluxDB 2, set the Organization parameter to the org that owns the bucket
|
|
352
|
+
- For InfluxDB 3 Cloud you can leave Organization blank`,
|
|
353
|
+
ja: `#### API \u30C8\u30FC\u30AF\u30F3\u306E\u767A\u884C
|
|
354
|
+
1. InfluxDB Cloud / OSS \u306B\u30B5\u30A4\u30F3\u30A4\u30F3
|
|
355
|
+
2. Load Data \u2192 API Tokens \u2192 Generate API Token
|
|
356
|
+
3. \u5BFE\u8C61\u306E database / bucket \u306B\u5BFE\u3057\u3066\u6700\u4F4E\u9650 read \u6A29\u9650\u3092\u6301\u3064 All-Access \u307E\u305F\u306F Custom \u30C8\u30FC\u30AF\u30F3\u3092\u4F5C\u6210
|
|
357
|
+
4. \u767A\u884C\u3057\u305F\u30C8\u30FC\u30AF\u30F3\u3092 API Token \u30D1\u30E9\u30E1\u30FC\u30BF\u306B\u8CBC\u308A\u4ED8\u3051
|
|
358
|
+
|
|
359
|
+
#### Database (\u307E\u305F\u306F Bucket) \u540D\u306E\u78BA\u8A8D
|
|
360
|
+
- InfluxDB 3: database \u540D\u3092\u4F7F\u7528
|
|
361
|
+
- InfluxDB 2: bucket \u540D\u3092\u4F7F\u7528\uFF08v1/v3 \u4E92\u63DB\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3067\u306F bucket \u304C database \u3068\u3057\u3066\u6271\u308F\u308C\u308B\uFF09
|
|
362
|
+
|
|
363
|
+
#### Organization\uFF08InfluxDB 2 \u306E\u307F\uFF09
|
|
364
|
+
- InfluxDB 2 \u306E\u5834\u5408\u3001bucket \u3092\u4FDD\u6709\u3059\u308B\u7D44\u7E54\u540D\u3092 Organization \u30D1\u30E9\u30E1\u30FC\u30BF\u306B\u8A2D\u5B9A
|
|
365
|
+
- InfluxDB 3 Cloud \u306E\u5834\u5408\u306F\u7A7A\u306E\u307E\u307E\u3067\u554F\u984C\u306A\u3044`
|
|
366
|
+
},
|
|
367
|
+
dataOverviewInstructions: {
|
|
368
|
+
en: `1. For InfluxDB 3: call influxdb_request with POST /api/v3/query_sql, body { "db": "<database>", "q": "SHOW TABLES" } to list measurements
|
|
369
|
+
2. For InfluxDB 3: inspect a sample measurement with POST /api/v3/query_sql, body { "db": "<database>", "q": "SELECT * FROM <measurement> ORDER BY time DESC LIMIT 5" }
|
|
370
|
+
3. For InfluxDB 2: call influxdb_request with POST /api/v2/query?org=<org>, contentType 'application/vnd.flux', body 'buckets()' to list buckets, then 'from(bucket:"<bucket>") |> range(start: -1h) |> limit(n:5)' to inspect data`,
|
|
371
|
+
ja: `1. InfluxDB 3 \u306E\u5834\u5408: influxdb_request \u3067 POST /api/v3/query_sql\u3001body { "db": "<database>", "q": "SHOW TABLES" } \u3092\u5B9F\u884C\u3057 measurement \u4E00\u89A7\u3092\u53D6\u5F97
|
|
372
|
+
2. InfluxDB 3 \u306E\u5834\u5408: POST /api/v3/query_sql\u3001body { "db": "<database>", "q": "SELECT * FROM <measurement> ORDER BY time DESC LIMIT 5" } \u3067\u4EE3\u8868\u7684\u306A measurement \u306E\u69CB\u9020\u3092\u78BA\u8A8D
|
|
373
|
+
3. InfluxDB 2 \u306E\u5834\u5408: POST /api/v2/query?org=<org>\u3001contentType 'application/vnd.flux'\u3001body 'buckets()' \u3067 bucket \u4E00\u89A7\u3092\u53D6\u5F97\u3057\u3001\u7D9A\u3044\u3066 'from(bucket:"<bucket>") |> range(start: -1h) |> limit(n:5)' \u3067\u30C7\u30FC\u30BF\u3092\u78BA\u8A8D`
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
// ../connectors/src/connectors/influxdb/tools/request.ts
|
|
378
|
+
import { z } from "zod";
|
|
379
|
+
var REQUEST_TIMEOUT_MS = 6e4;
|
|
380
|
+
var inputSchema = z.object({
|
|
381
|
+
toolUseIntent: z.string().optional().describe(
|
|
382
|
+
"Brief description of what you intend to accomplish with this tool call"
|
|
383
|
+
),
|
|
384
|
+
connectionId: z.string().describe("ID of the InfluxDB connection to use"),
|
|
385
|
+
method: z.enum(["GET", "POST", "DELETE"]).describe(
|
|
386
|
+
"HTTP method. POST for SQL/InfluxQL/Flux queries and writes, GET for metadata endpoints, DELETE for delete endpoints."
|
|
387
|
+
),
|
|
388
|
+
path: z.string().describe(
|
|
389
|
+
"API path appended to the InfluxDB base URL. Use '/api/v3/query_sql' for InfluxDB 3 SQL, '/api/v3/query_influxql' for InfluxDB 3 InfluxQL, '/api/v2/query?org={org}' for InfluxDB 2 Flux, '/api/v2/write?org={org}&bucket={bucket}' for writes."
|
|
390
|
+
),
|
|
391
|
+
body: z.union([z.record(z.string(), z.unknown()), z.string()]).optional().describe(
|
|
392
|
+
"Request body. JSON object for query endpoints ({ db, q } for InfluxDB 3 SQL; { query, type } for v2 query); raw string for Flux queries and line-protocol writes."
|
|
393
|
+
),
|
|
394
|
+
contentType: z.string().optional().describe(
|
|
395
|
+
"Content-Type header override. Use 'application/vnd.flux' for Flux queries and 'text/plain; charset=utf-8' for line-protocol writes. Defaults to 'application/json'."
|
|
396
|
+
)
|
|
397
|
+
});
|
|
398
|
+
var outputSchema = z.discriminatedUnion("success", [
|
|
399
|
+
z.object({
|
|
400
|
+
success: z.literal(true),
|
|
401
|
+
status: z.number(),
|
|
402
|
+
data: z.unknown()
|
|
403
|
+
}),
|
|
404
|
+
z.object({
|
|
405
|
+
success: z.literal(false),
|
|
406
|
+
error: z.string()
|
|
407
|
+
})
|
|
408
|
+
]);
|
|
409
|
+
var requestTool = new ConnectorTool({
|
|
410
|
+
name: "request",
|
|
411
|
+
description: `Send authenticated requests to the InfluxDB HTTP API.
|
|
412
|
+
Authentication is handled automatically using the API token (\`Authorization: Token {token}\`). The instance URL is resolved from the connection.
|
|
413
|
+
Use this tool for all InfluxDB interactions: running SQL / InfluxQL / Flux queries, writing line protocol, and managing buckets / databases.
|
|
414
|
+
For read-only data exploration prefer SQL (InfluxDB 3) or InfluxQL queries \u2014 they return JSON that is straightforward to parse. Flux queries return annotated CSV.`,
|
|
415
|
+
inputSchema,
|
|
416
|
+
outputSchema,
|
|
417
|
+
async execute({ connectionId, method, path: path2, body, contentType }, connections) {
|
|
418
|
+
const connection2 = connections.find((c) => c.id === connectionId);
|
|
419
|
+
if (!connection2) {
|
|
420
|
+
return {
|
|
421
|
+
success: false,
|
|
422
|
+
error: `Connection ${connectionId} not found`
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
console.log(
|
|
426
|
+
`[connector-request] influxdb/${connection2.name}: ${method} ${path2}`
|
|
427
|
+
);
|
|
428
|
+
try {
|
|
429
|
+
const url = parameters.url.getValue(connection2).replace(/\/$/, "");
|
|
430
|
+
const token = parameters.token.getValue(connection2);
|
|
431
|
+
const fullUrl = `${url}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
432
|
+
const controller = new AbortController();
|
|
433
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
434
|
+
const resolvedContentType = contentType ?? (typeof body === "string" ? "text/plain; charset=utf-8" : "application/json");
|
|
435
|
+
const serializedBody = body === void 0 ? void 0 : typeof body === "string" ? body : JSON.stringify(body);
|
|
436
|
+
try {
|
|
437
|
+
const response = await fetch(fullUrl, {
|
|
438
|
+
method,
|
|
439
|
+
headers: {
|
|
440
|
+
Authorization: `Token ${token}`,
|
|
441
|
+
"Content-Type": resolvedContentType,
|
|
442
|
+
Accept: "application/json"
|
|
443
|
+
},
|
|
444
|
+
body: serializedBody,
|
|
445
|
+
signal: controller.signal
|
|
446
|
+
});
|
|
447
|
+
const text = await response.text();
|
|
448
|
+
let data;
|
|
449
|
+
const resContentType = response.headers.get("content-type") ?? "";
|
|
450
|
+
if (resContentType.includes("application/json")) {
|
|
451
|
+
try {
|
|
452
|
+
data = text ? JSON.parse(text) : null;
|
|
453
|
+
} catch {
|
|
454
|
+
data = { raw: text };
|
|
455
|
+
}
|
|
456
|
+
} else {
|
|
457
|
+
data = text;
|
|
458
|
+
}
|
|
459
|
+
if (!response.ok) {
|
|
460
|
+
let errorMessage = `HTTP ${response.status} ${response.statusText}`;
|
|
461
|
+
if (data && typeof data === "object" && !Array.isArray(data) && typeof data.message === "string") {
|
|
462
|
+
errorMessage = data.message;
|
|
463
|
+
} else if (typeof data === "string" && data) {
|
|
464
|
+
errorMessage = data;
|
|
465
|
+
}
|
|
466
|
+
return { success: false, error: errorMessage };
|
|
467
|
+
}
|
|
468
|
+
return { success: true, status: response.status, data };
|
|
469
|
+
} finally {
|
|
470
|
+
clearTimeout(timeout);
|
|
471
|
+
}
|
|
472
|
+
} catch (err) {
|
|
473
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
474
|
+
return { success: false, error: msg };
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
// ../connectors/src/connectors/influxdb/index.ts
|
|
480
|
+
var tools = { request: requestTool };
|
|
481
|
+
var influxdbConnector = new ConnectorPlugin({
|
|
482
|
+
slug: "influxdb",
|
|
483
|
+
authType: AUTH_TYPES.API_KEY,
|
|
484
|
+
name: "InfluxDB",
|
|
485
|
+
description: "Connect to InfluxDB (Cloud or OSS) to query time-series data with SQL, InfluxQL, or Flux and to write line protocol.",
|
|
486
|
+
iconUrl: "https://upload.wikimedia.org/wikipedia/commons/b/b2/Influxdb_logo.svg",
|
|
487
|
+
parameters,
|
|
488
|
+
releaseFlag: { dev1: true, dev2: false, prod: false },
|
|
489
|
+
onboarding: influxdbOnboarding,
|
|
490
|
+
systemPrompt: {
|
|
491
|
+
en: `### Tools
|
|
492
|
+
|
|
493
|
+
- \`influxdb_request\`: The only way to call the InfluxDB HTTP API. Use it to run SQL / InfluxQL / Flux queries, write line protocol, and inspect buckets / databases. Authentication (\`Authorization: Token {token}\`) and the instance URL are configured automatically. For InfluxDB 3 prefer SQL (\`POST /api/v3/query_sql\`) \u2014 it returns JSON rows that are directly usable. For InfluxDB 2 use Flux (\`POST /api/v2/query?org={org}\`) \u2014 the response is annotated CSV. Writes use \`POST /api/v3/write_lp?db={db}\` (v3) or \`POST /api/v2/write?org={org}&bucket={bucket}\` (v2) with a line-protocol body and \`contentType\` set to \`text/plain; charset=utf-8\`.
|
|
494
|
+
|
|
495
|
+
### Business Logic
|
|
496
|
+
|
|
497
|
+
The business logic type for this connector is "typescript". Use the connector SDK in your handler. Do NOT read credentials from environment variables.
|
|
498
|
+
|
|
499
|
+
SDK methods (client created via \`connection(connectionId)\`):
|
|
500
|
+
- \`client.request(path, init?)\` \u2014 low-level authenticated fetch against the InfluxDB base URL
|
|
501
|
+
- \`client.querySql<T>(sql, options?)\` \u2014 InfluxDB 3 SQL query; returns an array of row objects, defaults \`db\` to the configured database
|
|
502
|
+
- \`client.queryInfluxql<T>(influxql, options?)\` \u2014 InfluxDB 3 InfluxQL query; same shape as \`querySql\`
|
|
503
|
+
- \`client.queryFlux(flux, options?)\` \u2014 InfluxDB 2 Flux query; returns raw annotated CSV (parse as needed)
|
|
504
|
+
- \`client.writeLineProtocol(lineProtocol, options?)\` \u2014 append-only write; uses v3 or v2 endpoint depending on whether \`org\` is configured
|
|
505
|
+
- \`client.database\` / \`client.org\` \u2014 connection-level defaults
|
|
506
|
+
|
|
507
|
+
\`\`\`ts
|
|
508
|
+
import type { Context } from "hono";
|
|
509
|
+
import { connection } from "@squadbase/vite-server/connectors/influxdb";
|
|
510
|
+
|
|
511
|
+
const influx = connection("<connectionId>");
|
|
512
|
+
|
|
513
|
+
export default async function handler(c: Context) {
|
|
514
|
+
const { measurement = "cpu", limit = 60 } = await c.req.json<{
|
|
515
|
+
measurement?: string;
|
|
516
|
+
limit?: number;
|
|
517
|
+
}>();
|
|
518
|
+
|
|
519
|
+
const rows = await influx.querySql<{
|
|
520
|
+
time: string;
|
|
521
|
+
usage_user: number;
|
|
522
|
+
host: string;
|
|
523
|
+
}>(
|
|
524
|
+
\`SELECT time, usage_user, host FROM \${measurement} ORDER BY time DESC LIMIT \${limit}\`,
|
|
525
|
+
);
|
|
526
|
+
|
|
527
|
+
return c.json({ series: rows });
|
|
528
|
+
}
|
|
529
|
+
\`\`\`
|
|
530
|
+
|
|
531
|
+
### InfluxDB HTTP API Reference
|
|
532
|
+
|
|
533
|
+
- Base URL: the \`url\` parameter (e.g., \`https://us-east-1-1.aws.cloud2.influxdata.com\`)
|
|
534
|
+
- Authentication: \`Authorization: Token {token}\` (handled automatically)
|
|
535
|
+
- Response content types: \`application/json\` for SQL/InfluxQL, annotated CSV for Flux
|
|
536
|
+
|
|
537
|
+
#### InfluxDB 3 Endpoints
|
|
538
|
+
- POST \`/api/v3/query_sql\` \u2014 Body: \`{ "db": "<database>", "q": "<sql>" }\` \u2192 JSON rows
|
|
539
|
+
- POST \`/api/v3/query_influxql\` \u2014 Body: \`{ "db": "<database>", "q": "<influxql>" }\` \u2192 JSON rows
|
|
540
|
+
- POST \`/api/v3/write_lp?db=<database>&precision=ns\` \u2014 Body: raw line protocol
|
|
541
|
+
- GET \`/api/v3/configure/database\` \u2014 List databases
|
|
542
|
+
|
|
543
|
+
#### InfluxDB 2 Endpoints
|
|
544
|
+
- POST \`/api/v2/query?org=<org>\` \u2014 Body: Flux script (Content-Type: \`application/vnd.flux\`) \u2192 annotated CSV
|
|
545
|
+
- POST \`/api/v2/write?org=<org>&bucket=<bucket>&precision=ns\` \u2014 Body: raw line protocol
|
|
546
|
+
- GET \`/api/v2/buckets?org=<org>\` \u2014 List buckets
|
|
547
|
+
- GET \`/api/v2/orgs\` \u2014 List organizations
|
|
548
|
+
|
|
549
|
+
#### SQL Reference (InfluxDB 3)
|
|
550
|
+
- \`SELECT field_list FROM measurement WHERE time >= now() - INTERVAL '1 hour' AND tag = 'x' ORDER BY time DESC LIMIT 100\`
|
|
551
|
+
- Time filtering uses standard SQL \`time\` column comparisons (\`time >= now() - INTERVAL '...' \`)
|
|
552
|
+
- Aggregates: \`AVG\`, \`SUM\`, \`MIN\`, \`MAX\`, \`COUNT\`; bucket time with \`date_bin('5 minutes', time)\`
|
|
553
|
+
- List measurements: \`SHOW TABLES\`; list columns: \`SHOW COLUMNS FROM <measurement>\``,
|
|
554
|
+
ja: `### \u30C4\u30FC\u30EB
|
|
555
|
+
|
|
556
|
+
- \`influxdb_request\`: InfluxDB HTTP API \u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002SQL / InfluxQL / Flux \u30AF\u30A8\u30EA\u306E\u5B9F\u884C\u3001line protocol \u66F8\u304D\u8FBC\u307F\u3001bucket / database \u306E\u78BA\u8A8D\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u8A8D\u8A3C\uFF08\`Authorization: Token {token}\`\uFF09\u3068 instance URL \u306F\u81EA\u52D5\u3067\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002InfluxDB 3 \u3067\u306F SQL (\`POST /api/v3/query_sql\`) \u304C JSON \u884C\u3092\u8FD4\u3059\u305F\u3081\u6700\u3082\u6271\u3044\u3084\u3059\u3044\u3067\u3059\u3002InfluxDB 2 \u3067\u306F Flux (\`POST /api/v2/query?org={org}\`) \u3092\u4F7F\u7528\u3057\u3001\u30EC\u30B9\u30DD\u30F3\u30B9\u306F\u6CE8\u91C8\u4ED8\u304D CSV \u3067\u3059\u3002\u66F8\u304D\u8FBC\u307F\u306F \`POST /api/v3/write_lp?db={db}\` (v3) \u307E\u305F\u306F \`POST /api/v2/write?org={org}&bucket={bucket}\` (v2) \u306B line protocol \u3092\u9001\u308A\u307E\u3059\uFF08\`contentType\` \u306F \`text/plain; charset=utf-8\`\uFF09\u3002
|
|
557
|
+
|
|
558
|
+
### Business Logic
|
|
559
|
+
|
|
560
|
+
\u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "typescript" \u3067\u3059\u3002\u30CF\u30F3\u30C9\u30E9\u5185\u3067\u306F\u30B3\u30CD\u30AF\u30BF SDK \u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u74B0\u5883\u5909\u6570\u304B\u3089\u8A8D\u8A3C\u60C5\u5831\u3092\u8AAD\u307F\u53D6\u3089\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
|
|
561
|
+
|
|
562
|
+
SDK\u30E1\u30BD\u30C3\u30C9 (\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8):
|
|
563
|
+
- \`client.request(path, init?)\` \u2014 InfluxDB \u30D9\u30FC\u30B9 URL \u306B\u5BFE\u3059\u308B\u4F4E\u30EC\u30D9\u30EB\u306E\u8A8D\u8A3C\u4ED8\u304D fetch
|
|
564
|
+
- \`client.querySql<T>(sql, options?)\` \u2014 InfluxDB 3 \u306E SQL \u30AF\u30A8\u30EA\u3002\u884C\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u306E\u914D\u5217\u3092\u8FD4\u5374\u3057\u3001\`db\` \u306F\u65E2\u5B9A\u3067\u63A5\u7D9A\u306E database
|
|
565
|
+
- \`client.queryInfluxql<T>(influxql, options?)\` \u2014 InfluxDB 3 \u306E InfluxQL \u30AF\u30A8\u30EA\uFF08\`querySql\` \u3068\u540C\u3058\u5F62\u5F0F\uFF09
|
|
566
|
+
- \`client.queryFlux(flux, options?)\` \u2014 InfluxDB 2 \u306E Flux \u30AF\u30A8\u30EA\u3002\u6CE8\u91C8\u4ED8\u304D CSV \u3092\u6587\u5B57\u5217\u3067\u8FD4\u5374\uFF08\u5FC5\u8981\u306B\u5FDC\u3058\u3066\u30D1\u30FC\u30B9\uFF09
|
|
567
|
+
- \`client.writeLineProtocol(lineProtocol, options?)\` \u2014 append-only \u66F8\u304D\u8FBC\u307F\u3002\`org\` \u306E\u6709\u7121\u3067 v3 / v2 \u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3092\u5207\u308A\u66FF\u3048
|
|
568
|
+
- \`client.database\` / \`client.org\` \u2014 \u63A5\u7D9A\u5358\u4F4D\u306E\u30C7\u30D5\u30A9\u30EB\u30C8\u5024
|
|
569
|
+
|
|
570
|
+
\`\`\`ts
|
|
571
|
+
import type { Context } from "hono";
|
|
572
|
+
import { connection } from "@squadbase/vite-server/connectors/influxdb";
|
|
573
|
+
|
|
574
|
+
const influx = connection("<connectionId>");
|
|
575
|
+
|
|
576
|
+
export default async function handler(c: Context) {
|
|
577
|
+
const { measurement = "cpu", limit = 60 } = await c.req.json<{
|
|
578
|
+
measurement?: string;
|
|
579
|
+
limit?: number;
|
|
580
|
+
}>();
|
|
581
|
+
|
|
582
|
+
const rows = await influx.querySql<{
|
|
583
|
+
time: string;
|
|
584
|
+
usage_user: number;
|
|
585
|
+
host: string;
|
|
586
|
+
}>(
|
|
587
|
+
\`SELECT time, usage_user, host FROM \${measurement} ORDER BY time DESC LIMIT \${limit}\`,
|
|
588
|
+
);
|
|
589
|
+
|
|
590
|
+
return c.json({ series: rows });
|
|
591
|
+
}
|
|
592
|
+
\`\`\`
|
|
593
|
+
|
|
594
|
+
### InfluxDB HTTP API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
|
|
595
|
+
|
|
596
|
+
- \u30D9\u30FC\u30B9 URL: \`url\` \u30D1\u30E9\u30E1\u30FC\u30BF\u3067\u6307\u5B9A\uFF08\u4F8B: \`https://us-east-1-1.aws.cloud2.influxdata.com\`\uFF09
|
|
597
|
+
- \u8A8D\u8A3C: \`Authorization: Token {token}\`\uFF08\u81EA\u52D5\u8A2D\u5B9A\uFF09
|
|
598
|
+
- \u30EC\u30B9\u30DD\u30F3\u30B9\u5F62\u5F0F: SQL/InfluxQL \u306F JSON\u3001Flux \u306F\u6CE8\u91C8\u4ED8\u304D CSV
|
|
599
|
+
|
|
600
|
+
#### InfluxDB 3 \u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
|
|
601
|
+
- POST \`/api/v3/query_sql\` \u2014 Body: \`{ "db": "<database>", "q": "<sql>" }\` \u2192 JSON \u884C
|
|
602
|
+
- POST \`/api/v3/query_influxql\` \u2014 Body: \`{ "db": "<database>", "q": "<influxql>" }\` \u2192 JSON \u884C
|
|
603
|
+
- POST \`/api/v3/write_lp?db=<database>&precision=ns\` \u2014 Body: line protocol \u751F\u6587\u5B57\u5217
|
|
604
|
+
- GET \`/api/v3/configure/database\` \u2014 database \u4E00\u89A7
|
|
605
|
+
|
|
606
|
+
#### InfluxDB 2 \u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
|
|
607
|
+
- POST \`/api/v2/query?org=<org>\` \u2014 Body: Flux \u30B9\u30AF\u30EA\u30D7\u30C8\uFF08Content-Type: \`application/vnd.flux\`\uFF09\u2192 \u6CE8\u91C8\u4ED8\u304D CSV
|
|
608
|
+
- POST \`/api/v2/write?org=<org>&bucket=<bucket>&precision=ns\` \u2014 Body: line protocol \u751F\u6587\u5B57\u5217
|
|
609
|
+
- GET \`/api/v2/buckets?org=<org>\` \u2014 bucket \u4E00\u89A7
|
|
610
|
+
- GET \`/api/v2/orgs\` \u2014 organization \u4E00\u89A7
|
|
611
|
+
|
|
612
|
+
#### SQL \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9 (InfluxDB 3)
|
|
613
|
+
- \`SELECT field_list FROM measurement WHERE time >= now() - INTERVAL '1 hour' AND tag = 'x' ORDER BY time DESC LIMIT 100\`
|
|
614
|
+
- \u6642\u523B\u30D5\u30A3\u30EB\u30BF\u306F\u6A19\u6E96 SQL \u306E \`time\` \u5217\u6BD4\u8F03\uFF08\`time >= now() - INTERVAL '...'\`\uFF09
|
|
615
|
+
- \u96C6\u8A08: \`AVG\`, \`SUM\`, \`MIN\`, \`MAX\`, \`COUNT\`\u3002\u6642\u9593\u30D0\u30B1\u30C3\u30C8: \`date_bin('5 minutes', time)\`
|
|
616
|
+
- measurement \u4E00\u89A7: \`SHOW TABLES\`\u3001\u5217\u4E00\u89A7: \`SHOW COLUMNS FROM <measurement>\``
|
|
617
|
+
},
|
|
618
|
+
tools
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
// src/connectors/create-connector-sdk.ts
|
|
622
|
+
import { readFileSync } from "fs";
|
|
623
|
+
import path from "path";
|
|
624
|
+
|
|
625
|
+
// src/connector-client/env.ts
|
|
626
|
+
function resolveEnvVar(entry, key, connectionId) {
|
|
627
|
+
const envVarName = entry.envVars[key];
|
|
628
|
+
if (!envVarName) {
|
|
629
|
+
throw new Error(`Connection "${connectionId}" is missing envVars mapping for key "${key}"`);
|
|
630
|
+
}
|
|
631
|
+
const value = process.env[envVarName];
|
|
632
|
+
if (!value) {
|
|
633
|
+
throw new Error(`Environment variable "${envVarName}" (for connection "${connectionId}", key "${key}") is not set`);
|
|
634
|
+
}
|
|
635
|
+
return value;
|
|
636
|
+
}
|
|
637
|
+
function resolveEnvVarOptional(entry, key) {
|
|
638
|
+
const envVarName = entry.envVars[key];
|
|
639
|
+
if (!envVarName) return void 0;
|
|
640
|
+
return process.env[envVarName] || void 0;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// src/connector-client/proxy-fetch.ts
|
|
644
|
+
import { getContext } from "hono/context-storage";
|
|
645
|
+
import { getCookie } from "hono/cookie";
|
|
646
|
+
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
647
|
+
function normalizeHeaders(input) {
|
|
648
|
+
const out = {};
|
|
649
|
+
if (!input) return out;
|
|
650
|
+
new Headers(input).forEach((value, key) => {
|
|
651
|
+
out[key] = value;
|
|
652
|
+
});
|
|
653
|
+
return out;
|
|
654
|
+
}
|
|
655
|
+
function createSandboxProxyFetch(connectionId) {
|
|
656
|
+
return async (input, init) => {
|
|
657
|
+
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
658
|
+
const sandboxId = process.env.INTERNAL_SQUADBASE_SANDBOX_ID;
|
|
659
|
+
if (!token || !sandboxId) {
|
|
660
|
+
throw new Error(
|
|
661
|
+
"Connection proxy is not configured. Please check your deployment settings."
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
665
|
+
const originalMethod = init?.method ?? "GET";
|
|
666
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
667
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
668
|
+
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
669
|
+
return fetch(proxyUrl, {
|
|
670
|
+
method: "POST",
|
|
671
|
+
headers: {
|
|
672
|
+
"Content-Type": "application/json",
|
|
673
|
+
Authorization: `Bearer ${token}`
|
|
674
|
+
},
|
|
675
|
+
body: JSON.stringify({
|
|
676
|
+
url: originalUrl,
|
|
677
|
+
method: originalMethod,
|
|
678
|
+
headers: normalizeHeaders(init?.headers),
|
|
679
|
+
body: originalBody
|
|
680
|
+
})
|
|
681
|
+
});
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
function createDeployedAppProxyFetch(connectionId) {
|
|
685
|
+
const projectId = process.env["SQUADBASE_PROJECT_ID"];
|
|
686
|
+
if (!projectId) {
|
|
687
|
+
throw new Error(
|
|
688
|
+
"Connection proxy is not configured. Please check your deployment settings."
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
692
|
+
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
693
|
+
return async (input, init) => {
|
|
694
|
+
const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
695
|
+
const originalMethod = init?.method ?? "GET";
|
|
696
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
697
|
+
const c = getContext();
|
|
698
|
+
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
699
|
+
if (!appSession) {
|
|
700
|
+
throw new Error(
|
|
701
|
+
"No authentication method available for connection proxy."
|
|
702
|
+
);
|
|
703
|
+
}
|
|
704
|
+
return fetch(proxyUrl, {
|
|
705
|
+
method: "POST",
|
|
706
|
+
headers: {
|
|
707
|
+
"Content-Type": "application/json",
|
|
708
|
+
Authorization: `Bearer ${appSession}`
|
|
709
|
+
},
|
|
710
|
+
body: JSON.stringify({
|
|
711
|
+
url: originalUrl,
|
|
712
|
+
method: originalMethod,
|
|
713
|
+
headers: normalizeHeaders(init?.headers),
|
|
714
|
+
body: originalBody
|
|
715
|
+
})
|
|
716
|
+
});
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
function createProxyFetch(connectionId) {
|
|
720
|
+
if (process.env.INTERNAL_SQUADBASE_SANDBOX_ID) {
|
|
721
|
+
return createSandboxProxyFetch(connectionId);
|
|
722
|
+
}
|
|
723
|
+
return createDeployedAppProxyFetch(connectionId);
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// src/connectors/create-connector-sdk.ts
|
|
727
|
+
function loadConnectionsSync() {
|
|
728
|
+
const filePath = process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), ".squadbase/connections.json");
|
|
729
|
+
try {
|
|
730
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
731
|
+
return JSON.parse(raw);
|
|
732
|
+
} catch {
|
|
733
|
+
return {};
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
function createConnectorSdk(plugin, createClient2) {
|
|
737
|
+
return (connectionId) => {
|
|
738
|
+
const connections = loadConnectionsSync();
|
|
739
|
+
const entry = connections[connectionId];
|
|
740
|
+
if (!entry) {
|
|
741
|
+
throw new Error(
|
|
742
|
+
`Connection "${connectionId}" not found in .squadbase/connections.json`
|
|
743
|
+
);
|
|
744
|
+
}
|
|
745
|
+
if (entry.connector.slug !== plugin.slug) {
|
|
746
|
+
throw new Error(
|
|
747
|
+
`Connection "${connectionId}" is not a ${plugin.slug} connection (got "${entry.connector.slug}")`
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
const params = {};
|
|
751
|
+
for (const param of Object.values(plugin.parameters)) {
|
|
752
|
+
if (param.required) {
|
|
753
|
+
params[param.slug] = resolveEnvVar(entry, param.slug, connectionId);
|
|
754
|
+
} else {
|
|
755
|
+
const val = resolveEnvVarOptional(entry, param.slug);
|
|
756
|
+
if (val !== void 0) params[param.slug] = val;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
return createClient2(params, createProxyFetch(connectionId));
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// src/connectors/entries/influxdb.ts
|
|
764
|
+
var connection = createConnectorSdk(influxdbConnector, createClient);
|
|
765
|
+
export {
|
|
766
|
+
connection
|
|
767
|
+
};
|