@squadbase/vite-server 0.1.12-dev.93b8799 → 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 +12128 -934
- package/dist/connectors/airtable-oauth.js +248 -46
- package/dist/connectors/airtable.js +285 -51
- package/dist/connectors/amplitude.js +288 -47
- package/dist/connectors/anthropic.js +126 -47
- package/dist/connectors/asana.js +293 -49
- package/dist/connectors/attio.js +268 -49
- package/dist/connectors/aws-billing.js +253 -46
- package/dist/connectors/azure-sql.js +387 -102
- package/dist/connectors/backlog-api-key.js +283 -47
- package/dist/connectors/clickup.js +304 -49
- package/dist/connectors/cosmosdb.js +271 -50
- package/dist/connectors/customerio.js +285 -47
- package/dist/connectors/dbt.js +306 -47
- package/dist/connectors/freshdesk.js +308 -53
- package/dist/connectors/freshsales.js +299 -52
- package/dist/connectors/freshservice.js +327 -53
- package/dist/connectors/gamma.js +293 -52
- package/dist/connectors/gemini.js +125 -47
- package/dist/connectors/github.js +352 -49
- package/dist/connectors/gmail-oauth.js +170 -7
- package/dist/connectors/gmail.js +316 -47
- package/dist/connectors/google-ads.js +254 -46
- package/dist/connectors/google-analytics-oauth.js +276 -46
- package/dist/connectors/google-analytics.js +378 -49
- package/dist/connectors/google-audit-log.js +404 -47
- package/dist/connectors/google-calendar-oauth.js +225 -46
- package/dist/connectors/google-calendar.js +325 -47
- package/dist/connectors/google-docs.js +186 -6
- package/dist/connectors/google-drive.js +228 -5
- package/dist/connectors/google-search-console-oauth.js +222 -46
- package/dist/connectors/google-sheets.js +238 -47
- package/dist/connectors/google-slides.js +171 -6
- package/dist/connectors/grafana.js +298 -49
- package/dist/connectors/hubspot-oauth.js +174 -5
- package/dist/connectors/hubspot.js +272 -49
- package/dist/connectors/influxdb.js +382 -51
- package/dist/connectors/intercom-oauth.js +176 -5
- package/dist/connectors/intercom.js +268 -49
- package/dist/connectors/jdbc.js +728 -110
- package/dist/connectors/jira-api-key.js +292 -47
- package/dist/connectors/kintone-api-token.js +247 -47
- package/dist/connectors/kintone.js +294 -47
- package/dist/connectors/linear.js +296 -49
- package/dist/connectors/linkedin-ads.js +234 -50
- package/dist/connectors/mailchimp-oauth.js +234 -46
- package/dist/connectors/mailchimp.js +286 -49
- package/dist/connectors/meta-ads-oauth.js +239 -48
- package/dist/connectors/meta-ads.js +251 -50
- package/dist/connectors/mixpanel.js +304 -47
- package/dist/connectors/monday.js +326 -49
- package/dist/connectors/mongodb.js +285 -57
- package/dist/connectors/notion-oauth.js +197 -5
- package/dist/connectors/notion.js +289 -51
- package/dist/connectors/openai.js +125 -47
- package/dist/connectors/oracle.js +405 -103
- package/dist/connectors/outlook-oauth.js +170 -5
- package/dist/connectors/powerbi-oauth.js +217 -5
- package/dist/connectors/salesforce.js +350 -49
- package/dist/connectors/semrush.js +280 -49
- package/dist/connectors/sentry.js +255 -50
- package/dist/connectors/shopify-oauth.js +153 -5
- package/dist/connectors/shopify.js +323 -47
- package/dist/connectors/sqlserver.js +381 -102
- package/dist/connectors/stripe-api-key.js +235 -46
- package/dist/connectors/stripe-oauth.js +168 -5
- package/dist/connectors/supabase.js +269 -48
- package/dist/connectors/tableau.js +337 -206
- package/dist/connectors/tiktok-ads.js +245 -48
- package/dist/connectors/wix-store.js +286 -49
- package/dist/connectors/zendesk-oauth.js +205 -5
- package/dist/connectors/zendesk.js +324 -47
- package/dist/index.d.ts +149 -1
- package/dist/index.js +18297 -6886
- package/dist/main.js +12785 -1382
- package/dist/vite-plugin.js +12140 -936
- package/package.json +1 -1
|
@@ -1,46 +1,57 @@
|
|
|
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/google-sheets/sdk/index.ts
|
|
46
57
|
var SHEETS_BASE_URL = "https://sheets.googleapis.com/v4/spreadsheets";
|
|
@@ -191,6 +202,20 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
191
202
|
* `runSetupFlow` from `setup-flow.ts`.
|
|
192
203
|
*/
|
|
193
204
|
setup;
|
|
205
|
+
/**
|
|
206
|
+
* Opt-out of the default "verify before save" behavior on connection
|
|
207
|
+
* creation. The backend invokes `checkConnection` synchronously while
|
|
208
|
+
* creating the connection and aborts (no row inserted) if it fails — this
|
|
209
|
+
* flag disables that for connectors where the check cannot succeed pre-save:
|
|
210
|
+
*
|
|
211
|
+
* - `squadbase-db` populates `connection-url` only after Neon provisioning
|
|
212
|
+
* - OAuth connectors require an OAuth-aware proxyFetch keyed by the
|
|
213
|
+
* connectionId, which doesn't exist until the row is saved
|
|
214
|
+
*
|
|
215
|
+
* Exceptions are the explicit position; new credential-input connectors get
|
|
216
|
+
* the default verify-on-create behavior without opt-in.
|
|
217
|
+
*/
|
|
218
|
+
skipConnectionCheckOnCreate;
|
|
194
219
|
constructor(config) {
|
|
195
220
|
this.slug = config.slug;
|
|
196
221
|
this.authType = config.authType;
|
|
@@ -208,6 +233,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
208
233
|
this.query = config.query;
|
|
209
234
|
this.checkConnection = config.checkConnection;
|
|
210
235
|
this.setup = config.setup;
|
|
236
|
+
this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
|
|
211
237
|
}
|
|
212
238
|
get connectorKey() {
|
|
213
239
|
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
@@ -272,6 +298,51 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
272
298
|
}
|
|
273
299
|
};
|
|
274
300
|
|
|
301
|
+
// ../connectors/src/setup-flow.ts
|
|
302
|
+
async function runSetupFlow(flow, params, ctx, config) {
|
|
303
|
+
const runtime = {
|
|
304
|
+
params,
|
|
305
|
+
language: ctx.language,
|
|
306
|
+
config
|
|
307
|
+
};
|
|
308
|
+
let state = flow.initialState();
|
|
309
|
+
let answerIdx = 0;
|
|
310
|
+
for (const step of flow.steps) {
|
|
311
|
+
const ans = ctx.answers[answerIdx];
|
|
312
|
+
if (ans && ans.questionSlug === step.slug) {
|
|
313
|
+
state = step.applyAnswer(state, ans.answer);
|
|
314
|
+
answerIdx += 1;
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
if (step.type === "text") {
|
|
318
|
+
return {
|
|
319
|
+
type: "nextQuestion",
|
|
320
|
+
questionSlug: step.slug,
|
|
321
|
+
question: step.question[ctx.language],
|
|
322
|
+
questionType: "text"
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
326
|
+
if (options.length === 0) {
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
return {
|
|
330
|
+
type: "nextQuestion",
|
|
331
|
+
questionSlug: step.slug,
|
|
332
|
+
question: step.question[ctx.language],
|
|
333
|
+
questionType: step.type,
|
|
334
|
+
options
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
338
|
+
return { type: "fulfilled", dataInvestigationResult };
|
|
339
|
+
}
|
|
340
|
+
async function resolveSetupSelection(params) {
|
|
341
|
+
const { selected, allSentinel, fetchAll, limit } = params;
|
|
342
|
+
const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
|
|
343
|
+
return resolved.slice(0, limit);
|
|
344
|
+
}
|
|
345
|
+
|
|
275
346
|
// ../connectors/src/auth-types.ts
|
|
276
347
|
var AUTH_TYPES = {
|
|
277
348
|
OAUTH: "oauth",
|
|
@@ -470,7 +541,105 @@ var googleSheetsOnboarding = new ConnectorOnboarding({
|
|
|
470
541
|
}
|
|
471
542
|
});
|
|
472
543
|
|
|
544
|
+
// ../connectors/src/connectors/google-sheets/utils.ts
|
|
545
|
+
async function googleApiFetch(config, url) {
|
|
546
|
+
const res = await config.proxyFetch(url, { method: "GET" });
|
|
547
|
+
if (!res.ok) {
|
|
548
|
+
const text = await res.text().catch(() => res.statusText);
|
|
549
|
+
throw new Error(`Google API ${url} failed: HTTP ${res.status} ${text}`);
|
|
550
|
+
}
|
|
551
|
+
return await res.json();
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// ../connectors/src/connectors/google-sheets/setup-flow.ts
|
|
555
|
+
var ALL_SPREADSHEETS = "__ALL_SPREADSHEETS__";
|
|
556
|
+
var GOOGLE_SHEETS_SETUP_MAX_SPREADSHEETS = 10;
|
|
557
|
+
var DRIVE_LIST_PAGE_SIZE = 50;
|
|
558
|
+
async function listSpreadsheets(config) {
|
|
559
|
+
const q = encodeURIComponent(
|
|
560
|
+
"mimeType='application/vnd.google-apps.spreadsheet' and trashed=false"
|
|
561
|
+
);
|
|
562
|
+
const url = `https://www.googleapis.com/drive/v3/files?q=${q}&pageSize=${DRIVE_LIST_PAGE_SIZE}&orderBy=modifiedTime%20desc&fields=files(id,name,modifiedTime)`;
|
|
563
|
+
const data = await googleApiFetch(config, url);
|
|
564
|
+
return data.files ?? [];
|
|
565
|
+
}
|
|
566
|
+
var googleSheetsSetupFlow = {
|
|
567
|
+
initialState: () => ({}),
|
|
568
|
+
steps: [
|
|
569
|
+
{
|
|
570
|
+
slug: "spreadsheets",
|
|
571
|
+
type: "multiSelect",
|
|
572
|
+
question: {
|
|
573
|
+
ja: "\u5BFE\u8C61\u306E\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
574
|
+
en: "Select target spreadsheets (multi-select allowed)"
|
|
575
|
+
},
|
|
576
|
+
async fetchOptions(_state, rt) {
|
|
577
|
+
const files = await listSpreadsheets(rt.config);
|
|
578
|
+
const fileOptions = files.map((f) => ({
|
|
579
|
+
value: f.id,
|
|
580
|
+
label: f.name
|
|
581
|
+
}));
|
|
582
|
+
return [
|
|
583
|
+
{
|
|
584
|
+
value: ALL_SPREADSHEETS,
|
|
585
|
+
label: rt.language === "ja" ? "\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u3059\u3079\u3066\u306E\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8" : "All accessible spreadsheets"
|
|
586
|
+
},
|
|
587
|
+
...fileOptions
|
|
588
|
+
];
|
|
589
|
+
},
|
|
590
|
+
applyAnswer: (state, answer) => ({ ...state, spreadsheets: answer })
|
|
591
|
+
}
|
|
592
|
+
],
|
|
593
|
+
async finalize(state, rt) {
|
|
594
|
+
if (!state.spreadsheets) {
|
|
595
|
+
throw new Error("Google Sheets setup: incomplete state on finalize");
|
|
596
|
+
}
|
|
597
|
+
const targetIds = await resolveSetupSelection({
|
|
598
|
+
selected: state.spreadsheets,
|
|
599
|
+
allSentinel: ALL_SPREADSHEETS,
|
|
600
|
+
fetchAll: async () => {
|
|
601
|
+
const files = await listSpreadsheets(rt.config);
|
|
602
|
+
return files.map((f) => f.id);
|
|
603
|
+
},
|
|
604
|
+
limit: GOOGLE_SHEETS_SETUP_MAX_SPREADSHEETS
|
|
605
|
+
});
|
|
606
|
+
const sections = ["## Google Sheets", ""];
|
|
607
|
+
if (targetIds.length === 0) {
|
|
608
|
+
sections.push(
|
|
609
|
+
rt.language === "ja" ? "\u5BFE\u8C61\u306E\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002" : "No spreadsheets selected."
|
|
610
|
+
);
|
|
611
|
+
return sections.join("\n");
|
|
612
|
+
}
|
|
613
|
+
for (const id of targetIds) {
|
|
614
|
+
const url = `https://sheets.googleapis.com/v4/spreadsheets/${encodeURIComponent(id)}?fields=spreadsheetId,properties(title),sheets(properties(title,sheetId,gridProperties))`;
|
|
615
|
+
const meta = await googleApiFetch(
|
|
616
|
+
rt.config,
|
|
617
|
+
url
|
|
618
|
+
);
|
|
619
|
+
const title = meta.properties?.title ?? id;
|
|
620
|
+
sections.push(`### Spreadsheet: ${title}`, "", `- ID: ${id}`, "");
|
|
621
|
+
const sheets = meta.sheets ?? [];
|
|
622
|
+
if (sheets.length === 0) {
|
|
623
|
+
sections.push("- (no sheet tabs)", "");
|
|
624
|
+
continue;
|
|
625
|
+
}
|
|
626
|
+
sections.push("| Sheet | Rows | Columns |");
|
|
627
|
+
sections.push("|-------|------|---------|");
|
|
628
|
+
for (const s of sheets) {
|
|
629
|
+
const p = s.properties ?? {};
|
|
630
|
+
const sheetTitle = p.title ?? "(untitled)";
|
|
631
|
+
const rows = p.gridProperties?.rowCount ?? "-";
|
|
632
|
+
const cols = p.gridProperties?.columnCount ?? "-";
|
|
633
|
+
sections.push(`| ${sheetTitle} | ${rows} | ${cols} |`);
|
|
634
|
+
}
|
|
635
|
+
sections.push("");
|
|
636
|
+
}
|
|
637
|
+
return sections.join("\n");
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
|
|
473
641
|
// ../connectors/src/connectors/google-sheets/parameters.ts
|
|
642
|
+
init_parameter_definition();
|
|
474
643
|
var parameters = {
|
|
475
644
|
spreadsheetId: new ParameterDefinition({
|
|
476
645
|
slug: "spreadsheet-id",
|
|
@@ -488,6 +657,7 @@ var tools = { request: requestTool };
|
|
|
488
657
|
var googleSheetsConnector = new ConnectorPlugin({
|
|
489
658
|
slug: "google-sheets",
|
|
490
659
|
authType: AUTH_TYPES.OAUTH,
|
|
660
|
+
skipConnectionCheckOnCreate: true,
|
|
491
661
|
name: "Google Sheets",
|
|
492
662
|
description: "Connect to Google Sheets for read/write access via OAuth. Any spreadsheet the authenticated Google account can access is supported \u2014 the target spreadsheetId is passed per call.",
|
|
493
663
|
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/1UPQuggyiZmbb26CuaSr2h/032770e8739b183fa00b7625f024e536/google-sheets.svg",
|
|
@@ -653,7 +823,8 @@ await sheets.batchUpdate(spreadsheetId, [
|
|
|
653
823
|
]);
|
|
654
824
|
\`\`\``
|
|
655
825
|
},
|
|
656
|
-
tools
|
|
826
|
+
tools,
|
|
827
|
+
setup: (params, ctx, config) => runSetupFlow(googleSheetsSetupFlow, params, ctx, config)
|
|
657
828
|
});
|
|
658
829
|
|
|
659
830
|
// src/connectors/create-connector-sdk.ts
|
|
@@ -682,6 +853,7 @@ function resolveEnvVarOptional(entry, key) {
|
|
|
682
853
|
import { getContext } from "hono/context-storage";
|
|
683
854
|
import { getCookie } from "hono/cookie";
|
|
684
855
|
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
856
|
+
var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
|
|
685
857
|
function normalizeHeaders(input) {
|
|
686
858
|
const out = {};
|
|
687
859
|
if (!input) return out;
|
|
@@ -690,6 +862,11 @@ function normalizeHeaders(input) {
|
|
|
690
862
|
});
|
|
691
863
|
return out;
|
|
692
864
|
}
|
|
865
|
+
function extractInputUrl(input) {
|
|
866
|
+
if (typeof input === "string") return input;
|
|
867
|
+
if (input instanceof URL) return input.href;
|
|
868
|
+
return input.url;
|
|
869
|
+
}
|
|
693
870
|
function createSandboxProxyFetch(connectionId) {
|
|
694
871
|
return async (input, init) => {
|
|
695
872
|
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
@@ -699,10 +876,17 @@ function createSandboxProxyFetch(connectionId) {
|
|
|
699
876
|
"Connection proxy is not configured. Please check your deployment settings."
|
|
700
877
|
);
|
|
701
878
|
}
|
|
702
|
-
const originalUrl =
|
|
879
|
+
const originalUrl = extractInputUrl(input);
|
|
880
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
881
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
882
|
+
const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
883
|
+
return fetch(sessionUrl, {
|
|
884
|
+
method: "POST",
|
|
885
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
886
|
+
});
|
|
887
|
+
}
|
|
703
888
|
const originalMethod = init?.method ?? "GET";
|
|
704
889
|
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
705
|
-
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
706
890
|
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
707
891
|
return fetch(proxyUrl, {
|
|
708
892
|
method: "POST",
|
|
@@ -728,10 +912,9 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
728
912
|
}
|
|
729
913
|
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
730
914
|
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
915
|
+
const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
731
916
|
return async (input, init) => {
|
|
732
|
-
const originalUrl =
|
|
733
|
-
const originalMethod = init?.method ?? "GET";
|
|
734
|
-
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
917
|
+
const originalUrl = extractInputUrl(input);
|
|
735
918
|
const c = getContext();
|
|
736
919
|
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
737
920
|
if (!appSession) {
|
|
@@ -739,6 +922,14 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
739
922
|
"No authentication method available for connection proxy."
|
|
740
923
|
);
|
|
741
924
|
}
|
|
925
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
926
|
+
return fetch(sessionUrl, {
|
|
927
|
+
method: "POST",
|
|
928
|
+
headers: { Authorization: `Bearer ${appSession}` }
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
const originalMethod = init?.method ?? "GET";
|
|
932
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
742
933
|
return fetch(proxyUrl, {
|
|
743
934
|
method: "POST",
|
|
744
935
|
headers: {
|
|
@@ -133,6 +133,20 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
133
133
|
* `runSetupFlow` from `setup-flow.ts`.
|
|
134
134
|
*/
|
|
135
135
|
setup;
|
|
136
|
+
/**
|
|
137
|
+
* Opt-out of the default "verify before save" behavior on connection
|
|
138
|
+
* creation. The backend invokes `checkConnection` synchronously while
|
|
139
|
+
* creating the connection and aborts (no row inserted) if it fails — this
|
|
140
|
+
* flag disables that for connectors where the check cannot succeed pre-save:
|
|
141
|
+
*
|
|
142
|
+
* - `squadbase-db` populates `connection-url` only after Neon provisioning
|
|
143
|
+
* - OAuth connectors require an OAuth-aware proxyFetch keyed by the
|
|
144
|
+
* connectionId, which doesn't exist until the row is saved
|
|
145
|
+
*
|
|
146
|
+
* Exceptions are the explicit position; new credential-input connectors get
|
|
147
|
+
* the default verify-on-create behavior without opt-in.
|
|
148
|
+
*/
|
|
149
|
+
skipConnectionCheckOnCreate;
|
|
136
150
|
constructor(config) {
|
|
137
151
|
this.slug = config.slug;
|
|
138
152
|
this.authType = config.authType;
|
|
@@ -150,6 +164,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
150
164
|
this.query = config.query;
|
|
151
165
|
this.checkConnection = config.checkConnection;
|
|
152
166
|
this.setup = config.setup;
|
|
167
|
+
this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
|
|
153
168
|
}
|
|
154
169
|
get connectorKey() {
|
|
155
170
|
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
@@ -214,6 +229,51 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
214
229
|
}
|
|
215
230
|
};
|
|
216
231
|
|
|
232
|
+
// ../connectors/src/setup-flow.ts
|
|
233
|
+
async function runSetupFlow(flow, params, ctx, config) {
|
|
234
|
+
const runtime = {
|
|
235
|
+
params,
|
|
236
|
+
language: ctx.language,
|
|
237
|
+
config
|
|
238
|
+
};
|
|
239
|
+
let state = flow.initialState();
|
|
240
|
+
let answerIdx = 0;
|
|
241
|
+
for (const step of flow.steps) {
|
|
242
|
+
const ans = ctx.answers[answerIdx];
|
|
243
|
+
if (ans && ans.questionSlug === step.slug) {
|
|
244
|
+
state = step.applyAnswer(state, ans.answer);
|
|
245
|
+
answerIdx += 1;
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
if (step.type === "text") {
|
|
249
|
+
return {
|
|
250
|
+
type: "nextQuestion",
|
|
251
|
+
questionSlug: step.slug,
|
|
252
|
+
question: step.question[ctx.language],
|
|
253
|
+
questionType: "text"
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
257
|
+
if (options.length === 0) {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
type: "nextQuestion",
|
|
262
|
+
questionSlug: step.slug,
|
|
263
|
+
question: step.question[ctx.language],
|
|
264
|
+
questionType: step.type,
|
|
265
|
+
options
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
269
|
+
return { type: "fulfilled", dataInvestigationResult };
|
|
270
|
+
}
|
|
271
|
+
async function resolveSetupSelection(params) {
|
|
272
|
+
const { selected, allSentinel, fetchAll, limit } = params;
|
|
273
|
+
const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
|
|
274
|
+
return resolved.slice(0, limit);
|
|
275
|
+
}
|
|
276
|
+
|
|
217
277
|
// ../connectors/src/auth-types.ts
|
|
218
278
|
var AUTH_TYPES = {
|
|
219
279
|
OAUTH: "oauth",
|
|
@@ -244,6 +304,89 @@ var googleSlidesOnboarding = new ConnectorOnboarding({
|
|
|
244
304
|
}
|
|
245
305
|
});
|
|
246
306
|
|
|
307
|
+
// ../connectors/src/connectors/google-slides/utils.ts
|
|
308
|
+
async function googleApiFetch(config, url) {
|
|
309
|
+
const res = await config.proxyFetch(url, { method: "GET" });
|
|
310
|
+
if (!res.ok) {
|
|
311
|
+
const text = await res.text().catch(() => res.statusText);
|
|
312
|
+
throw new Error(`Google Slides ${url} failed: HTTP ${res.status} ${text}`);
|
|
313
|
+
}
|
|
314
|
+
return await res.json();
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// ../connectors/src/connectors/google-slides/setup-flow.ts
|
|
318
|
+
var ALL_PRESENTATIONS = "__ALL_PRESENTATIONS__";
|
|
319
|
+
var GOOGLE_SLIDES_SETUP_MAX_PRESENTATIONS = 10;
|
|
320
|
+
var DRIVE_LIST_PAGE_SIZE = 50;
|
|
321
|
+
async function listPresentations(config) {
|
|
322
|
+
const q = encodeURIComponent(
|
|
323
|
+
"mimeType='application/vnd.google-apps.presentation' and trashed=false"
|
|
324
|
+
);
|
|
325
|
+
const url = `https://www.googleapis.com/drive/v3/files?q=${q}&pageSize=${DRIVE_LIST_PAGE_SIZE}&orderBy=modifiedTime%20desc&fields=files(id,name,modifiedTime)`;
|
|
326
|
+
const data = await googleApiFetch(config, url);
|
|
327
|
+
return data.files ?? [];
|
|
328
|
+
}
|
|
329
|
+
var googleSlidesSetupFlow = {
|
|
330
|
+
initialState: () => ({}),
|
|
331
|
+
steps: [
|
|
332
|
+
{
|
|
333
|
+
slug: "presentations",
|
|
334
|
+
type: "multiSelect",
|
|
335
|
+
question: {
|
|
336
|
+
ja: "\u5BFE\u8C61\u306E\u30D7\u30EC\u30BC\u30F3\u30C6\u30FC\u30B7\u30E7\u30F3\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
337
|
+
en: "Select target presentations (multi-select allowed)"
|
|
338
|
+
},
|
|
339
|
+
async fetchOptions(_state, rt) {
|
|
340
|
+
const files = await listPresentations(rt.config);
|
|
341
|
+
return [
|
|
342
|
+
{
|
|
343
|
+
value: ALL_PRESENTATIONS,
|
|
344
|
+
label: rt.language === "ja" ? "\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u3059\u3079\u3066\u306E\u30D7\u30EC\u30BC\u30F3\u30C6\u30FC\u30B7\u30E7\u30F3" : "All accessible presentations"
|
|
345
|
+
},
|
|
346
|
+
...files.map((f) => ({ value: f.id, label: f.name }))
|
|
347
|
+
];
|
|
348
|
+
},
|
|
349
|
+
applyAnswer: (state, answer) => ({ ...state, presentations: answer })
|
|
350
|
+
}
|
|
351
|
+
],
|
|
352
|
+
async finalize(state, rt) {
|
|
353
|
+
if (!state.presentations) {
|
|
354
|
+
throw new Error("Google Slides setup: incomplete state on finalize");
|
|
355
|
+
}
|
|
356
|
+
const targetIds = await resolveSetupSelection({
|
|
357
|
+
selected: state.presentations,
|
|
358
|
+
allSentinel: ALL_PRESENTATIONS,
|
|
359
|
+
fetchAll: async () => {
|
|
360
|
+
const files = await listPresentations(rt.config);
|
|
361
|
+
return files.map((f) => f.id);
|
|
362
|
+
},
|
|
363
|
+
limit: GOOGLE_SLIDES_SETUP_MAX_PRESENTATIONS
|
|
364
|
+
});
|
|
365
|
+
const sections = ["## Google Slides", ""];
|
|
366
|
+
if (targetIds.length === 0) {
|
|
367
|
+
sections.push(
|
|
368
|
+
rt.language === "ja" ? "\u5BFE\u8C61\u306E\u30D7\u30EC\u30BC\u30F3\u30C6\u30FC\u30B7\u30E7\u30F3\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002" : "No presentations selected."
|
|
369
|
+
);
|
|
370
|
+
return sections.join("\n");
|
|
371
|
+
}
|
|
372
|
+
for (const id of targetIds) {
|
|
373
|
+
const url = `https://slides.googleapis.com/v1/presentations/${encodeURIComponent(id)}?fields=presentationId,title,revisionId,slides(objectId)`;
|
|
374
|
+
const meta = await googleApiFetch(
|
|
375
|
+
rt.config,
|
|
376
|
+
url
|
|
377
|
+
);
|
|
378
|
+
const title = meta.title ?? id;
|
|
379
|
+
const slideCount = (meta.slides ?? []).length;
|
|
380
|
+
sections.push(`### Presentation: ${title}`, "");
|
|
381
|
+
sections.push(`- ID: ${id}`);
|
|
382
|
+
sections.push(`- Slides: ${slideCount}`);
|
|
383
|
+
if (meta.revisionId) sections.push(`- Revision: ${meta.revisionId}`);
|
|
384
|
+
sections.push("");
|
|
385
|
+
}
|
|
386
|
+
return sections.join("\n");
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
|
|
247
390
|
// ../connectors/src/connectors/google-slides/parameters.ts
|
|
248
391
|
var parameters = {};
|
|
249
392
|
|
|
@@ -374,6 +517,7 @@ var tools = { request: requestTool };
|
|
|
374
517
|
var googleSlidesConnector = new ConnectorPlugin({
|
|
375
518
|
slug: "google-slides",
|
|
376
519
|
authType: AUTH_TYPES.OAUTH,
|
|
520
|
+
skipConnectionCheckOnCreate: true,
|
|
377
521
|
name: "Google Slides",
|
|
378
522
|
description: "Connect to Google Slides for presentation data access and creation using OAuth.",
|
|
379
523
|
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/4oyF4yTRpemMA43X49masx/e1582d25e3b4c9a63ba83df2147c1968/google_slide.png",
|
|
@@ -549,7 +693,8 @@ await slides.batchUpdate(presentationId, [
|
|
|
549
693
|
|
|
550
694
|
\u30CF\u30F3\u30C9\u30E9\u306E\u30C6\u30B9\u30C8\u304C \`Connection proxy is not configured\` \u3067\u5931\u6557\u3059\u308B\u5834\u5408\u306F\u518D\u8A66\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u901A\u5E38\u306F\u30B5\u30F3\u30C9\u30DC\u30C3\u30AF\u30B9\u306E\u521D\u671F\u5316\u4E2D\u306B\u8D77\u304D\u307E\u3059\u3002SDK \u3092\u8AE6\u3081\u3066 OAuth \u30D7\u30ED\u30AD\u30B7\u306E URL \u3092\u81EA\u5206\u3067\u7D44\u307F\u7ACB\u3066\u308B\u3053\u3068\u306F **\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044**\u3002`
|
|
551
695
|
},
|
|
552
|
-
tools
|
|
696
|
+
tools,
|
|
697
|
+
setup: (params, ctx, config) => runSetupFlow(googleSlidesSetupFlow, params, ctx, config)
|
|
553
698
|
});
|
|
554
699
|
|
|
555
700
|
// src/connectors/create-connector-sdk.ts
|
|
@@ -578,6 +723,7 @@ function resolveEnvVarOptional(entry, key) {
|
|
|
578
723
|
import { getContext } from "hono/context-storage";
|
|
579
724
|
import { getCookie } from "hono/cookie";
|
|
580
725
|
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
726
|
+
var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
|
|
581
727
|
function normalizeHeaders(input) {
|
|
582
728
|
const out = {};
|
|
583
729
|
if (!input) return out;
|
|
@@ -586,6 +732,11 @@ function normalizeHeaders(input) {
|
|
|
586
732
|
});
|
|
587
733
|
return out;
|
|
588
734
|
}
|
|
735
|
+
function extractInputUrl(input) {
|
|
736
|
+
if (typeof input === "string") return input;
|
|
737
|
+
if (input instanceof URL) return input.href;
|
|
738
|
+
return input.url;
|
|
739
|
+
}
|
|
589
740
|
function createSandboxProxyFetch(connectionId) {
|
|
590
741
|
return async (input, init) => {
|
|
591
742
|
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
@@ -595,10 +746,17 @@ function createSandboxProxyFetch(connectionId) {
|
|
|
595
746
|
"Connection proxy is not configured. Please check your deployment settings."
|
|
596
747
|
);
|
|
597
748
|
}
|
|
598
|
-
const originalUrl =
|
|
749
|
+
const originalUrl = extractInputUrl(input);
|
|
750
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
751
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
752
|
+
const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
753
|
+
return fetch(sessionUrl, {
|
|
754
|
+
method: "POST",
|
|
755
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
756
|
+
});
|
|
757
|
+
}
|
|
599
758
|
const originalMethod = init?.method ?? "GET";
|
|
600
759
|
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
601
|
-
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
602
760
|
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
603
761
|
return fetch(proxyUrl, {
|
|
604
762
|
method: "POST",
|
|
@@ -624,10 +782,9 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
624
782
|
}
|
|
625
783
|
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
626
784
|
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
785
|
+
const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
627
786
|
return async (input, init) => {
|
|
628
|
-
const originalUrl =
|
|
629
|
-
const originalMethod = init?.method ?? "GET";
|
|
630
|
-
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
787
|
+
const originalUrl = extractInputUrl(input);
|
|
631
788
|
const c = getContext();
|
|
632
789
|
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
633
790
|
if (!appSession) {
|
|
@@ -635,6 +792,14 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
635
792
|
"No authentication method available for connection proxy."
|
|
636
793
|
);
|
|
637
794
|
}
|
|
795
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
796
|
+
return fetch(sessionUrl, {
|
|
797
|
+
method: "POST",
|
|
798
|
+
headers: { Authorization: `Bearer ${appSession}` }
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
const originalMethod = init?.method ?? "GET";
|
|
802
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
638
803
|
return fetch(proxyUrl, {
|
|
639
804
|
method: "POST",
|
|
640
805
|
headers: {
|