@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/stripe-api-key/parameters.ts
|
|
57
|
+
init_parameter_definition();
|
|
46
58
|
var parameters = {
|
|
47
59
|
apiKey: new ParameterDefinition({
|
|
48
60
|
slug: "api-key",
|
|
@@ -133,6 +145,28 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
133
145
|
tools;
|
|
134
146
|
query;
|
|
135
147
|
checkConnection;
|
|
148
|
+
/**
|
|
149
|
+
* SQPD-1212: Logic-based, rule-driven connection setup. Connectors that
|
|
150
|
+
* implement this expose a step-by-step exploration flow (database/schema/
|
|
151
|
+
* table/etc. discovery) that the dashboard backend drives via the
|
|
152
|
+
* `/connections/:connectionId/setup` endpoint. Implement by delegating to
|
|
153
|
+
* `runSetupFlow` from `setup-flow.ts`.
|
|
154
|
+
*/
|
|
155
|
+
setup;
|
|
156
|
+
/**
|
|
157
|
+
* Opt-out of the default "verify before save" behavior on connection
|
|
158
|
+
* creation. The backend invokes `checkConnection` synchronously while
|
|
159
|
+
* creating the connection and aborts (no row inserted) if it fails — this
|
|
160
|
+
* flag disables that for connectors where the check cannot succeed pre-save:
|
|
161
|
+
*
|
|
162
|
+
* - `squadbase-db` populates `connection-url` only after Neon provisioning
|
|
163
|
+
* - OAuth connectors require an OAuth-aware proxyFetch keyed by the
|
|
164
|
+
* connectionId, which doesn't exist until the row is saved
|
|
165
|
+
*
|
|
166
|
+
* Exceptions are the explicit position; new credential-input connectors get
|
|
167
|
+
* the default verify-on-create behavior without opt-in.
|
|
168
|
+
*/
|
|
169
|
+
skipConnectionCheckOnCreate;
|
|
136
170
|
constructor(config) {
|
|
137
171
|
this.slug = config.slug;
|
|
138
172
|
this.authType = config.authType;
|
|
@@ -149,6 +183,8 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
149
183
|
this.tools = config.tools;
|
|
150
184
|
this.query = config.query;
|
|
151
185
|
this.checkConnection = config.checkConnection;
|
|
186
|
+
this.setup = config.setup;
|
|
187
|
+
this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
|
|
152
188
|
}
|
|
153
189
|
get connectorKey() {
|
|
154
190
|
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
@@ -213,6 +249,71 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
213
249
|
}
|
|
214
250
|
};
|
|
215
251
|
|
|
252
|
+
// ../connectors/src/setup-flow.ts
|
|
253
|
+
async function runSetupFlow(flow, params, ctx, config) {
|
|
254
|
+
const runtime = {
|
|
255
|
+
params,
|
|
256
|
+
language: ctx.language,
|
|
257
|
+
config
|
|
258
|
+
};
|
|
259
|
+
let state = flow.initialState();
|
|
260
|
+
let answerIdx = 0;
|
|
261
|
+
const pendingParameterUpdates = [];
|
|
262
|
+
for (const step of flow.steps) {
|
|
263
|
+
const ans = ctx.answers[answerIdx];
|
|
264
|
+
if (ans && ans.questionSlug === step.slug) {
|
|
265
|
+
state = step.applyAnswer(state, ans.answer);
|
|
266
|
+
if (step.toParameterUpdates) {
|
|
267
|
+
pendingParameterUpdates.push(...step.toParameterUpdates(state));
|
|
268
|
+
}
|
|
269
|
+
answerIdx += 1;
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
|
|
273
|
+
if (step.type === "text") {
|
|
274
|
+
if (step.fetchOptions) {
|
|
275
|
+
const options2 = await step.fetchOptions(state, runtime);
|
|
276
|
+
if (options2.length === 0) {
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return {
|
|
281
|
+
type: "nextQuestion",
|
|
282
|
+
questionSlug: step.slug,
|
|
283
|
+
question: step.question[ctx.language],
|
|
284
|
+
questionType: "text",
|
|
285
|
+
allowFreeText: resolvedAllowFreeText,
|
|
286
|
+
...pendingParameterUpdates.length > 0 && {
|
|
287
|
+
parameterUpdates: pendingParameterUpdates
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
292
|
+
if (options.length === 0) {
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
return {
|
|
296
|
+
type: "nextQuestion",
|
|
297
|
+
questionSlug: step.slug,
|
|
298
|
+
question: step.question[ctx.language],
|
|
299
|
+
questionType: step.type,
|
|
300
|
+
options,
|
|
301
|
+
allowFreeText: resolvedAllowFreeText,
|
|
302
|
+
...pendingParameterUpdates.length > 0 && {
|
|
303
|
+
parameterUpdates: pendingParameterUpdates
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
308
|
+
return {
|
|
309
|
+
type: "fulfilled",
|
|
310
|
+
dataInvestigationResult,
|
|
311
|
+
...pendingParameterUpdates.length > 0 && {
|
|
312
|
+
parameterUpdates: pendingParameterUpdates
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
216
317
|
// ../connectors/src/auth-types.ts
|
|
217
318
|
var AUTH_TYPES = {
|
|
218
319
|
OAUTH: "oauth",
|
|
@@ -352,6 +453,107 @@ var stripeApiKeyOnboarding = new ConnectorOnboarding({
|
|
|
352
453
|
}
|
|
353
454
|
});
|
|
354
455
|
|
|
456
|
+
// ../connectors/src/connectors/stripe-api-key/utils.ts
|
|
457
|
+
var BASE_URL3 = "https://api.stripe.com";
|
|
458
|
+
async function apiFetch(params, path2, init) {
|
|
459
|
+
const apiKey = params[parameters.apiKey.slug];
|
|
460
|
+
if (!apiKey) {
|
|
461
|
+
throw new Error("stripe-api-key: missing required parameter: api-key");
|
|
462
|
+
}
|
|
463
|
+
const url = `${BASE_URL3}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
464
|
+
const headers = new Headers(init?.headers);
|
|
465
|
+
headers.set("Authorization", `Bearer ${apiKey}`);
|
|
466
|
+
return fetch(url, { ...init, headers });
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// ../connectors/src/connectors/stripe-api-key/setup-flow.ts
|
|
470
|
+
var STRIPE_SETUP_MAX_ENTITIES = 10;
|
|
471
|
+
var ENTITY_LABELS = {
|
|
472
|
+
customers: { en: "Customers", ja: "Customers (\u9867\u5BA2)" },
|
|
473
|
+
charges: { en: "Charges", ja: "Charges (\u652F\u6255\u3044)" },
|
|
474
|
+
invoices: { en: "Invoices", ja: "Invoices (\u8ACB\u6C42\u66F8)" },
|
|
475
|
+
subscriptions: {
|
|
476
|
+
en: "Subscriptions",
|
|
477
|
+
ja: "Subscriptions (\u30B5\u30D6\u30B9\u30AF\u30EA\u30D7\u30B7\u30E7\u30F3)"
|
|
478
|
+
},
|
|
479
|
+
products: { en: "Products", ja: "Products (\u5546\u54C1)" },
|
|
480
|
+
prices: { en: "Prices", ja: "Prices (\u4FA1\u683C)" },
|
|
481
|
+
payouts: { en: "Payouts", ja: "Payouts (\u652F\u6255\u3044)" },
|
|
482
|
+
refunds: { en: "Refunds", ja: "Refunds (\u8FD4\u91D1)" },
|
|
483
|
+
disputes: { en: "Disputes", ja: "Disputes (\u7570\u8B70)" },
|
|
484
|
+
paymentIntents: {
|
|
485
|
+
en: "Payment intents",
|
|
486
|
+
ja: "Payment intents (\u652F\u6255\u3044\u30A4\u30F3\u30C6\u30F3\u30C8)"
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
var ENTITY_PATHS = {
|
|
490
|
+
customers: "/v1/customers?limit=1",
|
|
491
|
+
charges: "/v1/charges?limit=1",
|
|
492
|
+
invoices: "/v1/invoices?limit=1",
|
|
493
|
+
subscriptions: "/v1/subscriptions?limit=1",
|
|
494
|
+
products: "/v1/products?limit=1",
|
|
495
|
+
prices: "/v1/prices?limit=1",
|
|
496
|
+
payouts: "/v1/payouts?limit=1",
|
|
497
|
+
refunds: "/v1/refunds?limit=1",
|
|
498
|
+
disputes: "/v1/disputes?limit=1",
|
|
499
|
+
paymentIntents: "/v1/payment_intents?limit=1"
|
|
500
|
+
};
|
|
501
|
+
var ENTITY_VALUES = Object.keys(ENTITY_PATHS);
|
|
502
|
+
async function defaultFetchEntity(params, path2) {
|
|
503
|
+
return apiFetch(params, path2);
|
|
504
|
+
}
|
|
505
|
+
function createStripeSetupFlow(fetchEntity = defaultFetchEntity, labelPrefix = "Stripe") {
|
|
506
|
+
return {
|
|
507
|
+
initialState: () => ({}),
|
|
508
|
+
steps: [
|
|
509
|
+
{
|
|
510
|
+
slug: "entities",
|
|
511
|
+
type: "multiSelect",
|
|
512
|
+
question: {
|
|
513
|
+
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",
|
|
514
|
+
en: "Select target entities (multi-select allowed)"
|
|
515
|
+
},
|
|
516
|
+
async fetchOptions(_state, rt) {
|
|
517
|
+
return ENTITY_VALUES.map((value) => ({
|
|
518
|
+
value,
|
|
519
|
+
label: ENTITY_LABELS[value][rt.language]
|
|
520
|
+
}));
|
|
521
|
+
},
|
|
522
|
+
applyAnswer: (state, answer) => ({ ...state, entities: answer })
|
|
523
|
+
}
|
|
524
|
+
],
|
|
525
|
+
async finalize(state, rt) {
|
|
526
|
+
if (!state.entities) {
|
|
527
|
+
throw new Error("Stripe setup: incomplete state on finalize");
|
|
528
|
+
}
|
|
529
|
+
const selected = state.entities.filter(
|
|
530
|
+
(e) => ENTITY_VALUES.includes(e)
|
|
531
|
+
).slice(0, STRIPE_SETUP_MAX_ENTITIES);
|
|
532
|
+
const sections = [`## ${labelPrefix}`, ""];
|
|
533
|
+
for (const entity of selected) {
|
|
534
|
+
let count = "available";
|
|
535
|
+
const res = await fetchEntity(rt.params, ENTITY_PATHS[entity]);
|
|
536
|
+
if (res.ok) {
|
|
537
|
+
const data = await res.json();
|
|
538
|
+
if (Array.isArray(data.data) && data.data.length === 0) {
|
|
539
|
+
count = "0";
|
|
540
|
+
} else if (data.has_more === false) {
|
|
541
|
+
count = String(data.data?.length ?? 1);
|
|
542
|
+
} else if (Array.isArray(data.data)) {
|
|
543
|
+
count = "1+ (paginated)";
|
|
544
|
+
}
|
|
545
|
+
} else {
|
|
546
|
+
count = "unavailable";
|
|
547
|
+
}
|
|
548
|
+
sections.push(`### ${ENTITY_LABELS[entity].en}`, "");
|
|
549
|
+
sections.push(`Status: ${count}`, "");
|
|
550
|
+
}
|
|
551
|
+
return sections.join("\n");
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
var stripeApiKeySetupFlow = createStripeSetupFlow();
|
|
556
|
+
|
|
355
557
|
// ../connectors/src/connectors/stripe-api-key/index.ts
|
|
356
558
|
var tools = { request: requestTool };
|
|
357
559
|
var stripeApiKeyConnector = new ConnectorPlugin({
|
|
@@ -469,6 +671,7 @@ const data = await res.json();
|
|
|
469
671
|
\`\`\``
|
|
470
672
|
},
|
|
471
673
|
tools,
|
|
674
|
+
setup: (params, ctx, config) => runSetupFlow(stripeApiKeySetupFlow, params, ctx, config),
|
|
472
675
|
async checkConnection(params) {
|
|
473
676
|
try {
|
|
474
677
|
const apiKey = params["api-key"];
|
|
@@ -525,6 +728,7 @@ function resolveEnvVarOptional(entry, key) {
|
|
|
525
728
|
import { getContext } from "hono/context-storage";
|
|
526
729
|
import { getCookie } from "hono/cookie";
|
|
527
730
|
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
731
|
+
var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
|
|
528
732
|
function normalizeHeaders(input) {
|
|
529
733
|
const out = {};
|
|
530
734
|
if (!input) return out;
|
|
@@ -533,6 +737,11 @@ function normalizeHeaders(input) {
|
|
|
533
737
|
});
|
|
534
738
|
return out;
|
|
535
739
|
}
|
|
740
|
+
function extractInputUrl(input) {
|
|
741
|
+
if (typeof input === "string") return input;
|
|
742
|
+
if (input instanceof URL) return input.href;
|
|
743
|
+
return input.url;
|
|
744
|
+
}
|
|
536
745
|
function createSandboxProxyFetch(connectionId) {
|
|
537
746
|
return async (input, init) => {
|
|
538
747
|
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
@@ -542,10 +751,17 @@ function createSandboxProxyFetch(connectionId) {
|
|
|
542
751
|
"Connection proxy is not configured. Please check your deployment settings."
|
|
543
752
|
);
|
|
544
753
|
}
|
|
545
|
-
const originalUrl =
|
|
754
|
+
const originalUrl = extractInputUrl(input);
|
|
755
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
756
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
757
|
+
const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
758
|
+
return fetch(sessionUrl, {
|
|
759
|
+
method: "POST",
|
|
760
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
761
|
+
});
|
|
762
|
+
}
|
|
546
763
|
const originalMethod = init?.method ?? "GET";
|
|
547
764
|
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
548
|
-
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
549
765
|
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
550
766
|
return fetch(proxyUrl, {
|
|
551
767
|
method: "POST",
|
|
@@ -571,10 +787,9 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
571
787
|
}
|
|
572
788
|
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
573
789
|
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
790
|
+
const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
574
791
|
return async (input, init) => {
|
|
575
|
-
const originalUrl =
|
|
576
|
-
const originalMethod = init?.method ?? "GET";
|
|
577
|
-
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
792
|
+
const originalUrl = extractInputUrl(input);
|
|
578
793
|
const c = getContext();
|
|
579
794
|
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
580
795
|
if (!appSession) {
|
|
@@ -582,6 +797,14 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
582
797
|
"No authentication method available for connection proxy."
|
|
583
798
|
);
|
|
584
799
|
}
|
|
800
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
801
|
+
return fetch(sessionUrl, {
|
|
802
|
+
method: "POST",
|
|
803
|
+
headers: { Authorization: `Bearer ${appSession}` }
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
const originalMethod = init?.method ?? "GET";
|
|
807
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
585
808
|
return fetch(proxyUrl, {
|
|
586
809
|
method: "POST",
|
|
587
810
|
headers: {
|
|
@@ -67,6 +67,28 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
67
67
|
tools;
|
|
68
68
|
query;
|
|
69
69
|
checkConnection;
|
|
70
|
+
/**
|
|
71
|
+
* SQPD-1212: Logic-based, rule-driven connection setup. Connectors that
|
|
72
|
+
* implement this expose a step-by-step exploration flow (database/schema/
|
|
73
|
+
* table/etc. discovery) that the dashboard backend drives via the
|
|
74
|
+
* `/connections/:connectionId/setup` endpoint. Implement by delegating to
|
|
75
|
+
* `runSetupFlow` from `setup-flow.ts`.
|
|
76
|
+
*/
|
|
77
|
+
setup;
|
|
78
|
+
/**
|
|
79
|
+
* Opt-out of the default "verify before save" behavior on connection
|
|
80
|
+
* creation. The backend invokes `checkConnection` synchronously while
|
|
81
|
+
* creating the connection and aborts (no row inserted) if it fails — this
|
|
82
|
+
* flag disables that for connectors where the check cannot succeed pre-save:
|
|
83
|
+
*
|
|
84
|
+
* - `squadbase-db` populates `connection-url` only after Neon provisioning
|
|
85
|
+
* - OAuth connectors require an OAuth-aware proxyFetch keyed by the
|
|
86
|
+
* connectionId, which doesn't exist until the row is saved
|
|
87
|
+
*
|
|
88
|
+
* Exceptions are the explicit position; new credential-input connectors get
|
|
89
|
+
* the default verify-on-create behavior without opt-in.
|
|
90
|
+
*/
|
|
91
|
+
skipConnectionCheckOnCreate;
|
|
70
92
|
constructor(config) {
|
|
71
93
|
this.slug = config.slug;
|
|
72
94
|
this.authType = config.authType;
|
|
@@ -83,6 +105,8 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
83
105
|
this.tools = config.tools;
|
|
84
106
|
this.query = config.query;
|
|
85
107
|
this.checkConnection = config.checkConnection;
|
|
108
|
+
this.setup = config.setup;
|
|
109
|
+
this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
|
|
86
110
|
}
|
|
87
111
|
get connectorKey() {
|
|
88
112
|
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
@@ -147,6 +171,71 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
147
171
|
}
|
|
148
172
|
};
|
|
149
173
|
|
|
174
|
+
// ../connectors/src/setup-flow.ts
|
|
175
|
+
async function runSetupFlow(flow, params, ctx, config) {
|
|
176
|
+
const runtime = {
|
|
177
|
+
params,
|
|
178
|
+
language: ctx.language,
|
|
179
|
+
config
|
|
180
|
+
};
|
|
181
|
+
let state = flow.initialState();
|
|
182
|
+
let answerIdx = 0;
|
|
183
|
+
const pendingParameterUpdates = [];
|
|
184
|
+
for (const step of flow.steps) {
|
|
185
|
+
const ans = ctx.answers[answerIdx];
|
|
186
|
+
if (ans && ans.questionSlug === step.slug) {
|
|
187
|
+
state = step.applyAnswer(state, ans.answer);
|
|
188
|
+
if (step.toParameterUpdates) {
|
|
189
|
+
pendingParameterUpdates.push(...step.toParameterUpdates(state));
|
|
190
|
+
}
|
|
191
|
+
answerIdx += 1;
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
|
|
195
|
+
if (step.type === "text") {
|
|
196
|
+
if (step.fetchOptions) {
|
|
197
|
+
const options2 = await step.fetchOptions(state, runtime);
|
|
198
|
+
if (options2.length === 0) {
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
type: "nextQuestion",
|
|
204
|
+
questionSlug: step.slug,
|
|
205
|
+
question: step.question[ctx.language],
|
|
206
|
+
questionType: "text",
|
|
207
|
+
allowFreeText: resolvedAllowFreeText,
|
|
208
|
+
...pendingParameterUpdates.length > 0 && {
|
|
209
|
+
parameterUpdates: pendingParameterUpdates
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
214
|
+
if (options.length === 0) {
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
type: "nextQuestion",
|
|
219
|
+
questionSlug: step.slug,
|
|
220
|
+
question: step.question[ctx.language],
|
|
221
|
+
questionType: step.type,
|
|
222
|
+
options,
|
|
223
|
+
allowFreeText: resolvedAllowFreeText,
|
|
224
|
+
...pendingParameterUpdates.length > 0 && {
|
|
225
|
+
parameterUpdates: pendingParameterUpdates
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
230
|
+
return {
|
|
231
|
+
type: "fulfilled",
|
|
232
|
+
dataInvestigationResult,
|
|
233
|
+
...pendingParameterUpdates.length > 0 && {
|
|
234
|
+
parameterUpdates: pendingParameterUpdates
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
150
239
|
// ../connectors/src/auth-types.ts
|
|
151
240
|
var AUTH_TYPES = {
|
|
152
241
|
OAUTH: "oauth",
|
|
@@ -310,11 +399,98 @@ var stripeOnboarding = new ConnectorOnboarding({
|
|
|
310
399
|
// ../connectors/src/connectors/stripe-oauth/parameters.ts
|
|
311
400
|
var parameters = {};
|
|
312
401
|
|
|
402
|
+
// ../connectors/src/connectors/stripe-oauth/setup-flow.ts
|
|
403
|
+
var BASE_URL3 = "https://api.stripe.com";
|
|
404
|
+
var STRIPE_OAUTH_SETUP_MAX_ENTITIES = 10;
|
|
405
|
+
var ENTITY_LABELS = {
|
|
406
|
+
customers: { en: "Customers", ja: "Customers (\u9867\u5BA2)" },
|
|
407
|
+
charges: { en: "Charges", ja: "Charges (\u652F\u6255\u3044)" },
|
|
408
|
+
invoices: { en: "Invoices", ja: "Invoices (\u8ACB\u6C42\u66F8)" },
|
|
409
|
+
subscriptions: {
|
|
410
|
+
en: "Subscriptions",
|
|
411
|
+
ja: "Subscriptions (\u30B5\u30D6\u30B9\u30AF\u30EA\u30D7\u30B7\u30E7\u30F3)"
|
|
412
|
+
},
|
|
413
|
+
products: { en: "Products", ja: "Products (\u5546\u54C1)" },
|
|
414
|
+
prices: { en: "Prices", ja: "Prices (\u4FA1\u683C)" },
|
|
415
|
+
payouts: { en: "Payouts", ja: "Payouts (\u652F\u6255\u3044)" },
|
|
416
|
+
refunds: { en: "Refunds", ja: "Refunds (\u8FD4\u91D1)" },
|
|
417
|
+
disputes: { en: "Disputes", ja: "Disputes (\u7570\u8B70)" },
|
|
418
|
+
paymentIntents: {
|
|
419
|
+
en: "Payment intents",
|
|
420
|
+
ja: "Payment intents (\u652F\u6255\u3044\u30A4\u30F3\u30C6\u30F3\u30C8)"
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
var ENTITY_PATHS = {
|
|
424
|
+
customers: "/v1/customers?limit=1",
|
|
425
|
+
charges: "/v1/charges?limit=1",
|
|
426
|
+
invoices: "/v1/invoices?limit=1",
|
|
427
|
+
subscriptions: "/v1/subscriptions?limit=1",
|
|
428
|
+
products: "/v1/products?limit=1",
|
|
429
|
+
prices: "/v1/prices?limit=1",
|
|
430
|
+
payouts: "/v1/payouts?limit=1",
|
|
431
|
+
refunds: "/v1/refunds?limit=1",
|
|
432
|
+
disputes: "/v1/disputes?limit=1",
|
|
433
|
+
paymentIntents: "/v1/payment_intents?limit=1"
|
|
434
|
+
};
|
|
435
|
+
var ENTITY_VALUES = Object.keys(ENTITY_PATHS);
|
|
436
|
+
var stripeOauthSetupFlow = {
|
|
437
|
+
initialState: () => ({}),
|
|
438
|
+
steps: [
|
|
439
|
+
{
|
|
440
|
+
slug: "entities",
|
|
441
|
+
type: "multiSelect",
|
|
442
|
+
question: {
|
|
443
|
+
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",
|
|
444
|
+
en: "Select target entities (multi-select allowed)"
|
|
445
|
+
},
|
|
446
|
+
async fetchOptions(_state, rt) {
|
|
447
|
+
return ENTITY_VALUES.map((value) => ({
|
|
448
|
+
value,
|
|
449
|
+
label: ENTITY_LABELS[value][rt.language]
|
|
450
|
+
}));
|
|
451
|
+
},
|
|
452
|
+
applyAnswer: (state, answer) => ({ ...state, entities: answer })
|
|
453
|
+
}
|
|
454
|
+
],
|
|
455
|
+
async finalize(state, rt) {
|
|
456
|
+
if (!state.entities) {
|
|
457
|
+
throw new Error("Stripe setup: incomplete state on finalize");
|
|
458
|
+
}
|
|
459
|
+
const selected = state.entities.filter(
|
|
460
|
+
(e) => ENTITY_VALUES.includes(e)
|
|
461
|
+
).slice(0, STRIPE_OAUTH_SETUP_MAX_ENTITIES);
|
|
462
|
+
const sections = ["## Stripe", ""];
|
|
463
|
+
for (const entity of selected) {
|
|
464
|
+
let count = "available";
|
|
465
|
+
const res = await rt.config.proxyFetch(
|
|
466
|
+
`${BASE_URL3}${ENTITY_PATHS[entity]}`,
|
|
467
|
+
{ method: "GET" }
|
|
468
|
+
);
|
|
469
|
+
if (res.ok) {
|
|
470
|
+
const data = await res.json();
|
|
471
|
+
if (Array.isArray(data.data) && data.data.length === 0) {
|
|
472
|
+
count = "0";
|
|
473
|
+
} else if (data.has_more === false) {
|
|
474
|
+
count = String(data.data?.length ?? 1);
|
|
475
|
+
} else if (Array.isArray(data.data)) {
|
|
476
|
+
count = "1+ (paginated)";
|
|
477
|
+
}
|
|
478
|
+
} else {
|
|
479
|
+
count = "unavailable";
|
|
480
|
+
}
|
|
481
|
+
sections.push(`### ${ENTITY_LABELS[entity].en}`, "");
|
|
482
|
+
sections.push(`Status: ${count}`, "");
|
|
483
|
+
}
|
|
484
|
+
return sections.join("\n");
|
|
485
|
+
}
|
|
486
|
+
};
|
|
487
|
+
|
|
313
488
|
// ../connectors/src/connectors/stripe-oauth/index.ts
|
|
314
489
|
var tools = { request: requestTool };
|
|
315
490
|
var stripeOauthConnector = new ConnectorPlugin({
|
|
316
491
|
slug: "stripe",
|
|
317
492
|
authType: AUTH_TYPES.OAUTH,
|
|
493
|
+
skipConnectionCheckOnCreate: true,
|
|
318
494
|
name: "Stripe",
|
|
319
495
|
description: "Connect to Stripe for payment, customer, and subscription data using OAuth.",
|
|
320
496
|
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/2QNK0u2doqp41uL0POS4Ks/7a92367e2388ec77c7f4ada143606f9a/stripe.jpeg",
|
|
@@ -431,6 +607,7 @@ const data = await res.json();
|
|
|
431
607
|
\`\`\``
|
|
432
608
|
},
|
|
433
609
|
tools,
|
|
610
|
+
setup: (params, ctx, config) => runSetupFlow(stripeOauthSetupFlow, params, ctx, config),
|
|
434
611
|
async checkConnection(_params, config) {
|
|
435
612
|
const { proxyFetch } = config;
|
|
436
613
|
try {
|
|
@@ -480,6 +657,7 @@ function resolveEnvVarOptional(entry, key) {
|
|
|
480
657
|
import { getContext } from "hono/context-storage";
|
|
481
658
|
import { getCookie } from "hono/cookie";
|
|
482
659
|
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
660
|
+
var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
|
|
483
661
|
function normalizeHeaders(input) {
|
|
484
662
|
const out = {};
|
|
485
663
|
if (!input) return out;
|
|
@@ -488,6 +666,11 @@ function normalizeHeaders(input) {
|
|
|
488
666
|
});
|
|
489
667
|
return out;
|
|
490
668
|
}
|
|
669
|
+
function extractInputUrl(input) {
|
|
670
|
+
if (typeof input === "string") return input;
|
|
671
|
+
if (input instanceof URL) return input.href;
|
|
672
|
+
return input.url;
|
|
673
|
+
}
|
|
491
674
|
function createSandboxProxyFetch(connectionId) {
|
|
492
675
|
return async (input, init) => {
|
|
493
676
|
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
@@ -497,10 +680,17 @@ function createSandboxProxyFetch(connectionId) {
|
|
|
497
680
|
"Connection proxy is not configured. Please check your deployment settings."
|
|
498
681
|
);
|
|
499
682
|
}
|
|
500
|
-
const originalUrl =
|
|
683
|
+
const originalUrl = extractInputUrl(input);
|
|
684
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
685
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
686
|
+
const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
687
|
+
return fetch(sessionUrl, {
|
|
688
|
+
method: "POST",
|
|
689
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
690
|
+
});
|
|
691
|
+
}
|
|
501
692
|
const originalMethod = init?.method ?? "GET";
|
|
502
693
|
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
503
|
-
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
504
694
|
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
505
695
|
return fetch(proxyUrl, {
|
|
506
696
|
method: "POST",
|
|
@@ -526,10 +716,9 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
526
716
|
}
|
|
527
717
|
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
528
718
|
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
719
|
+
const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
529
720
|
return async (input, init) => {
|
|
530
|
-
const originalUrl =
|
|
531
|
-
const originalMethod = init?.method ?? "GET";
|
|
532
|
-
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
721
|
+
const originalUrl = extractInputUrl(input);
|
|
533
722
|
const c = getContext();
|
|
534
723
|
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
535
724
|
if (!appSession) {
|
|
@@ -537,6 +726,14 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
537
726
|
"No authentication method available for connection proxy."
|
|
538
727
|
);
|
|
539
728
|
}
|
|
729
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
730
|
+
return fetch(sessionUrl, {
|
|
731
|
+
method: "POST",
|
|
732
|
+
headers: { Authorization: `Bearer ${appSession}` }
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
const originalMethod = init?.method ?? "GET";
|
|
736
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
540
737
|
return fetch(proxyUrl, {
|
|
541
738
|
method: "POST",
|
|
542
739
|
headers: {
|