@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.
Files changed (73) hide show
  1. package/dist/cli/index.js +1682 -425
  2. package/dist/connectors/airtable-oauth.js +22 -3
  3. package/dist/connectors/airtable.js +22 -3
  4. package/dist/connectors/amplitude.js +22 -3
  5. package/dist/connectors/asana.js +22 -3
  6. package/dist/connectors/attio.js +22 -3
  7. package/dist/connectors/aws-billing.js +22 -3
  8. package/dist/connectors/azure-sql.js +25 -6
  9. package/dist/connectors/backlog-api-key.js +22 -3
  10. package/dist/connectors/clickup.js +22 -3
  11. package/dist/connectors/cosmosdb.js +22 -3
  12. package/dist/connectors/customerio.js +23 -4
  13. package/dist/connectors/dbt.js +22 -3
  14. package/dist/connectors/freshdesk.js +22 -3
  15. package/dist/connectors/freshsales.js +22 -3
  16. package/dist/connectors/freshservice.js +22 -3
  17. package/dist/connectors/gamma.js +24 -5
  18. package/dist/connectors/github.js +22 -3
  19. package/dist/connectors/gmail-oauth.js +22 -3
  20. package/dist/connectors/gmail.js +22 -3
  21. package/dist/connectors/google-ads.js +22 -3
  22. package/dist/connectors/google-analytics-oauth.js +22 -3
  23. package/dist/connectors/google-analytics.js +222 -68
  24. package/dist/connectors/google-audit-log.js +22 -3
  25. package/dist/connectors/google-calendar-oauth.js +22 -3
  26. package/dist/connectors/google-calendar.js +22 -3
  27. package/dist/connectors/google-docs.js +22 -3
  28. package/dist/connectors/google-drive.js +22 -3
  29. package/dist/connectors/google-search-console-oauth.js +22 -3
  30. package/dist/connectors/google-sheets.js +22 -3
  31. package/dist/connectors/google-slides.js +22 -3
  32. package/dist/connectors/grafana.js +22 -3
  33. package/dist/connectors/hubspot-oauth.js +22 -3
  34. package/dist/connectors/hubspot.js +22 -3
  35. package/dist/connectors/influxdb.js +22 -3
  36. package/dist/connectors/intercom-oauth.js +22 -3
  37. package/dist/connectors/intercom.js +22 -3
  38. package/dist/connectors/jdbc.js +22 -3
  39. package/dist/connectors/jira-api-key.js +22 -3
  40. package/dist/connectors/kintone-api-token.js +22 -3
  41. package/dist/connectors/kintone.js +22 -3
  42. package/dist/connectors/linear.js +22 -3
  43. package/dist/connectors/linkedin-ads.js +22 -3
  44. package/dist/connectors/mailchimp-oauth.js +22 -3
  45. package/dist/connectors/mailchimp.js +22 -3
  46. package/dist/connectors/meta-ads-oauth.js +22 -3
  47. package/dist/connectors/meta-ads.js +22 -3
  48. package/dist/connectors/mixpanel.js +22 -3
  49. package/dist/connectors/monday.js +22 -3
  50. package/dist/connectors/mongodb.js +22 -3
  51. package/dist/connectors/notion-oauth.js +22 -3
  52. package/dist/connectors/notion.js +22 -3
  53. package/dist/connectors/oracle.js +48 -14
  54. package/dist/connectors/outlook-oauth.js +22 -3
  55. package/dist/connectors/powerbi-oauth.js +303 -37
  56. package/dist/connectors/salesforce.js +22 -3
  57. package/dist/connectors/semrush.js +360 -46
  58. package/dist/connectors/sentry.js +22 -3
  59. package/dist/connectors/shopify-oauth.js +22 -3
  60. package/dist/connectors/shopify.js +22 -3
  61. package/dist/connectors/sqlserver.js +25 -6
  62. package/dist/connectors/stripe-api-key.js +22 -3
  63. package/dist/connectors/stripe-oauth.js +22 -3
  64. package/dist/connectors/supabase.js +25 -6
  65. package/dist/connectors/tableau.js +240 -78
  66. package/dist/connectors/tiktok-ads.js +22 -3
  67. package/dist/connectors/wix-store.js +22 -3
  68. package/dist/connectors/zendesk-oauth.js +22 -3
  69. package/dist/connectors/zendesk.js +22 -3
  70. package/dist/index.js +1682 -425
  71. package/dist/main.js +1682 -425
  72. package/dist/vite-plugin.js +1682 -425
  73. 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: true
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 { type: "fulfilled", dataInvestigationResult };
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
- const summaries = await listAccountSummaries(rt.params);
591
- return summaries.map((s) => {
592
- const accountResource = s.account ?? s.name ?? "";
593
- if (!accountResource) return null;
594
- return {
595
- value: accountResource,
596
- label: s.displayName ?? accountResource
597
- };
598
- }).filter((v) => v != null);
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
- const summaries = await listAccountSummaries(rt.params);
612
- const account = summaries.find(
613
- (s) => (s.account ?? s.name) === state.account
614
- );
615
- const props = (account?.propertySummaries ?? []).map((p) => {
616
- const id = propertyIdFromResource(p.property);
617
- if (!id) return null;
618
- return {
619
- value: id,
620
- label: p.displayName ? `${p.displayName} (${id})` : id
621
- };
622
- }).filter((v) => v != null);
623
- if (props.length === 0) return [];
624
- return [
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: ALL_PROPERTIES,
627
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30D7\u30ED\u30D1\u30C6\u30A3" : "All properties"
628
- },
629
- ...props
736
+ value: "example",
737
+ label: rt.language === "ja" ? "\u4F8B: 123456789" : "Example: 123456789"
738
+ }
630
739
  ];
631
740
  },
632
- applyAnswer: (state, answer) => ({ ...state, properties: 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
- if (!state.account || !state.properties) {
637
- throw new Error("Google Analytics setup: incomplete state on finalize");
638
- }
639
- const summaries = await listAccountSummaries(rt.params);
640
- const account = summaries.find(
641
- (s) => (s.account ?? s.name) === state.account
642
- );
643
- const accountLabel = account?.displayName ?? state.account.replace(/^accounts\//, "");
644
- const targetPropertyIds = await resolveSetupSelection({
645
- selected: state.properties,
646
- allSentinel: ALL_PROPERTIES,
647
- fetchAll: async () => (account?.propertySummaries ?? []).map((p) => propertyIdFromResource(p.property)).filter((v) => v),
648
- limit: GOOGLE_ANALYTICS_SETUP_MAX_PROPERTIES
649
- });
650
- const sections = [
651
- "## Google Analytics",
652
- "",
653
- `### Account: ${accountLabel}`,
654
- ""
655
- ];
656
- if (targetPropertyIds.length === 0) {
657
- sections.push("_No properties selected._", "");
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
- sections.push("| Property ID | Display Name | Time Zone | Currency | Industry |");
661
- sections.push("|-------------|--------------|-----------|----------|----------|");
662
- for (const propertyId of targetPropertyIds) {
663
- const prop = await getProperty(rt.params, propertyId);
664
- const displayName = (prop?.displayName ?? "-").replace(/\|/g, "\\|");
665
- const timeZone = prop?.timeZone ?? "-";
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 adminFetch(params, "/accountSummaries?pageSize=1");
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: `google-analytics: accountSummaries failed (${res.status}): ${body}`
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 { type: "fulfilled", dataInvestigationResult };
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 { type: "fulfilled", dataInvestigationResult };
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 { type: "fulfilled", dataInvestigationResult };
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 { type: "fulfilled", dataInvestigationResult };
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 { type: "fulfilled", dataInvestigationResult };
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;