@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/shopify/parameters.ts
|
|
57
|
+
init_parameter_definition();
|
|
46
58
|
var parameters = {
|
|
47
59
|
storeDomain: new ParameterDefinition({
|
|
48
60
|
slug: "store-domain",
|
|
@@ -340,6 +352,28 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
340
352
|
tools;
|
|
341
353
|
query;
|
|
342
354
|
checkConnection;
|
|
355
|
+
/**
|
|
356
|
+
* SQPD-1212: Logic-based, rule-driven connection setup. Connectors that
|
|
357
|
+
* implement this expose a step-by-step exploration flow (database/schema/
|
|
358
|
+
* table/etc. discovery) that the dashboard backend drives via the
|
|
359
|
+
* `/connections/:connectionId/setup` endpoint. Implement by delegating to
|
|
360
|
+
* `runSetupFlow` from `setup-flow.ts`.
|
|
361
|
+
*/
|
|
362
|
+
setup;
|
|
363
|
+
/**
|
|
364
|
+
* Opt-out of the default "verify before save" behavior on connection
|
|
365
|
+
* creation. The backend invokes `checkConnection` synchronously while
|
|
366
|
+
* creating the connection and aborts (no row inserted) if it fails — this
|
|
367
|
+
* flag disables that for connectors where the check cannot succeed pre-save:
|
|
368
|
+
*
|
|
369
|
+
* - `squadbase-db` populates `connection-url` only after Neon provisioning
|
|
370
|
+
* - OAuth connectors require an OAuth-aware proxyFetch keyed by the
|
|
371
|
+
* connectionId, which doesn't exist until the row is saved
|
|
372
|
+
*
|
|
373
|
+
* Exceptions are the explicit position; new credential-input connectors get
|
|
374
|
+
* the default verify-on-create behavior without opt-in.
|
|
375
|
+
*/
|
|
376
|
+
skipConnectionCheckOnCreate;
|
|
343
377
|
constructor(config) {
|
|
344
378
|
this.slug = config.slug;
|
|
345
379
|
this.authType = config.authType;
|
|
@@ -356,6 +390,8 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
356
390
|
this.tools = config.tools;
|
|
357
391
|
this.query = config.query;
|
|
358
392
|
this.checkConnection = config.checkConnection;
|
|
393
|
+
this.setup = config.setup;
|
|
394
|
+
this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
|
|
359
395
|
}
|
|
360
396
|
get connectorKey() {
|
|
361
397
|
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
@@ -420,6 +456,71 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
420
456
|
}
|
|
421
457
|
};
|
|
422
458
|
|
|
459
|
+
// ../connectors/src/setup-flow.ts
|
|
460
|
+
async function runSetupFlow(flow, params, ctx, config) {
|
|
461
|
+
const runtime = {
|
|
462
|
+
params,
|
|
463
|
+
language: ctx.language,
|
|
464
|
+
config
|
|
465
|
+
};
|
|
466
|
+
let state = flow.initialState();
|
|
467
|
+
let answerIdx = 0;
|
|
468
|
+
const pendingParameterUpdates = [];
|
|
469
|
+
for (const step of flow.steps) {
|
|
470
|
+
const ans = ctx.answers[answerIdx];
|
|
471
|
+
if (ans && ans.questionSlug === step.slug) {
|
|
472
|
+
state = step.applyAnswer(state, ans.answer);
|
|
473
|
+
if (step.toParameterUpdates) {
|
|
474
|
+
pendingParameterUpdates.push(...step.toParameterUpdates(state));
|
|
475
|
+
}
|
|
476
|
+
answerIdx += 1;
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
|
|
480
|
+
if (step.type === "text") {
|
|
481
|
+
if (step.fetchOptions) {
|
|
482
|
+
const options2 = await step.fetchOptions(state, runtime);
|
|
483
|
+
if (options2.length === 0) {
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
return {
|
|
488
|
+
type: "nextQuestion",
|
|
489
|
+
questionSlug: step.slug,
|
|
490
|
+
question: step.question[ctx.language],
|
|
491
|
+
questionType: "text",
|
|
492
|
+
allowFreeText: resolvedAllowFreeText,
|
|
493
|
+
...pendingParameterUpdates.length > 0 && {
|
|
494
|
+
parameterUpdates: pendingParameterUpdates
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
499
|
+
if (options.length === 0) {
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
return {
|
|
503
|
+
type: "nextQuestion",
|
|
504
|
+
questionSlug: step.slug,
|
|
505
|
+
question: step.question[ctx.language],
|
|
506
|
+
questionType: step.type,
|
|
507
|
+
options,
|
|
508
|
+
allowFreeText: resolvedAllowFreeText,
|
|
509
|
+
...pendingParameterUpdates.length > 0 && {
|
|
510
|
+
parameterUpdates: pendingParameterUpdates
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
515
|
+
return {
|
|
516
|
+
type: "fulfilled",
|
|
517
|
+
dataInvestigationResult,
|
|
518
|
+
...pendingParameterUpdates.length > 0 && {
|
|
519
|
+
parameterUpdates: pendingParameterUpdates
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
423
524
|
// ../connectors/src/auth-types.ts
|
|
424
525
|
var AUTH_TYPES = {
|
|
425
526
|
OAUTH: "oauth",
|
|
@@ -442,6 +543,133 @@ var shopifyOnboarding = new ConnectorOnboarding({
|
|
|
442
543
|
}
|
|
443
544
|
});
|
|
444
545
|
|
|
546
|
+
// ../connectors/src/connectors/shopify/utils.ts
|
|
547
|
+
var SHOPIFY_API_VERSION = "2024-10";
|
|
548
|
+
function getStoreBaseUrl(params) {
|
|
549
|
+
const storeDomain = params[parameters.storeDomain.slug];
|
|
550
|
+
if (!storeDomain) {
|
|
551
|
+
throw new Error("shopify: missing required parameter: store-domain");
|
|
552
|
+
}
|
|
553
|
+
const host = storeDomain.includes(".") ? storeDomain : `${storeDomain}.myshopify.com`;
|
|
554
|
+
return `https://${host}`;
|
|
555
|
+
}
|
|
556
|
+
async function getAccessToken(params) {
|
|
557
|
+
const clientId = params[parameters.clientId.slug];
|
|
558
|
+
const clientSecret = params[parameters.clientSecret.slug];
|
|
559
|
+
if (!clientId || !clientSecret) {
|
|
560
|
+
throw new Error(
|
|
561
|
+
"shopify: missing required parameters: client-id and client-secret"
|
|
562
|
+
);
|
|
563
|
+
}
|
|
564
|
+
const base = getStoreBaseUrl(params);
|
|
565
|
+
const res = await fetch(`${base}/admin/oauth/access_token`, {
|
|
566
|
+
method: "POST",
|
|
567
|
+
headers: { "Content-Type": "application/json" },
|
|
568
|
+
body: JSON.stringify({
|
|
569
|
+
grant_type: "client_credentials",
|
|
570
|
+
client_id: clientId,
|
|
571
|
+
client_secret: clientSecret
|
|
572
|
+
})
|
|
573
|
+
});
|
|
574
|
+
if (!res.ok) {
|
|
575
|
+
const body = await res.text().catch(() => res.statusText);
|
|
576
|
+
throw new Error(
|
|
577
|
+
`shopify: failed to obtain access token (${res.status}): ${body}`
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
const data = await res.json();
|
|
581
|
+
if (!data.access_token) {
|
|
582
|
+
throw new Error("shopify: access_token missing in token response");
|
|
583
|
+
}
|
|
584
|
+
return data.access_token;
|
|
585
|
+
}
|
|
586
|
+
async function apiFetch(params, path2, init) {
|
|
587
|
+
const token = await getAccessToken(params);
|
|
588
|
+
const url = `${getStoreBaseUrl(params)}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
589
|
+
const headers = new Headers(init?.headers);
|
|
590
|
+
headers.set("X-Shopify-Access-Token", token);
|
|
591
|
+
if (!headers.has("Content-Type")) {
|
|
592
|
+
headers.set("Content-Type", "application/json");
|
|
593
|
+
}
|
|
594
|
+
return fetch(url, { ...init, headers });
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// ../connectors/src/connectors/shopify/setup-flow.ts
|
|
598
|
+
var SHOPIFY_SETUP_MAX_ENTITIES = 10;
|
|
599
|
+
var ENTITY_LABELS = {
|
|
600
|
+
products: { en: "Products", ja: "Products (\u5546\u54C1)" },
|
|
601
|
+
orders: { en: "Orders", ja: "Orders (\u6CE8\u6587)" },
|
|
602
|
+
customers: { en: "Customers", ja: "Customers (\u9867\u5BA2)" },
|
|
603
|
+
collections: { en: "Collections", ja: "Collections (\u30B3\u30EC\u30AF\u30B7\u30E7\u30F3)" },
|
|
604
|
+
inventory: { en: "Inventory items", ja: "Inventory items (\u5728\u5EAB)" },
|
|
605
|
+
discounts: { en: "Discounts", ja: "Discounts (\u5272\u5F15)" }
|
|
606
|
+
};
|
|
607
|
+
var ENTITY_VALUES = [
|
|
608
|
+
"products",
|
|
609
|
+
"orders",
|
|
610
|
+
"customers",
|
|
611
|
+
"collections",
|
|
612
|
+
"inventory",
|
|
613
|
+
"discounts"
|
|
614
|
+
];
|
|
615
|
+
var COUNT_PATHS = {
|
|
616
|
+
products: `/admin/api/${SHOPIFY_API_VERSION}/products/count.json`,
|
|
617
|
+
orders: `/admin/api/${SHOPIFY_API_VERSION}/orders/count.json?status=any`,
|
|
618
|
+
customers: `/admin/api/${SHOPIFY_API_VERSION}/customers/count.json`,
|
|
619
|
+
collections: `/admin/api/${SHOPIFY_API_VERSION}/custom_collections/count.json`,
|
|
620
|
+
inventory: null,
|
|
621
|
+
discounts: `/admin/api/${SHOPIFY_API_VERSION}/price_rules/count.json`
|
|
622
|
+
};
|
|
623
|
+
async function defaultFetchCount(params, path2) {
|
|
624
|
+
return apiFetch(params, path2);
|
|
625
|
+
}
|
|
626
|
+
function createShopifySetupFlow(fetchCount = defaultFetchCount, labelPrefix = "Shopify") {
|
|
627
|
+
return {
|
|
628
|
+
initialState: () => ({}),
|
|
629
|
+
steps: [
|
|
630
|
+
{
|
|
631
|
+
slug: "entities",
|
|
632
|
+
type: "multiSelect",
|
|
633
|
+
question: {
|
|
634
|
+
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",
|
|
635
|
+
en: "Select target entities (multi-select allowed)"
|
|
636
|
+
},
|
|
637
|
+
async fetchOptions(_state, rt) {
|
|
638
|
+
return ENTITY_VALUES.map((value) => ({
|
|
639
|
+
value,
|
|
640
|
+
label: ENTITY_LABELS[value][rt.language]
|
|
641
|
+
}));
|
|
642
|
+
},
|
|
643
|
+
applyAnswer: (state, answer) => ({ ...state, entities: answer })
|
|
644
|
+
}
|
|
645
|
+
],
|
|
646
|
+
async finalize(state, rt) {
|
|
647
|
+
if (!state.entities) {
|
|
648
|
+
throw new Error("Shopify setup: incomplete state on finalize");
|
|
649
|
+
}
|
|
650
|
+
const selected = state.entities.filter(
|
|
651
|
+
(e) => ENTITY_VALUES.includes(e)
|
|
652
|
+
).slice(0, SHOPIFY_SETUP_MAX_ENTITIES);
|
|
653
|
+
const sections = [`## ${labelPrefix}`, ""];
|
|
654
|
+
for (const entity of selected) {
|
|
655
|
+
const path2 = COUNT_PATHS[entity];
|
|
656
|
+
let count = "available";
|
|
657
|
+
if (path2) {
|
|
658
|
+
const res = await fetchCount(rt.params, path2);
|
|
659
|
+
if (res.ok) {
|
|
660
|
+
const data = await res.json();
|
|
661
|
+
if (typeof data.count === "number") count = String(data.count);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
sections.push(`### ${ENTITY_LABELS[entity].en}`, "");
|
|
665
|
+
sections.push(`Count: ${count}`, "");
|
|
666
|
+
}
|
|
667
|
+
return sections.join("\n");
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
var shopifySetupFlow = createShopifySetupFlow();
|
|
672
|
+
|
|
445
673
|
// ../connectors/src/connectors/shopify/tools/request.ts
|
|
446
674
|
import { z } from "zod";
|
|
447
675
|
var REQUEST_TIMEOUT_MS = 6e4;
|
|
@@ -705,7 +933,69 @@ export default async function handler(c: Context) {
|
|
|
705
933
|
- \`updated_at_min\`, \`updated_at_max\` \u2014 \u66F4\u65B0\u65E5\u30D5\u30A3\u30EB\u30BF\u30FC\uFF08ISO 8601\uFF09
|
|
706
934
|
- \`status\` \u2014 \u30B9\u30C6\u30FC\u30BF\u30B9\u3067\u30D5\u30A3\u30EB\u30BF\u30FC\uFF08\u4F8B: \u5546\u54C1\u306E\u5834\u5408 active, draft, archived\u3001\u6CE8\u6587\u306E\u5834\u5408 open, closed, cancelled, any\uFF09`
|
|
707
935
|
},
|
|
708
|
-
tools
|
|
936
|
+
tools,
|
|
937
|
+
setup: (params, ctx, config) => runSetupFlow(shopifySetupFlow, params, ctx, config),
|
|
938
|
+
async checkConnection(params, _config) {
|
|
939
|
+
const storeDomain = params[parameters.storeDomain.slug];
|
|
940
|
+
const clientId = params[parameters.clientId.slug];
|
|
941
|
+
const clientSecret = params[parameters.clientSecret.slug];
|
|
942
|
+
if (!storeDomain || !clientId || !clientSecret) {
|
|
943
|
+
return {
|
|
944
|
+
success: false,
|
|
945
|
+
error: "Missing required parameters: store-domain, client-id, and client-secret"
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
const host = storeDomain.includes(".") ? storeDomain : `${storeDomain}.myshopify.com`;
|
|
949
|
+
const base = `https://${host}`;
|
|
950
|
+
try {
|
|
951
|
+
const tokenRes = await fetch(`${base}/admin/oauth/access_token`, {
|
|
952
|
+
method: "POST",
|
|
953
|
+
headers: { "Content-Type": "application/json" },
|
|
954
|
+
body: JSON.stringify({
|
|
955
|
+
grant_type: "client_credentials",
|
|
956
|
+
client_id: clientId,
|
|
957
|
+
client_secret: clientSecret
|
|
958
|
+
})
|
|
959
|
+
});
|
|
960
|
+
if (!tokenRes.ok) {
|
|
961
|
+
const errorText = await tokenRes.text().catch(() => tokenRes.statusText);
|
|
962
|
+
return {
|
|
963
|
+
success: false,
|
|
964
|
+
error: `Shopify token request failed: HTTP ${tokenRes.status} ${errorText}`
|
|
965
|
+
};
|
|
966
|
+
}
|
|
967
|
+
const tokenData = await tokenRes.json();
|
|
968
|
+
if (!tokenData.access_token) {
|
|
969
|
+
return {
|
|
970
|
+
success: false,
|
|
971
|
+
error: "Shopify token response missing access_token"
|
|
972
|
+
};
|
|
973
|
+
}
|
|
974
|
+
const shopRes = await fetch(
|
|
975
|
+
`${base}/admin/api/${SHOPIFY_API_VERSION}/shop.json`,
|
|
976
|
+
{
|
|
977
|
+
method: "GET",
|
|
978
|
+
headers: {
|
|
979
|
+
"X-Shopify-Access-Token": tokenData.access_token,
|
|
980
|
+
Accept: "application/json"
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
);
|
|
984
|
+
if (!shopRes.ok) {
|
|
985
|
+
const errorText = await shopRes.text().catch(() => shopRes.statusText);
|
|
986
|
+
return {
|
|
987
|
+
success: false,
|
|
988
|
+
error: `Shopify API failed: HTTP ${shopRes.status} ${errorText}`
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
return { success: true };
|
|
992
|
+
} catch (error) {
|
|
993
|
+
return {
|
|
994
|
+
success: false,
|
|
995
|
+
error: error instanceof Error ? error.message : String(error)
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
}
|
|
709
999
|
});
|
|
710
1000
|
|
|
711
1001
|
// src/connectors/create-connector-sdk.ts
|
|
@@ -734,6 +1024,7 @@ function resolveEnvVarOptional(entry, key) {
|
|
|
734
1024
|
import { getContext } from "hono/context-storage";
|
|
735
1025
|
import { getCookie } from "hono/cookie";
|
|
736
1026
|
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
1027
|
+
var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
|
|
737
1028
|
function normalizeHeaders(input) {
|
|
738
1029
|
const out = {};
|
|
739
1030
|
if (!input) return out;
|
|
@@ -742,6 +1033,11 @@ function normalizeHeaders(input) {
|
|
|
742
1033
|
});
|
|
743
1034
|
return out;
|
|
744
1035
|
}
|
|
1036
|
+
function extractInputUrl(input) {
|
|
1037
|
+
if (typeof input === "string") return input;
|
|
1038
|
+
if (input instanceof URL) return input.href;
|
|
1039
|
+
return input.url;
|
|
1040
|
+
}
|
|
745
1041
|
function createSandboxProxyFetch(connectionId) {
|
|
746
1042
|
return async (input, init) => {
|
|
747
1043
|
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
@@ -751,10 +1047,17 @@ function createSandboxProxyFetch(connectionId) {
|
|
|
751
1047
|
"Connection proxy is not configured. Please check your deployment settings."
|
|
752
1048
|
);
|
|
753
1049
|
}
|
|
754
|
-
const originalUrl =
|
|
1050
|
+
const originalUrl = extractInputUrl(input);
|
|
1051
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
1052
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
1053
|
+
const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
1054
|
+
return fetch(sessionUrl, {
|
|
1055
|
+
method: "POST",
|
|
1056
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
755
1059
|
const originalMethod = init?.method ?? "GET";
|
|
756
1060
|
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
757
|
-
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
758
1061
|
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
759
1062
|
return fetch(proxyUrl, {
|
|
760
1063
|
method: "POST",
|
|
@@ -780,10 +1083,9 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
780
1083
|
}
|
|
781
1084
|
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
782
1085
|
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
1086
|
+
const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
783
1087
|
return async (input, init) => {
|
|
784
|
-
const originalUrl =
|
|
785
|
-
const originalMethod = init?.method ?? "GET";
|
|
786
|
-
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
1088
|
+
const originalUrl = extractInputUrl(input);
|
|
787
1089
|
const c = getContext();
|
|
788
1090
|
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
789
1091
|
if (!appSession) {
|
|
@@ -791,6 +1093,14 @@ function createDeployedAppProxyFetch(connectionId) {
|
|
|
791
1093
|
"No authentication method available for connection proxy."
|
|
792
1094
|
);
|
|
793
1095
|
}
|
|
1096
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
1097
|
+
return fetch(sessionUrl, {
|
|
1098
|
+
method: "POST",
|
|
1099
|
+
headers: { Authorization: `Bearer ${appSession}` }
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
const originalMethod = init?.method ?? "GET";
|
|
1103
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
794
1104
|
return fetch(proxyUrl, {
|
|
795
1105
|
method: "POST",
|
|
796
1106
|
headers: {
|