@squadbase/vite-server 0.1.12-dev.a9ac647 → 0.1.17-dev.24af54e
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 +12374 -883
- package/dist/connectors/airtable-oauth.js +257 -46
- package/dist/connectors/airtable.js +294 -51
- package/dist/connectors/amplitude.js +297 -47
- package/dist/connectors/anthropic.js +135 -47
- package/dist/connectors/asana.js +302 -49
- package/dist/connectors/attio.js +277 -49
- package/dist/connectors/aws-billing.js +262 -46
- package/dist/connectors/azure-sql.js +396 -102
- package/dist/connectors/backlog-api-key.js +292 -47
- package/dist/connectors/clickup.js +313 -49
- package/dist/connectors/cosmosdb.js +280 -50
- package/dist/connectors/customerio.js +294 -47
- package/dist/connectors/dbt.js +315 -47
- package/dist/connectors/freshdesk.js +317 -53
- package/dist/connectors/freshsales.js +308 -52
- package/dist/connectors/freshservice.js +336 -53
- package/dist/connectors/gamma.js +302 -52
- package/dist/connectors/gemini.js +134 -47
- package/dist/connectors/github.js +361 -49
- package/dist/connectors/gmail-oauth.js +179 -7
- package/dist/connectors/gmail.js +325 -47
- package/dist/connectors/google-ads.js +263 -46
- package/dist/connectors/google-analytics-oauth.js +285 -46
- package/dist/connectors/google-analytics.js +387 -49
- package/dist/connectors/google-audit-log.js +413 -47
- package/dist/connectors/google-calendar-oauth.js +234 -46
- package/dist/connectors/google-calendar.js +334 -47
- package/dist/connectors/google-docs.js +195 -6
- package/dist/connectors/google-drive.js +237 -5
- package/dist/connectors/google-search-console-oauth.js +231 -46
- package/dist/connectors/google-sheets.js +247 -47
- package/dist/connectors/google-slides.js +180 -6
- package/dist/connectors/grafana.js +307 -49
- package/dist/connectors/hubspot-oauth.js +183 -5
- package/dist/connectors/hubspot.js +281 -49
- package/dist/connectors/influxdb.js +391 -51
- package/dist/connectors/intercom-oauth.js +185 -5
- package/dist/connectors/intercom.js +277 -49
- package/dist/connectors/jdbc.js +737 -110
- package/dist/connectors/jira-api-key.js +301 -47
- package/dist/connectors/kintone-api-token.js +256 -47
- package/dist/connectors/kintone.js +303 -47
- package/dist/connectors/linear.js +305 -49
- package/dist/connectors/linkedin-ads.js +243 -50
- package/dist/connectors/mailchimp-oauth.js +243 -46
- package/dist/connectors/mailchimp.js +295 -49
- package/dist/connectors/meta-ads-oauth.js +248 -48
- package/dist/connectors/meta-ads.js +260 -50
- package/dist/connectors/mixpanel.js +313 -47
- package/dist/connectors/monday.js +335 -49
- package/dist/connectors/mongodb.js +294 -57
- package/dist/connectors/notion-oauth.js +206 -5
- package/dist/connectors/notion.js +298 -51
- package/dist/connectors/openai.js +134 -47
- package/dist/connectors/oracle.js +414 -103
- package/dist/connectors/outlook-oauth.js +179 -5
- package/dist/connectors/powerbi-oauth.js +226 -5
- package/dist/connectors/salesforce.js +359 -49
- package/dist/connectors/semrush.js +289 -49
- package/dist/connectors/sentry.js +264 -50
- package/dist/connectors/shopify-oauth.js +162 -5
- package/dist/connectors/shopify.js +332 -47
- package/dist/connectors/sqlserver.js +390 -102
- package/dist/connectors/stripe-api-key.js +244 -46
- package/dist/connectors/stripe-oauth.js +177 -5
- package/dist/connectors/supabase.js +278 -48
- package/dist/connectors/tableau.js +389 -184
- package/dist/connectors/tiktok-ads.js +254 -48
- package/dist/connectors/wix-store.js +295 -49
- package/dist/connectors/zendesk-oauth.js +214 -5
- package/dist/connectors/zendesk.js +333 -47
- package/dist/index.d.ts +149 -1
- package/dist/index.js +13677 -1969
- package/dist/main.js +13627 -1927
- package/dist/vite-plugin.js +12391 -890
- 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/amplitude/parameters.ts
|
|
57
|
+
init_parameter_definition();
|
|
46
58
|
var parameters = {
|
|
47
59
|
apiKey: new ParameterDefinition({
|
|
48
60
|
slug: "api-key",
|
|
@@ -216,6 +228,28 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
216
228
|
tools;
|
|
217
229
|
query;
|
|
218
230
|
checkConnection;
|
|
231
|
+
/**
|
|
232
|
+
* SQPD-1212: Logic-based, rule-driven connection setup. Connectors that
|
|
233
|
+
* implement this expose a step-by-step exploration flow (database/schema/
|
|
234
|
+
* table/etc. discovery) that the dashboard backend drives via the
|
|
235
|
+
* `/connections/:connectionId/setup` endpoint. Implement by delegating to
|
|
236
|
+
* `runSetupFlow` from `setup-flow.ts`.
|
|
237
|
+
*/
|
|
238
|
+
setup;
|
|
239
|
+
/**
|
|
240
|
+
* Opt-out of the default "verify before save" behavior on connection
|
|
241
|
+
* creation. The backend invokes `checkConnection` synchronously while
|
|
242
|
+
* creating the connection and aborts (no row inserted) if it fails — this
|
|
243
|
+
* flag disables that for connectors where the check cannot succeed pre-save:
|
|
244
|
+
*
|
|
245
|
+
* - `squadbase-db` populates `connection-url` only after Neon provisioning
|
|
246
|
+
* - OAuth connectors require an OAuth-aware proxyFetch keyed by the
|
|
247
|
+
* connectionId, which doesn't exist until the row is saved
|
|
248
|
+
*
|
|
249
|
+
* Exceptions are the explicit position; new credential-input connectors get
|
|
250
|
+
* the default verify-on-create behavior without opt-in.
|
|
251
|
+
*/
|
|
252
|
+
skipConnectionCheckOnCreate;
|
|
219
253
|
constructor(config) {
|
|
220
254
|
this.slug = config.slug;
|
|
221
255
|
this.authType = config.authType;
|
|
@@ -232,6 +266,8 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
232
266
|
this.tools = config.tools;
|
|
233
267
|
this.query = config.query;
|
|
234
268
|
this.checkConnection = config.checkConnection;
|
|
269
|
+
this.setup = config.setup;
|
|
270
|
+
this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
|
|
235
271
|
}
|
|
236
272
|
get connectorKey() {
|
|
237
273
|
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
@@ -296,6 +332,46 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
296
332
|
}
|
|
297
333
|
};
|
|
298
334
|
|
|
335
|
+
// ../connectors/src/setup-flow.ts
|
|
336
|
+
async function runSetupFlow(flow, params, ctx, config) {
|
|
337
|
+
const runtime = {
|
|
338
|
+
params,
|
|
339
|
+
language: ctx.language,
|
|
340
|
+
config
|
|
341
|
+
};
|
|
342
|
+
let state = flow.initialState();
|
|
343
|
+
let answerIdx = 0;
|
|
344
|
+
for (const step of flow.steps) {
|
|
345
|
+
const ans = ctx.answers[answerIdx];
|
|
346
|
+
if (ans && ans.questionSlug === step.slug) {
|
|
347
|
+
state = step.applyAnswer(state, ans.answer);
|
|
348
|
+
answerIdx += 1;
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
if (step.type === "text") {
|
|
352
|
+
return {
|
|
353
|
+
type: "nextQuestion",
|
|
354
|
+
questionSlug: step.slug,
|
|
355
|
+
question: step.question[ctx.language],
|
|
356
|
+
questionType: "text"
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
360
|
+
if (options.length === 0) {
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
return {
|
|
364
|
+
type: "nextQuestion",
|
|
365
|
+
questionSlug: step.slug,
|
|
366
|
+
question: step.question[ctx.language],
|
|
367
|
+
questionType: step.type,
|
|
368
|
+
options
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
372
|
+
return { type: "fulfilled", dataInvestigationResult };
|
|
373
|
+
}
|
|
374
|
+
|
|
299
375
|
// ../connectors/src/auth-types.ts
|
|
300
376
|
var AUTH_TYPES = {
|
|
301
377
|
OAUTH: "oauth",
|
|
@@ -322,6 +398,125 @@ NOTE: The Dashboard REST API endpoints (events/segmentation, funnels, retention,
|
|
|
322
398
|
}
|
|
323
399
|
});
|
|
324
400
|
|
|
401
|
+
// ../connectors/src/connectors/amplitude/utils.ts
|
|
402
|
+
function getBaseUrl(params) {
|
|
403
|
+
const region = params[parameters.region.slug];
|
|
404
|
+
return region === "eu" ? "https://analytics.eu.amplitude.com" : "https://amplitude.com";
|
|
405
|
+
}
|
|
406
|
+
async function apiFetch(params, path2, init) {
|
|
407
|
+
const apiKey = params[parameters.apiKey.slug];
|
|
408
|
+
const secretKey = params[parameters.secretKey.slug];
|
|
409
|
+
if (!apiKey || !secretKey) {
|
|
410
|
+
throw new Error(
|
|
411
|
+
"amplitude: missing required parameters: api-key and secret-key"
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
const url = `${getBaseUrl(params)}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
415
|
+
const headers = new Headers(init?.headers);
|
|
416
|
+
headers.set("Authorization", `Basic ${btoa(`${apiKey}:${secretKey}`)}`);
|
|
417
|
+
return fetch(url, { ...init, headers });
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// ../connectors/src/connectors/amplitude/setup-flow.ts
|
|
421
|
+
var AMPLITUDE_SETUP_MAX_ENTITIES = 10;
|
|
422
|
+
var AMPLITUDE_SETUP_MAX_EVENTS = 50;
|
|
423
|
+
var ENTITY_LABELS = {
|
|
424
|
+
events: { en: "Events", ja: "Events (\u30A4\u30D9\u30F3\u30C8)" },
|
|
425
|
+
userProperties: {
|
|
426
|
+
en: "User properties",
|
|
427
|
+
ja: "User properties (\u30E6\u30FC\u30B6\u30FC\u30D7\u30ED\u30D1\u30C6\u30A3)"
|
|
428
|
+
},
|
|
429
|
+
cohorts: { en: "Cohorts", ja: "Cohorts (\u30B3\u30DB\u30FC\u30C8)" },
|
|
430
|
+
charts: { en: "Charts", ja: "Charts (\u30C1\u30E3\u30FC\u30C8)" },
|
|
431
|
+
dashboards: { en: "Dashboards", ja: "Dashboards (\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9)" }
|
|
432
|
+
};
|
|
433
|
+
var ENTITY_DESCRIPTIONS = {
|
|
434
|
+
events: {
|
|
435
|
+
en: "Tracked event types with metadata.",
|
|
436
|
+
ja: "\u30E1\u30BF\u30C7\u30FC\u30BF\u4ED8\u304D\u3067\u8FFD\u8DE1\u3055\u308C\u3066\u3044\u308B\u30A4\u30D9\u30F3\u30C8\u30BF\u30A4\u30D7\u3002"
|
|
437
|
+
},
|
|
438
|
+
userProperties: {
|
|
439
|
+
en: "User-level properties used for segmentation.",
|
|
440
|
+
ja: "\u30BB\u30B0\u30E1\u30F3\u30C6\u30FC\u30B7\u30E7\u30F3\u306B\u4F7F\u308F\u308C\u308B\u30E6\u30FC\u30B6\u30FC\u30EC\u30D9\u30EB\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u3002"
|
|
441
|
+
},
|
|
442
|
+
cohorts: {
|
|
443
|
+
en: "Saved user cohorts.",
|
|
444
|
+
ja: "\u4FDD\u5B58\u6E08\u307F\u306E\u30E6\u30FC\u30B6\u30FC\u30B3\u30DB\u30FC\u30C8\u3002"
|
|
445
|
+
},
|
|
446
|
+
charts: {
|
|
447
|
+
en: "Saved analytics charts.",
|
|
448
|
+
ja: "\u4FDD\u5B58\u6E08\u307F\u306E\u30A2\u30CA\u30EA\u30C6\u30A3\u30AF\u30B9\u30C1\u30E3\u30FC\u30C8\u3002"
|
|
449
|
+
},
|
|
450
|
+
dashboards: {
|
|
451
|
+
en: "Saved dashboards.",
|
|
452
|
+
ja: "\u4FDD\u5B58\u6E08\u307F\u306E\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9\u3002"
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
var ENTITY_VALUES = [
|
|
456
|
+
"events",
|
|
457
|
+
"userProperties",
|
|
458
|
+
"cohorts",
|
|
459
|
+
"charts",
|
|
460
|
+
"dashboards"
|
|
461
|
+
];
|
|
462
|
+
async function fetchEventNames(params) {
|
|
463
|
+
try {
|
|
464
|
+
const res = await apiFetch(params, "/api/2/taxonomy/event");
|
|
465
|
+
if (!res.ok) return [];
|
|
466
|
+
const data = await res.json();
|
|
467
|
+
return (data.data ?? []).map((e) => e.event_type ?? "").filter((name) => name);
|
|
468
|
+
} catch {
|
|
469
|
+
return [];
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
var amplitudeSetupFlow = {
|
|
473
|
+
initialState: () => ({}),
|
|
474
|
+
steps: [
|
|
475
|
+
{
|
|
476
|
+
slug: "entities",
|
|
477
|
+
type: "multiSelect",
|
|
478
|
+
question: {
|
|
479
|
+
ja: "\u5BFE\u8C61\u306E\u30A8\u30F3\u30C6\u30A3\u30C6\u30A3\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
480
|
+
en: "Select target entities (multi-select allowed)"
|
|
481
|
+
},
|
|
482
|
+
async fetchOptions(_state, rt) {
|
|
483
|
+
return ENTITY_VALUES.map((value) => ({
|
|
484
|
+
value,
|
|
485
|
+
label: ENTITY_LABELS[value][rt.language]
|
|
486
|
+
}));
|
|
487
|
+
},
|
|
488
|
+
applyAnswer: (state, answer) => ({ ...state, entities: answer })
|
|
489
|
+
}
|
|
490
|
+
],
|
|
491
|
+
async finalize(state, rt) {
|
|
492
|
+
if (!state.entities) {
|
|
493
|
+
throw new Error("Amplitude setup: incomplete state on finalize");
|
|
494
|
+
}
|
|
495
|
+
const selected = state.entities.filter(
|
|
496
|
+
(e) => ENTITY_VALUES.includes(e)
|
|
497
|
+
).slice(0, AMPLITUDE_SETUP_MAX_ENTITIES);
|
|
498
|
+
const sections = ["## Amplitude", ""];
|
|
499
|
+
for (const entity of selected) {
|
|
500
|
+
sections.push(`### ${ENTITY_LABELS[entity].en}`, "");
|
|
501
|
+
sections.push(ENTITY_DESCRIPTIONS[entity][rt.language], "");
|
|
502
|
+
if (entity === "events") {
|
|
503
|
+
const names = (await fetchEventNames(rt.params)).slice(
|
|
504
|
+
0,
|
|
505
|
+
AMPLITUDE_SETUP_MAX_EVENTS
|
|
506
|
+
);
|
|
507
|
+
if (names.length > 0) {
|
|
508
|
+
sections.push("Event names:", "");
|
|
509
|
+
for (const name of names) {
|
|
510
|
+
sections.push(`- ${name}`);
|
|
511
|
+
}
|
|
512
|
+
sections.push("");
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
return sections.join("\n");
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
|
|
325
520
|
// ../connectors/src/connectors/amplitude/tools/request.ts
|
|
326
521
|
import { z } from "zod";
|
|
327
522
|
var REQUEST_TIMEOUT_MS = 6e4;
|
|
@@ -550,7 +745,42 @@ export default async function handler(c: Context) {
|
|
|
550
745
|
- \`i\` \u2014 \u30A4\u30F3\u30BF\u30FC\u30D0\u30EB\uFF081=\u65E5\u6B21\u30017=\u9031\u6B21\u300130=\u6708\u6B21\uFF09
|
|
551
746
|
- \`g\` \u2014 \u30B0\u30EB\u30FC\u30D7\u5316\u30D7\u30ED\u30D1\u30C6\u30A3`
|
|
552
747
|
},
|
|
553
|
-
tools
|
|
748
|
+
tools,
|
|
749
|
+
setup: (params, ctx, config) => runSetupFlow(amplitudeSetupFlow, params, ctx, config),
|
|
750
|
+
async checkConnection(params, _config) {
|
|
751
|
+
const apiKey = params[parameters.apiKey.slug];
|
|
752
|
+
const secretKey = params[parameters.secretKey.slug];
|
|
753
|
+
if (!apiKey || !secretKey) {
|
|
754
|
+
return {
|
|
755
|
+
success: false,
|
|
756
|
+
error: "Missing required parameters: api-key and secret-key"
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
const region = params[parameters.region.slug];
|
|
760
|
+
const baseUrl = region === "eu" ? "https://analytics.eu.amplitude.com" : "https://amplitude.com";
|
|
761
|
+
try {
|
|
762
|
+
const res = await fetch(`${baseUrl}/api/2/events/list`, {
|
|
763
|
+
method: "GET",
|
|
764
|
+
headers: {
|
|
765
|
+
Authorization: `Basic ${btoa(`${apiKey}:${secretKey}`)}`,
|
|
766
|
+
Accept: "application/json"
|
|
767
|
+
}
|
|
768
|
+
});
|
|
769
|
+
if (!res.ok) {
|
|
770
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
771
|
+
return {
|
|
772
|
+
success: false,
|
|
773
|
+
error: `Amplitude API failed: HTTP ${res.status} ${errorText}`
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
return { success: true };
|
|
777
|
+
} catch (error) {
|
|
778
|
+
return {
|
|
779
|
+
success: false,
|
|
780
|
+
error: error instanceof Error ? error.message : String(error)
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
}
|
|
554
784
|
});
|
|
555
785
|
|
|
556
786
|
// src/connectors/create-connector-sdk.ts
|
|
@@ -579,6 +809,7 @@ function resolveEnvVarOptional(entry, key) {
|
|
|
579
809
|
import { getContext } from "hono/context-storage";
|
|
580
810
|
import { getCookie } from "hono/cookie";
|
|
581
811
|
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
812
|
+
var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
|
|
582
813
|
function normalizeHeaders(input) {
|
|
583
814
|
const out = {};
|
|
584
815
|
if (!input) return out;
|
|
@@ -587,6 +818,11 @@ function normalizeHeaders(input) {
|
|
|
587
818
|
});
|
|
588
819
|
return out;
|
|
589
820
|
}
|
|
821
|
+
function extractInputUrl(input) {
|
|
822
|
+
if (typeof input === "string") return input;
|
|
823
|
+
if (input instanceof URL) return input.href;
|
|
824
|
+
return input.url;
|
|
825
|
+
}
|
|
590
826
|
function createSandboxProxyFetch(connectionId) {
|
|
591
827
|
return async (input, init) => {
|
|
592
828
|
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
@@ -596,10 +832,17 @@ function createSandboxProxyFetch(connectionId) {
|
|
|
596
832
|
"Connection proxy is not configured. Please check your deployment settings."
|
|
597
833
|
);
|
|
598
834
|
}
|
|
599
|
-
const originalUrl =
|
|
835
|
+
const originalUrl = extractInputUrl(input);
|
|
836
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
837
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
838
|
+
const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
839
|
+
return fetch(sessionUrl, {
|
|
840
|
+
method: "POST",
|
|
841
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
842
|
+
});
|
|
843
|
+
}
|
|
600
844
|
const originalMethod = init?.method ?? "GET";
|
|
601
845
|
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
602
|
-
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
603
846
|
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
604
847
|
return fetch(proxyUrl, {
|
|
605
848
|
method: "POST",
|
|
@@ -625,10 +868,9 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
625
868
|
}
|
|
626
869
|
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
627
870
|
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
871
|
+
const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
628
872
|
return async (input, init) => {
|
|
629
|
-
const originalUrl =
|
|
630
|
-
const originalMethod = init?.method ?? "GET";
|
|
631
|
-
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
873
|
+
const originalUrl = extractInputUrl(input);
|
|
632
874
|
const c = getContext();
|
|
633
875
|
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
634
876
|
if (!appSession) {
|
|
@@ -636,6 +878,14 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
636
878
|
"No authentication method available for connection proxy."
|
|
637
879
|
);
|
|
638
880
|
}
|
|
881
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
882
|
+
return fetch(sessionUrl, {
|
|
883
|
+
method: "POST",
|
|
884
|
+
headers: { Authorization: `Bearer ${appSession}` }
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
const originalMethod = init?.method ?? "GET";
|
|
888
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
639
889
|
return fetch(proxyUrl, {
|
|
640
890
|
method: "POST",
|
|
641
891
|
headers: {
|
|
@@ -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/anthropic/parameters.ts
|
|
57
|
+
init_parameter_definition();
|
|
46
58
|
var parameters = {
|
|
47
59
|
apiKey: new ParameterDefinition({
|
|
48
60
|
slug: "api-key",
|
|
@@ -83,6 +95,28 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
83
95
|
tools;
|
|
84
96
|
query;
|
|
85
97
|
checkConnection;
|
|
98
|
+
/**
|
|
99
|
+
* SQPD-1212: Logic-based, rule-driven connection setup. Connectors that
|
|
100
|
+
* implement this expose a step-by-step exploration flow (database/schema/
|
|
101
|
+
* table/etc. discovery) that the dashboard backend drives via the
|
|
102
|
+
* `/connections/:connectionId/setup` endpoint. Implement by delegating to
|
|
103
|
+
* `runSetupFlow` from `setup-flow.ts`.
|
|
104
|
+
*/
|
|
105
|
+
setup;
|
|
106
|
+
/**
|
|
107
|
+
* Opt-out of the default "verify before save" behavior on connection
|
|
108
|
+
* creation. The backend invokes `checkConnection` synchronously while
|
|
109
|
+
* creating the connection and aborts (no row inserted) if it fails — this
|
|
110
|
+
* flag disables that for connectors where the check cannot succeed pre-save:
|
|
111
|
+
*
|
|
112
|
+
* - `squadbase-db` populates `connection-url` only after Neon provisioning
|
|
113
|
+
* - OAuth connectors require an OAuth-aware proxyFetch keyed by the
|
|
114
|
+
* connectionId, which doesn't exist until the row is saved
|
|
115
|
+
*
|
|
116
|
+
* Exceptions are the explicit position; new credential-input connectors get
|
|
117
|
+
* the default verify-on-create behavior without opt-in.
|
|
118
|
+
*/
|
|
119
|
+
skipConnectionCheckOnCreate;
|
|
86
120
|
constructor(config) {
|
|
87
121
|
this.slug = config.slug;
|
|
88
122
|
this.authType = config.authType;
|
|
@@ -99,6 +133,8 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
99
133
|
this.tools = config.tools;
|
|
100
134
|
this.query = config.query;
|
|
101
135
|
this.checkConnection = config.checkConnection;
|
|
136
|
+
this.setup = config.setup;
|
|
137
|
+
this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
|
|
102
138
|
}
|
|
103
139
|
get connectorKey() {
|
|
104
140
|
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
@@ -234,7 +270,39 @@ export default async function handler(c: Context) {
|
|
|
234
270
|
}
|
|
235
271
|
\`\`\``
|
|
236
272
|
},
|
|
237
|
-
tools
|
|
273
|
+
tools,
|
|
274
|
+
async checkConnection(params, _config) {
|
|
275
|
+
try {
|
|
276
|
+
const apiKey = params[parameters.apiKey.slug];
|
|
277
|
+
if (!apiKey) {
|
|
278
|
+
return {
|
|
279
|
+
success: false,
|
|
280
|
+
error: "Missing required parameter: api-key"
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
const res = await fetch("https://api.anthropic.com/v1/models", {
|
|
284
|
+
method: "GET",
|
|
285
|
+
headers: {
|
|
286
|
+
"x-api-key": apiKey,
|
|
287
|
+
"anthropic-version": "2023-06-01",
|
|
288
|
+
Accept: "application/json"
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
if (!res.ok) {
|
|
292
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
293
|
+
return {
|
|
294
|
+
success: false,
|
|
295
|
+
error: `Anthropic API failed: HTTP ${res.status} ${errorText}`
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
return { success: true };
|
|
299
|
+
} catch (error) {
|
|
300
|
+
return {
|
|
301
|
+
success: false,
|
|
302
|
+
error: error instanceof Error ? error.message : String(error)
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
}
|
|
238
306
|
});
|
|
239
307
|
|
|
240
308
|
// src/connectors/create-connector-sdk.ts
|
|
@@ -263,6 +331,7 @@ function resolveEnvVarOptional(entry, key) {
|
|
|
263
331
|
import { getContext } from "hono/context-storage";
|
|
264
332
|
import { getCookie } from "hono/cookie";
|
|
265
333
|
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
334
|
+
var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
|
|
266
335
|
function normalizeHeaders(input) {
|
|
267
336
|
const out = {};
|
|
268
337
|
if (!input) return out;
|
|
@@ -271,6 +340,11 @@ function normalizeHeaders(input) {
|
|
|
271
340
|
});
|
|
272
341
|
return out;
|
|
273
342
|
}
|
|
343
|
+
function extractInputUrl(input) {
|
|
344
|
+
if (typeof input === "string") return input;
|
|
345
|
+
if (input instanceof URL) return input.href;
|
|
346
|
+
return input.url;
|
|
347
|
+
}
|
|
274
348
|
function createSandboxProxyFetch(connectionId) {
|
|
275
349
|
return async (input, init) => {
|
|
276
350
|
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
@@ -280,10 +354,17 @@ function createSandboxProxyFetch(connectionId) {
|
|
|
280
354
|
"Connection proxy is not configured. Please check your deployment settings."
|
|
281
355
|
);
|
|
282
356
|
}
|
|
283
|
-
const originalUrl =
|
|
357
|
+
const originalUrl = extractInputUrl(input);
|
|
358
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
359
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
360
|
+
const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
361
|
+
return fetch(sessionUrl, {
|
|
362
|
+
method: "POST",
|
|
363
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
364
|
+
});
|
|
365
|
+
}
|
|
284
366
|
const originalMethod = init?.method ?? "GET";
|
|
285
367
|
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
286
|
-
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
287
368
|
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
288
369
|
return fetch(proxyUrl, {
|
|
289
370
|
method: "POST",
|
|
@@ -309,10 +390,9 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
309
390
|
}
|
|
310
391
|
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
311
392
|
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
393
|
+
const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
312
394
|
return async (input, init) => {
|
|
313
|
-
const originalUrl =
|
|
314
|
-
const originalMethod = init?.method ?? "GET";
|
|
315
|
-
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
395
|
+
const originalUrl = extractInputUrl(input);
|
|
316
396
|
const c = getContext();
|
|
317
397
|
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
318
398
|
if (!appSession) {
|
|
@@ -320,6 +400,14 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
320
400
|
"No authentication method available for connection proxy."
|
|
321
401
|
);
|
|
322
402
|
}
|
|
403
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
404
|
+
return fetch(sessionUrl, {
|
|
405
|
+
method: "POST",
|
|
406
|
+
headers: { Authorization: `Bearer ${appSession}` }
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
const originalMethod = init?.method ?? "GET";
|
|
410
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
323
411
|
return fetch(proxyUrl, {
|
|
324
412
|
method: "POST",
|
|
325
413
|
headers: {
|