@squadbase/vite-server 0.1.17-dev.24af54e → 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.
Files changed (73) hide show
  1. package/dist/cli/index.js +1681 -449
  2. package/dist/connectors/airtable-oauth.js +28 -3
  3. package/dist/connectors/airtable.js +28 -3
  4. package/dist/connectors/amplitude.js +28 -3
  5. package/dist/connectors/asana.js +28 -3
  6. package/dist/connectors/attio.js +28 -3
  7. package/dist/connectors/aws-billing.js +28 -3
  8. package/dist/connectors/azure-sql.js +31 -6
  9. package/dist/connectors/backlog-api-key.js +28 -3
  10. package/dist/connectors/clickup.js +28 -3
  11. package/dist/connectors/cosmosdb.js +28 -3
  12. package/dist/connectors/customerio.js +29 -4
  13. package/dist/connectors/dbt.js +28 -3
  14. package/dist/connectors/freshdesk.js +28 -3
  15. package/dist/connectors/freshsales.js +28 -3
  16. package/dist/connectors/freshservice.js +28 -3
  17. package/dist/connectors/gamma.js +30 -5
  18. package/dist/connectors/github.js +28 -3
  19. package/dist/connectors/gmail-oauth.js +28 -3
  20. package/dist/connectors/gmail.js +28 -3
  21. package/dist/connectors/google-ads.js +28 -3
  22. package/dist/connectors/google-analytics-oauth.js +28 -3
  23. package/dist/connectors/google-analytics.js +227 -105
  24. package/dist/connectors/google-audit-log.js +28 -3
  25. package/dist/connectors/google-calendar-oauth.js +28 -3
  26. package/dist/connectors/google-calendar.js +28 -3
  27. package/dist/connectors/google-docs.js +28 -3
  28. package/dist/connectors/google-drive.js +28 -3
  29. package/dist/connectors/google-search-console-oauth.js +28 -3
  30. package/dist/connectors/google-sheets.js +28 -3
  31. package/dist/connectors/google-slides.js +28 -3
  32. package/dist/connectors/grafana.js +28 -3
  33. package/dist/connectors/hubspot-oauth.js +28 -3
  34. package/dist/connectors/hubspot.js +28 -3
  35. package/dist/connectors/influxdb.js +28 -3
  36. package/dist/connectors/intercom-oauth.js +28 -3
  37. package/dist/connectors/intercom.js +28 -3
  38. package/dist/connectors/jdbc.js +28 -3
  39. package/dist/connectors/jira-api-key.js +28 -3
  40. package/dist/connectors/kintone-api-token.js +28 -3
  41. package/dist/connectors/kintone.js +28 -3
  42. package/dist/connectors/linear.js +28 -3
  43. package/dist/connectors/linkedin-ads.js +28 -3
  44. package/dist/connectors/mailchimp-oauth.js +28 -3
  45. package/dist/connectors/mailchimp.js +28 -3
  46. package/dist/connectors/meta-ads-oauth.js +28 -3
  47. package/dist/connectors/meta-ads.js +28 -3
  48. package/dist/connectors/mixpanel.js +28 -3
  49. package/dist/connectors/monday.js +28 -3
  50. package/dist/connectors/mongodb.js +28 -3
  51. package/dist/connectors/notion-oauth.js +28 -3
  52. package/dist/connectors/notion.js +28 -3
  53. package/dist/connectors/oracle.js +54 -14
  54. package/dist/connectors/outlook-oauth.js +28 -3
  55. package/dist/connectors/powerbi-oauth.js +309 -37
  56. package/dist/connectors/salesforce.js +28 -3
  57. package/dist/connectors/semrush.js +366 -46
  58. package/dist/connectors/sentry.js +28 -3
  59. package/dist/connectors/shopify-oauth.js +28 -3
  60. package/dist/connectors/shopify.js +28 -3
  61. package/dist/connectors/sqlserver.js +31 -6
  62. package/dist/connectors/stripe-api-key.js +28 -3
  63. package/dist/connectors/stripe-oauth.js +28 -3
  64. package/dist/connectors/supabase.js +31 -6
  65. package/dist/connectors/tableau.js +246 -78
  66. package/dist/connectors/tiktok-ads.js +28 -3
  67. package/dist/connectors/wix-store.js +28 -3
  68. package/dist/connectors/zendesk-oauth.js +28 -3
  69. package/dist/connectors/zendesk.js +28 -3
  70. package/dist/index.js +1681 -449
  71. package/dist/main.js +1681 -449
  72. package/dist/vite-plugin.js +1681 -449
  73. package/package.json +1 -1
@@ -256,19 +256,34 @@ async function runSetupFlow(flow, params, ctx, config) {
256
256
  };
257
257
  let state = flow.initialState();
258
258
  let answerIdx = 0;
259
+ const pendingParameterUpdates = [];
259
260
  for (const step of flow.steps) {
260
261
  const ans = ctx.answers[answerIdx];
261
262
  if (ans && ans.questionSlug === step.slug) {
262
263
  state = step.applyAnswer(state, ans.answer);
264
+ if (step.toParameterUpdates) {
265
+ pendingParameterUpdates.push(...step.toParameterUpdates(state));
266
+ }
263
267
  answerIdx += 1;
264
268
  continue;
265
269
  }
270
+ const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
266
271
  if (step.type === "text") {
272
+ if (step.fetchOptions) {
273
+ const options2 = await step.fetchOptions(state, runtime);
274
+ if (options2.length === 0) {
275
+ continue;
276
+ }
277
+ }
267
278
  return {
268
279
  type: "nextQuestion",
269
280
  questionSlug: step.slug,
270
281
  question: step.question[ctx.language],
271
- questionType: "text"
282
+ questionType: "text",
283
+ allowFreeText: resolvedAllowFreeText,
284
+ ...pendingParameterUpdates.length > 0 && {
285
+ parameterUpdates: pendingParameterUpdates
286
+ }
272
287
  };
273
288
  }
274
289
  const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
@@ -280,11 +295,21 @@ async function runSetupFlow(flow, params, ctx, config) {
280
295
  questionSlug: step.slug,
281
296
  question: step.question[ctx.language],
282
297
  questionType: step.type,
283
- options
298
+ options,
299
+ allowFreeText: resolvedAllowFreeText,
300
+ ...pendingParameterUpdates.length > 0 && {
301
+ parameterUpdates: pendingParameterUpdates
302
+ }
284
303
  };
285
304
  }
286
305
  const dataInvestigationResult = await flow.finalize(state, runtime);
287
- return { type: "fulfilled", dataInvestigationResult };
306
+ return {
307
+ type: "fulfilled",
308
+ dataInvestigationResult,
309
+ ...pendingParameterUpdates.length > 0 && {
310
+ parameterUpdates: pendingParameterUpdates
311
+ }
312
+ };
288
313
  }
289
314
  async function resolveSetupSelection(params) {
290
315
  const { selected, allSentinel, fetchAll, limit } = params;
@@ -489,6 +514,10 @@ function apiFetch(proxyFetch, path2, init) {
489
514
 
490
515
  // ../connectors/src/connectors/powerbi-oauth/setup-flow.ts
491
516
  var ALL_WORKSPACES = "__ALL_WORKSPACES__";
517
+ var MY_WORKSPACE = "__MY_WORKSPACE__";
518
+ var ALL_DATASETS = "__ALL_DATASETS__";
519
+ var ALL_REPORTS = "__ALL_REPORTS__";
520
+ var ALL_DASHBOARDS = "__ALL_DASHBOARDS__";
492
521
  var POWERBI_SETUP_MAX_WORKSPACES = 10;
493
522
  var RESOURCE_DISPLAY_LIMIT = 25;
494
523
  var RESOURCE_DATASETS = "datasets";
@@ -504,14 +533,12 @@ async function listGroups(proxyFetch) {
504
533
  return data.value ?? [];
505
534
  }
506
535
  async function listResource(proxyFetch, groupId, resource) {
507
- const res = await apiFetch(
508
- proxyFetch,
509
- `/groups/${encodeURIComponent(groupId)}/${resource}`
510
- );
536
+ const path2 = groupId === MY_WORKSPACE ? `/${resource}` : `/groups/${encodeURIComponent(groupId)}/${resource}`;
537
+ const res = await apiFetch(proxyFetch, path2);
511
538
  if (!res.ok) {
512
539
  const body = await res.text().catch(() => res.statusText);
513
540
  throw new Error(
514
- `powerbi: list ${resource} for group ${groupId} failed (${res.status}): ${body}`
541
+ `powerbi: list ${resource} for ${groupId === MY_WORKSPACE ? "My workspace" : `group ${groupId}`} failed (${res.status}): ${body}`
515
542
  );
516
543
  }
517
544
  const data = await res.json();
@@ -520,6 +547,99 @@ async function listResource(proxyFetch, groupId, resource) {
520
547
  function resourceLabel(r) {
521
548
  return r.name ?? r.displayName ?? r.id ?? "(unknown)";
522
549
  }
550
+ var INTERNAL_TABLE_PREFIXES = [
551
+ "DateTableTemplate_",
552
+ "LocalDateTable_"
553
+ ];
554
+ function isInternalColumn(name) {
555
+ return /^RowNumber-[0-9A-Fa-f-]+$/.test(name);
556
+ }
557
+ async function fetchDatasetSchema(proxyFetch, wsId, datasetId) {
558
+ const pathPrefix = wsId === MY_WORKSPACE ? "" : `/groups/${encodeURIComponent(wsId)}`;
559
+ const daxQuery = 'EVALUATE SELECTCOLUMNS(COLUMNSTATISTICS(), "T", [Table Name], "C", [Column Name])';
560
+ const res = await apiFetch(
561
+ proxyFetch,
562
+ `${pathPrefix}/datasets/${encodeURIComponent(datasetId)}/executeQueries`,
563
+ {
564
+ method: "POST",
565
+ headers: { "Content-Type": "application/json" },
566
+ body: JSON.stringify({
567
+ queries: [{ query: daxQuery }],
568
+ serializerSettings: { includeNulls: true }
569
+ })
570
+ }
571
+ );
572
+ if (!res.ok) return /* @__PURE__ */ new Map();
573
+ const data = await res.json();
574
+ const rows = data.results?.[0]?.tables?.[0]?.rows ?? [];
575
+ const schema = /* @__PURE__ */ new Map();
576
+ for (const row of rows) {
577
+ const table = row["[T]"] ?? "";
578
+ const column = row["[C]"] ?? "";
579
+ if (!table || !column) continue;
580
+ if (INTERNAL_TABLE_PREFIXES.some((p) => table.startsWith(p))) continue;
581
+ if (isInternalColumn(column)) continue;
582
+ if (!schema.has(table)) schema.set(table, []);
583
+ schema.get(table).push(column);
584
+ }
585
+ return schema;
586
+ }
587
+ function workspaceName(wsId, groupById, language) {
588
+ if (wsId === MY_WORKSPACE) {
589
+ return language === "ja" ? "\u30DE\u30A4 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9" : "My workspace";
590
+ }
591
+ return groupById.get(wsId)?.name ?? wsId;
592
+ }
593
+ async function resolveWorkspaceIds(selected, proxyFetch) {
594
+ return resolveSetupSelection({
595
+ selected,
596
+ allSentinel: ALL_WORKSPACES,
597
+ fetchAll: async () => {
598
+ const groups = await listGroups(proxyFetch);
599
+ return [MY_WORKSPACE, ...groups.map((g) => g.id).filter(Boolean)];
600
+ },
601
+ limit: POWERBI_SETUP_MAX_WORKSPACES
602
+ });
603
+ }
604
+ function compoundKey(wsId, objectId) {
605
+ return `${wsId}:${objectId}`;
606
+ }
607
+ function parseCompoundKey(key) {
608
+ const idx = key.indexOf(":");
609
+ if (idx < 0) return { wsId: "", objectId: key };
610
+ return { wsId: key.slice(0, idx), objectId: key.slice(idx + 1) };
611
+ }
612
+ async function fetchObjectOptions(state, resource, allSentinel, allLabelJa, allLabelEn, rt) {
613
+ if (!state.workspaces?.length || !state.resources?.includes(resource))
614
+ return [];
615
+ const wsIds = await resolveWorkspaceIds(
616
+ state.workspaces,
617
+ rt.config.proxyFetch
618
+ );
619
+ const allGroups = await listGroups(rt.config.proxyFetch);
620
+ const groupById = new Map(allGroups.map((g) => [g.id, g]));
621
+ const multiWorkspace = wsIds.length > 1;
622
+ const options = [];
623
+ for (const wsId of wsIds) {
624
+ const wsLabel = workspaceName(wsId, groupById, rt.language);
625
+ const items = await listResource(rt.config.proxyFetch, wsId, resource);
626
+ for (const item of items) {
627
+ if (!item.id) continue;
628
+ options.push({
629
+ value: compoundKey(wsId, item.id),
630
+ label: multiWorkspace ? `${wsLabel} / ${resourceLabel(item)}` : resourceLabel(item)
631
+ });
632
+ }
633
+ }
634
+ if (options.length === 0) return [];
635
+ return [
636
+ {
637
+ value: allSentinel,
638
+ label: rt.language === "ja" ? allLabelJa : allLabelEn
639
+ },
640
+ ...options
641
+ ];
642
+ }
523
643
  var powerbiOauthSetupFlow = {
524
644
  initialState: () => ({}),
525
645
  steps: [
@@ -538,6 +658,10 @@ var powerbiOauthSetupFlow = {
538
658
  value: ALL_WORKSPACES,
539
659
  label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9" : "All workspaces"
540
660
  },
661
+ {
662
+ value: MY_WORKSPACE,
663
+ label: rt.language === "ja" ? "\u30DE\u30A4 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9" : "My workspace"
664
+ },
541
665
  ...options
542
666
  ];
543
667
  },
@@ -552,16 +676,82 @@ var powerbiOauthSetupFlow = {
552
676
  },
553
677
  async fetchOptions(state, rt) {
554
678
  if (!state.workspaces?.length) return [];
555
- const datasetsLabel = rt.language === "ja" ? "\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8" : "Datasets";
556
- const reportsLabel = rt.language === "ja" ? "\u30EC\u30DD\u30FC\u30C8" : "Reports";
557
- const dashboardsLabel = rt.language === "ja" ? "\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9" : "Dashboards";
558
679
  return [
559
- { value: RESOURCE_DATASETS, label: datasetsLabel },
560
- { value: RESOURCE_REPORTS, label: reportsLabel },
561
- { value: RESOURCE_DASHBOARDS, label: dashboardsLabel }
680
+ {
681
+ value: RESOURCE_DATASETS,
682
+ label: rt.language === "ja" ? "\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8" : "Datasets"
683
+ },
684
+ {
685
+ value: RESOURCE_REPORTS,
686
+ label: rt.language === "ja" ? "\u30EC\u30DD\u30FC\u30C8" : "Reports"
687
+ },
688
+ {
689
+ value: RESOURCE_DASHBOARDS,
690
+ label: rt.language === "ja" ? "\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9" : "Dashboards"
691
+ }
562
692
  ];
563
693
  },
564
694
  applyAnswer: (state, answer) => ({ ...state, resources: answer })
695
+ },
696
+ {
697
+ slug: "datasets",
698
+ type: "multiSelect",
699
+ question: {
700
+ ja: "\u4F7F\u7528\u3059\u308B\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
701
+ en: "Select the datasets you want to use (multi-select allowed)"
702
+ },
703
+ async fetchOptions(state, rt) {
704
+ return fetchObjectOptions(
705
+ state,
706
+ RESOURCE_DATASETS,
707
+ ALL_DATASETS,
708
+ "\u3059\u3079\u3066\u306E\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8",
709
+ "All datasets",
710
+ rt
711
+ );
712
+ },
713
+ applyAnswer: (state, answer) => ({ ...state, selectedDatasets: answer })
714
+ },
715
+ {
716
+ slug: "reports",
717
+ type: "multiSelect",
718
+ question: {
719
+ ja: "\u4F7F\u7528\u3059\u308B\u30EC\u30DD\u30FC\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
720
+ en: "Select the reports you want to use (multi-select allowed)"
721
+ },
722
+ async fetchOptions(state, rt) {
723
+ return fetchObjectOptions(
724
+ state,
725
+ RESOURCE_REPORTS,
726
+ ALL_REPORTS,
727
+ "\u3059\u3079\u3066\u306E\u30EC\u30DD\u30FC\u30C8",
728
+ "All reports",
729
+ rt
730
+ );
731
+ },
732
+ applyAnswer: (state, answer) => ({ ...state, selectedReports: answer })
733
+ },
734
+ {
735
+ slug: "dashboards",
736
+ type: "multiSelect",
737
+ question: {
738
+ ja: "\u4F7F\u7528\u3059\u308B\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
739
+ en: "Select the dashboards you want to use (multi-select allowed)"
740
+ },
741
+ async fetchOptions(state, rt) {
742
+ return fetchObjectOptions(
743
+ state,
744
+ RESOURCE_DASHBOARDS,
745
+ ALL_DASHBOARDS,
746
+ "\u3059\u3079\u3066\u306E\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9",
747
+ "All dashboards",
748
+ rt
749
+ );
750
+ },
751
+ applyAnswer: (state, answer) => ({
752
+ ...state,
753
+ selectedDashboards: answer
754
+ })
565
755
  }
566
756
  ],
567
757
  async finalize(state, rt) {
@@ -570,37 +760,119 @@ var powerbiOauthSetupFlow = {
570
760
  }
571
761
  const allGroups = await listGroups(rt.config.proxyFetch);
572
762
  const groupById = new Map(allGroups.map((g) => [g.id, g]));
573
- const targetIds = await resolveSetupSelection({
574
- selected: state.workspaces,
575
- allSentinel: ALL_WORKSPACES,
576
- fetchAll: async () => allGroups.map((g) => g.id).filter((id) => id),
577
- limit: POWERBI_SETUP_MAX_WORKSPACES
578
- });
763
+ const wsIds = await resolveWorkspaceIds(
764
+ state.workspaces,
765
+ rt.config.proxyFetch
766
+ );
579
767
  const selectedResources = new Set(state.resources);
768
+ async function resolveObjects(selected, allSentinel, resource) {
769
+ const byWorkspace = /* @__PURE__ */ new Map();
770
+ if (!selected || !selectedResources.has(resource)) return byWorkspace;
771
+ if (selected.includes(allSentinel)) {
772
+ for (const wsId of wsIds) {
773
+ const items = await listResource(
774
+ rt.config.proxyFetch,
775
+ wsId,
776
+ resource
777
+ );
778
+ const ids = items.map((i) => i.id).filter((id) => !!id);
779
+ if (ids.length > 0) byWorkspace.set(wsId, new Set(ids));
780
+ }
781
+ } else {
782
+ for (const key of selected) {
783
+ if (key === allSentinel) continue;
784
+ const { wsId, objectId } = parseCompoundKey(key);
785
+ if (!byWorkspace.has(wsId)) byWorkspace.set(wsId, /* @__PURE__ */ new Set());
786
+ byWorkspace.get(wsId).add(objectId);
787
+ }
788
+ }
789
+ return byWorkspace;
790
+ }
791
+ const datasetsByWs = await resolveObjects(
792
+ state.selectedDatasets,
793
+ ALL_DATASETS,
794
+ RESOURCE_DATASETS
795
+ );
796
+ const reportsByWs = await resolveObjects(
797
+ state.selectedReports,
798
+ ALL_REPORTS,
799
+ RESOURCE_REPORTS
800
+ );
801
+ const dashboardsByWs = await resolveObjects(
802
+ state.selectedDashboards,
803
+ ALL_DASHBOARDS,
804
+ RESOURCE_DASHBOARDS
805
+ );
806
+ const allWsIds = /* @__PURE__ */ new Set([
807
+ ...datasetsByWs.keys(),
808
+ ...reportsByWs.keys(),
809
+ ...dashboardsByWs.keys()
810
+ ]);
580
811
  const sections = ["## Power BI", ""];
581
- if (!targetIds.length) {
582
- sections.push("_No workspaces selected._", "");
812
+ if (allWsIds.size === 0) {
813
+ sections.push("_No resources selected._", "");
583
814
  return sections.join("\n");
584
815
  }
585
- for (const id of targetIds) {
586
- const group = groupById.get(id);
587
- const name = group?.name ?? id;
588
- sections.push(`### Workspace: ${name}`, "", `- id: \`${id}\``);
589
- for (const resource of [
590
- RESOURCE_DATASETS,
591
- RESOURCE_REPORTS,
592
- RESOURCE_DASHBOARDS
816
+ for (const wsId of wsIds) {
817
+ if (!allWsIds.has(wsId)) continue;
818
+ const name = workspaceName(wsId, groupById, rt.language);
819
+ sections.push(`### Workspace: ${name}`, "");
820
+ if (wsId !== MY_WORKSPACE) {
821
+ sections.push(`- id: \`${wsId}\``);
822
+ }
823
+ const datasetIds = datasetsByWs.get(wsId);
824
+ if (datasetIds?.size) {
825
+ const items = await listResource(
826
+ rt.config.proxyFetch,
827
+ wsId,
828
+ RESOURCE_DATASETS
829
+ );
830
+ const filtered = items.filter(
831
+ (item) => item.id && datasetIds.has(item.id)
832
+ );
833
+ for (const item of filtered.slice(0, RESOURCE_DISPLAY_LIMIT)) {
834
+ sections.push(`#### Dataset: ${resourceLabel(item)}`, "");
835
+ const schema = await fetchDatasetSchema(
836
+ rt.config.proxyFetch,
837
+ wsId,
838
+ item.id
839
+ );
840
+ if (schema.size > 0) {
841
+ for (const [table, columns] of schema) {
842
+ sections.push(`##### Table: ${table}`, "");
843
+ sections.push("| Column |");
844
+ sections.push("|--------|");
845
+ for (const col of columns) {
846
+ sections.push(`| ${col} |`);
847
+ }
848
+ sections.push("");
849
+ }
850
+ } else {
851
+ sections.push("_Schema not available._", "");
852
+ }
853
+ }
854
+ }
855
+ for (const [resource, selectedByWs, heading] of [
856
+ [RESOURCE_REPORTS, reportsByWs, "Reports"],
857
+ [RESOURCE_DASHBOARDS, dashboardsByWs, "Dashboards"]
593
858
  ]) {
594
- if (!selectedResources.has(resource)) continue;
595
- const items = await listResource(rt.config.proxyFetch, id, resource);
596
- const heading = resource === RESOURCE_DATASETS ? "Datasets" : resource === RESOURCE_REPORTS ? "Reports" : "Dashboards";
597
- sections.push(`- ${heading} (${items.length}):`);
598
- for (const item of items.slice(0, RESOURCE_DISPLAY_LIMIT)) {
859
+ const selectedIds = selectedByWs.get(wsId);
860
+ if (!selectedIds?.size) continue;
861
+ const items = await listResource(
862
+ rt.config.proxyFetch,
863
+ wsId,
864
+ resource
865
+ );
866
+ const filtered = items.filter(
867
+ (item) => item.id && selectedIds.has(item.id)
868
+ );
869
+ sections.push(`- ${heading} (${filtered.length}):`);
870
+ for (const item of filtered.slice(0, RESOURCE_DISPLAY_LIMIT)) {
599
871
  sections.push(` - ${resourceLabel(item)}`);
600
872
  }
601
- if (items.length > RESOURCE_DISPLAY_LIMIT) {
873
+ if (filtered.length > RESOURCE_DISPLAY_LIMIT) {
602
874
  sections.push(
603
- ` - \u2026and ${items.length - RESOURCE_DISPLAY_LIMIT} more`
875
+ ` - \u2026and ${filtered.length - RESOURCE_DISPLAY_LIMIT} more`
604
876
  );
605
877
  }
606
878
  }
@@ -397,19 +397,34 @@ async function runSetupFlow(flow, params, ctx, config) {
397
397
  };
398
398
  let state = flow.initialState();
399
399
  let answerIdx = 0;
400
+ const pendingParameterUpdates = [];
400
401
  for (const step of flow.steps) {
401
402
  const ans = ctx.answers[answerIdx];
402
403
  if (ans && ans.questionSlug === step.slug) {
403
404
  state = step.applyAnswer(state, ans.answer);
405
+ if (step.toParameterUpdates) {
406
+ pendingParameterUpdates.push(...step.toParameterUpdates(state));
407
+ }
404
408
  answerIdx += 1;
405
409
  continue;
406
410
  }
411
+ const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
407
412
  if (step.type === "text") {
413
+ if (step.fetchOptions) {
414
+ const options2 = await step.fetchOptions(state, runtime);
415
+ if (options2.length === 0) {
416
+ continue;
417
+ }
418
+ }
408
419
  return {
409
420
  type: "nextQuestion",
410
421
  questionSlug: step.slug,
411
422
  question: step.question[ctx.language],
412
- questionType: "text"
423
+ questionType: "text",
424
+ allowFreeText: resolvedAllowFreeText,
425
+ ...pendingParameterUpdates.length > 0 && {
426
+ parameterUpdates: pendingParameterUpdates
427
+ }
413
428
  };
414
429
  }
415
430
  const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
@@ -421,11 +436,21 @@ async function runSetupFlow(flow, params, ctx, config) {
421
436
  questionSlug: step.slug,
422
437
  question: step.question[ctx.language],
423
438
  questionType: step.type,
424
- options
439
+ options,
440
+ allowFreeText: resolvedAllowFreeText,
441
+ ...pendingParameterUpdates.length > 0 && {
442
+ parameterUpdates: pendingParameterUpdates
443
+ }
425
444
  };
426
445
  }
427
446
  const dataInvestigationResult = await flow.finalize(state, runtime);
428
- return { type: "fulfilled", dataInvestigationResult };
447
+ return {
448
+ type: "fulfilled",
449
+ dataInvestigationResult,
450
+ ...pendingParameterUpdates.length > 0 && {
451
+ parameterUpdates: pendingParameterUpdates
452
+ }
453
+ };
429
454
  }
430
455
  async function resolveSetupSelection(params) {
431
456
  const { selected, allSentinel, fetchAll, limit } = params;