@squadbase/vite-server 0.1.12-dev.a9ac647 → 0.1.17-dev.3b633bb
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 +14375 -1652
- package/dist/connectors/airtable-oauth.js +282 -46
- package/dist/connectors/airtable.js +319 -51
- package/dist/connectors/amplitude.js +322 -47
- package/dist/connectors/anthropic.js +135 -47
- package/dist/connectors/asana.js +327 -49
- package/dist/connectors/attio.js +302 -49
- package/dist/connectors/aws-billing.js +287 -46
- package/dist/connectors/azure-sql.js +421 -102
- package/dist/connectors/backlog-api-key.js +317 -47
- package/dist/connectors/clickup.js +338 -49
- package/dist/connectors/cosmosdb.js +305 -50
- package/dist/connectors/customerio.js +319 -47
- package/dist/connectors/dbt.js +340 -47
- package/dist/connectors/freshdesk.js +342 -53
- package/dist/connectors/freshsales.js +333 -52
- package/dist/connectors/freshservice.js +361 -53
- package/dist/connectors/gamma.js +327 -52
- package/dist/connectors/gemini.js +134 -47
- package/dist/connectors/github.js +386 -49
- package/dist/connectors/gmail-oauth.js +204 -7
- package/dist/connectors/gmail.js +350 -47
- package/dist/connectors/google-ads.js +288 -46
- package/dist/connectors/google-analytics-oauth.js +310 -46
- package/dist/connectors/google-analytics.js +547 -87
- package/dist/connectors/google-audit-log.js +438 -47
- package/dist/connectors/google-calendar-oauth.js +259 -46
- package/dist/connectors/google-calendar.js +359 -47
- package/dist/connectors/google-docs.js +220 -6
- package/dist/connectors/google-drive.js +262 -5
- package/dist/connectors/google-search-console-oauth.js +256 -46
- package/dist/connectors/google-sheets.js +272 -47
- package/dist/connectors/google-slides.js +205 -6
- package/dist/connectors/grafana.js +332 -49
- package/dist/connectors/hubspot-oauth.js +208 -5
- package/dist/connectors/hubspot.js +306 -49
- package/dist/connectors/influxdb.js +416 -51
- package/dist/connectors/intercom-oauth.js +210 -5
- package/dist/connectors/intercom.js +302 -49
- package/dist/connectors/jdbc.js +762 -110
- package/dist/connectors/jira-api-key.js +326 -47
- package/dist/connectors/kintone-api-token.js +281 -47
- package/dist/connectors/kintone.js +328 -47
- package/dist/connectors/linear.js +330 -49
- package/dist/connectors/linkedin-ads.js +268 -50
- package/dist/connectors/mailchimp-oauth.js +268 -46
- package/dist/connectors/mailchimp.js +320 -49
- package/dist/connectors/meta-ads-oauth.js +273 -48
- package/dist/connectors/meta-ads.js +285 -50
- package/dist/connectors/mixpanel.js +338 -47
- package/dist/connectors/monday.js +360 -49
- package/dist/connectors/mongodb.js +319 -57
- package/dist/connectors/notion-oauth.js +231 -5
- package/dist/connectors/notion.js +323 -51
- package/dist/connectors/openai.js +134 -47
- package/dist/connectors/oracle.js +454 -103
- package/dist/connectors/outlook-oauth.js +204 -5
- package/dist/connectors/powerbi-oauth.js +498 -5
- package/dist/connectors/salesforce.js +384 -49
- package/dist/connectors/semrush.js +609 -49
- package/dist/connectors/sentry.js +289 -50
- package/dist/connectors/shopify-oauth.js +187 -5
- package/dist/connectors/shopify.js +357 -47
- package/dist/connectors/sqlserver.js +415 -102
- package/dist/connectors/stripe-api-key.js +269 -46
- package/dist/connectors/stripe-oauth.js +202 -5
- package/dist/connectors/supabase.js +303 -48
- package/dist/connectors/tableau.js +536 -163
- package/dist/connectors/tiktok-ads.js +279 -48
- package/dist/connectors/wix-store.js +320 -49
- package/dist/connectors/zendesk-oauth.js +239 -5
- package/dist/connectors/zendesk.js +358 -47
- package/dist/index.d.ts +149 -1
- package/dist/index.js +15057 -2117
- package/dist/main.js +15005 -2073
- package/dist/vite-plugin.js +14752 -2019
- package/package.json +1 -1
|
@@ -1,48 +1,60 @@
|
|
|
1
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
2
|
+
var __esm = (fn, res) => function __init() {
|
|
3
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
4
|
+
};
|
|
5
|
+
|
|
1
6
|
// ../connectors/src/parameter-definition.ts
|
|
2
|
-
var ParameterDefinition
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
7
|
+
var ParameterDefinition;
|
|
8
|
+
var init_parameter_definition = __esm({
|
|
9
|
+
"../connectors/src/parameter-definition.ts"() {
|
|
10
|
+
"use strict";
|
|
11
|
+
ParameterDefinition = class {
|
|
12
|
+
slug;
|
|
13
|
+
name;
|
|
14
|
+
description;
|
|
15
|
+
envVarBaseKey;
|
|
16
|
+
type;
|
|
17
|
+
secret;
|
|
18
|
+
required;
|
|
19
|
+
constructor(config) {
|
|
20
|
+
this.slug = config.slug;
|
|
21
|
+
this.name = config.name;
|
|
22
|
+
this.description = config.description;
|
|
23
|
+
this.envVarBaseKey = config.envVarBaseKey;
|
|
24
|
+
this.type = config.type;
|
|
25
|
+
this.secret = config.secret;
|
|
26
|
+
this.required = config.required;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get the parameter value from a ConnectorConnectionObject.
|
|
30
|
+
*/
|
|
31
|
+
getValue(connection2) {
|
|
32
|
+
const param = connection2.parameters.find(
|
|
33
|
+
(p) => p.parameterSlug === this.slug
|
|
34
|
+
);
|
|
35
|
+
if (!param || param.value == null) {
|
|
36
|
+
throw new Error(
|
|
37
|
+
`Parameter "${this.slug}" not found or has no value in connection "${connection2.id}"`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
return param.value;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Try to get the parameter value. Returns undefined if not found (for optional params).
|
|
44
|
+
*/
|
|
45
|
+
tryGetValue(connection2) {
|
|
46
|
+
const param = connection2.parameters.find(
|
|
47
|
+
(p) => p.parameterSlug === this.slug
|
|
48
|
+
);
|
|
49
|
+
if (!param || param.value == null) return void 0;
|
|
50
|
+
return param.value;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
42
53
|
}
|
|
43
|
-
};
|
|
54
|
+
});
|
|
44
55
|
|
|
45
56
|
// ../connectors/src/connectors/grafana/parameters.ts
|
|
57
|
+
init_parameter_definition();
|
|
46
58
|
var parameters = {
|
|
47
59
|
url: new ParameterDefinition({
|
|
48
60
|
slug: "url",
|
|
@@ -83,7 +95,7 @@ function createClient(params) {
|
|
|
83
95
|
headers.set("Accept", "application/json");
|
|
84
96
|
return fetch(url, { ...init, headers });
|
|
85
97
|
}
|
|
86
|
-
async function
|
|
98
|
+
async function listDatasources2() {
|
|
87
99
|
const response = await request("/api/datasources");
|
|
88
100
|
if (!response.ok) {
|
|
89
101
|
const body = await response.text();
|
|
@@ -155,7 +167,7 @@ function createClient(params) {
|
|
|
155
167
|
}
|
|
156
168
|
return {
|
|
157
169
|
request,
|
|
158
|
-
listDatasources,
|
|
170
|
+
listDatasources: listDatasources2,
|
|
159
171
|
getDatasource,
|
|
160
172
|
queryDatasource,
|
|
161
173
|
searchDashboards,
|
|
@@ -222,6 +234,28 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
222
234
|
tools;
|
|
223
235
|
query;
|
|
224
236
|
checkConnection;
|
|
237
|
+
/**
|
|
238
|
+
* SQPD-1212: Logic-based, rule-driven connection setup. Connectors that
|
|
239
|
+
* implement this expose a step-by-step exploration flow (database/schema/
|
|
240
|
+
* table/etc. discovery) that the dashboard backend drives via the
|
|
241
|
+
* `/connections/:connectionId/setup` endpoint. Implement by delegating to
|
|
242
|
+
* `runSetupFlow` from `setup-flow.ts`.
|
|
243
|
+
*/
|
|
244
|
+
setup;
|
|
245
|
+
/**
|
|
246
|
+
* Opt-out of the default "verify before save" behavior on connection
|
|
247
|
+
* creation. The backend invokes `checkConnection` synchronously while
|
|
248
|
+
* creating the connection and aborts (no row inserted) if it fails — this
|
|
249
|
+
* flag disables that for connectors where the check cannot succeed pre-save:
|
|
250
|
+
*
|
|
251
|
+
* - `squadbase-db` populates `connection-url` only after Neon provisioning
|
|
252
|
+
* - OAuth connectors require an OAuth-aware proxyFetch keyed by the
|
|
253
|
+
* connectionId, which doesn't exist until the row is saved
|
|
254
|
+
*
|
|
255
|
+
* Exceptions are the explicit position; new credential-input connectors get
|
|
256
|
+
* the default verify-on-create behavior without opt-in.
|
|
257
|
+
*/
|
|
258
|
+
skipConnectionCheckOnCreate;
|
|
225
259
|
constructor(config) {
|
|
226
260
|
this.slug = config.slug;
|
|
227
261
|
this.authType = config.authType;
|
|
@@ -238,6 +272,8 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
238
272
|
this.tools = config.tools;
|
|
239
273
|
this.query = config.query;
|
|
240
274
|
this.checkConnection = config.checkConnection;
|
|
275
|
+
this.setup = config.setup;
|
|
276
|
+
this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
|
|
241
277
|
}
|
|
242
278
|
get connectorKey() {
|
|
243
279
|
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
@@ -302,6 +338,76 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
302
338
|
}
|
|
303
339
|
};
|
|
304
340
|
|
|
341
|
+
// ../connectors/src/setup-flow.ts
|
|
342
|
+
async function runSetupFlow(flow, params, ctx, config) {
|
|
343
|
+
const runtime = {
|
|
344
|
+
params,
|
|
345
|
+
language: ctx.language,
|
|
346
|
+
config
|
|
347
|
+
};
|
|
348
|
+
let state = flow.initialState();
|
|
349
|
+
let answerIdx = 0;
|
|
350
|
+
const pendingParameterUpdates = [];
|
|
351
|
+
for (const step of flow.steps) {
|
|
352
|
+
const ans = ctx.answers[answerIdx];
|
|
353
|
+
if (ans && ans.questionSlug === step.slug) {
|
|
354
|
+
state = step.applyAnswer(state, ans.answer);
|
|
355
|
+
if (step.toParameterUpdates) {
|
|
356
|
+
pendingParameterUpdates.push(...step.toParameterUpdates(state));
|
|
357
|
+
}
|
|
358
|
+
answerIdx += 1;
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
|
|
362
|
+
if (step.type === "text") {
|
|
363
|
+
if (step.fetchOptions) {
|
|
364
|
+
const options2 = await step.fetchOptions(state, runtime);
|
|
365
|
+
if (options2.length === 0) {
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return {
|
|
370
|
+
type: "nextQuestion",
|
|
371
|
+
questionSlug: step.slug,
|
|
372
|
+
question: step.question[ctx.language],
|
|
373
|
+
questionType: "text",
|
|
374
|
+
allowFreeText: resolvedAllowFreeText,
|
|
375
|
+
...pendingParameterUpdates.length > 0 && {
|
|
376
|
+
parameterUpdates: pendingParameterUpdates
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
381
|
+
if (options.length === 0) {
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
return {
|
|
385
|
+
type: "nextQuestion",
|
|
386
|
+
questionSlug: step.slug,
|
|
387
|
+
question: step.question[ctx.language],
|
|
388
|
+
questionType: step.type,
|
|
389
|
+
options,
|
|
390
|
+
allowFreeText: resolvedAllowFreeText,
|
|
391
|
+
...pendingParameterUpdates.length > 0 && {
|
|
392
|
+
parameterUpdates: pendingParameterUpdates
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
397
|
+
return {
|
|
398
|
+
type: "fulfilled",
|
|
399
|
+
dataInvestigationResult,
|
|
400
|
+
...pendingParameterUpdates.length > 0 && {
|
|
401
|
+
parameterUpdates: pendingParameterUpdates
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
async function resolveSetupSelection(params) {
|
|
406
|
+
const { selected, allSentinel, fetchAll, limit } = params;
|
|
407
|
+
const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
|
|
408
|
+
return resolved.slice(0, limit);
|
|
409
|
+
}
|
|
410
|
+
|
|
305
411
|
// ../connectors/src/auth-types.ts
|
|
306
412
|
var AUTH_TYPES = {
|
|
307
413
|
OAUTH: "oauth",
|
|
@@ -324,6 +430,129 @@ var grafanaOnboarding = new ConnectorOnboarding({
|
|
|
324
430
|
}
|
|
325
431
|
});
|
|
326
432
|
|
|
433
|
+
// ../connectors/src/connectors/grafana/utils.ts
|
|
434
|
+
async function apiFetch(params, path2, init) {
|
|
435
|
+
const apiKey = params[parameters.apiKey.slug];
|
|
436
|
+
const rawUrl = params[parameters.url.slug];
|
|
437
|
+
if (!apiKey || !rawUrl) {
|
|
438
|
+
throw new Error("grafana: missing required parameters: url and api-key");
|
|
439
|
+
}
|
|
440
|
+
const baseUrl = rawUrl.replace(/\/+$/, "");
|
|
441
|
+
const url = `${baseUrl}${path2.startsWith("/") ? path2 : `/${path2}`}`;
|
|
442
|
+
const headers = new Headers(init?.headers);
|
|
443
|
+
headers.set("Authorization", `Bearer ${apiKey}`);
|
|
444
|
+
if (!headers.has("Accept")) headers.set("Accept", "application/json");
|
|
445
|
+
return fetch(url, { ...init, headers });
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// ../connectors/src/connectors/grafana/setup-flow.ts
|
|
449
|
+
var ALL_DATASOURCES = "__ALL_DATASOURCES__";
|
|
450
|
+
var GRAFANA_SETUP_MAX_DATASOURCES = 10;
|
|
451
|
+
async function listOrgs(params) {
|
|
452
|
+
try {
|
|
453
|
+
const res = await apiFetch(params, "/api/orgs");
|
|
454
|
+
if (res.ok) {
|
|
455
|
+
const data = await res.json();
|
|
456
|
+
if (Array.isArray(data)) return data;
|
|
457
|
+
}
|
|
458
|
+
} catch {
|
|
459
|
+
}
|
|
460
|
+
try {
|
|
461
|
+
const res = await apiFetch(params, "/api/org");
|
|
462
|
+
if (!res.ok) return [];
|
|
463
|
+
const data = await res.json();
|
|
464
|
+
if (data && typeof data.id === "number" && typeof data.name === "string") {
|
|
465
|
+
return [data];
|
|
466
|
+
}
|
|
467
|
+
} catch {
|
|
468
|
+
}
|
|
469
|
+
return [];
|
|
470
|
+
}
|
|
471
|
+
async function listDatasources(params) {
|
|
472
|
+
const res = await apiFetch(params, "/api/datasources");
|
|
473
|
+
if (!res.ok) {
|
|
474
|
+
const body = await res.text().catch(() => res.statusText);
|
|
475
|
+
throw new Error(`grafana: listDatasources failed (${res.status}): ${body}`);
|
|
476
|
+
}
|
|
477
|
+
const data = await res.json();
|
|
478
|
+
return data ?? [];
|
|
479
|
+
}
|
|
480
|
+
var grafanaSetupFlow = {
|
|
481
|
+
initialState: () => ({}),
|
|
482
|
+
steps: [
|
|
483
|
+
{
|
|
484
|
+
slug: "organization",
|
|
485
|
+
type: "select",
|
|
486
|
+
question: {
|
|
487
|
+
ja: "\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u306B\u4F7F\u3046\u7D44\u7E54\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044",
|
|
488
|
+
en: "Select the organization to use for setup"
|
|
489
|
+
},
|
|
490
|
+
async fetchOptions(_state, rt) {
|
|
491
|
+
const orgs = await listOrgs(rt.params);
|
|
492
|
+
return orgs.map((o) => ({ value: String(o.id), label: o.name }));
|
|
493
|
+
},
|
|
494
|
+
applyAnswer: (state, answer) => ({ ...state, organization: answer[0] })
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
slug: "datasources",
|
|
498
|
+
type: "multiSelect",
|
|
499
|
+
question: {
|
|
500
|
+
ja: "\u5BFE\u8C61\u30C7\u30FC\u30BF\u30BD\u30FC\u30B9\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
501
|
+
en: "Select target datasources (multi-select allowed)"
|
|
502
|
+
},
|
|
503
|
+
async fetchOptions(_state, rt) {
|
|
504
|
+
const datasources = await listDatasources(rt.params);
|
|
505
|
+
const opts = datasources.filter((d) => d.uid && d.name).map((d) => ({
|
|
506
|
+
value: d.uid,
|
|
507
|
+
label: `${d.name} (${d.type})`
|
|
508
|
+
}));
|
|
509
|
+
if (opts.length === 0) return [];
|
|
510
|
+
return [
|
|
511
|
+
{
|
|
512
|
+
value: ALL_DATASOURCES,
|
|
513
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C7\u30FC\u30BF\u30BD\u30FC\u30B9" : "All datasources"
|
|
514
|
+
},
|
|
515
|
+
...opts
|
|
516
|
+
];
|
|
517
|
+
},
|
|
518
|
+
applyAnswer: (state, answer) => ({ ...state, datasources: answer })
|
|
519
|
+
}
|
|
520
|
+
],
|
|
521
|
+
async finalize(state, rt) {
|
|
522
|
+
if (!state.datasources) {
|
|
523
|
+
throw new Error("Grafana setup: incomplete state on finalize");
|
|
524
|
+
}
|
|
525
|
+
const datasources = await listDatasources(rt.params);
|
|
526
|
+
const byUid = new Map(datasources.map((d) => [d.uid, d]));
|
|
527
|
+
const targetUids = await resolveSetupSelection({
|
|
528
|
+
selected: state.datasources,
|
|
529
|
+
allSentinel: ALL_DATASOURCES,
|
|
530
|
+
fetchAll: async () => datasources.map((d) => d.uid).filter((u) => u),
|
|
531
|
+
limit: GRAFANA_SETUP_MAX_DATASOURCES
|
|
532
|
+
});
|
|
533
|
+
const sections = ["## Grafana", ""];
|
|
534
|
+
if (state.organization) {
|
|
535
|
+
sections.push(`### Organization: ${state.organization}`, "");
|
|
536
|
+
}
|
|
537
|
+
for (const uid of targetUids) {
|
|
538
|
+
const ds = byUid.get(uid);
|
|
539
|
+
if (!ds) {
|
|
540
|
+
sections.push(`#### Datasource: ${uid}`, "", "_Not found._", "");
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
sections.push(`#### Datasource: ${ds.name}`, "");
|
|
544
|
+
sections.push("| Field | Value |");
|
|
545
|
+
sections.push("|-------|-------|");
|
|
546
|
+
sections.push(`| UID | ${ds.uid} |`);
|
|
547
|
+
sections.push(`| Type | ${ds.type} |`);
|
|
548
|
+
sections.push(`| URL | ${ds.url ?? "-"} |`);
|
|
549
|
+
sections.push(`| Default | ${ds.isDefault ? "yes" : "no"} |`);
|
|
550
|
+
sections.push("");
|
|
551
|
+
}
|
|
552
|
+
return sections.join("\n");
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
|
|
327
556
|
// ../connectors/src/connectors/grafana/tools/request.ts
|
|
328
557
|
import { z } from "zod";
|
|
329
558
|
var REQUEST_TIMEOUT_MS = 6e4;
|
|
@@ -536,7 +765,41 @@ export default async function handler(c: Context) {
|
|
|
536
765
|
- \`GET /api/org\` \u2014 \u73FE\u5728\u306E\u7D44\u7E54\u3092\u53D6\u5F97
|
|
537
766
|
- \`GET /api/health\` \u2014 \u30D8\u30EB\u30B9\u30C1\u30A7\u30C3\u30AF`
|
|
538
767
|
},
|
|
539
|
-
tools
|
|
768
|
+
tools,
|
|
769
|
+
setup: (params, ctx, config) => runSetupFlow(grafanaSetupFlow, params, ctx, config),
|
|
770
|
+
async checkConnection(params, _config) {
|
|
771
|
+
const apiKey = params[parameters.apiKey.slug];
|
|
772
|
+
const rawUrl = params[parameters.url.slug];
|
|
773
|
+
if (!apiKey || !rawUrl) {
|
|
774
|
+
return {
|
|
775
|
+
success: false,
|
|
776
|
+
error: "Missing required parameters: url and api-key"
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
const baseUrl = rawUrl.replace(/\/+$/, "");
|
|
780
|
+
try {
|
|
781
|
+
const res = await fetch(`${baseUrl}/api/org`, {
|
|
782
|
+
method: "GET",
|
|
783
|
+
headers: {
|
|
784
|
+
Authorization: `Bearer ${apiKey}`,
|
|
785
|
+
Accept: "application/json"
|
|
786
|
+
}
|
|
787
|
+
});
|
|
788
|
+
if (!res.ok) {
|
|
789
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
790
|
+
return {
|
|
791
|
+
success: false,
|
|
792
|
+
error: `Grafana API failed: HTTP ${res.status} ${errorText}`
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
return { success: true };
|
|
796
|
+
} catch (error) {
|
|
797
|
+
return {
|
|
798
|
+
success: false,
|
|
799
|
+
error: error instanceof Error ? error.message : String(error)
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
}
|
|
540
803
|
});
|
|
541
804
|
|
|
542
805
|
// src/connectors/create-connector-sdk.ts
|
|
@@ -565,6 +828,7 @@ function resolveEnvVarOptional(entry, key) {
|
|
|
565
828
|
import { getContext } from "hono/context-storage";
|
|
566
829
|
import { getCookie } from "hono/cookie";
|
|
567
830
|
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
831
|
+
var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
|
|
568
832
|
function normalizeHeaders(input) {
|
|
569
833
|
const out = {};
|
|
570
834
|
if (!input) return out;
|
|
@@ -573,6 +837,11 @@ function normalizeHeaders(input) {
|
|
|
573
837
|
});
|
|
574
838
|
return out;
|
|
575
839
|
}
|
|
840
|
+
function extractInputUrl(input) {
|
|
841
|
+
if (typeof input === "string") return input;
|
|
842
|
+
if (input instanceof URL) return input.href;
|
|
843
|
+
return input.url;
|
|
844
|
+
}
|
|
576
845
|
function createSandboxProxyFetch(connectionId) {
|
|
577
846
|
return async (input, init) => {
|
|
578
847
|
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
@@ -582,10 +851,17 @@ function createSandboxProxyFetch(connectionId) {
|
|
|
582
851
|
"Connection proxy is not configured. Please check your deployment settings."
|
|
583
852
|
);
|
|
584
853
|
}
|
|
585
|
-
const originalUrl =
|
|
854
|
+
const originalUrl = extractInputUrl(input);
|
|
855
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
856
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
857
|
+
const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
858
|
+
return fetch(sessionUrl, {
|
|
859
|
+
method: "POST",
|
|
860
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
861
|
+
});
|
|
862
|
+
}
|
|
586
863
|
const originalMethod = init?.method ?? "GET";
|
|
587
864
|
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
588
|
-
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
589
865
|
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
590
866
|
return fetch(proxyUrl, {
|
|
591
867
|
method: "POST",
|
|
@@ -611,10 +887,9 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
611
887
|
}
|
|
612
888
|
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
613
889
|
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
890
|
+
const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
614
891
|
return async (input, init) => {
|
|
615
|
-
const originalUrl =
|
|
616
|
-
const originalMethod = init?.method ?? "GET";
|
|
617
|
-
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
892
|
+
const originalUrl = extractInputUrl(input);
|
|
618
893
|
const c = getContext();
|
|
619
894
|
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
620
895
|
if (!appSession) {
|
|
@@ -622,6 +897,14 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
622
897
|
"No authentication method available for connection proxy."
|
|
623
898
|
);
|
|
624
899
|
}
|
|
900
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
901
|
+
return fetch(sessionUrl, {
|
|
902
|
+
method: "POST",
|
|
903
|
+
headers: { Authorization: `Bearer ${appSession}` }
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
const originalMethod = init?.method ?? "GET";
|
|
907
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
625
908
|
return fetch(proxyUrl, {
|
|
626
909
|
method: "POST",
|
|
627
910
|
headers: {
|