@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,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/sentry/parameters.ts
|
|
57
|
+
init_parameter_definition();
|
|
46
58
|
var parameters = {
|
|
47
59
|
organizationSlug: new ParameterDefinition({
|
|
48
60
|
slug: "organization-slug",
|
|
@@ -94,7 +106,7 @@ function createClient(params) {
|
|
|
94
106
|
const url = `${BASE_URL}${resolved.startsWith("/") ? "" : "/"}${resolved}`;
|
|
95
107
|
return authenticatedFetch(url, init);
|
|
96
108
|
}
|
|
97
|
-
async function
|
|
109
|
+
async function listProjects2() {
|
|
98
110
|
const url = `${BASE_URL}/organizations/${organizationSlug}/projects/`;
|
|
99
111
|
const response = await authenticatedFetch(url);
|
|
100
112
|
if (!response.ok) {
|
|
@@ -160,7 +172,7 @@ function createClient(params) {
|
|
|
160
172
|
}
|
|
161
173
|
return {
|
|
162
174
|
request,
|
|
163
|
-
listProjects,
|
|
175
|
+
listProjects: listProjects2,
|
|
164
176
|
listIssues,
|
|
165
177
|
getIssue,
|
|
166
178
|
listIssueEvents,
|
|
@@ -235,6 +247,20 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
235
247
|
* `runSetupFlow` from `setup-flow.ts`.
|
|
236
248
|
*/
|
|
237
249
|
setup;
|
|
250
|
+
/**
|
|
251
|
+
* Opt-out of the default "verify before save" behavior on connection
|
|
252
|
+
* creation. The backend invokes `checkConnection` synchronously while
|
|
253
|
+
* creating the connection and aborts (no row inserted) if it fails — this
|
|
254
|
+
* flag disables that for connectors where the check cannot succeed pre-save:
|
|
255
|
+
*
|
|
256
|
+
* - `squadbase-db` populates `connection-url` only after Neon provisioning
|
|
257
|
+
* - OAuth connectors require an OAuth-aware proxyFetch keyed by the
|
|
258
|
+
* connectionId, which doesn't exist until the row is saved
|
|
259
|
+
*
|
|
260
|
+
* Exceptions are the explicit position; new credential-input connectors get
|
|
261
|
+
* the default verify-on-create behavior without opt-in.
|
|
262
|
+
*/
|
|
263
|
+
skipConnectionCheckOnCreate;
|
|
238
264
|
constructor(config) {
|
|
239
265
|
this.slug = config.slug;
|
|
240
266
|
this.authType = config.authType;
|
|
@@ -252,6 +278,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
252
278
|
this.query = config.query;
|
|
253
279
|
this.checkConnection = config.checkConnection;
|
|
254
280
|
this.setup = config.setup;
|
|
281
|
+
this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
|
|
255
282
|
}
|
|
256
283
|
get connectorKey() {
|
|
257
284
|
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
@@ -316,6 +343,51 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
316
343
|
}
|
|
317
344
|
};
|
|
318
345
|
|
|
346
|
+
// ../connectors/src/setup-flow.ts
|
|
347
|
+
async function runSetupFlow(flow, params, ctx, config) {
|
|
348
|
+
const runtime = {
|
|
349
|
+
params,
|
|
350
|
+
language: ctx.language,
|
|
351
|
+
config
|
|
352
|
+
};
|
|
353
|
+
let state = flow.initialState();
|
|
354
|
+
let answerIdx = 0;
|
|
355
|
+
for (const step of flow.steps) {
|
|
356
|
+
const ans = ctx.answers[answerIdx];
|
|
357
|
+
if (ans && ans.questionSlug === step.slug) {
|
|
358
|
+
state = step.applyAnswer(state, ans.answer);
|
|
359
|
+
answerIdx += 1;
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
if (step.type === "text") {
|
|
363
|
+
return {
|
|
364
|
+
type: "nextQuestion",
|
|
365
|
+
questionSlug: step.slug,
|
|
366
|
+
question: step.question[ctx.language],
|
|
367
|
+
questionType: "text"
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
371
|
+
if (options.length === 0) {
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
return {
|
|
375
|
+
type: "nextQuestion",
|
|
376
|
+
questionSlug: step.slug,
|
|
377
|
+
question: step.question[ctx.language],
|
|
378
|
+
questionType: step.type,
|
|
379
|
+
options
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
383
|
+
return { type: "fulfilled", dataInvestigationResult };
|
|
384
|
+
}
|
|
385
|
+
async function resolveSetupSelection(params) {
|
|
386
|
+
const { selected, allSentinel, fetchAll, limit } = params;
|
|
387
|
+
const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
|
|
388
|
+
return resolved.slice(0, limit);
|
|
389
|
+
}
|
|
390
|
+
|
|
319
391
|
// ../connectors/src/auth-types.ts
|
|
320
392
|
var AUTH_TYPES = {
|
|
321
393
|
OAUTH: "oauth",
|
|
@@ -338,9 +410,121 @@ var sentryOnboarding = new ConnectorOnboarding({
|
|
|
338
410
|
}
|
|
339
411
|
});
|
|
340
412
|
|
|
413
|
+
// ../connectors/src/connectors/sentry/utils.ts
|
|
414
|
+
var BASE_URL2 = "https://sentry.io/api/0";
|
|
415
|
+
async function apiFetch(params, path2, init) {
|
|
416
|
+
const authToken = params[parameters.authToken.slug];
|
|
417
|
+
if (!authToken) {
|
|
418
|
+
throw new Error("sentry: missing required parameter: auth-token");
|
|
419
|
+
}
|
|
420
|
+
const url = `${BASE_URL2}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
421
|
+
const headers = new Headers(init?.headers);
|
|
422
|
+
headers.set("Authorization", `Bearer ${authToken}`);
|
|
423
|
+
if (!headers.has("Accept")) headers.set("Accept", "application/json");
|
|
424
|
+
return fetch(url, { ...init, headers });
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// ../connectors/src/connectors/sentry/setup-flow.ts
|
|
428
|
+
var ALL_PROJECTS = "__ALL_PROJECTS__";
|
|
429
|
+
var SENTRY_SETUP_MAX_PROJECTS = 20;
|
|
430
|
+
async function listOrganizations(params) {
|
|
431
|
+
const res = await apiFetch(params, "/organizations/");
|
|
432
|
+
if (!res.ok) {
|
|
433
|
+
const body = await res.text().catch(() => res.statusText);
|
|
434
|
+
throw new Error(`sentry: listOrganizations failed (${res.status}): ${body}`);
|
|
435
|
+
}
|
|
436
|
+
const data = await res.json();
|
|
437
|
+
return data ?? [];
|
|
438
|
+
}
|
|
439
|
+
async function listProjects(params, orgSlug) {
|
|
440
|
+
const res = await apiFetch(params, `/organizations/${orgSlug}/projects/`);
|
|
441
|
+
if (!res.ok) {
|
|
442
|
+
const body = await res.text().catch(() => res.statusText);
|
|
443
|
+
throw new Error(`sentry: listProjects failed (${res.status}): ${body}`);
|
|
444
|
+
}
|
|
445
|
+
const data = await res.json();
|
|
446
|
+
return data ?? [];
|
|
447
|
+
}
|
|
448
|
+
var sentrySetupFlow = {
|
|
449
|
+
initialState: () => ({}),
|
|
450
|
+
steps: [
|
|
451
|
+
{
|
|
452
|
+
slug: "organization",
|
|
453
|
+
type: "select",
|
|
454
|
+
question: {
|
|
455
|
+
ja: "\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u306B\u4F7F\u3046\u7D44\u7E54\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044",
|
|
456
|
+
en: "Select the organization to use for setup"
|
|
457
|
+
},
|
|
458
|
+
async fetchOptions(_state, rt) {
|
|
459
|
+
const orgs = await listOrganizations(rt.params);
|
|
460
|
+
return orgs.filter((o) => o.slug).map((o) => ({ value: o.slug, label: o.name || o.slug }));
|
|
461
|
+
},
|
|
462
|
+
applyAnswer: (state, answer) => ({ ...state, organization: answer[0] })
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
slug: "projects",
|
|
466
|
+
type: "multiSelect",
|
|
467
|
+
question: {
|
|
468
|
+
ja: "\u5BFE\u8C61\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
469
|
+
en: "Select target projects (multi-select allowed)"
|
|
470
|
+
},
|
|
471
|
+
async fetchOptions(state, rt) {
|
|
472
|
+
if (!state.organization) return [];
|
|
473
|
+
const projects = await listProjects(rt.params, state.organization);
|
|
474
|
+
const opts = projects.filter((p) => p.slug).map((p) => ({ value: p.slug, label: p.name || p.slug }));
|
|
475
|
+
if (opts.length === 0) return [];
|
|
476
|
+
return [
|
|
477
|
+
{
|
|
478
|
+
value: ALL_PROJECTS,
|
|
479
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8" : "All projects"
|
|
480
|
+
},
|
|
481
|
+
...opts
|
|
482
|
+
];
|
|
483
|
+
},
|
|
484
|
+
applyAnswer: (state, answer) => ({ ...state, projects: answer })
|
|
485
|
+
}
|
|
486
|
+
],
|
|
487
|
+
async finalize(state, rt) {
|
|
488
|
+
if (!state.organization || !state.projects) {
|
|
489
|
+
throw new Error("Sentry setup: incomplete state on finalize");
|
|
490
|
+
}
|
|
491
|
+
const orgSlug = state.organization;
|
|
492
|
+
const projects = await listProjects(rt.params, orgSlug);
|
|
493
|
+
const bySlug = new Map(projects.map((p) => [p.slug, p]));
|
|
494
|
+
const targetSlugs = await resolveSetupSelection({
|
|
495
|
+
selected: state.projects,
|
|
496
|
+
allSentinel: ALL_PROJECTS,
|
|
497
|
+
fetchAll: async () => projects.map((p) => p.slug).filter((s) => s),
|
|
498
|
+
limit: SENTRY_SETUP_MAX_PROJECTS
|
|
499
|
+
});
|
|
500
|
+
const sections = [
|
|
501
|
+
"## Sentry",
|
|
502
|
+
"",
|
|
503
|
+
`### Organization: ${orgSlug}`,
|
|
504
|
+
""
|
|
505
|
+
];
|
|
506
|
+
for (const slug of targetSlugs) {
|
|
507
|
+
const project = bySlug.get(slug);
|
|
508
|
+
if (!project) {
|
|
509
|
+
sections.push(`#### Project: ${slug}`, "", "_Not found._", "");
|
|
510
|
+
continue;
|
|
511
|
+
}
|
|
512
|
+
sections.push(`#### Project: ${project.name || project.slug}`, "");
|
|
513
|
+
sections.push("| Field | Value |");
|
|
514
|
+
sections.push("|-------|-------|");
|
|
515
|
+
sections.push(`| Slug | ${project.slug} |`);
|
|
516
|
+
sections.push(`| Platform | ${project.platform ?? "-"} |`);
|
|
517
|
+
sections.push(`| First event | ${project.firstEvent ?? "-"} |`);
|
|
518
|
+
sections.push(`| Created | ${project.dateCreated ?? "-"} |`);
|
|
519
|
+
sections.push("");
|
|
520
|
+
}
|
|
521
|
+
return sections.join("\n");
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
|
|
341
525
|
// ../connectors/src/connectors/sentry/tools/request.ts
|
|
342
526
|
import { z } from "zod";
|
|
343
|
-
var
|
|
527
|
+
var BASE_URL3 = "https://sentry.io/api/0";
|
|
344
528
|
var REQUEST_TIMEOUT_MS = 6e4;
|
|
345
529
|
var inputSchema = z.object({
|
|
346
530
|
toolUseIntent: z.string().optional().describe(
|
|
@@ -390,7 +574,7 @@ Authentication is handled automatically via Bearer token.
|
|
|
390
574
|
/\{organizationSlug\}/g,
|
|
391
575
|
organizationSlug
|
|
392
576
|
);
|
|
393
|
-
const url = `${
|
|
577
|
+
const url = `${BASE_URL3}${resolvedPath.startsWith("/") ? "" : "/"}${resolvedPath}`;
|
|
394
578
|
const controller = new AbortController();
|
|
395
579
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
396
580
|
try {
|
|
@@ -599,6 +783,7 @@ await sentry.updateIssue("12345", { status: "resolved" });
|
|
|
599
783
|
\`\`\``
|
|
600
784
|
},
|
|
601
785
|
tools,
|
|
786
|
+
setup: (params, ctx, config) => runSetupFlow(sentrySetupFlow, params, ctx, config),
|
|
602
787
|
async checkConnection(params) {
|
|
603
788
|
const authToken = params[parameters.authToken.slug];
|
|
604
789
|
const organizationSlug = params[parameters.organizationSlug.slug];
|
|
@@ -660,6 +845,7 @@ function resolveEnvVarOptional(entry, key) {
|
|
|
660
845
|
import { getContext } from "hono/context-storage";
|
|
661
846
|
import { getCookie } from "hono/cookie";
|
|
662
847
|
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
848
|
+
var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
|
|
663
849
|
function normalizeHeaders(input) {
|
|
664
850
|
const out = {};
|
|
665
851
|
if (!input) return out;
|
|
@@ -668,6 +854,11 @@ function normalizeHeaders(input) {
|
|
|
668
854
|
});
|
|
669
855
|
return out;
|
|
670
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
|
+
}
|
|
671
862
|
function createSandboxProxyFetch(connectionId) {
|
|
672
863
|
return async (input, init) => {
|
|
673
864
|
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
@@ -677,10 +868,17 @@ function createSandboxProxyFetch(connectionId) {
|
|
|
677
868
|
"Connection proxy is not configured. Please check your deployment settings."
|
|
678
869
|
);
|
|
679
870
|
}
|
|
680
|
-
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
|
+
}
|
|
681
880
|
const originalMethod = init?.method ?? "GET";
|
|
682
881
|
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
683
|
-
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
684
882
|
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
685
883
|
return fetch(proxyUrl, {
|
|
686
884
|
method: "POST",
|
|
@@ -706,10 +904,9 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
706
904
|
}
|
|
707
905
|
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
708
906
|
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
907
|
+
const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
709
908
|
return async (input, init) => {
|
|
710
|
-
const originalUrl =
|
|
711
|
-
const originalMethod = init?.method ?? "GET";
|
|
712
|
-
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
909
|
+
const originalUrl = extractInputUrl(input);
|
|
713
910
|
const c = getContext();
|
|
714
911
|
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
715
912
|
if (!appSession) {
|
|
@@ -717,6 +914,14 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
717
914
|
"No authentication method available for connection proxy."
|
|
718
915
|
);
|
|
719
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;
|
|
720
925
|
return fetch(proxyUrl, {
|
|
721
926
|
method: "POST",
|
|
722
927
|
headers: {
|
|
@@ -73,6 +73,20 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
73
73
|
* `runSetupFlow` from `setup-flow.ts`.
|
|
74
74
|
*/
|
|
75
75
|
setup;
|
|
76
|
+
/**
|
|
77
|
+
* Opt-out of the default "verify before save" behavior on connection
|
|
78
|
+
* creation. The backend invokes `checkConnection` synchronously while
|
|
79
|
+
* creating the connection and aborts (no row inserted) if it fails — this
|
|
80
|
+
* flag disables that for connectors where the check cannot succeed pre-save:
|
|
81
|
+
*
|
|
82
|
+
* - `squadbase-db` populates `connection-url` only after Neon provisioning
|
|
83
|
+
* - OAuth connectors require an OAuth-aware proxyFetch keyed by the
|
|
84
|
+
* connectionId, which doesn't exist until the row is saved
|
|
85
|
+
*
|
|
86
|
+
* Exceptions are the explicit position; new credential-input connectors get
|
|
87
|
+
* the default verify-on-create behavior without opt-in.
|
|
88
|
+
*/
|
|
89
|
+
skipConnectionCheckOnCreate;
|
|
76
90
|
constructor(config) {
|
|
77
91
|
this.slug = config.slug;
|
|
78
92
|
this.authType = config.authType;
|
|
@@ -90,6 +104,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
90
104
|
this.query = config.query;
|
|
91
105
|
this.checkConnection = config.checkConnection;
|
|
92
106
|
this.setup = config.setup;
|
|
107
|
+
this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
|
|
93
108
|
}
|
|
94
109
|
get connectorKey() {
|
|
95
110
|
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
@@ -154,6 +169,46 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
154
169
|
}
|
|
155
170
|
};
|
|
156
171
|
|
|
172
|
+
// ../connectors/src/setup-flow.ts
|
|
173
|
+
async function runSetupFlow(flow, params, ctx, config) {
|
|
174
|
+
const runtime = {
|
|
175
|
+
params,
|
|
176
|
+
language: ctx.language,
|
|
177
|
+
config
|
|
178
|
+
};
|
|
179
|
+
let state = flow.initialState();
|
|
180
|
+
let answerIdx = 0;
|
|
181
|
+
for (const step of flow.steps) {
|
|
182
|
+
const ans = ctx.answers[answerIdx];
|
|
183
|
+
if (ans && ans.questionSlug === step.slug) {
|
|
184
|
+
state = step.applyAnswer(state, ans.answer);
|
|
185
|
+
answerIdx += 1;
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if (step.type === "text") {
|
|
189
|
+
return {
|
|
190
|
+
type: "nextQuestion",
|
|
191
|
+
questionSlug: step.slug,
|
|
192
|
+
question: step.question[ctx.language],
|
|
193
|
+
questionType: "text"
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
197
|
+
if (options.length === 0) {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
type: "nextQuestion",
|
|
202
|
+
questionSlug: step.slug,
|
|
203
|
+
question: step.question[ctx.language],
|
|
204
|
+
questionType: step.type,
|
|
205
|
+
options
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
209
|
+
return { type: "fulfilled", dataInvestigationResult };
|
|
210
|
+
}
|
|
211
|
+
|
|
157
212
|
// ../connectors/src/auth-types.ts
|
|
158
213
|
var AUTH_TYPES = {
|
|
159
214
|
OAUTH: "oauth",
|
|
@@ -316,11 +371,83 @@ var shopifyOauthOnboarding = new ConnectorOnboarding({
|
|
|
316
371
|
// ../connectors/src/connectors/shopify-oauth/parameters.ts
|
|
317
372
|
var parameters = {};
|
|
318
373
|
|
|
374
|
+
// ../connectors/src/connectors/shopify-oauth/setup-flow.ts
|
|
375
|
+
var SHOPIFY_API_VERSION = "2024-10";
|
|
376
|
+
var SHOPIFY_OAUTH_SETUP_MAX_ENTITIES = 10;
|
|
377
|
+
var ENTITY_LABELS = {
|
|
378
|
+
products: { en: "Products", ja: "Products (\u5546\u54C1)" },
|
|
379
|
+
orders: { en: "Orders", ja: "Orders (\u6CE8\u6587)" },
|
|
380
|
+
customers: { en: "Customers", ja: "Customers (\u9867\u5BA2)" },
|
|
381
|
+
collections: { en: "Collections", ja: "Collections (\u30B3\u30EC\u30AF\u30B7\u30E7\u30F3)" },
|
|
382
|
+
inventory: { en: "Inventory items", ja: "Inventory items (\u5728\u5EAB)" },
|
|
383
|
+
discounts: { en: "Discounts", ja: "Discounts (\u5272\u5F15)" }
|
|
384
|
+
};
|
|
385
|
+
var ENTITY_VALUES = [
|
|
386
|
+
"products",
|
|
387
|
+
"orders",
|
|
388
|
+
"customers",
|
|
389
|
+
"collections",
|
|
390
|
+
"inventory",
|
|
391
|
+
"discounts"
|
|
392
|
+
];
|
|
393
|
+
var COUNT_PATHS = {
|
|
394
|
+
products: `/admin/api/${SHOPIFY_API_VERSION}/products/count.json`,
|
|
395
|
+
orders: `/admin/api/${SHOPIFY_API_VERSION}/orders/count.json?status=any`,
|
|
396
|
+
customers: `/admin/api/${SHOPIFY_API_VERSION}/customers/count.json`,
|
|
397
|
+
collections: `/admin/api/${SHOPIFY_API_VERSION}/custom_collections/count.json`,
|
|
398
|
+
inventory: null,
|
|
399
|
+
discounts: `/admin/api/${SHOPIFY_API_VERSION}/price_rules/count.json`
|
|
400
|
+
};
|
|
401
|
+
var shopifyOauthSetupFlow = {
|
|
402
|
+
initialState: () => ({}),
|
|
403
|
+
steps: [
|
|
404
|
+
{
|
|
405
|
+
slug: "entities",
|
|
406
|
+
type: "multiSelect",
|
|
407
|
+
question: {
|
|
408
|
+
ja: "\u5BFE\u8C61\u306E\u30A8\u30F3\u30C6\u30A3\u30C6\u30A3\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
409
|
+
en: "Select target entities (multi-select allowed)"
|
|
410
|
+
},
|
|
411
|
+
async fetchOptions(_state, rt) {
|
|
412
|
+
return ENTITY_VALUES.map((value) => ({
|
|
413
|
+
value,
|
|
414
|
+
label: ENTITY_LABELS[value][rt.language]
|
|
415
|
+
}));
|
|
416
|
+
},
|
|
417
|
+
applyAnswer: (state, answer) => ({ ...state, entities: answer })
|
|
418
|
+
}
|
|
419
|
+
],
|
|
420
|
+
async finalize(state, rt) {
|
|
421
|
+
if (!state.entities) {
|
|
422
|
+
throw new Error("Shopify setup: incomplete state on finalize");
|
|
423
|
+
}
|
|
424
|
+
const selected = state.entities.filter(
|
|
425
|
+
(e) => ENTITY_VALUES.includes(e)
|
|
426
|
+
).slice(0, SHOPIFY_OAUTH_SETUP_MAX_ENTITIES);
|
|
427
|
+
const sections = ["## Shopify", ""];
|
|
428
|
+
for (const entity of selected) {
|
|
429
|
+
const path2 = COUNT_PATHS[entity];
|
|
430
|
+
let count = "available";
|
|
431
|
+
if (path2) {
|
|
432
|
+
const res = await rt.config.proxyFetch(path2, { method: "GET" });
|
|
433
|
+
if (res.ok) {
|
|
434
|
+
const data = await res.json();
|
|
435
|
+
if (typeof data.count === "number") count = String(data.count);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
sections.push(`### ${ENTITY_LABELS[entity].en}`, "");
|
|
439
|
+
sections.push(`Count: ${count}`, "");
|
|
440
|
+
}
|
|
441
|
+
return sections.join("\n");
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
|
|
319
445
|
// ../connectors/src/connectors/shopify-oauth/index.ts
|
|
320
446
|
var tools = { request: requestTool };
|
|
321
447
|
var shopifyOauthConnector = new ConnectorPlugin({
|
|
322
448
|
slug: "shopify",
|
|
323
449
|
authType: AUTH_TYPES.OAUTH,
|
|
450
|
+
skipConnectionCheckOnCreate: true,
|
|
324
451
|
name: "Shopify",
|
|
325
452
|
description: "Connect to Shopify for e-commerce data including products, orders, and customers using OAuth.",
|
|
326
453
|
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/57KEjZCBskKgSxgKyU4Sm0/117d681a410f48dc36f97cdd9c0593c5/shopify-icon.svg",
|
|
@@ -433,6 +560,7 @@ const data = await res.json();
|
|
|
433
560
|
\`\`\``
|
|
434
561
|
},
|
|
435
562
|
tools,
|
|
563
|
+
setup: (params, ctx, config) => runSetupFlow(shopifyOauthSetupFlow, params, ctx, config),
|
|
436
564
|
async checkConnection(_params, config) {
|
|
437
565
|
const { proxyFetch } = config;
|
|
438
566
|
try {
|
|
@@ -482,6 +610,7 @@ function resolveEnvVarOptional(entry, key) {
|
|
|
482
610
|
import { getContext } from "hono/context-storage";
|
|
483
611
|
import { getCookie } from "hono/cookie";
|
|
484
612
|
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
613
|
+
var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
|
|
485
614
|
function normalizeHeaders(input) {
|
|
486
615
|
const out = {};
|
|
487
616
|
if (!input) return out;
|
|
@@ -490,6 +619,11 @@ function normalizeHeaders(input) {
|
|
|
490
619
|
});
|
|
491
620
|
return out;
|
|
492
621
|
}
|
|
622
|
+
function extractInputUrl(input) {
|
|
623
|
+
if (typeof input === "string") return input;
|
|
624
|
+
if (input instanceof URL) return input.href;
|
|
625
|
+
return input.url;
|
|
626
|
+
}
|
|
493
627
|
function createSandboxProxyFetch(connectionId) {
|
|
494
628
|
return async (input, init) => {
|
|
495
629
|
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
@@ -499,10 +633,17 @@ function createSandboxProxyFetch(connectionId) {
|
|
|
499
633
|
"Connection proxy is not configured. Please check your deployment settings."
|
|
500
634
|
);
|
|
501
635
|
}
|
|
502
|
-
const originalUrl =
|
|
636
|
+
const originalUrl = extractInputUrl(input);
|
|
637
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
638
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
639
|
+
const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
640
|
+
return fetch(sessionUrl, {
|
|
641
|
+
method: "POST",
|
|
642
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
643
|
+
});
|
|
644
|
+
}
|
|
503
645
|
const originalMethod = init?.method ?? "GET";
|
|
504
646
|
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
505
|
-
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
506
647
|
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
507
648
|
return fetch(proxyUrl, {
|
|
508
649
|
method: "POST",
|
|
@@ -528,10 +669,9 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
528
669
|
}
|
|
529
670
|
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
530
671
|
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
672
|
+
const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
531
673
|
return async (input, init) => {
|
|
532
|
-
const originalUrl =
|
|
533
|
-
const originalMethod = init?.method ?? "GET";
|
|
534
|
-
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
674
|
+
const originalUrl = extractInputUrl(input);
|
|
535
675
|
const c = getContext();
|
|
536
676
|
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
537
677
|
if (!appSession) {
|
|
@@ -539,6 +679,14 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
539
679
|
"No authentication method available for connection proxy."
|
|
540
680
|
);
|
|
541
681
|
}
|
|
682
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
683
|
+
return fetch(sessionUrl, {
|
|
684
|
+
method: "POST",
|
|
685
|
+
headers: { Authorization: `Bearer ${appSession}` }
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
const originalMethod = init?.method ?? "GET";
|
|
689
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
542
690
|
return fetch(proxyUrl, {
|
|
543
691
|
method: "POST",
|
|
544
692
|
headers: {
|