@squadbase/vite-server 0.1.17-dev.24af54e → 0.1.17-dev.7408ec4
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 +1682 -425
- package/dist/connectors/airtable-oauth.js +22 -3
- package/dist/connectors/airtable.js +22 -3
- package/dist/connectors/amplitude.js +22 -3
- package/dist/connectors/asana.js +22 -3
- package/dist/connectors/attio.js +22 -3
- package/dist/connectors/aws-billing.js +22 -3
- package/dist/connectors/azure-sql.js +25 -6
- package/dist/connectors/backlog-api-key.js +22 -3
- package/dist/connectors/clickup.js +22 -3
- package/dist/connectors/cosmosdb.js +22 -3
- package/dist/connectors/customerio.js +23 -4
- package/dist/connectors/dbt.js +22 -3
- package/dist/connectors/freshdesk.js +22 -3
- package/dist/connectors/freshsales.js +22 -3
- package/dist/connectors/freshservice.js +22 -3
- package/dist/connectors/gamma.js +24 -5
- package/dist/connectors/github.js +22 -3
- package/dist/connectors/gmail-oauth.js +22 -3
- package/dist/connectors/gmail.js +22 -3
- package/dist/connectors/google-ads.js +22 -3
- package/dist/connectors/google-analytics-oauth.js +22 -3
- package/dist/connectors/google-analytics.js +222 -68
- package/dist/connectors/google-audit-log.js +22 -3
- package/dist/connectors/google-calendar-oauth.js +22 -3
- package/dist/connectors/google-calendar.js +22 -3
- package/dist/connectors/google-docs.js +22 -3
- package/dist/connectors/google-drive.js +22 -3
- package/dist/connectors/google-search-console-oauth.js +22 -3
- package/dist/connectors/google-sheets.js +22 -3
- package/dist/connectors/google-slides.js +22 -3
- package/dist/connectors/grafana.js +22 -3
- package/dist/connectors/hubspot-oauth.js +22 -3
- package/dist/connectors/hubspot.js +22 -3
- package/dist/connectors/influxdb.js +22 -3
- package/dist/connectors/intercom-oauth.js +22 -3
- package/dist/connectors/intercom.js +22 -3
- package/dist/connectors/jdbc.js +22 -3
- package/dist/connectors/jira-api-key.js +22 -3
- package/dist/connectors/kintone-api-token.js +22 -3
- package/dist/connectors/kintone.js +22 -3
- package/dist/connectors/linear.js +22 -3
- package/dist/connectors/linkedin-ads.js +22 -3
- package/dist/connectors/mailchimp-oauth.js +22 -3
- package/dist/connectors/mailchimp.js +22 -3
- package/dist/connectors/meta-ads-oauth.js +22 -3
- package/dist/connectors/meta-ads.js +22 -3
- package/dist/connectors/mixpanel.js +22 -3
- package/dist/connectors/monday.js +22 -3
- package/dist/connectors/mongodb.js +22 -3
- package/dist/connectors/notion-oauth.js +22 -3
- package/dist/connectors/notion.js +22 -3
- package/dist/connectors/oracle.js +48 -14
- package/dist/connectors/outlook-oauth.js +22 -3
- package/dist/connectors/powerbi-oauth.js +303 -37
- package/dist/connectors/salesforce.js +22 -3
- package/dist/connectors/semrush.js +360 -46
- package/dist/connectors/sentry.js +22 -3
- package/dist/connectors/shopify-oauth.js +22 -3
- package/dist/connectors/shopify.js +22 -3
- package/dist/connectors/sqlserver.js +25 -6
- package/dist/connectors/stripe-api-key.js +22 -3
- package/dist/connectors/stripe-oauth.js +22 -3
- package/dist/connectors/supabase.js +25 -6
- package/dist/connectors/tableau.js +240 -78
- package/dist/connectors/tiktok-ads.js +22 -3
- package/dist/connectors/wix-store.js +22 -3
- package/dist/connectors/zendesk-oauth.js +22 -3
- package/dist/connectors/zendesk.js +22 -3
- package/dist/index.js +1682 -425
- package/dist/main.js +1682 -425
- package/dist/vite-plugin.js +1682 -425
- package/package.json +1 -1
|
@@ -71,11 +71,11 @@ var parameters = {
|
|
|
71
71
|
propertyId: new ParameterDefinition({
|
|
72
72
|
slug: "property-id",
|
|
73
73
|
name: "Google Analytics Property ID",
|
|
74
|
-
description: "The Google Analytics 4 property ID (e.g., 123456789).",
|
|
74
|
+
description: "The Google Analytics 4 property ID (e.g., 123456789). Automatically set during the setup flow.",
|
|
75
75
|
envVarBaseKey: "GA_PROPERTY_ID",
|
|
76
76
|
type: "text",
|
|
77
77
|
secret: false,
|
|
78
|
-
required:
|
|
78
|
+
required: false
|
|
79
79
|
})
|
|
80
80
|
};
|
|
81
81
|
|
|
@@ -405,19 +405,28 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
405
405
|
};
|
|
406
406
|
let state = flow.initialState();
|
|
407
407
|
let answerIdx = 0;
|
|
408
|
+
const pendingParameterUpdates = [];
|
|
408
409
|
for (const step of flow.steps) {
|
|
409
410
|
const ans = ctx.answers[answerIdx];
|
|
410
411
|
if (ans && ans.questionSlug === step.slug) {
|
|
411
412
|
state = step.applyAnswer(state, ans.answer);
|
|
413
|
+
if (step.toParameterUpdates) {
|
|
414
|
+
pendingParameterUpdates.push(...step.toParameterUpdates(state));
|
|
415
|
+
}
|
|
412
416
|
answerIdx += 1;
|
|
413
417
|
continue;
|
|
414
418
|
}
|
|
419
|
+
const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
|
|
415
420
|
if (step.type === "text") {
|
|
416
421
|
return {
|
|
417
422
|
type: "nextQuestion",
|
|
418
423
|
questionSlug: step.slug,
|
|
419
424
|
question: step.question[ctx.language],
|
|
420
|
-
questionType: "text"
|
|
425
|
+
questionType: "text",
|
|
426
|
+
allowFreeText: resolvedAllowFreeText,
|
|
427
|
+
...pendingParameterUpdates.length > 0 && {
|
|
428
|
+
parameterUpdates: pendingParameterUpdates
|
|
429
|
+
}
|
|
421
430
|
};
|
|
422
431
|
}
|
|
423
432
|
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
@@ -429,11 +438,21 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
429
438
|
questionSlug: step.slug,
|
|
430
439
|
question: step.question[ctx.language],
|
|
431
440
|
questionType: step.type,
|
|
432
|
-
options
|
|
441
|
+
options,
|
|
442
|
+
allowFreeText: resolvedAllowFreeText,
|
|
443
|
+
...pendingParameterUpdates.length > 0 && {
|
|
444
|
+
parameterUpdates: pendingParameterUpdates
|
|
445
|
+
}
|
|
433
446
|
};
|
|
434
447
|
}
|
|
435
448
|
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
436
|
-
return {
|
|
449
|
+
return {
|
|
450
|
+
type: "fulfilled",
|
|
451
|
+
dataInvestigationResult,
|
|
452
|
+
...pendingParameterUpdates.length > 0 && {
|
|
453
|
+
parameterUpdates: pendingParameterUpdates
|
|
454
|
+
}
|
|
455
|
+
};
|
|
437
456
|
}
|
|
438
457
|
async function resolveSetupSelection(params) {
|
|
439
458
|
const { selected, allSentinel, fetchAll, limit } = params;
|
|
@@ -465,6 +484,7 @@ var googleAnalyticsOnboarding = new ConnectorOnboarding({
|
|
|
465
484
|
import * as crypto2 from "crypto";
|
|
466
485
|
var TOKEN_URL2 = "https://oauth2.googleapis.com/token";
|
|
467
486
|
var ADMIN_BASE_URL = "https://analyticsadmin.googleapis.com/v1beta";
|
|
487
|
+
var DATA_BASE_URL = "https://analyticsdata.googleapis.com/v1beta";
|
|
468
488
|
var SCOPE2 = "https://www.googleapis.com/auth/analytics.readonly";
|
|
469
489
|
function base64url2(input) {
|
|
470
490
|
const buf = typeof input === "string" ? Buffer.from(input) : input;
|
|
@@ -546,10 +566,25 @@ async function adminFetch(params, path2, init) {
|
|
|
546
566
|
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
547
567
|
return fetch(url, { ...init, headers });
|
|
548
568
|
}
|
|
569
|
+
async function dataFetch(params, path2, init) {
|
|
570
|
+
const keyJsonBase64 = params[parameters.serviceAccountKeyJsonBase64.slug];
|
|
571
|
+
if (!keyJsonBase64) {
|
|
572
|
+
throw new Error(
|
|
573
|
+
"google-analytics: missing required parameter: service-account-key-json-base64"
|
|
574
|
+
);
|
|
575
|
+
}
|
|
576
|
+
const serviceAccountKey = decodeServiceAccount(keyJsonBase64);
|
|
577
|
+
const accessToken = await getAccessToken(serviceAccountKey);
|
|
578
|
+
const url = `${DATA_BASE_URL}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
579
|
+
const headers = new Headers(init?.headers);
|
|
580
|
+
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
581
|
+
return fetch(url, { ...init, headers });
|
|
582
|
+
}
|
|
549
583
|
|
|
550
584
|
// ../connectors/src/connectors/google-analytics/setup-flow.ts
|
|
551
585
|
var ALL_PROPERTIES = "__ALL_PROPERTIES__";
|
|
552
586
|
var GOOGLE_ANALYTICS_SETUP_MAX_PROPERTIES = 20;
|
|
587
|
+
var METADATA_DISPLAY_LIMIT = 30;
|
|
553
588
|
async function listAccountSummaries(params) {
|
|
554
589
|
const summaries = [];
|
|
555
590
|
let pageToken;
|
|
@@ -576,6 +611,48 @@ async function getProperty(params, propertyId) {
|
|
|
576
611
|
if (!res.ok) return null;
|
|
577
612
|
return await res.json();
|
|
578
613
|
}
|
|
614
|
+
async function getMetadata(params, propertyId) {
|
|
615
|
+
try {
|
|
616
|
+
const res = await dataFetch(
|
|
617
|
+
params,
|
|
618
|
+
`/properties/${propertyId}/metadata`
|
|
619
|
+
);
|
|
620
|
+
if (!res.ok) return { dimensions: [], metrics: [] };
|
|
621
|
+
const data = await res.json();
|
|
622
|
+
return {
|
|
623
|
+
dimensions: data.dimensions ?? [],
|
|
624
|
+
metrics: data.metrics ?? []
|
|
625
|
+
};
|
|
626
|
+
} catch {
|
|
627
|
+
return { dimensions: [], metrics: [] };
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
function appendMetadataSection(sections, dimensions, metrics) {
|
|
631
|
+
if (dimensions.length > 0) {
|
|
632
|
+
sections.push(`#### Dimensions (${dimensions.length})`, "");
|
|
633
|
+
for (const d of dimensions.slice(0, METADATA_DISPLAY_LIMIT)) {
|
|
634
|
+
sections.push(`- ${d.apiName ?? d.uiName ?? "(unknown)"}`);
|
|
635
|
+
}
|
|
636
|
+
if (dimensions.length > METADATA_DISPLAY_LIMIT) {
|
|
637
|
+
sections.push(
|
|
638
|
+
`- \u2026and ${dimensions.length - METADATA_DISPLAY_LIMIT} more`
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
sections.push("");
|
|
642
|
+
}
|
|
643
|
+
if (metrics.length > 0) {
|
|
644
|
+
sections.push(`#### Metrics (${metrics.length})`, "");
|
|
645
|
+
for (const m of metrics.slice(0, METADATA_DISPLAY_LIMIT)) {
|
|
646
|
+
sections.push(`- ${m.apiName ?? m.uiName ?? "(unknown)"}`);
|
|
647
|
+
}
|
|
648
|
+
if (metrics.length > METADATA_DISPLAY_LIMIT) {
|
|
649
|
+
sections.push(
|
|
650
|
+
`- \u2026and ${metrics.length - METADATA_DISPLAY_LIMIT} more`
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
sections.push("");
|
|
654
|
+
}
|
|
655
|
+
}
|
|
579
656
|
var googleAnalyticsSetupFlow = {
|
|
580
657
|
initialState: () => ({}),
|
|
581
658
|
steps: [
|
|
@@ -587,15 +664,19 @@ var googleAnalyticsSetupFlow = {
|
|
|
587
664
|
en: "Select a Google Analytics account"
|
|
588
665
|
},
|
|
589
666
|
async fetchOptions(_state, rt) {
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
667
|
+
try {
|
|
668
|
+
const summaries = await listAccountSummaries(rt.params);
|
|
669
|
+
return summaries.map((s) => {
|
|
670
|
+
const accountResource = s.account ?? s.name ?? "";
|
|
671
|
+
if (!accountResource) return null;
|
|
672
|
+
return {
|
|
673
|
+
value: accountResource,
|
|
674
|
+
label: s.displayName ?? accountResource
|
|
675
|
+
};
|
|
676
|
+
}).filter((v) => v != null);
|
|
677
|
+
} catch {
|
|
678
|
+
return [];
|
|
679
|
+
}
|
|
599
680
|
},
|
|
600
681
|
applyAnswer: (state, answer) => ({ ...state, account: answer[0] })
|
|
601
682
|
},
|
|
@@ -608,68 +689,134 @@ var googleAnalyticsSetupFlow = {
|
|
|
608
689
|
},
|
|
609
690
|
async fetchOptions(state, rt) {
|
|
610
691
|
if (!state.account) return [];
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
const
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
692
|
+
try {
|
|
693
|
+
const summaries = await listAccountSummaries(rt.params);
|
|
694
|
+
const account = summaries.find(
|
|
695
|
+
(s) => (s.account ?? s.name) === state.account
|
|
696
|
+
);
|
|
697
|
+
const props = (account?.propertySummaries ?? []).map((p) => {
|
|
698
|
+
const id = propertyIdFromResource(p.property);
|
|
699
|
+
if (!id) return null;
|
|
700
|
+
return {
|
|
701
|
+
value: id,
|
|
702
|
+
label: p.displayName ? `${p.displayName} (${id})` : id
|
|
703
|
+
};
|
|
704
|
+
}).filter((v) => v != null);
|
|
705
|
+
if (props.length === 0) return [];
|
|
706
|
+
return [
|
|
707
|
+
{
|
|
708
|
+
value: ALL_PROPERTIES,
|
|
709
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30D7\u30ED\u30D1\u30C6\u30A3" : "All properties"
|
|
710
|
+
},
|
|
711
|
+
...props
|
|
712
|
+
];
|
|
713
|
+
} catch {
|
|
714
|
+
return [];
|
|
715
|
+
}
|
|
716
|
+
},
|
|
717
|
+
applyAnswer: (state, answer) => ({ ...state, properties: answer }),
|
|
718
|
+
toParameterUpdates: (state) => {
|
|
719
|
+
const first = state.properties?.find((v) => v !== ALL_PROPERTIES);
|
|
720
|
+
return first ? [{ slug: parameters.propertyId.slug, value: first }] : [];
|
|
721
|
+
}
|
|
722
|
+
},
|
|
723
|
+
{
|
|
724
|
+
slug: "manualPropertyId",
|
|
725
|
+
type: "select",
|
|
726
|
+
allowFreeText: true,
|
|
727
|
+
question: {
|
|
728
|
+
ja: "GA4 \u30D7\u30ED\u30D1\u30C6\u30A3 ID \u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u4F8B: 123456789\uFF09\u3002GA4 \u7BA1\u7406\u753B\u9762 > \u30D7\u30ED\u30D1\u30C6\u30A3\u8A2D\u5B9A\u3067\u78BA\u8A8D\u3067\u304D\u307E\u3059\u3002",
|
|
729
|
+
en: "Enter your GA4 Property ID (e.g., 123456789). Found in GA4 Admin > Property Settings."
|
|
730
|
+
},
|
|
731
|
+
async fetchOptions(state, rt) {
|
|
732
|
+
if (state.properties?.length) return [];
|
|
733
|
+
const existing = rt.params[parameters.propertyId.slug];
|
|
734
|
+
return existing ? [{ value: existing, label: existing }] : [
|
|
625
735
|
{
|
|
626
|
-
value:
|
|
627
|
-
label: rt.language === "ja" ? "\
|
|
628
|
-
}
|
|
629
|
-
...props
|
|
736
|
+
value: "example",
|
|
737
|
+
label: rt.language === "ja" ? "\u4F8B: 123456789" : "Example: 123456789"
|
|
738
|
+
}
|
|
630
739
|
];
|
|
631
740
|
},
|
|
632
|
-
applyAnswer: (state, answer) => ({
|
|
741
|
+
applyAnswer: (state, answer) => ({
|
|
742
|
+
...state,
|
|
743
|
+
manualPropertyId: answer[0]
|
|
744
|
+
}),
|
|
745
|
+
toParameterUpdates: (state) => state.manualPropertyId ? [
|
|
746
|
+
{
|
|
747
|
+
slug: parameters.propertyId.slug,
|
|
748
|
+
value: state.manualPropertyId
|
|
749
|
+
}
|
|
750
|
+
] : []
|
|
633
751
|
}
|
|
634
752
|
],
|
|
635
753
|
async finalize(state, rt) {
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
`### Account: ${accountLabel}`,
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
754
|
+
const sections = ["## Google Analytics", ""];
|
|
755
|
+
if (state.account && state.properties) {
|
|
756
|
+
let summaries = [];
|
|
757
|
+
try {
|
|
758
|
+
summaries = await listAccountSummaries(rt.params);
|
|
759
|
+
} catch {
|
|
760
|
+
}
|
|
761
|
+
const account = summaries.find(
|
|
762
|
+
(s) => (s.account ?? s.name) === state.account
|
|
763
|
+
);
|
|
764
|
+
const accountLabel = account?.displayName ?? state.account.replace(/^accounts\//, "");
|
|
765
|
+
const targetPropertyIds = await resolveSetupSelection({
|
|
766
|
+
selected: state.properties,
|
|
767
|
+
allSentinel: ALL_PROPERTIES,
|
|
768
|
+
fetchAll: async () => (account?.propertySummaries ?? []).map((p) => propertyIdFromResource(p.property)).filter((v) => v),
|
|
769
|
+
limit: GOOGLE_ANALYTICS_SETUP_MAX_PROPERTIES
|
|
770
|
+
});
|
|
771
|
+
sections.push(`### Account: ${accountLabel}`, "");
|
|
772
|
+
if (targetPropertyIds.length === 0) {
|
|
773
|
+
sections.push("_No properties selected._", "");
|
|
774
|
+
return sections.join("\n");
|
|
775
|
+
}
|
|
776
|
+
sections.push(
|
|
777
|
+
"| Property ID | Display Name | Time Zone | Currency | Industry |"
|
|
778
|
+
);
|
|
779
|
+
sections.push(
|
|
780
|
+
"|-------------|--------------|-----------|----------|----------|"
|
|
781
|
+
);
|
|
782
|
+
for (const pid of targetPropertyIds) {
|
|
783
|
+
const prop = await getProperty(rt.params, pid).catch(() => null);
|
|
784
|
+
const displayName = (prop?.displayName ?? "-").replace(/\|/g, "\\|");
|
|
785
|
+
const timeZone = prop?.timeZone ?? "-";
|
|
786
|
+
const currency = prop?.currencyCode ?? "-";
|
|
787
|
+
const industry = (prop?.industryCategory ?? "-").replace(
|
|
788
|
+
/\|/g,
|
|
789
|
+
"\\|"
|
|
790
|
+
);
|
|
791
|
+
sections.push(
|
|
792
|
+
`| ${pid} | ${displayName} | ${timeZone} | ${currency} | ${industry} |`
|
|
793
|
+
);
|
|
794
|
+
}
|
|
795
|
+
sections.push("");
|
|
796
|
+
const firstPropertyId = targetPropertyIds[0];
|
|
797
|
+
if (firstPropertyId) {
|
|
798
|
+
const { dimensions, metrics } = await getMetadata(
|
|
799
|
+
rt.params,
|
|
800
|
+
firstPropertyId
|
|
801
|
+
);
|
|
802
|
+
appendMetadataSection(sections, dimensions, metrics);
|
|
803
|
+
}
|
|
658
804
|
return sections.join("\n");
|
|
659
805
|
}
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
const
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
const currency = prop?.currencyCode ?? "-";
|
|
667
|
-
const industry = (prop?.industryCategory ?? "-").replace(/\|/g, "\\|");
|
|
668
|
-
sections.push(
|
|
669
|
-
`| ${propertyId} | ${displayName} | ${timeZone} | ${currency} | ${industry} |`
|
|
806
|
+
const propertyId = state.manualPropertyId ?? rt.params[parameters.propertyId.slug];
|
|
807
|
+
if (propertyId) {
|
|
808
|
+
sections.push(`### Property: ${propertyId}`, "");
|
|
809
|
+
const { dimensions, metrics } = await getMetadata(
|
|
810
|
+
rt.params,
|
|
811
|
+
propertyId
|
|
670
812
|
);
|
|
813
|
+
appendMetadataSection(sections, dimensions, metrics);
|
|
814
|
+
return sections.join("\n");
|
|
671
815
|
}
|
|
672
|
-
sections.push(
|
|
816
|
+
sections.push(
|
|
817
|
+
"_Could not list GA4 accounts. Please enable the Google Analytics Admin API in your GCP project, or set the Property ID parameter manually._",
|
|
818
|
+
""
|
|
819
|
+
);
|
|
673
820
|
return sections.join("\n");
|
|
674
821
|
}
|
|
675
822
|
};
|
|
@@ -917,13 +1064,20 @@ activeUsers, sessions, screenPageViews, bounceRate, averageSessionDuration, conv
|
|
|
917
1064
|
error: "google-analytics: missing service account key"
|
|
918
1065
|
};
|
|
919
1066
|
}
|
|
1067
|
+
const propertyId = params[parameters.propertyId.slug];
|
|
1068
|
+
if (!propertyId) {
|
|
1069
|
+
return { success: true };
|
|
1070
|
+
}
|
|
920
1071
|
try {
|
|
921
|
-
const res = await
|
|
1072
|
+
const res = await dataFetch(
|
|
1073
|
+
params,
|
|
1074
|
+
`/properties/${propertyId}/metadata`
|
|
1075
|
+
);
|
|
922
1076
|
if (!res.ok) {
|
|
923
1077
|
const body = await res.text().catch(() => res.statusText);
|
|
924
1078
|
return {
|
|
925
1079
|
success: false,
|
|
926
|
-
error: `
|
|
1080
|
+
error: `Google Analytics API failed: HTTP ${res.status} ${body}`
|
|
927
1081
|
};
|
|
928
1082
|
}
|
|
929
1083
|
return { success: true };
|
|
@@ -290,19 +290,28 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
290
290
|
};
|
|
291
291
|
let state = flow.initialState();
|
|
292
292
|
let answerIdx = 0;
|
|
293
|
+
const pendingParameterUpdates = [];
|
|
293
294
|
for (const step of flow.steps) {
|
|
294
295
|
const ans = ctx.answers[answerIdx];
|
|
295
296
|
if (ans && ans.questionSlug === step.slug) {
|
|
296
297
|
state = step.applyAnswer(state, ans.answer);
|
|
298
|
+
if (step.toParameterUpdates) {
|
|
299
|
+
pendingParameterUpdates.push(...step.toParameterUpdates(state));
|
|
300
|
+
}
|
|
297
301
|
answerIdx += 1;
|
|
298
302
|
continue;
|
|
299
303
|
}
|
|
304
|
+
const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
|
|
300
305
|
if (step.type === "text") {
|
|
301
306
|
return {
|
|
302
307
|
type: "nextQuestion",
|
|
303
308
|
questionSlug: step.slug,
|
|
304
309
|
question: step.question[ctx.language],
|
|
305
|
-
questionType: "text"
|
|
310
|
+
questionType: "text",
|
|
311
|
+
allowFreeText: resolvedAllowFreeText,
|
|
312
|
+
...pendingParameterUpdates.length > 0 && {
|
|
313
|
+
parameterUpdates: pendingParameterUpdates
|
|
314
|
+
}
|
|
306
315
|
};
|
|
307
316
|
}
|
|
308
317
|
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
@@ -314,11 +323,21 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
314
323
|
questionSlug: step.slug,
|
|
315
324
|
question: step.question[ctx.language],
|
|
316
325
|
questionType: step.type,
|
|
317
|
-
options
|
|
326
|
+
options,
|
|
327
|
+
allowFreeText: resolvedAllowFreeText,
|
|
328
|
+
...pendingParameterUpdates.length > 0 && {
|
|
329
|
+
parameterUpdates: pendingParameterUpdates
|
|
330
|
+
}
|
|
318
331
|
};
|
|
319
332
|
}
|
|
320
333
|
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
321
|
-
return {
|
|
334
|
+
return {
|
|
335
|
+
type: "fulfilled",
|
|
336
|
+
dataInvestigationResult,
|
|
337
|
+
...pendingParameterUpdates.length > 0 && {
|
|
338
|
+
parameterUpdates: pendingParameterUpdates
|
|
339
|
+
}
|
|
340
|
+
};
|
|
322
341
|
}
|
|
323
342
|
async function resolveSetupSelection(params) {
|
|
324
343
|
const { selected, allSentinel, fetchAll, limit } = params;
|
|
@@ -306,19 +306,28 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
306
306
|
};
|
|
307
307
|
let state = flow.initialState();
|
|
308
308
|
let answerIdx = 0;
|
|
309
|
+
const pendingParameterUpdates = [];
|
|
309
310
|
for (const step of flow.steps) {
|
|
310
311
|
const ans = ctx.answers[answerIdx];
|
|
311
312
|
if (ans && ans.questionSlug === step.slug) {
|
|
312
313
|
state = step.applyAnswer(state, ans.answer);
|
|
314
|
+
if (step.toParameterUpdates) {
|
|
315
|
+
pendingParameterUpdates.push(...step.toParameterUpdates(state));
|
|
316
|
+
}
|
|
313
317
|
answerIdx += 1;
|
|
314
318
|
continue;
|
|
315
319
|
}
|
|
320
|
+
const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
|
|
316
321
|
if (step.type === "text") {
|
|
317
322
|
return {
|
|
318
323
|
type: "nextQuestion",
|
|
319
324
|
questionSlug: step.slug,
|
|
320
325
|
question: step.question[ctx.language],
|
|
321
|
-
questionType: "text"
|
|
326
|
+
questionType: "text",
|
|
327
|
+
allowFreeText: resolvedAllowFreeText,
|
|
328
|
+
...pendingParameterUpdates.length > 0 && {
|
|
329
|
+
parameterUpdates: pendingParameterUpdates
|
|
330
|
+
}
|
|
322
331
|
};
|
|
323
332
|
}
|
|
324
333
|
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
@@ -330,11 +339,21 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
330
339
|
questionSlug: step.slug,
|
|
331
340
|
question: step.question[ctx.language],
|
|
332
341
|
questionType: step.type,
|
|
333
|
-
options
|
|
342
|
+
options,
|
|
343
|
+
allowFreeText: resolvedAllowFreeText,
|
|
344
|
+
...pendingParameterUpdates.length > 0 && {
|
|
345
|
+
parameterUpdates: pendingParameterUpdates
|
|
346
|
+
}
|
|
334
347
|
};
|
|
335
348
|
}
|
|
336
349
|
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
337
|
-
return {
|
|
350
|
+
return {
|
|
351
|
+
type: "fulfilled",
|
|
352
|
+
dataInvestigationResult,
|
|
353
|
+
...pendingParameterUpdates.length > 0 && {
|
|
354
|
+
parameterUpdates: pendingParameterUpdates
|
|
355
|
+
}
|
|
356
|
+
};
|
|
338
357
|
}
|
|
339
358
|
async function resolveSetupSelection(params) {
|
|
340
359
|
const { selected, allSentinel, fetchAll, limit } = params;
|
|
@@ -311,19 +311,28 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
311
311
|
};
|
|
312
312
|
let state = flow.initialState();
|
|
313
313
|
let answerIdx = 0;
|
|
314
|
+
const pendingParameterUpdates = [];
|
|
314
315
|
for (const step of flow.steps) {
|
|
315
316
|
const ans = ctx.answers[answerIdx];
|
|
316
317
|
if (ans && ans.questionSlug === step.slug) {
|
|
317
318
|
state = step.applyAnswer(state, ans.answer);
|
|
319
|
+
if (step.toParameterUpdates) {
|
|
320
|
+
pendingParameterUpdates.push(...step.toParameterUpdates(state));
|
|
321
|
+
}
|
|
318
322
|
answerIdx += 1;
|
|
319
323
|
continue;
|
|
320
324
|
}
|
|
325
|
+
const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
|
|
321
326
|
if (step.type === "text") {
|
|
322
327
|
return {
|
|
323
328
|
type: "nextQuestion",
|
|
324
329
|
questionSlug: step.slug,
|
|
325
330
|
question: step.question[ctx.language],
|
|
326
|
-
questionType: "text"
|
|
331
|
+
questionType: "text",
|
|
332
|
+
allowFreeText: resolvedAllowFreeText,
|
|
333
|
+
...pendingParameterUpdates.length > 0 && {
|
|
334
|
+
parameterUpdates: pendingParameterUpdates
|
|
335
|
+
}
|
|
327
336
|
};
|
|
328
337
|
}
|
|
329
338
|
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
@@ -335,11 +344,21 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
335
344
|
questionSlug: step.slug,
|
|
336
345
|
question: step.question[ctx.language],
|
|
337
346
|
questionType: step.type,
|
|
338
|
-
options
|
|
347
|
+
options,
|
|
348
|
+
allowFreeText: resolvedAllowFreeText,
|
|
349
|
+
...pendingParameterUpdates.length > 0 && {
|
|
350
|
+
parameterUpdates: pendingParameterUpdates
|
|
351
|
+
}
|
|
339
352
|
};
|
|
340
353
|
}
|
|
341
354
|
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
342
|
-
return {
|
|
355
|
+
return {
|
|
356
|
+
type: "fulfilled",
|
|
357
|
+
dataInvestigationResult,
|
|
358
|
+
...pendingParameterUpdates.length > 0 && {
|
|
359
|
+
parameterUpdates: pendingParameterUpdates
|
|
360
|
+
}
|
|
361
|
+
};
|
|
343
362
|
}
|
|
344
363
|
async function resolveSetupSelection(params) {
|
|
345
364
|
const { selected, allSentinel, fetchAll, limit } = params;
|
|
@@ -226,19 +226,28 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
226
226
|
};
|
|
227
227
|
let state = flow.initialState();
|
|
228
228
|
let answerIdx = 0;
|
|
229
|
+
const pendingParameterUpdates = [];
|
|
229
230
|
for (const step of flow.steps) {
|
|
230
231
|
const ans = ctx.answers[answerIdx];
|
|
231
232
|
if (ans && ans.questionSlug === step.slug) {
|
|
232
233
|
state = step.applyAnswer(state, ans.answer);
|
|
234
|
+
if (step.toParameterUpdates) {
|
|
235
|
+
pendingParameterUpdates.push(...step.toParameterUpdates(state));
|
|
236
|
+
}
|
|
233
237
|
answerIdx += 1;
|
|
234
238
|
continue;
|
|
235
239
|
}
|
|
240
|
+
const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
|
|
236
241
|
if (step.type === "text") {
|
|
237
242
|
return {
|
|
238
243
|
type: "nextQuestion",
|
|
239
244
|
questionSlug: step.slug,
|
|
240
245
|
question: step.question[ctx.language],
|
|
241
|
-
questionType: "text"
|
|
246
|
+
questionType: "text",
|
|
247
|
+
allowFreeText: resolvedAllowFreeText,
|
|
248
|
+
...pendingParameterUpdates.length > 0 && {
|
|
249
|
+
parameterUpdates: pendingParameterUpdates
|
|
250
|
+
}
|
|
242
251
|
};
|
|
243
252
|
}
|
|
244
253
|
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
@@ -250,11 +259,21 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
250
259
|
questionSlug: step.slug,
|
|
251
260
|
question: step.question[ctx.language],
|
|
252
261
|
questionType: step.type,
|
|
253
|
-
options
|
|
262
|
+
options,
|
|
263
|
+
allowFreeText: resolvedAllowFreeText,
|
|
264
|
+
...pendingParameterUpdates.length > 0 && {
|
|
265
|
+
parameterUpdates: pendingParameterUpdates
|
|
266
|
+
}
|
|
254
267
|
};
|
|
255
268
|
}
|
|
256
269
|
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
257
|
-
return {
|
|
270
|
+
return {
|
|
271
|
+
type: "fulfilled",
|
|
272
|
+
dataInvestigationResult,
|
|
273
|
+
...pendingParameterUpdates.length > 0 && {
|
|
274
|
+
parameterUpdates: pendingParameterUpdates
|
|
275
|
+
}
|
|
276
|
+
};
|
|
258
277
|
}
|
|
259
278
|
async function resolveSetupSelection(params) {
|
|
260
279
|
const { selected, allSentinel, fetchAll, limit } = params;
|
|
@@ -315,19 +315,28 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
315
315
|
};
|
|
316
316
|
let state = flow.initialState();
|
|
317
317
|
let answerIdx = 0;
|
|
318
|
+
const pendingParameterUpdates = [];
|
|
318
319
|
for (const step of flow.steps) {
|
|
319
320
|
const ans = ctx.answers[answerIdx];
|
|
320
321
|
if (ans && ans.questionSlug === step.slug) {
|
|
321
322
|
state = step.applyAnswer(state, ans.answer);
|
|
323
|
+
if (step.toParameterUpdates) {
|
|
324
|
+
pendingParameterUpdates.push(...step.toParameterUpdates(state));
|
|
325
|
+
}
|
|
322
326
|
answerIdx += 1;
|
|
323
327
|
continue;
|
|
324
328
|
}
|
|
329
|
+
const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
|
|
325
330
|
if (step.type === "text") {
|
|
326
331
|
return {
|
|
327
332
|
type: "nextQuestion",
|
|
328
333
|
questionSlug: step.slug,
|
|
329
334
|
question: step.question[ctx.language],
|
|
330
|
-
questionType: "text"
|
|
335
|
+
questionType: "text",
|
|
336
|
+
allowFreeText: resolvedAllowFreeText,
|
|
337
|
+
...pendingParameterUpdates.length > 0 && {
|
|
338
|
+
parameterUpdates: pendingParameterUpdates
|
|
339
|
+
}
|
|
331
340
|
};
|
|
332
341
|
}
|
|
333
342
|
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
@@ -339,11 +348,21 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
339
348
|
questionSlug: step.slug,
|
|
340
349
|
question: step.question[ctx.language],
|
|
341
350
|
questionType: step.type,
|
|
342
|
-
options
|
|
351
|
+
options,
|
|
352
|
+
allowFreeText: resolvedAllowFreeText,
|
|
353
|
+
...pendingParameterUpdates.length > 0 && {
|
|
354
|
+
parameterUpdates: pendingParameterUpdates
|
|
355
|
+
}
|
|
343
356
|
};
|
|
344
357
|
}
|
|
345
358
|
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
346
|
-
return {
|
|
359
|
+
return {
|
|
360
|
+
type: "fulfilled",
|
|
361
|
+
dataInvestigationResult,
|
|
362
|
+
...pendingParameterUpdates.length > 0 && {
|
|
363
|
+
parameterUpdates: pendingParameterUpdates
|
|
364
|
+
}
|
|
365
|
+
};
|
|
347
366
|
}
|
|
348
367
|
async function resolveSetupSelection(params) {
|
|
349
368
|
const { selected, allSentinel, fetchAll, limit } = params;
|