@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
|
@@ -75,6 +75,20 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
75
75
|
* `runSetupFlow` from `setup-flow.ts`.
|
|
76
76
|
*/
|
|
77
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;
|
|
78
92
|
constructor(config) {
|
|
79
93
|
this.slug = config.slug;
|
|
80
94
|
this.authType = config.authType;
|
|
@@ -92,6 +106,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
92
106
|
this.query = config.query;
|
|
93
107
|
this.checkConnection = config.checkConnection;
|
|
94
108
|
this.setup = config.setup;
|
|
109
|
+
this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
|
|
95
110
|
}
|
|
96
111
|
get connectorKey() {
|
|
97
112
|
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
@@ -156,6 +171,51 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
156
171
|
}
|
|
157
172
|
};
|
|
158
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
|
+
for (const step of flow.steps) {
|
|
184
|
+
const ans = ctx.answers[answerIdx];
|
|
185
|
+
if (ans && ans.questionSlug === step.slug) {
|
|
186
|
+
state = step.applyAnswer(state, ans.answer);
|
|
187
|
+
answerIdx += 1;
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (step.type === "text") {
|
|
191
|
+
return {
|
|
192
|
+
type: "nextQuestion",
|
|
193
|
+
questionSlug: step.slug,
|
|
194
|
+
question: step.question[ctx.language],
|
|
195
|
+
questionType: "text"
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
199
|
+
if (options.length === 0) {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
type: "nextQuestion",
|
|
204
|
+
questionSlug: step.slug,
|
|
205
|
+
question: step.question[ctx.language],
|
|
206
|
+
questionType: step.type,
|
|
207
|
+
options
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
211
|
+
return { type: "fulfilled", dataInvestigationResult };
|
|
212
|
+
}
|
|
213
|
+
async function resolveSetupSelection(params) {
|
|
214
|
+
const { selected, allSentinel, fetchAll, limit } = params;
|
|
215
|
+
const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
|
|
216
|
+
return resolved.slice(0, limit);
|
|
217
|
+
}
|
|
218
|
+
|
|
159
219
|
// ../connectors/src/auth-types.ts
|
|
160
220
|
var AUTH_TYPES = {
|
|
161
221
|
OAUTH: "oauth",
|
|
@@ -323,6 +383,95 @@ var intercomOauthOnboarding = new ConnectorOnboarding({
|
|
|
323
383
|
}
|
|
324
384
|
});
|
|
325
385
|
|
|
386
|
+
// ../connectors/src/connectors/intercom-oauth/utils.ts
|
|
387
|
+
var BASE_URL3 = "https://api.intercom.io";
|
|
388
|
+
var INTERCOM_VERSION = "2.11";
|
|
389
|
+
function apiFetch(proxyFetch, path2, init) {
|
|
390
|
+
const url = `${BASE_URL3}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
391
|
+
const headers = new Headers(init?.headers);
|
|
392
|
+
headers.set("Accept", "application/json");
|
|
393
|
+
headers.set("Intercom-Version", INTERCOM_VERSION);
|
|
394
|
+
return proxyFetch(url, { ...init, headers });
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// ../connectors/src/connectors/intercom-oauth/setup-flow.ts
|
|
398
|
+
var INTERCOM_SETUP_MAX_SCOPES = 10;
|
|
399
|
+
var INTERCOM_SCOPES = [
|
|
400
|
+
{ value: "contacts", label: "Contacts", countPath: "/contacts?per_page=1" },
|
|
401
|
+
{ value: "companies", label: "Companies", countPath: "/companies?per_page=1" },
|
|
402
|
+
{
|
|
403
|
+
value: "conversations",
|
|
404
|
+
label: "Conversations",
|
|
405
|
+
countPath: "/conversations?per_page=1"
|
|
406
|
+
},
|
|
407
|
+
{ value: "articles", label: "Articles", countPath: "/articles?per_page=1" },
|
|
408
|
+
{ value: "teams", label: "Teams", countPath: "/teams" }
|
|
409
|
+
];
|
|
410
|
+
async function fetchCount(proxyFetch, path2) {
|
|
411
|
+
const res = await apiFetch(proxyFetch, path2);
|
|
412
|
+
if (!res.ok) {
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
const data = await res.json();
|
|
416
|
+
if (typeof data.total_count === "number") return data.total_count;
|
|
417
|
+
if (Array.isArray(data.teams)) return data.teams.length;
|
|
418
|
+
if (Array.isArray(data.data)) return data.data.length;
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
var intercomOauthSetupFlow = {
|
|
422
|
+
initialState: () => ({}),
|
|
423
|
+
steps: [
|
|
424
|
+
{
|
|
425
|
+
slug: "scopes",
|
|
426
|
+
type: "multiSelect",
|
|
427
|
+
question: {
|
|
428
|
+
ja: "\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3067\u6982\u89B3\u3057\u305F\u3044Intercom\u30C7\u30FC\u30BF\u30B9\u30B3\u30FC\u30D7\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
429
|
+
en: "Select the Intercom data scopes to include in setup (multi-select allowed)"
|
|
430
|
+
},
|
|
431
|
+
async fetchOptions(_state, _rt) {
|
|
432
|
+
return INTERCOM_SCOPES.map((s) => ({
|
|
433
|
+
value: s.value,
|
|
434
|
+
label: s.label
|
|
435
|
+
}));
|
|
436
|
+
},
|
|
437
|
+
applyAnswer: (state, answer) => ({ ...state, scopes: answer })
|
|
438
|
+
}
|
|
439
|
+
],
|
|
440
|
+
async finalize(state, rt) {
|
|
441
|
+
if (!state.scopes) {
|
|
442
|
+
throw new Error("Intercom setup: incomplete state on finalize");
|
|
443
|
+
}
|
|
444
|
+
const targetScopes = await resolveSetupSelection({
|
|
445
|
+
selected: state.scopes,
|
|
446
|
+
allSentinel: "__ALL__",
|
|
447
|
+
fetchAll: async () => INTERCOM_SCOPES.map((s) => s.value),
|
|
448
|
+
limit: INTERCOM_SETUP_MAX_SCOPES
|
|
449
|
+
});
|
|
450
|
+
const scopeByValue = new Map(INTERCOM_SCOPES.map((s) => [s.value, s]));
|
|
451
|
+
const sections = [
|
|
452
|
+
"## Intercom",
|
|
453
|
+
"",
|
|
454
|
+
"### Selected scopes",
|
|
455
|
+
"",
|
|
456
|
+
"| Scope | Count |",
|
|
457
|
+
"|-------|-------|"
|
|
458
|
+
];
|
|
459
|
+
for (const value of targetScopes) {
|
|
460
|
+
const scope = scopeByValue.get(value);
|
|
461
|
+
if (!scope) {
|
|
462
|
+
sections.push(`| ${value} | _unknown_ |`);
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
const count = await fetchCount(rt.config.proxyFetch, scope.countPath);
|
|
466
|
+
sections.push(
|
|
467
|
+
`| ${scope.label} (${scope.value}) | ${count == null ? "-" : count} |`
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
sections.push("");
|
|
471
|
+
return sections.join("\n");
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
|
|
326
475
|
// ../connectors/src/connectors/intercom-oauth/parameters.ts
|
|
327
476
|
var parameters = {};
|
|
328
477
|
|
|
@@ -331,6 +480,7 @@ var tools = { request: requestTool };
|
|
|
331
480
|
var intercomOauthConnector = new ConnectorPlugin({
|
|
332
481
|
slug: "intercom",
|
|
333
482
|
authType: AUTH_TYPES.OAUTH,
|
|
483
|
+
skipConnectionCheckOnCreate: true,
|
|
334
484
|
name: "Intercom",
|
|
335
485
|
description: "Connect to Intercom for contacts, conversations, companies, and customer engagement data using OAuth.",
|
|
336
486
|
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/sb2cRMGClpId0LKiSqsok/ae90a0849f21ffe3faf73e04a5676b45/intercom.svg",
|
|
@@ -465,6 +615,7 @@ const data = await res.json();
|
|
|
465
615
|
\`\`\``
|
|
466
616
|
},
|
|
467
617
|
tools,
|
|
618
|
+
setup: (params, ctx, config) => runSetupFlow(intercomOauthSetupFlow, params, ctx, config),
|
|
468
619
|
async checkConnection(_params, config) {
|
|
469
620
|
const { proxyFetch } = config;
|
|
470
621
|
try {
|
|
@@ -514,6 +665,7 @@ function resolveEnvVarOptional(entry, key) {
|
|
|
514
665
|
import { getContext } from "hono/context-storage";
|
|
515
666
|
import { getCookie } from "hono/cookie";
|
|
516
667
|
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
668
|
+
var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
|
|
517
669
|
function normalizeHeaders(input) {
|
|
518
670
|
const out = {};
|
|
519
671
|
if (!input) return out;
|
|
@@ -522,6 +674,11 @@ function normalizeHeaders(input) {
|
|
|
522
674
|
});
|
|
523
675
|
return out;
|
|
524
676
|
}
|
|
677
|
+
function extractInputUrl(input) {
|
|
678
|
+
if (typeof input === "string") return input;
|
|
679
|
+
if (input instanceof URL) return input.href;
|
|
680
|
+
return input.url;
|
|
681
|
+
}
|
|
525
682
|
function createSandboxProxyFetch(connectionId) {
|
|
526
683
|
return async (input, init) => {
|
|
527
684
|
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
@@ -531,10 +688,17 @@ function createSandboxProxyFetch(connectionId) {
|
|
|
531
688
|
"Connection proxy is not configured. Please check your deployment settings."
|
|
532
689
|
);
|
|
533
690
|
}
|
|
534
|
-
const originalUrl =
|
|
691
|
+
const originalUrl = extractInputUrl(input);
|
|
692
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
693
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
694
|
+
const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
695
|
+
return fetch(sessionUrl, {
|
|
696
|
+
method: "POST",
|
|
697
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
698
|
+
});
|
|
699
|
+
}
|
|
535
700
|
const originalMethod = init?.method ?? "GET";
|
|
536
701
|
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
537
|
-
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
538
702
|
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
539
703
|
return fetch(proxyUrl, {
|
|
540
704
|
method: "POST",
|
|
@@ -560,10 +724,9 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
560
724
|
}
|
|
561
725
|
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
562
726
|
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
727
|
+
const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
563
728
|
return async (input, init) => {
|
|
564
|
-
const originalUrl =
|
|
565
|
-
const originalMethod = init?.method ?? "GET";
|
|
566
|
-
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
729
|
+
const originalUrl = extractInputUrl(input);
|
|
567
730
|
const c = getContext();
|
|
568
731
|
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
569
732
|
if (!appSession) {
|
|
@@ -571,6 +734,14 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
571
734
|
"No authentication method available for connection proxy."
|
|
572
735
|
);
|
|
573
736
|
}
|
|
737
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
738
|
+
return fetch(sessionUrl, {
|
|
739
|
+
method: "POST",
|
|
740
|
+
headers: { Authorization: `Bearer ${appSession}` }
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
const originalMethod = init?.method ?? "GET";
|
|
744
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
574
745
|
return fetch(proxyUrl, {
|
|
575
746
|
method: "POST",
|
|
576
747
|
headers: {
|
|
@@ -1,48 +1,60 @@
|
|
|
1
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
2
|
+
var __esm = (fn, res) => function __init() {
|
|
3
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
4
|
+
};
|
|
5
|
+
|
|
1
6
|
// ../connectors/src/parameter-definition.ts
|
|
2
|
-
var ParameterDefinition
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
7
|
+
var ParameterDefinition;
|
|
8
|
+
var init_parameter_definition = __esm({
|
|
9
|
+
"../connectors/src/parameter-definition.ts"() {
|
|
10
|
+
"use strict";
|
|
11
|
+
ParameterDefinition = class {
|
|
12
|
+
slug;
|
|
13
|
+
name;
|
|
14
|
+
description;
|
|
15
|
+
envVarBaseKey;
|
|
16
|
+
type;
|
|
17
|
+
secret;
|
|
18
|
+
required;
|
|
19
|
+
constructor(config) {
|
|
20
|
+
this.slug = config.slug;
|
|
21
|
+
this.name = config.name;
|
|
22
|
+
this.description = config.description;
|
|
23
|
+
this.envVarBaseKey = config.envVarBaseKey;
|
|
24
|
+
this.type = config.type;
|
|
25
|
+
this.secret = config.secret;
|
|
26
|
+
this.required = config.required;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get the parameter value from a ConnectorConnectionObject.
|
|
30
|
+
*/
|
|
31
|
+
getValue(connection2) {
|
|
32
|
+
const param = connection2.parameters.find(
|
|
33
|
+
(p) => p.parameterSlug === this.slug
|
|
34
|
+
);
|
|
35
|
+
if (!param || param.value == null) {
|
|
36
|
+
throw new Error(
|
|
37
|
+
`Parameter "${this.slug}" not found or has no value in connection "${connection2.id}"`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
return param.value;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Try to get the parameter value. Returns undefined if not found (for optional params).
|
|
44
|
+
*/
|
|
45
|
+
tryGetValue(connection2) {
|
|
46
|
+
const param = connection2.parameters.find(
|
|
47
|
+
(p) => p.parameterSlug === this.slug
|
|
48
|
+
);
|
|
49
|
+
if (!param || param.value == null) return void 0;
|
|
50
|
+
return param.value;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
42
53
|
}
|
|
43
|
-
};
|
|
54
|
+
});
|
|
44
55
|
|
|
45
56
|
// ../connectors/src/connectors/intercom/parameters.ts
|
|
57
|
+
init_parameter_definition();
|
|
46
58
|
var parameters = {
|
|
47
59
|
accessToken: new ParameterDefinition({
|
|
48
60
|
slug: "access-token",
|
|
@@ -222,6 +234,20 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
222
234
|
* `runSetupFlow` from `setup-flow.ts`.
|
|
223
235
|
*/
|
|
224
236
|
setup;
|
|
237
|
+
/**
|
|
238
|
+
* Opt-out of the default "verify before save" behavior on connection
|
|
239
|
+
* creation. The backend invokes `checkConnection` synchronously while
|
|
240
|
+
* creating the connection and aborts (no row inserted) if it fails — this
|
|
241
|
+
* flag disables that for connectors where the check cannot succeed pre-save:
|
|
242
|
+
*
|
|
243
|
+
* - `squadbase-db` populates `connection-url` only after Neon provisioning
|
|
244
|
+
* - OAuth connectors require an OAuth-aware proxyFetch keyed by the
|
|
245
|
+
* connectionId, which doesn't exist until the row is saved
|
|
246
|
+
*
|
|
247
|
+
* Exceptions are the explicit position; new credential-input connectors get
|
|
248
|
+
* the default verify-on-create behavior without opt-in.
|
|
249
|
+
*/
|
|
250
|
+
skipConnectionCheckOnCreate;
|
|
225
251
|
constructor(config) {
|
|
226
252
|
this.slug = config.slug;
|
|
227
253
|
this.authType = config.authType;
|
|
@@ -239,6 +265,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
239
265
|
this.query = config.query;
|
|
240
266
|
this.checkConnection = config.checkConnection;
|
|
241
267
|
this.setup = config.setup;
|
|
268
|
+
this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
|
|
242
269
|
}
|
|
243
270
|
get connectorKey() {
|
|
244
271
|
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
@@ -303,6 +330,51 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
303
330
|
}
|
|
304
331
|
};
|
|
305
332
|
|
|
333
|
+
// ../connectors/src/setup-flow.ts
|
|
334
|
+
async function runSetupFlow(flow, params, ctx, config) {
|
|
335
|
+
const runtime = {
|
|
336
|
+
params,
|
|
337
|
+
language: ctx.language,
|
|
338
|
+
config
|
|
339
|
+
};
|
|
340
|
+
let state = flow.initialState();
|
|
341
|
+
let answerIdx = 0;
|
|
342
|
+
for (const step of flow.steps) {
|
|
343
|
+
const ans = ctx.answers[answerIdx];
|
|
344
|
+
if (ans && ans.questionSlug === step.slug) {
|
|
345
|
+
state = step.applyAnswer(state, ans.answer);
|
|
346
|
+
answerIdx += 1;
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
if (step.type === "text") {
|
|
350
|
+
return {
|
|
351
|
+
type: "nextQuestion",
|
|
352
|
+
questionSlug: step.slug,
|
|
353
|
+
question: step.question[ctx.language],
|
|
354
|
+
questionType: "text"
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
358
|
+
if (options.length === 0) {
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
return {
|
|
362
|
+
type: "nextQuestion",
|
|
363
|
+
questionSlug: step.slug,
|
|
364
|
+
question: step.question[ctx.language],
|
|
365
|
+
questionType: step.type,
|
|
366
|
+
options
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
370
|
+
return { type: "fulfilled", dataInvestigationResult };
|
|
371
|
+
}
|
|
372
|
+
async function resolveSetupSelection(params) {
|
|
373
|
+
const { selected, allSentinel, fetchAll, limit } = params;
|
|
374
|
+
const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
|
|
375
|
+
return resolved.slice(0, limit);
|
|
376
|
+
}
|
|
377
|
+
|
|
306
378
|
// ../connectors/src/auth-types.ts
|
|
307
379
|
var AUTH_TYPES = {
|
|
308
380
|
OAUTH: "oauth",
|
|
@@ -327,9 +399,103 @@ var intercomOnboarding = new ConnectorOnboarding({
|
|
|
327
399
|
}
|
|
328
400
|
});
|
|
329
401
|
|
|
402
|
+
// ../connectors/src/connectors/intercom/utils.ts
|
|
403
|
+
var BASE_URL2 = "https://api.intercom.io";
|
|
404
|
+
var INTERCOM_VERSION = "2.11";
|
|
405
|
+
async function apiFetch(params, path2, init) {
|
|
406
|
+
const accessToken = params[parameters.accessToken.slug];
|
|
407
|
+
if (!accessToken) {
|
|
408
|
+
throw new Error("intercom: missing required parameter: access-token");
|
|
409
|
+
}
|
|
410
|
+
const url = `${BASE_URL2}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
411
|
+
const headers = new Headers(init?.headers);
|
|
412
|
+
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
413
|
+
headers.set("Accept", "application/json");
|
|
414
|
+
headers.set("Intercom-Version", INTERCOM_VERSION);
|
|
415
|
+
return fetch(url, { ...init, headers });
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// ../connectors/src/connectors/intercom/setup-flow.ts
|
|
419
|
+
var INTERCOM_SETUP_MAX_SCOPES = 10;
|
|
420
|
+
var INTERCOM_SCOPES = [
|
|
421
|
+
{ value: "contacts", label: "Contacts", countPath: "/contacts?per_page=1" },
|
|
422
|
+
{ value: "companies", label: "Companies", countPath: "/companies?per_page=1" },
|
|
423
|
+
{
|
|
424
|
+
value: "conversations",
|
|
425
|
+
label: "Conversations",
|
|
426
|
+
countPath: "/conversations?per_page=1"
|
|
427
|
+
},
|
|
428
|
+
{ value: "articles", label: "Articles", countPath: "/articles?per_page=1" },
|
|
429
|
+
{ value: "teams", label: "Teams", countPath: "/teams" }
|
|
430
|
+
];
|
|
431
|
+
async function fetchCount(params, path2) {
|
|
432
|
+
const res = await apiFetch(params, path2);
|
|
433
|
+
if (!res.ok) {
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
const data = await res.json();
|
|
437
|
+
if (typeof data.total_count === "number") return data.total_count;
|
|
438
|
+
if (Array.isArray(data.teams)) return data.teams.length;
|
|
439
|
+
if (Array.isArray(data.data)) return data.data.length;
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
var intercomSetupFlow = {
|
|
443
|
+
initialState: () => ({}),
|
|
444
|
+
steps: [
|
|
445
|
+
{
|
|
446
|
+
slug: "scopes",
|
|
447
|
+
type: "multiSelect",
|
|
448
|
+
question: {
|
|
449
|
+
ja: "\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3067\u6982\u89B3\u3057\u305F\u3044Intercom\u30C7\u30FC\u30BF\u30B9\u30B3\u30FC\u30D7\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
450
|
+
en: "Select the Intercom data scopes to include in setup (multi-select allowed)"
|
|
451
|
+
},
|
|
452
|
+
async fetchOptions(_state, _rt) {
|
|
453
|
+
return INTERCOM_SCOPES.map((s) => ({
|
|
454
|
+
value: s.value,
|
|
455
|
+
label: s.label
|
|
456
|
+
}));
|
|
457
|
+
},
|
|
458
|
+
applyAnswer: (state, answer) => ({ ...state, scopes: answer })
|
|
459
|
+
}
|
|
460
|
+
],
|
|
461
|
+
async finalize(state, rt) {
|
|
462
|
+
if (!state.scopes) {
|
|
463
|
+
throw new Error("Intercom setup: incomplete state on finalize");
|
|
464
|
+
}
|
|
465
|
+
const targetScopes = await resolveSetupSelection({
|
|
466
|
+
selected: state.scopes,
|
|
467
|
+
allSentinel: "__ALL__",
|
|
468
|
+
fetchAll: async () => INTERCOM_SCOPES.map((s) => s.value),
|
|
469
|
+
limit: INTERCOM_SETUP_MAX_SCOPES
|
|
470
|
+
});
|
|
471
|
+
const scopeByValue = new Map(INTERCOM_SCOPES.map((s) => [s.value, s]));
|
|
472
|
+
const sections = [
|
|
473
|
+
"## Intercom",
|
|
474
|
+
"",
|
|
475
|
+
"### Selected scopes",
|
|
476
|
+
"",
|
|
477
|
+
"| Scope | Count |",
|
|
478
|
+
"|-------|-------|"
|
|
479
|
+
];
|
|
480
|
+
for (const value of targetScopes) {
|
|
481
|
+
const scope = scopeByValue.get(value);
|
|
482
|
+
if (!scope) {
|
|
483
|
+
sections.push(`| ${value} | _unknown_ |`);
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
const count = await fetchCount(rt.params, scope.countPath);
|
|
487
|
+
sections.push(
|
|
488
|
+
`| ${scope.label} (${scope.value}) | ${count == null ? "-" : count} |`
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
sections.push("");
|
|
492
|
+
return sections.join("\n");
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
|
|
330
496
|
// ../connectors/src/connectors/intercom/tools/request.ts
|
|
331
497
|
import { z } from "zod";
|
|
332
|
-
var
|
|
498
|
+
var BASE_URL3 = "https://api.intercom.io";
|
|
333
499
|
var API_VERSION2 = "2.11";
|
|
334
500
|
var REQUEST_TIMEOUT_MS = 6e4;
|
|
335
501
|
var inputSchema = z.object({
|
|
@@ -379,7 +545,7 @@ The Intercom-Version header is set to 2.11 automatically.`,
|
|
|
379
545
|
);
|
|
380
546
|
try {
|
|
381
547
|
const accessToken = parameters.accessToken.getValue(connection2);
|
|
382
|
-
const url = `${
|
|
548
|
+
const url = `${BASE_URL3}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
383
549
|
const controller = new AbortController();
|
|
384
550
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
385
551
|
try {
|
|
@@ -617,7 +783,40 @@ export default async function handler(c: Context) {
|
|
|
617
783
|
- \u8AD6\u7406\u6F14\u7B97\u5B50: \`AND\`, \`OR\`\uFF08\u8907\u6570\u30D5\u30A3\u30EB\u30BF\u306E\u7D50\u5408\uFF09
|
|
618
784
|
- \u65E5\u4ED8\u30D5\u30A3\u30FC\u30EB\u30C9\u306FUnix\u30BF\u30A4\u30E0\u30B9\u30BF\u30F3\u30D7\u3092\u4F7F\u7528`
|
|
619
785
|
},
|
|
620
|
-
tools
|
|
786
|
+
tools,
|
|
787
|
+
setup: (params, ctx, config) => runSetupFlow(intercomSetupFlow, params, ctx, config),
|
|
788
|
+
async checkConnection(params, _config) {
|
|
789
|
+
const accessToken = params[parameters.accessToken.slug];
|
|
790
|
+
if (!accessToken) {
|
|
791
|
+
return {
|
|
792
|
+
success: false,
|
|
793
|
+
error: `Missing required parameter: ${parameters.accessToken.slug}`
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
try {
|
|
797
|
+
const res = await fetch("https://api.intercom.io/me", {
|
|
798
|
+
method: "GET",
|
|
799
|
+
headers: {
|
|
800
|
+
Authorization: `Bearer ${accessToken}`,
|
|
801
|
+
"Intercom-Version": "2.11",
|
|
802
|
+
Accept: "application/json"
|
|
803
|
+
}
|
|
804
|
+
});
|
|
805
|
+
if (!res.ok) {
|
|
806
|
+
const errText = await res.text().catch(() => res.statusText);
|
|
807
|
+
return {
|
|
808
|
+
success: false,
|
|
809
|
+
error: `Intercom API failed: HTTP ${res.status} ${errText}`
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
return { success: true };
|
|
813
|
+
} catch (error) {
|
|
814
|
+
return {
|
|
815
|
+
success: false,
|
|
816
|
+
error: error instanceof Error ? error.message : String(error)
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
}
|
|
621
820
|
});
|
|
622
821
|
|
|
623
822
|
// src/connectors/create-connector-sdk.ts
|
|
@@ -646,6 +845,7 @@ function resolveEnvVarOptional(entry, key) {
|
|
|
646
845
|
import { getContext } from "hono/context-storage";
|
|
647
846
|
import { getCookie } from "hono/cookie";
|
|
648
847
|
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
848
|
+
var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
|
|
649
849
|
function normalizeHeaders(input) {
|
|
650
850
|
const out = {};
|
|
651
851
|
if (!input) return out;
|
|
@@ -654,6 +854,11 @@ function normalizeHeaders(input) {
|
|
|
654
854
|
});
|
|
655
855
|
return out;
|
|
656
856
|
}
|
|
857
|
+
function extractInputUrl(input) {
|
|
858
|
+
if (typeof input === "string") return input;
|
|
859
|
+
if (input instanceof URL) return input.href;
|
|
860
|
+
return input.url;
|
|
861
|
+
}
|
|
657
862
|
function createSandboxProxyFetch(connectionId) {
|
|
658
863
|
return async (input, init) => {
|
|
659
864
|
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
@@ -663,10 +868,17 @@ function createSandboxProxyFetch(connectionId) {
|
|
|
663
868
|
"Connection proxy is not configured. Please check your deployment settings."
|
|
664
869
|
);
|
|
665
870
|
}
|
|
666
|
-
const originalUrl =
|
|
871
|
+
const originalUrl = extractInputUrl(input);
|
|
872
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
873
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
874
|
+
const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
875
|
+
return fetch(sessionUrl, {
|
|
876
|
+
method: "POST",
|
|
877
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
878
|
+
});
|
|
879
|
+
}
|
|
667
880
|
const originalMethod = init?.method ?? "GET";
|
|
668
881
|
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
669
|
-
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
670
882
|
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
671
883
|
return fetch(proxyUrl, {
|
|
672
884
|
method: "POST",
|
|
@@ -692,10 +904,9 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
692
904
|
}
|
|
693
905
|
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
694
906
|
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
907
|
+
const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
695
908
|
return async (input, init) => {
|
|
696
|
-
const originalUrl =
|
|
697
|
-
const originalMethod = init?.method ?? "GET";
|
|
698
|
-
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
909
|
+
const originalUrl = extractInputUrl(input);
|
|
699
910
|
const c = getContext();
|
|
700
911
|
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
701
912
|
if (!appSession) {
|
|
@@ -703,6 +914,14 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
703
914
|
"No authentication method available for connection proxy."
|
|
704
915
|
);
|
|
705
916
|
}
|
|
917
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
918
|
+
return fetch(sessionUrl, {
|
|
919
|
+
method: "POST",
|
|
920
|
+
headers: { Authorization: `Bearer ${appSession}` }
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
const originalMethod = init?.method ?? "GET";
|
|
924
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
706
925
|
return fetch(proxyUrl, {
|
|
707
926
|
method: "POST",
|
|
708
927
|
headers: {
|