@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/google-calendar/parameters.ts
|
|
57
|
+
init_parameter_definition();
|
|
46
58
|
var parameters = {
|
|
47
59
|
serviceAccountKeyJsonBase64: new ParameterDefinition({
|
|
48
60
|
slug: "service-account-key-json-base64",
|
|
@@ -186,6 +198,28 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
186
198
|
tools;
|
|
187
199
|
query;
|
|
188
200
|
checkConnection;
|
|
201
|
+
/**
|
|
202
|
+
* SQPD-1212: Logic-based, rule-driven connection setup. Connectors that
|
|
203
|
+
* implement this expose a step-by-step exploration flow (database/schema/
|
|
204
|
+
* table/etc. discovery) that the dashboard backend drives via the
|
|
205
|
+
* `/connections/:connectionId/setup` endpoint. Implement by delegating to
|
|
206
|
+
* `runSetupFlow` from `setup-flow.ts`.
|
|
207
|
+
*/
|
|
208
|
+
setup;
|
|
209
|
+
/**
|
|
210
|
+
* Opt-out of the default "verify before save" behavior on connection
|
|
211
|
+
* creation. The backend invokes `checkConnection` synchronously while
|
|
212
|
+
* creating the connection and aborts (no row inserted) if it fails — this
|
|
213
|
+
* flag disables that for connectors where the check cannot succeed pre-save:
|
|
214
|
+
*
|
|
215
|
+
* - `squadbase-db` populates `connection-url` only after Neon provisioning
|
|
216
|
+
* - OAuth connectors require an OAuth-aware proxyFetch keyed by the
|
|
217
|
+
* connectionId, which doesn't exist until the row is saved
|
|
218
|
+
*
|
|
219
|
+
* Exceptions are the explicit position; new credential-input connectors get
|
|
220
|
+
* the default verify-on-create behavior without opt-in.
|
|
221
|
+
*/
|
|
222
|
+
skipConnectionCheckOnCreate;
|
|
189
223
|
constructor(config) {
|
|
190
224
|
this.slug = config.slug;
|
|
191
225
|
this.authType = config.authType;
|
|
@@ -202,6 +236,8 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
202
236
|
this.tools = config.tools;
|
|
203
237
|
this.query = config.query;
|
|
204
238
|
this.checkConnection = config.checkConnection;
|
|
239
|
+
this.setup = config.setup;
|
|
240
|
+
this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
|
|
205
241
|
}
|
|
206
242
|
get connectorKey() {
|
|
207
243
|
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
@@ -266,6 +302,76 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
266
302
|
}
|
|
267
303
|
};
|
|
268
304
|
|
|
305
|
+
// ../connectors/src/setup-flow.ts
|
|
306
|
+
async function runSetupFlow(flow, params, ctx, config) {
|
|
307
|
+
const runtime = {
|
|
308
|
+
params,
|
|
309
|
+
language: ctx.language,
|
|
310
|
+
config
|
|
311
|
+
};
|
|
312
|
+
let state = flow.initialState();
|
|
313
|
+
let answerIdx = 0;
|
|
314
|
+
const pendingParameterUpdates = [];
|
|
315
|
+
for (const step of flow.steps) {
|
|
316
|
+
const ans = ctx.answers[answerIdx];
|
|
317
|
+
if (ans && ans.questionSlug === step.slug) {
|
|
318
|
+
state = step.applyAnswer(state, ans.answer);
|
|
319
|
+
if (step.toParameterUpdates) {
|
|
320
|
+
pendingParameterUpdates.push(...step.toParameterUpdates(state));
|
|
321
|
+
}
|
|
322
|
+
answerIdx += 1;
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
|
|
326
|
+
if (step.type === "text") {
|
|
327
|
+
if (step.fetchOptions) {
|
|
328
|
+
const options2 = await step.fetchOptions(state, runtime);
|
|
329
|
+
if (options2.length === 0) {
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
type: "nextQuestion",
|
|
335
|
+
questionSlug: step.slug,
|
|
336
|
+
question: step.question[ctx.language],
|
|
337
|
+
questionType: "text",
|
|
338
|
+
allowFreeText: resolvedAllowFreeText,
|
|
339
|
+
...pendingParameterUpdates.length > 0 && {
|
|
340
|
+
parameterUpdates: pendingParameterUpdates
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
345
|
+
if (options.length === 0) {
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
return {
|
|
349
|
+
type: "nextQuestion",
|
|
350
|
+
questionSlug: step.slug,
|
|
351
|
+
question: step.question[ctx.language],
|
|
352
|
+
questionType: step.type,
|
|
353
|
+
options,
|
|
354
|
+
allowFreeText: resolvedAllowFreeText,
|
|
355
|
+
...pendingParameterUpdates.length > 0 && {
|
|
356
|
+
parameterUpdates: pendingParameterUpdates
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
361
|
+
return {
|
|
362
|
+
type: "fulfilled",
|
|
363
|
+
dataInvestigationResult,
|
|
364
|
+
...pendingParameterUpdates.length > 0 && {
|
|
365
|
+
parameterUpdates: pendingParameterUpdates
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
async function resolveSetupSelection(params) {
|
|
370
|
+
const { selected, allSentinel, fetchAll, limit } = params;
|
|
371
|
+
const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
|
|
372
|
+
return resolved.slice(0, limit);
|
|
373
|
+
}
|
|
374
|
+
|
|
269
375
|
// ../connectors/src/auth-types.ts
|
|
270
376
|
var AUTH_TYPES = {
|
|
271
377
|
OAUTH: "oauth",
|
|
@@ -772,6 +878,144 @@ For each calendar:
|
|
|
772
878
|
}
|
|
773
879
|
});
|
|
774
880
|
|
|
881
|
+
// ../connectors/src/connectors/google-calendar/utils.ts
|
|
882
|
+
function decodeServiceAccount3(keyJsonBase64) {
|
|
883
|
+
const decoded = Buffer.from(keyJsonBase64, "base64").toString("utf-8");
|
|
884
|
+
return JSON.parse(decoded);
|
|
885
|
+
}
|
|
886
|
+
var READONLY_SCOPES2 = ["https://www.googleapis.com/auth/calendar.readonly"];
|
|
887
|
+
async function getAccessToken(params, subject, scopes) {
|
|
888
|
+
const keyJsonBase64 = params[parameters.serviceAccountKeyJsonBase64.slug];
|
|
889
|
+
if (!keyJsonBase64) {
|
|
890
|
+
throw new Error("Google Calendar setup: service account key is missing");
|
|
891
|
+
}
|
|
892
|
+
const sa = decodeServiceAccount3(keyJsonBase64);
|
|
893
|
+
const { GoogleAuth } = await import("google-auth-library");
|
|
894
|
+
const auth = new GoogleAuth({
|
|
895
|
+
credentials: { client_email: sa.client_email, private_key: sa.private_key },
|
|
896
|
+
scopes,
|
|
897
|
+
...subject ? { clientOptions: { subject } } : {}
|
|
898
|
+
});
|
|
899
|
+
const token = await auth.getAccessToken();
|
|
900
|
+
if (!token) {
|
|
901
|
+
throw new Error("Google Calendar setup: failed to obtain access token");
|
|
902
|
+
}
|
|
903
|
+
return token;
|
|
904
|
+
}
|
|
905
|
+
async function calendarApiFetch(params, subject, url) {
|
|
906
|
+
const token = await getAccessToken(params, subject, READONLY_SCOPES2);
|
|
907
|
+
const res = await fetch(url, {
|
|
908
|
+
method: "GET",
|
|
909
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
910
|
+
});
|
|
911
|
+
if (!res.ok) {
|
|
912
|
+
const text = await res.text().catch(() => res.statusText);
|
|
913
|
+
throw new Error(
|
|
914
|
+
`Google Calendar ${url} failed: HTTP ${res.status} ${text}`
|
|
915
|
+
);
|
|
916
|
+
}
|
|
917
|
+
return await res.json();
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
// ../connectors/src/connectors/google-calendar/setup-flow.ts
|
|
921
|
+
var ALL_CALENDARS = "__ALL_CALENDARS__";
|
|
922
|
+
var GOOGLE_CALENDAR_SETUP_MAX_CALENDARS = 20;
|
|
923
|
+
var NO_SUBJECT = "";
|
|
924
|
+
async function listCalendars(params, subject) {
|
|
925
|
+
const url = "https://www.googleapis.com/calendar/v3/users/me/calendarList?maxResults=250";
|
|
926
|
+
const data = await calendarApiFetch(
|
|
927
|
+
params,
|
|
928
|
+
subject,
|
|
929
|
+
url
|
|
930
|
+
);
|
|
931
|
+
return data.items ?? [];
|
|
932
|
+
}
|
|
933
|
+
function displayName(c) {
|
|
934
|
+
return c.summaryOverride ?? c.summary ?? c.id;
|
|
935
|
+
}
|
|
936
|
+
var googleCalendarSetupFlow = {
|
|
937
|
+
initialState: () => ({}),
|
|
938
|
+
steps: [
|
|
939
|
+
{
|
|
940
|
+
slug: "subject",
|
|
941
|
+
type: "text",
|
|
942
|
+
question: {
|
|
943
|
+
ja: "\u5BFE\u8C61\u3068\u3059\u308B Workspace \u30E6\u30FC\u30B6\u30FC\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u7A7A\u6B04\u3067\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u81EA\u8EAB\u3068\u3057\u3066\u30A2\u30AF\u30BB\u30B9\uFF09",
|
|
944
|
+
en: "Enter the Workspace user email to impersonate via Domain-wide Delegation (leave empty to access as the service account itself)"
|
|
945
|
+
},
|
|
946
|
+
applyAnswer: (state, answer) => ({
|
|
947
|
+
...state,
|
|
948
|
+
subject: (answer[0] ?? "").trim()
|
|
949
|
+
})
|
|
950
|
+
},
|
|
951
|
+
{
|
|
952
|
+
slug: "calendars",
|
|
953
|
+
type: "multiSelect",
|
|
954
|
+
question: {
|
|
955
|
+
ja: "\u5BFE\u8C61\u306E\u30AB\u30EC\u30F3\u30C0\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
956
|
+
en: "Select target calendars (multi-select allowed)"
|
|
957
|
+
},
|
|
958
|
+
async fetchOptions(state, rt) {
|
|
959
|
+
if (state.subject == null) return [];
|
|
960
|
+
const subj = state.subject === NO_SUBJECT ? null : state.subject;
|
|
961
|
+
const cals = await listCalendars(rt.params, subj);
|
|
962
|
+
return [
|
|
963
|
+
{
|
|
964
|
+
value: ALL_CALENDARS,
|
|
965
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30AB\u30EC\u30F3\u30C0\u30FC" : "All calendars"
|
|
966
|
+
},
|
|
967
|
+
...cals.map((c) => ({ value: c.id, label: displayName(c) }))
|
|
968
|
+
];
|
|
969
|
+
},
|
|
970
|
+
applyAnswer: (state, answer) => ({ ...state, calendars: answer })
|
|
971
|
+
}
|
|
972
|
+
],
|
|
973
|
+
async finalize(state, rt) {
|
|
974
|
+
if (state.subject == null || !state.calendars) {
|
|
975
|
+
throw new Error("Google Calendar setup: incomplete state on finalize");
|
|
976
|
+
}
|
|
977
|
+
const subj = state.subject === NO_SUBJECT ? null : state.subject;
|
|
978
|
+
const cals = await listCalendars(rt.params, subj);
|
|
979
|
+
const byId = new Map(cals.map((c) => [c.id, c]));
|
|
980
|
+
const targetIds = await resolveSetupSelection({
|
|
981
|
+
selected: state.calendars,
|
|
982
|
+
allSentinel: ALL_CALENDARS,
|
|
983
|
+
fetchAll: async () => cals.map((c) => c.id),
|
|
984
|
+
limit: GOOGLE_CALENDAR_SETUP_MAX_CALENDARS
|
|
985
|
+
});
|
|
986
|
+
const subjectLabel = subj ?? "(service account)";
|
|
987
|
+
const sections = [
|
|
988
|
+
"## Google Calendar",
|
|
989
|
+
"",
|
|
990
|
+
`### Subject: ${subjectLabel}`,
|
|
991
|
+
""
|
|
992
|
+
];
|
|
993
|
+
if (targetIds.length === 0) {
|
|
994
|
+
sections.push(
|
|
995
|
+
rt.language === "ja" ? "\u5BFE\u8C61\u306E\u30AB\u30EC\u30F3\u30C0\u30FC\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002" : "No calendars selected."
|
|
996
|
+
);
|
|
997
|
+
return sections.join("\n");
|
|
998
|
+
}
|
|
999
|
+
sections.push("| Calendar | Time Zone | Primary | Access |");
|
|
1000
|
+
sections.push("|----------|-----------|---------|--------|");
|
|
1001
|
+
for (const id of targetIds) {
|
|
1002
|
+
const c = byId.get(id);
|
|
1003
|
+
if (!c) {
|
|
1004
|
+
sections.push(`| ${id} | - | - | - |`);
|
|
1005
|
+
continue;
|
|
1006
|
+
}
|
|
1007
|
+
const tz = c.timeZone ?? "-";
|
|
1008
|
+
const primary = c.primary ? "yes" : "no";
|
|
1009
|
+
const access = c.accessRole ?? "-";
|
|
1010
|
+
sections.push(
|
|
1011
|
+
`| ${displayName(c)} | ${tz} | ${primary} | ${access} |`
|
|
1012
|
+
);
|
|
1013
|
+
}
|
|
1014
|
+
sections.push("");
|
|
1015
|
+
return sections.join("\n");
|
|
1016
|
+
}
|
|
1017
|
+
};
|
|
1018
|
+
|
|
775
1019
|
// ../connectors/src/connectors/google-calendar/index.ts
|
|
776
1020
|
var tools = {
|
|
777
1021
|
request: requestTool,
|
|
@@ -985,7 +1229,55 @@ export default async function handler(c: Context) {
|
|
|
985
1229
|
}
|
|
986
1230
|
\`\`\``
|
|
987
1231
|
},
|
|
988
|
-
tools
|
|
1232
|
+
tools,
|
|
1233
|
+
setup: (params, ctx, config) => runSetupFlow(googleCalendarSetupFlow, params, ctx, config),
|
|
1234
|
+
async checkConnection(params, _config) {
|
|
1235
|
+
const keyJsonBase64 = params[parameters.serviceAccountKeyJsonBase64.slug];
|
|
1236
|
+
if (!keyJsonBase64) {
|
|
1237
|
+
return {
|
|
1238
|
+
success: false,
|
|
1239
|
+
error: "google-calendar: missing service account key"
|
|
1240
|
+
};
|
|
1241
|
+
}
|
|
1242
|
+
let sa;
|
|
1243
|
+
try {
|
|
1244
|
+
const decoded = Buffer.from(keyJsonBase64, "base64").toString("utf-8");
|
|
1245
|
+
sa = JSON.parse(decoded);
|
|
1246
|
+
} catch (err) {
|
|
1247
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1248
|
+
return {
|
|
1249
|
+
success: false,
|
|
1250
|
+
error: `google-calendar: failed to parse service account JSON: ${msg}`
|
|
1251
|
+
};
|
|
1252
|
+
}
|
|
1253
|
+
if (!sa.client_email || !sa.private_key) {
|
|
1254
|
+
return {
|
|
1255
|
+
success: false,
|
|
1256
|
+
error: "google-calendar: service account JSON must contain client_email and private_key"
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
try {
|
|
1260
|
+
const { GoogleAuth } = await import("google-auth-library");
|
|
1261
|
+
const auth = new GoogleAuth({
|
|
1262
|
+
credentials: {
|
|
1263
|
+
client_email: sa.client_email,
|
|
1264
|
+
private_key: sa.private_key
|
|
1265
|
+
},
|
|
1266
|
+
scopes: ["https://www.googleapis.com/auth/calendar.readonly"]
|
|
1267
|
+
});
|
|
1268
|
+
const token = await auth.getAccessToken();
|
|
1269
|
+
if (!token) {
|
|
1270
|
+
return {
|
|
1271
|
+
success: false,
|
|
1272
|
+
error: "google-calendar: failed to obtain access token"
|
|
1273
|
+
};
|
|
1274
|
+
}
|
|
1275
|
+
return { success: true };
|
|
1276
|
+
} catch (err) {
|
|
1277
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1278
|
+
return { success: false, error: msg };
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
989
1281
|
});
|
|
990
1282
|
|
|
991
1283
|
// src/connectors/create-connector-sdk.ts
|
|
@@ -1014,6 +1306,7 @@ function resolveEnvVarOptional(entry, key) {
|
|
|
1014
1306
|
import { getContext } from "hono/context-storage";
|
|
1015
1307
|
import { getCookie } from "hono/cookie";
|
|
1016
1308
|
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
1309
|
+
var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
|
|
1017
1310
|
function normalizeHeaders(input) {
|
|
1018
1311
|
const out = {};
|
|
1019
1312
|
if (!input) return out;
|
|
@@ -1022,6 +1315,11 @@ function normalizeHeaders(input) {
|
|
|
1022
1315
|
});
|
|
1023
1316
|
return out;
|
|
1024
1317
|
}
|
|
1318
|
+
function extractInputUrl(input) {
|
|
1319
|
+
if (typeof input === "string") return input;
|
|
1320
|
+
if (input instanceof URL) return input.href;
|
|
1321
|
+
return input.url;
|
|
1322
|
+
}
|
|
1025
1323
|
function createSandboxProxyFetch(connectionId) {
|
|
1026
1324
|
return async (input, init) => {
|
|
1027
1325
|
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
@@ -1031,10 +1329,17 @@ function createSandboxProxyFetch(connectionId) {
|
|
|
1031
1329
|
"Connection proxy is not configured. Please check your deployment settings."
|
|
1032
1330
|
);
|
|
1033
1331
|
}
|
|
1034
|
-
const originalUrl =
|
|
1332
|
+
const originalUrl = extractInputUrl(input);
|
|
1333
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
1334
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
1335
|
+
const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
1336
|
+
return fetch(sessionUrl, {
|
|
1337
|
+
method: "POST",
|
|
1338
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
1339
|
+
});
|
|
1340
|
+
}
|
|
1035
1341
|
const originalMethod = init?.method ?? "GET";
|
|
1036
1342
|
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
1037
|
-
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
1038
1343
|
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
1039
1344
|
return fetch(proxyUrl, {
|
|
1040
1345
|
method: "POST",
|
|
@@ -1060,10 +1365,9 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
1060
1365
|
}
|
|
1061
1366
|
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
1062
1367
|
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
1368
|
+
const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
1063
1369
|
return async (input, init) => {
|
|
1064
|
-
const originalUrl =
|
|
1065
|
-
const originalMethod = init?.method ?? "GET";
|
|
1066
|
-
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
1370
|
+
const originalUrl = extractInputUrl(input);
|
|
1067
1371
|
const c = getContext();
|
|
1068
1372
|
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
1069
1373
|
if (!appSession) {
|
|
@@ -1071,6 +1375,14 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
1071
1375
|
"No authentication method available for connection proxy."
|
|
1072
1376
|
);
|
|
1073
1377
|
}
|
|
1378
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
1379
|
+
return fetch(sessionUrl, {
|
|
1380
|
+
method: "POST",
|
|
1381
|
+
headers: { Authorization: `Bearer ${appSession}` }
|
|
1382
|
+
});
|
|
1383
|
+
}
|
|
1384
|
+
const originalMethod = init?.method ?? "GET";
|
|
1385
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
1074
1386
|
return fetch(proxyUrl, {
|
|
1075
1387
|
method: "POST",
|
|
1076
1388
|
headers: {
|