@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
|
@@ -193,6 +193,20 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
193
193
|
* `runSetupFlow` from `setup-flow.ts`.
|
|
194
194
|
*/
|
|
195
195
|
setup;
|
|
196
|
+
/**
|
|
197
|
+
* Opt-out of the default "verify before save" behavior on connection
|
|
198
|
+
* creation. The backend invokes `checkConnection` synchronously while
|
|
199
|
+
* creating the connection and aborts (no row inserted) if it fails — this
|
|
200
|
+
* flag disables that for connectors where the check cannot succeed pre-save:
|
|
201
|
+
*
|
|
202
|
+
* - `squadbase-db` populates `connection-url` only after Neon provisioning
|
|
203
|
+
* - OAuth connectors require an OAuth-aware proxyFetch keyed by the
|
|
204
|
+
* connectionId, which doesn't exist until the row is saved
|
|
205
|
+
*
|
|
206
|
+
* Exceptions are the explicit position; new credential-input connectors get
|
|
207
|
+
* the default verify-on-create behavior without opt-in.
|
|
208
|
+
*/
|
|
209
|
+
skipConnectionCheckOnCreate;
|
|
196
210
|
constructor(config) {
|
|
197
211
|
this.slug = config.slug;
|
|
198
212
|
this.authType = config.authType;
|
|
@@ -210,6 +224,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
210
224
|
this.query = config.query;
|
|
211
225
|
this.checkConnection = config.checkConnection;
|
|
212
226
|
this.setup = config.setup;
|
|
227
|
+
this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
|
|
213
228
|
}
|
|
214
229
|
get connectorKey() {
|
|
215
230
|
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
@@ -274,6 +289,51 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
274
289
|
}
|
|
275
290
|
};
|
|
276
291
|
|
|
292
|
+
// ../connectors/src/setup-flow.ts
|
|
293
|
+
async function runSetupFlow(flow, params, ctx, config) {
|
|
294
|
+
const runtime = {
|
|
295
|
+
params,
|
|
296
|
+
language: ctx.language,
|
|
297
|
+
config
|
|
298
|
+
};
|
|
299
|
+
let state = flow.initialState();
|
|
300
|
+
let answerIdx = 0;
|
|
301
|
+
for (const step of flow.steps) {
|
|
302
|
+
const ans = ctx.answers[answerIdx];
|
|
303
|
+
if (ans && ans.questionSlug === step.slug) {
|
|
304
|
+
state = step.applyAnswer(state, ans.answer);
|
|
305
|
+
answerIdx += 1;
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
if (step.type === "text") {
|
|
309
|
+
return {
|
|
310
|
+
type: "nextQuestion",
|
|
311
|
+
questionSlug: step.slug,
|
|
312
|
+
question: step.question[ctx.language],
|
|
313
|
+
questionType: "text"
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
317
|
+
if (options.length === 0) {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
return {
|
|
321
|
+
type: "nextQuestion",
|
|
322
|
+
questionSlug: step.slug,
|
|
323
|
+
question: step.question[ctx.language],
|
|
324
|
+
questionType: step.type,
|
|
325
|
+
options
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
329
|
+
return { type: "fulfilled", dataInvestigationResult };
|
|
330
|
+
}
|
|
331
|
+
async function resolveSetupSelection(params) {
|
|
332
|
+
const { selected, allSentinel, fetchAll, limit } = params;
|
|
333
|
+
const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
|
|
334
|
+
return resolved.slice(0, limit);
|
|
335
|
+
}
|
|
336
|
+
|
|
277
337
|
// ../connectors/src/auth-types.ts
|
|
278
338
|
var AUTH_TYPES = {
|
|
279
339
|
OAUTH: "oauth",
|
|
@@ -472,6 +532,89 @@ Calendar
|
|
|
472
532
|
}
|
|
473
533
|
});
|
|
474
534
|
|
|
535
|
+
// ../connectors/src/connectors/outlook-oauth/utils.ts
|
|
536
|
+
async function graphApiFetch(config, url) {
|
|
537
|
+
const res = await config.proxyFetch(url, { method: "GET" });
|
|
538
|
+
if (!res.ok) {
|
|
539
|
+
const text = await res.text().catch(() => res.statusText);
|
|
540
|
+
throw new Error(`Microsoft Graph ${url} failed: HTTP ${res.status} ${text}`);
|
|
541
|
+
}
|
|
542
|
+
return await res.json();
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// ../connectors/src/connectors/outlook-oauth/setup-flow.ts
|
|
546
|
+
var ALL_FOLDERS = "__ALL_FOLDERS__";
|
|
547
|
+
var OUTLOOK_SETUP_MAX_FOLDERS = 20;
|
|
548
|
+
async function listMailFolders(config) {
|
|
549
|
+
const url = "https://graph.microsoft.com/v1.0/me/mailFolders?$top=100&$select=id,displayName,parentFolderId,childFolderCount,unreadItemCount,totalItemCount";
|
|
550
|
+
const data = await graphApiFetch(config, url);
|
|
551
|
+
return data.value ?? [];
|
|
552
|
+
}
|
|
553
|
+
var outlookOauthSetupFlow = {
|
|
554
|
+
initialState: () => ({}),
|
|
555
|
+
steps: [
|
|
556
|
+
{
|
|
557
|
+
slug: "folders",
|
|
558
|
+
type: "multiSelect",
|
|
559
|
+
question: {
|
|
560
|
+
ja: "\u5BFE\u8C61\u306E\u30E1\u30FC\u30EB\u30D5\u30A9\u30EB\u30C0\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
561
|
+
en: "Select target mail folders (multi-select allowed)"
|
|
562
|
+
},
|
|
563
|
+
async fetchOptions(_state, rt) {
|
|
564
|
+
const folders = await listMailFolders(rt.config);
|
|
565
|
+
return [
|
|
566
|
+
{
|
|
567
|
+
value: ALL_FOLDERS,
|
|
568
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30D5\u30A9\u30EB\u30C0" : "All folders"
|
|
569
|
+
},
|
|
570
|
+
...folders.map((f) => ({
|
|
571
|
+
value: f.id,
|
|
572
|
+
label: f.displayName ?? f.id
|
|
573
|
+
}))
|
|
574
|
+
];
|
|
575
|
+
},
|
|
576
|
+
applyAnswer: (state, answer) => ({ ...state, folders: answer })
|
|
577
|
+
}
|
|
578
|
+
],
|
|
579
|
+
async finalize(state, rt) {
|
|
580
|
+
if (!state.folders) {
|
|
581
|
+
throw new Error("Outlook setup: incomplete state on finalize");
|
|
582
|
+
}
|
|
583
|
+
const folders = await listMailFolders(rt.config);
|
|
584
|
+
const byId = new Map(folders.map((f) => [f.id, f]));
|
|
585
|
+
const targetIds = await resolveSetupSelection({
|
|
586
|
+
selected: state.folders,
|
|
587
|
+
allSentinel: ALL_FOLDERS,
|
|
588
|
+
fetchAll: async () => folders.map((f) => f.id),
|
|
589
|
+
limit: OUTLOOK_SETUP_MAX_FOLDERS
|
|
590
|
+
});
|
|
591
|
+
const sections = ["## Outlook", ""];
|
|
592
|
+
if (targetIds.length === 0) {
|
|
593
|
+
sections.push(
|
|
594
|
+
rt.language === "ja" ? "\u5BFE\u8C61\u306E\u30D5\u30A9\u30EB\u30C0\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002" : "No folders selected."
|
|
595
|
+
);
|
|
596
|
+
return sections.join("\n");
|
|
597
|
+
}
|
|
598
|
+
sections.push("| Folder | Total | Unread | Sub-folders |");
|
|
599
|
+
sections.push("|--------|-------|--------|-------------|");
|
|
600
|
+
for (const id of targetIds) {
|
|
601
|
+
const f = byId.get(id);
|
|
602
|
+
if (!f) {
|
|
603
|
+
sections.push(`| ${id} | - | - | - |`);
|
|
604
|
+
continue;
|
|
605
|
+
}
|
|
606
|
+
const total = f.totalItemCount ?? "-";
|
|
607
|
+
const unread = f.unreadItemCount ?? "-";
|
|
608
|
+
const subs = f.childFolderCount ?? 0;
|
|
609
|
+
sections.push(
|
|
610
|
+
`| ${f.displayName ?? id} | ${total} | ${unread} | ${subs} |`
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
sections.push("");
|
|
614
|
+
return sections.join("\n");
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
|
|
475
618
|
// ../connectors/src/connectors/outlook-oauth/parameters.ts
|
|
476
619
|
var parameters = {};
|
|
477
620
|
|
|
@@ -480,6 +623,7 @@ var tools = { request: requestTool };
|
|
|
480
623
|
var outlookOauthConnector = new ConnectorPlugin({
|
|
481
624
|
slug: "outlook",
|
|
482
625
|
authType: AUTH_TYPES.OAUTH,
|
|
626
|
+
skipConnectionCheckOnCreate: true,
|
|
483
627
|
name: "Outlook",
|
|
484
628
|
description: "Connect to Microsoft Outlook (Mail + Calendar) via Microsoft Graph using OAuth. Read-only access to the user's mailbox, mail folders, messages, attachments, calendars, and events.",
|
|
485
629
|
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/1J1FrRTYJjOh3CcSIqsz3I/6a467b4d926075ff99dc60820e0ae4b1/Microsoft_Outlook_Icon__2025%C3%A2__present_.svg",
|
|
@@ -764,6 +908,7 @@ events.value.forEach(e => console.log(e.start.dateTime, e.subject));
|
|
|
764
908
|
\`\`\``
|
|
765
909
|
},
|
|
766
910
|
tools,
|
|
911
|
+
setup: (params, ctx, config) => runSetupFlow(outlookOauthSetupFlow, params, ctx, config),
|
|
767
912
|
async checkConnection(_params, config) {
|
|
768
913
|
const { proxyFetch } = config;
|
|
769
914
|
const url = "https://graph.microsoft.com/v1.0/me";
|
|
@@ -812,6 +957,7 @@ function resolveEnvVarOptional(entry, key) {
|
|
|
812
957
|
import { getContext } from "hono/context-storage";
|
|
813
958
|
import { getCookie } from "hono/cookie";
|
|
814
959
|
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
960
|
+
var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
|
|
815
961
|
function normalizeHeaders(input) {
|
|
816
962
|
const out = {};
|
|
817
963
|
if (!input) return out;
|
|
@@ -820,6 +966,11 @@ function normalizeHeaders(input) {
|
|
|
820
966
|
});
|
|
821
967
|
return out;
|
|
822
968
|
}
|
|
969
|
+
function extractInputUrl(input) {
|
|
970
|
+
if (typeof input === "string") return input;
|
|
971
|
+
if (input instanceof URL) return input.href;
|
|
972
|
+
return input.url;
|
|
973
|
+
}
|
|
823
974
|
function createSandboxProxyFetch(connectionId) {
|
|
824
975
|
return async (input, init) => {
|
|
825
976
|
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
@@ -829,10 +980,17 @@ function createSandboxProxyFetch(connectionId) {
|
|
|
829
980
|
"Connection proxy is not configured. Please check your deployment settings."
|
|
830
981
|
);
|
|
831
982
|
}
|
|
832
|
-
const originalUrl =
|
|
983
|
+
const originalUrl = extractInputUrl(input);
|
|
984
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
985
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
986
|
+
const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
987
|
+
return fetch(sessionUrl, {
|
|
988
|
+
method: "POST",
|
|
989
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
990
|
+
});
|
|
991
|
+
}
|
|
833
992
|
const originalMethod = init?.method ?? "GET";
|
|
834
993
|
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
835
|
-
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
836
994
|
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
837
995
|
return fetch(proxyUrl, {
|
|
838
996
|
method: "POST",
|
|
@@ -858,10 +1016,9 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
858
1016
|
}
|
|
859
1017
|
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
860
1018
|
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
1019
|
+
const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
861
1020
|
return async (input, init) => {
|
|
862
|
-
const originalUrl =
|
|
863
|
-
const originalMethod = init?.method ?? "GET";
|
|
864
|
-
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
1021
|
+
const originalUrl = extractInputUrl(input);
|
|
865
1022
|
const c = getContext();
|
|
866
1023
|
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
867
1024
|
if (!appSession) {
|
|
@@ -869,6 +1026,14 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
869
1026
|
"No authentication method available for connection proxy."
|
|
870
1027
|
);
|
|
871
1028
|
}
|
|
1029
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
1030
|
+
return fetch(sessionUrl, {
|
|
1031
|
+
method: "POST",
|
|
1032
|
+
headers: { Authorization: `Bearer ${appSession}` }
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
const originalMethod = init?.method ?? "GET";
|
|
1036
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
872
1037
|
return fetch(proxyUrl, {
|
|
873
1038
|
method: "POST",
|
|
874
1039
|
headers: {
|
|
@@ -151,6 +151,20 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
151
151
|
* `runSetupFlow` from `setup-flow.ts`.
|
|
152
152
|
*/
|
|
153
153
|
setup;
|
|
154
|
+
/**
|
|
155
|
+
* Opt-out of the default "verify before save" behavior on connection
|
|
156
|
+
* creation. The backend invokes `checkConnection` synchronously while
|
|
157
|
+
* creating the connection and aborts (no row inserted) if it fails — this
|
|
158
|
+
* flag disables that for connectors where the check cannot succeed pre-save:
|
|
159
|
+
*
|
|
160
|
+
* - `squadbase-db` populates `connection-url` only after Neon provisioning
|
|
161
|
+
* - OAuth connectors require an OAuth-aware proxyFetch keyed by the
|
|
162
|
+
* connectionId, which doesn't exist until the row is saved
|
|
163
|
+
*
|
|
164
|
+
* Exceptions are the explicit position; new credential-input connectors get
|
|
165
|
+
* the default verify-on-create behavior without opt-in.
|
|
166
|
+
*/
|
|
167
|
+
skipConnectionCheckOnCreate;
|
|
154
168
|
constructor(config) {
|
|
155
169
|
this.slug = config.slug;
|
|
156
170
|
this.authType = config.authType;
|
|
@@ -168,6 +182,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
168
182
|
this.query = config.query;
|
|
169
183
|
this.checkConnection = config.checkConnection;
|
|
170
184
|
this.setup = config.setup;
|
|
185
|
+
this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
|
|
171
186
|
}
|
|
172
187
|
get connectorKey() {
|
|
173
188
|
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
@@ -232,6 +247,51 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
232
247
|
}
|
|
233
248
|
};
|
|
234
249
|
|
|
250
|
+
// ../connectors/src/setup-flow.ts
|
|
251
|
+
async function runSetupFlow(flow, params, ctx, config) {
|
|
252
|
+
const runtime = {
|
|
253
|
+
params,
|
|
254
|
+
language: ctx.language,
|
|
255
|
+
config
|
|
256
|
+
};
|
|
257
|
+
let state = flow.initialState();
|
|
258
|
+
let answerIdx = 0;
|
|
259
|
+
for (const step of flow.steps) {
|
|
260
|
+
const ans = ctx.answers[answerIdx];
|
|
261
|
+
if (ans && ans.questionSlug === step.slug) {
|
|
262
|
+
state = step.applyAnswer(state, ans.answer);
|
|
263
|
+
answerIdx += 1;
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
if (step.type === "text") {
|
|
267
|
+
return {
|
|
268
|
+
type: "nextQuestion",
|
|
269
|
+
questionSlug: step.slug,
|
|
270
|
+
question: step.question[ctx.language],
|
|
271
|
+
questionType: "text"
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
275
|
+
if (options.length === 0) {
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
type: "nextQuestion",
|
|
280
|
+
questionSlug: step.slug,
|
|
281
|
+
question: step.question[ctx.language],
|
|
282
|
+
questionType: step.type,
|
|
283
|
+
options
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
287
|
+
return { type: "fulfilled", dataInvestigationResult };
|
|
288
|
+
}
|
|
289
|
+
async function resolveSetupSelection(params) {
|
|
290
|
+
const { selected, allSentinel, fetchAll, limit } = params;
|
|
291
|
+
const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
|
|
292
|
+
return resolved.slice(0, limit);
|
|
293
|
+
}
|
|
294
|
+
|
|
235
295
|
// ../connectors/src/auth-types.ts
|
|
236
296
|
var AUTH_TYPES = {
|
|
237
297
|
OAUTH: "oauth",
|
|
@@ -420,11 +480,142 @@ var powerbiOauthOnboarding = new ConnectorOnboarding({
|
|
|
420
480
|
// ../connectors/src/connectors/powerbi-oauth/parameters.ts
|
|
421
481
|
var parameters = {};
|
|
422
482
|
|
|
483
|
+
// ../connectors/src/connectors/powerbi-oauth/utils.ts
|
|
484
|
+
var BASE_URL3 = "https://api.powerbi.com/v1.0/myorg";
|
|
485
|
+
function apiFetch(proxyFetch, path2, init) {
|
|
486
|
+
const url = `${BASE_URL3}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
487
|
+
return proxyFetch(url, init);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// ../connectors/src/connectors/powerbi-oauth/setup-flow.ts
|
|
491
|
+
var ALL_WORKSPACES = "__ALL_WORKSPACES__";
|
|
492
|
+
var POWERBI_SETUP_MAX_WORKSPACES = 10;
|
|
493
|
+
var RESOURCE_DISPLAY_LIMIT = 25;
|
|
494
|
+
var RESOURCE_DATASETS = "datasets";
|
|
495
|
+
var RESOURCE_REPORTS = "reports";
|
|
496
|
+
var RESOURCE_DASHBOARDS = "dashboards";
|
|
497
|
+
async function listGroups(proxyFetch) {
|
|
498
|
+
const res = await apiFetch(proxyFetch, "/groups");
|
|
499
|
+
if (!res.ok) {
|
|
500
|
+
const body = await res.text().catch(() => res.statusText);
|
|
501
|
+
throw new Error(`powerbi: listGroups failed (${res.status}): ${body}`);
|
|
502
|
+
}
|
|
503
|
+
const data = await res.json();
|
|
504
|
+
return data.value ?? [];
|
|
505
|
+
}
|
|
506
|
+
async function listResource(proxyFetch, groupId, resource) {
|
|
507
|
+
const res = await apiFetch(
|
|
508
|
+
proxyFetch,
|
|
509
|
+
`/groups/${encodeURIComponent(groupId)}/${resource}`
|
|
510
|
+
);
|
|
511
|
+
if (!res.ok) {
|
|
512
|
+
const body = await res.text().catch(() => res.statusText);
|
|
513
|
+
throw new Error(
|
|
514
|
+
`powerbi: list ${resource} for group ${groupId} failed (${res.status}): ${body}`
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
const data = await res.json();
|
|
518
|
+
return data.value ?? [];
|
|
519
|
+
}
|
|
520
|
+
function resourceLabel(r) {
|
|
521
|
+
return r.name ?? r.displayName ?? r.id ?? "(unknown)";
|
|
522
|
+
}
|
|
523
|
+
var powerbiOauthSetupFlow = {
|
|
524
|
+
initialState: () => ({}),
|
|
525
|
+
steps: [
|
|
526
|
+
{
|
|
527
|
+
slug: "workspaces",
|
|
528
|
+
type: "multiSelect",
|
|
529
|
+
question: {
|
|
530
|
+
ja: "\u5BFE\u8C61\u306E\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
531
|
+
en: "Select target workspaces (multi-select allowed)"
|
|
532
|
+
},
|
|
533
|
+
async fetchOptions(_state, rt) {
|
|
534
|
+
const groups = await listGroups(rt.config.proxyFetch);
|
|
535
|
+
const options = groups.filter((g) => g.id && g.name).map((g) => ({ value: g.id, label: g.name }));
|
|
536
|
+
return [
|
|
537
|
+
{
|
|
538
|
+
value: ALL_WORKSPACES,
|
|
539
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9" : "All workspaces"
|
|
540
|
+
},
|
|
541
|
+
...options
|
|
542
|
+
];
|
|
543
|
+
},
|
|
544
|
+
applyAnswer: (state, answer) => ({ ...state, workspaces: answer })
|
|
545
|
+
},
|
|
546
|
+
{
|
|
547
|
+
slug: "resources",
|
|
548
|
+
type: "multiSelect",
|
|
549
|
+
question: {
|
|
550
|
+
ja: "\u8981\u7D04\u306B\u542B\u3081\u308B\u30EA\u30BD\u30FC\u30B9\u7A2E\u5225\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
551
|
+
en: "Select which resource types to include in the summary"
|
|
552
|
+
},
|
|
553
|
+
async fetchOptions(state, rt) {
|
|
554
|
+
if (!state.workspaces?.length) return [];
|
|
555
|
+
const datasetsLabel = rt.language === "ja" ? "\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8" : "Datasets";
|
|
556
|
+
const reportsLabel = rt.language === "ja" ? "\u30EC\u30DD\u30FC\u30C8" : "Reports";
|
|
557
|
+
const dashboardsLabel = rt.language === "ja" ? "\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9" : "Dashboards";
|
|
558
|
+
return [
|
|
559
|
+
{ value: RESOURCE_DATASETS, label: datasetsLabel },
|
|
560
|
+
{ value: RESOURCE_REPORTS, label: reportsLabel },
|
|
561
|
+
{ value: RESOURCE_DASHBOARDS, label: dashboardsLabel }
|
|
562
|
+
];
|
|
563
|
+
},
|
|
564
|
+
applyAnswer: (state, answer) => ({ ...state, resources: answer })
|
|
565
|
+
}
|
|
566
|
+
],
|
|
567
|
+
async finalize(state, rt) {
|
|
568
|
+
if (!state.workspaces || !state.resources) {
|
|
569
|
+
throw new Error("Power BI setup: incomplete state on finalize");
|
|
570
|
+
}
|
|
571
|
+
const allGroups = await listGroups(rt.config.proxyFetch);
|
|
572
|
+
const groupById = new Map(allGroups.map((g) => [g.id, g]));
|
|
573
|
+
const targetIds = await resolveSetupSelection({
|
|
574
|
+
selected: state.workspaces,
|
|
575
|
+
allSentinel: ALL_WORKSPACES,
|
|
576
|
+
fetchAll: async () => allGroups.map((g) => g.id).filter((id) => id),
|
|
577
|
+
limit: POWERBI_SETUP_MAX_WORKSPACES
|
|
578
|
+
});
|
|
579
|
+
const selectedResources = new Set(state.resources);
|
|
580
|
+
const sections = ["## Power BI", ""];
|
|
581
|
+
if (!targetIds.length) {
|
|
582
|
+
sections.push("_No workspaces selected._", "");
|
|
583
|
+
return sections.join("\n");
|
|
584
|
+
}
|
|
585
|
+
for (const id of targetIds) {
|
|
586
|
+
const group = groupById.get(id);
|
|
587
|
+
const name = group?.name ?? id;
|
|
588
|
+
sections.push(`### Workspace: ${name}`, "", `- id: \`${id}\``);
|
|
589
|
+
for (const resource of [
|
|
590
|
+
RESOURCE_DATASETS,
|
|
591
|
+
RESOURCE_REPORTS,
|
|
592
|
+
RESOURCE_DASHBOARDS
|
|
593
|
+
]) {
|
|
594
|
+
if (!selectedResources.has(resource)) continue;
|
|
595
|
+
const items = await listResource(rt.config.proxyFetch, id, resource);
|
|
596
|
+
const heading = resource === RESOURCE_DATASETS ? "Datasets" : resource === RESOURCE_REPORTS ? "Reports" : "Dashboards";
|
|
597
|
+
sections.push(`- ${heading} (${items.length}):`);
|
|
598
|
+
for (const item of items.slice(0, RESOURCE_DISPLAY_LIMIT)) {
|
|
599
|
+
sections.push(` - ${resourceLabel(item)}`);
|
|
600
|
+
}
|
|
601
|
+
if (items.length > RESOURCE_DISPLAY_LIMIT) {
|
|
602
|
+
sections.push(
|
|
603
|
+
` - \u2026and ${items.length - RESOURCE_DISPLAY_LIMIT} more`
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
sections.push("");
|
|
608
|
+
}
|
|
609
|
+
return sections.join("\n");
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
|
|
423
613
|
// ../connectors/src/connectors/powerbi-oauth/index.ts
|
|
424
614
|
var tools = { request: requestTool };
|
|
425
615
|
var powerbiOauthConnector = new ConnectorPlugin({
|
|
426
616
|
slug: "powerbi",
|
|
427
617
|
authType: AUTH_TYPES.OAUTH,
|
|
618
|
+
skipConnectionCheckOnCreate: true,
|
|
428
619
|
name: "Power BI",
|
|
429
620
|
description: "Connect to Microsoft Power BI using OAuth (Microsoft Entra ID). Use it to enumerate workspaces, datasets, and reports the signed-in user has access to, and to run DAX queries.",
|
|
430
621
|
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/2vXQCKGpMJ9kGSaqkZl9IS/cc5669c267fc5d11e7b1f8c01723e461/power-bi-icon.png",
|
|
@@ -555,6 +746,7 @@ export default async function handler(c: Context) {
|
|
|
555
746
|
- \`executeQueries\` \u306F\u73FE\u72B6 1 \u30EA\u30AF\u30A8\u30B9\u30C8\u306B\u3064\u304D 1 \u30AF\u30A8\u30EA\u306E\u307F`
|
|
556
747
|
},
|
|
557
748
|
tools,
|
|
749
|
+
setup: (params, ctx, config) => runSetupFlow(powerbiOauthSetupFlow, params, ctx, config),
|
|
558
750
|
async checkConnection(_params, config) {
|
|
559
751
|
const { proxyFetch } = config;
|
|
560
752
|
const url = "https://api.powerbi.com/v1.0/myorg/groups?$top=1";
|
|
@@ -603,6 +795,7 @@ function resolveEnvVarOptional(entry, key) {
|
|
|
603
795
|
import { getContext } from "hono/context-storage";
|
|
604
796
|
import { getCookie } from "hono/cookie";
|
|
605
797
|
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
798
|
+
var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
|
|
606
799
|
function normalizeHeaders(input) {
|
|
607
800
|
const out = {};
|
|
608
801
|
if (!input) return out;
|
|
@@ -611,6 +804,11 @@ function normalizeHeaders(input) {
|
|
|
611
804
|
});
|
|
612
805
|
return out;
|
|
613
806
|
}
|
|
807
|
+
function extractInputUrl(input) {
|
|
808
|
+
if (typeof input === "string") return input;
|
|
809
|
+
if (input instanceof URL) return input.href;
|
|
810
|
+
return input.url;
|
|
811
|
+
}
|
|
614
812
|
function createSandboxProxyFetch(connectionId) {
|
|
615
813
|
return async (input, init) => {
|
|
616
814
|
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
@@ -620,10 +818,17 @@ function createSandboxProxyFetch(connectionId) {
|
|
|
620
818
|
"Connection proxy is not configured. Please check your deployment settings."
|
|
621
819
|
);
|
|
622
820
|
}
|
|
623
|
-
const originalUrl =
|
|
821
|
+
const originalUrl = extractInputUrl(input);
|
|
822
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
823
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
824
|
+
const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
825
|
+
return fetch(sessionUrl, {
|
|
826
|
+
method: "POST",
|
|
827
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
828
|
+
});
|
|
829
|
+
}
|
|
624
830
|
const originalMethod = init?.method ?? "GET";
|
|
625
831
|
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
626
|
-
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
627
832
|
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
628
833
|
return fetch(proxyUrl, {
|
|
629
834
|
method: "POST",
|
|
@@ -649,10 +854,9 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
649
854
|
}
|
|
650
855
|
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
651
856
|
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
857
|
+
const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
652
858
|
return async (input, init) => {
|
|
653
|
-
const originalUrl =
|
|
654
|
-
const originalMethod = init?.method ?? "GET";
|
|
655
|
-
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
859
|
+
const originalUrl = extractInputUrl(input);
|
|
656
860
|
const c = getContext();
|
|
657
861
|
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
658
862
|
if (!appSession) {
|
|
@@ -660,6 +864,14 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
660
864
|
"No authentication method available for connection proxy."
|
|
661
865
|
);
|
|
662
866
|
}
|
|
867
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
868
|
+
return fetch(sessionUrl, {
|
|
869
|
+
method: "POST",
|
|
870
|
+
headers: { Authorization: `Bearer ${appSession}` }
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
const originalMethod = init?.method ?? "GET";
|
|
874
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
663
875
|
return fetch(proxyUrl, {
|
|
664
876
|
method: "POST",
|
|
665
877
|
headers: {
|