@teamkeel/functions-runtime 0.414.3 → 0.414.5

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/index.d.cts CHANGED
@@ -335,9 +335,13 @@ type TableData<T extends Record<string, any>> = {
335
335
  columns?: Array<Extract<keyof T, string>>;
336
336
  };
337
337
  type UiElementTable = <const T extends Record<string, any>>(options: TableData<T>) => DisplayElementResponse;
338
+ type TableColumn = {
339
+ name: string;
340
+ index: number;
341
+ };
338
342
  interface UiElementTableApiResponse extends BaseUiDisplayResponse<"ui.display.table"> {
339
343
  data: any[];
340
- columns?: string[];
344
+ columns: TableColumn[];
341
345
  }
342
346
 
343
347
  type UiElementDivider = DisplayElement<{}>;
@@ -464,6 +468,82 @@ interface UiElementListApiResponse extends BaseUiDisplayResponse<"ui.display.lis
464
468
  data: ListItem[];
465
469
  }
466
470
 
471
+ type KeyValueMode = "list" | "grid" | "card";
472
+ type KeyValueData = {
473
+ key: string;
474
+ value: string | number | Date | boolean;
475
+ };
476
+ type UiElementKeyValue = DisplayElement<{
477
+ data: KeyValueData[];
478
+ mode?: KeyValueMode;
479
+ }>;
480
+ interface UiElementKeyValueApiResponse extends BaseUiDisplayResponse<"ui.display.keyValue"> {
481
+ data: KeyValueData[];
482
+ mode: KeyValueMode;
483
+ }
484
+
485
+ type CompleteOptions<C extends FlowConfig> = {
486
+ stage?: ExtractStageKeys<C>;
487
+ title?: string;
488
+ description?: string;
489
+ /** Automatically close the flow once complete.
490
+ * If set, the title and description will be shown in a notification.
491
+ * If set, you cannot return content as this will not be shown. */
492
+ autoClose?: boolean;
493
+ data?: any;
494
+ } & ({
495
+ autoClose: true;
496
+ content?: never;
497
+ } | {
498
+ autoClose?: false;
499
+ content?: DisplayElementResponse[];
500
+ });
501
+ type Complete<C extends FlowConfig> = (options: CompleteOptions<C>) => CompleteOptions<C> & {
502
+ __type: "ui.complete";
503
+ };
504
+
505
+ type SelectMode = "single" | "multi";
506
+ type UiElementSelectTable = <const T extends Record<string, any>, N extends string, const M extends SelectMode = "multi">(name: N, options: TableOptions<T, M>) => InputElementResponse<N, M extends "single" ? T : T[]>;
507
+ type TableOptions<T extends Record<string, any>, M extends SelectMode = "multi"> = Omit<BaseInputConfig<T>, "defaultValue" | "label"> & TableData<T> & {
508
+ mode?: M;
509
+ };
510
+ interface UiElementSelectTableApiResponse extends Omit<BaseUiInputResponse<"ui.select.table", any>, "defaultValue" | "label"> {
511
+ data: any[];
512
+ columns: TableColumn[];
513
+ mode: SelectMode;
514
+ }
515
+
516
+ type UiElementInputDataGrid = <N extends string, T extends Record<string, any>, const Cols extends Extract<keyof T, string>[], C extends ColumnConfig<Cols>[] | undefined = undefined>(name: N, options: DataGridOptions<T, C>) => InputElementResponse<N, C extends ColumnConfig<Cols>[] ? {
517
+ [K in C[number] as K["key"]]: MapDataType<K["type"], T[K["key"]]>;
518
+ }[] : T[]>;
519
+ type MapDataType<U, Fallback> = U extends "text" ? string : U extends "number" ? number : U extends "boolean" ? boolean : U extends "id" ? string : U extends "hidden" ? Fallback : Fallback;
520
+ type ColumnConfig<Cols extends string[]> = {
521
+ key: Cols[number];
522
+ label?: string;
523
+ type?: DataGridDataTypes;
524
+ editable?: boolean;
525
+ };
526
+ type DataGridOptions<T extends Record<string, any>, C> = Omit<BaseInputConfig<T>, "defaultValue" | "label" | "optional" | "disabled"> & {
527
+ data: T[];
528
+ columns?: C;
529
+ allowAddRows?: boolean;
530
+ allowDeleteRows?: boolean;
531
+ };
532
+ interface UiElementInputDataGridApiResponse extends Omit<BaseUiInputResponse<"ui.input.dataGrid", any>, "defaultValue" | "label" | "optional" | "disabled"> {
533
+ data: any[];
534
+ columns: DataGridColumn[];
535
+ allowAddRows: boolean;
536
+ allowDeleteRows: boolean;
537
+ }
538
+ type DataGridDataTypes = "text" | "number" | "boolean" | "id" | "hidden";
539
+ type DataGridColumn = {
540
+ key: string;
541
+ label: string;
542
+ index: number;
543
+ type: DataGridDataTypes;
544
+ editable: boolean;
545
+ };
546
+
467
547
  interface UI<C extends FlowConfig> {
468
548
  page: UiPage<C>;
469
549
  display: UiDisplayElements;
@@ -474,9 +554,11 @@ type UiInputsElements = {
474
554
  text: UiElementInputText;
475
555
  number: UiElementInputNumber;
476
556
  boolean: UiElementInputBoolean;
557
+ dataGrid: UiElementInputDataGrid;
477
558
  };
478
559
  type UiSelectElements = {
479
560
  one: UiElementSelectOne;
561
+ table: UiElementSelectTable;
480
562
  };
481
563
  type UiDisplayElements = {
482
564
  divider: UiElementDivider;
@@ -488,6 +570,7 @@ type UiDisplayElements = {
488
570
  grid: UiElementGrid;
489
571
  list: UiElementList;
490
572
  table: UiElementTable;
573
+ keyValue: UiElementKeyValue;
491
574
  };
492
575
  type InputElement<TValueType, TConfig extends any = never> = <N extends string>(name: N, options?: BaseInputConfig<TValueType> & TConfig) => InputElementResponse<N, TValueType>;
493
576
  type DisplayElement<TConfig extends any = never> = (options?: TConfig) => DisplayElementResponse;
@@ -535,26 +618,20 @@ type UIApiResponses = {
535
618
  grid: UiElementGridApiResponse;
536
619
  list: UiElementListApiResponse;
537
620
  table: UiElementTableApiResponse;
621
+ keyValue: UiElementKeyValueApiResponse;
538
622
  };
539
623
  input: {
540
624
  text: UiElementInputTextApiResponse;
541
625
  number: UiElementInputNumberApiResponse;
542
626
  boolean: UiElementInputBooleanApiResponse;
627
+ dataGrid: UiElementInputDataGridApiResponse;
543
628
  };
544
629
  select: {
545
630
  one: UiElementSelectOneApiResponse;
631
+ table: UiElementSelectTableApiResponse;
546
632
  };
547
633
  };
548
634
 
549
- type CompleteOptions<C extends FlowConfig> = {
550
- stage?: ExtractStageKeys<C>;
551
- title?: string;
552
- description?: string;
553
- content: DisplayElementResponse[];
554
- data?: any;
555
- };
556
- type Complete<C extends FlowConfig> = (options: CompleteOptions<C>) => CompleteOptions<C>;
557
-
558
635
  declare const enum STEP_STATUS {
559
636
  NEW = "NEW",
560
637
  RUNNING = "RUNNING",
package/dist/index.d.ts CHANGED
@@ -335,9 +335,13 @@ type TableData<T extends Record<string, any>> = {
335
335
  columns?: Array<Extract<keyof T, string>>;
336
336
  };
337
337
  type UiElementTable = <const T extends Record<string, any>>(options: TableData<T>) => DisplayElementResponse;
338
+ type TableColumn = {
339
+ name: string;
340
+ index: number;
341
+ };
338
342
  interface UiElementTableApiResponse extends BaseUiDisplayResponse<"ui.display.table"> {
339
343
  data: any[];
340
- columns?: string[];
344
+ columns: TableColumn[];
341
345
  }
342
346
 
343
347
  type UiElementDivider = DisplayElement<{}>;
@@ -464,6 +468,82 @@ interface UiElementListApiResponse extends BaseUiDisplayResponse<"ui.display.lis
464
468
  data: ListItem[];
465
469
  }
466
470
 
471
+ type KeyValueMode = "list" | "grid" | "card";
472
+ type KeyValueData = {
473
+ key: string;
474
+ value: string | number | Date | boolean;
475
+ };
476
+ type UiElementKeyValue = DisplayElement<{
477
+ data: KeyValueData[];
478
+ mode?: KeyValueMode;
479
+ }>;
480
+ interface UiElementKeyValueApiResponse extends BaseUiDisplayResponse<"ui.display.keyValue"> {
481
+ data: KeyValueData[];
482
+ mode: KeyValueMode;
483
+ }
484
+
485
+ type CompleteOptions<C extends FlowConfig> = {
486
+ stage?: ExtractStageKeys<C>;
487
+ title?: string;
488
+ description?: string;
489
+ /** Automatically close the flow once complete.
490
+ * If set, the title and description will be shown in a notification.
491
+ * If set, you cannot return content as this will not be shown. */
492
+ autoClose?: boolean;
493
+ data?: any;
494
+ } & ({
495
+ autoClose: true;
496
+ content?: never;
497
+ } | {
498
+ autoClose?: false;
499
+ content?: DisplayElementResponse[];
500
+ });
501
+ type Complete<C extends FlowConfig> = (options: CompleteOptions<C>) => CompleteOptions<C> & {
502
+ __type: "ui.complete";
503
+ };
504
+
505
+ type SelectMode = "single" | "multi";
506
+ type UiElementSelectTable = <const T extends Record<string, any>, N extends string, const M extends SelectMode = "multi">(name: N, options: TableOptions<T, M>) => InputElementResponse<N, M extends "single" ? T : T[]>;
507
+ type TableOptions<T extends Record<string, any>, M extends SelectMode = "multi"> = Omit<BaseInputConfig<T>, "defaultValue" | "label"> & TableData<T> & {
508
+ mode?: M;
509
+ };
510
+ interface UiElementSelectTableApiResponse extends Omit<BaseUiInputResponse<"ui.select.table", any>, "defaultValue" | "label"> {
511
+ data: any[];
512
+ columns: TableColumn[];
513
+ mode: SelectMode;
514
+ }
515
+
516
+ type UiElementInputDataGrid = <N extends string, T extends Record<string, any>, const Cols extends Extract<keyof T, string>[], C extends ColumnConfig<Cols>[] | undefined = undefined>(name: N, options: DataGridOptions<T, C>) => InputElementResponse<N, C extends ColumnConfig<Cols>[] ? {
517
+ [K in C[number] as K["key"]]: MapDataType<K["type"], T[K["key"]]>;
518
+ }[] : T[]>;
519
+ type MapDataType<U, Fallback> = U extends "text" ? string : U extends "number" ? number : U extends "boolean" ? boolean : U extends "id" ? string : U extends "hidden" ? Fallback : Fallback;
520
+ type ColumnConfig<Cols extends string[]> = {
521
+ key: Cols[number];
522
+ label?: string;
523
+ type?: DataGridDataTypes;
524
+ editable?: boolean;
525
+ };
526
+ type DataGridOptions<T extends Record<string, any>, C> = Omit<BaseInputConfig<T>, "defaultValue" | "label" | "optional" | "disabled"> & {
527
+ data: T[];
528
+ columns?: C;
529
+ allowAddRows?: boolean;
530
+ allowDeleteRows?: boolean;
531
+ };
532
+ interface UiElementInputDataGridApiResponse extends Omit<BaseUiInputResponse<"ui.input.dataGrid", any>, "defaultValue" | "label" | "optional" | "disabled"> {
533
+ data: any[];
534
+ columns: DataGridColumn[];
535
+ allowAddRows: boolean;
536
+ allowDeleteRows: boolean;
537
+ }
538
+ type DataGridDataTypes = "text" | "number" | "boolean" | "id" | "hidden";
539
+ type DataGridColumn = {
540
+ key: string;
541
+ label: string;
542
+ index: number;
543
+ type: DataGridDataTypes;
544
+ editable: boolean;
545
+ };
546
+
467
547
  interface UI<C extends FlowConfig> {
468
548
  page: UiPage<C>;
469
549
  display: UiDisplayElements;
@@ -474,9 +554,11 @@ type UiInputsElements = {
474
554
  text: UiElementInputText;
475
555
  number: UiElementInputNumber;
476
556
  boolean: UiElementInputBoolean;
557
+ dataGrid: UiElementInputDataGrid;
477
558
  };
478
559
  type UiSelectElements = {
479
560
  one: UiElementSelectOne;
561
+ table: UiElementSelectTable;
480
562
  };
481
563
  type UiDisplayElements = {
482
564
  divider: UiElementDivider;
@@ -488,6 +570,7 @@ type UiDisplayElements = {
488
570
  grid: UiElementGrid;
489
571
  list: UiElementList;
490
572
  table: UiElementTable;
573
+ keyValue: UiElementKeyValue;
491
574
  };
492
575
  type InputElement<TValueType, TConfig extends any = never> = <N extends string>(name: N, options?: BaseInputConfig<TValueType> & TConfig) => InputElementResponse<N, TValueType>;
493
576
  type DisplayElement<TConfig extends any = never> = (options?: TConfig) => DisplayElementResponse;
@@ -535,26 +618,20 @@ type UIApiResponses = {
535
618
  grid: UiElementGridApiResponse;
536
619
  list: UiElementListApiResponse;
537
620
  table: UiElementTableApiResponse;
621
+ keyValue: UiElementKeyValueApiResponse;
538
622
  };
539
623
  input: {
540
624
  text: UiElementInputTextApiResponse;
541
625
  number: UiElementInputNumberApiResponse;
542
626
  boolean: UiElementInputBooleanApiResponse;
627
+ dataGrid: UiElementInputDataGridApiResponse;
543
628
  };
544
629
  select: {
545
630
  one: UiElementSelectOneApiResponse;
631
+ table: UiElementSelectTableApiResponse;
546
632
  };
547
633
  };
548
634
 
549
- type CompleteOptions<C extends FlowConfig> = {
550
- stage?: ExtractStageKeys<C>;
551
- title?: string;
552
- description?: string;
553
- content: DisplayElementResponse[];
554
- data?: any;
555
- };
556
- type Complete<C extends FlowConfig> = (options: CompleteOptions<C>) => CompleteOptions<C>;
557
-
558
635
  declare const enum STEP_STATUS {
559
636
  NEW = "NEW",
560
637
  RUNNING = "RUNNING",
package/dist/index.js CHANGED
@@ -2395,20 +2395,30 @@ var markdown = /* @__PURE__ */ __name((options) => {
2395
2395
 
2396
2396
  // src/flows/ui/elements/display/table.ts
2397
2397
  var table = /* @__PURE__ */ __name((options) => {
2398
- const filteredData = options.columns ? options.data.map((item) => {
2399
- return Object.fromEntries(
2400
- Object.entries(item).filter(
2401
- ([key]) => options.columns?.includes(key)
2402
- )
2403
- );
2404
- }) : options.data;
2398
+ const { data, columns } = processTableData(options.data, options.columns);
2405
2399
  return {
2406
2400
  uiConfig: {
2407
2401
  __type: "ui.display.table",
2408
- data: filteredData || []
2402
+ data: data || [],
2403
+ columns: columns || []
2409
2404
  }
2410
2405
  };
2411
2406
  }, "table");
2407
+ var processTableData = /* @__PURE__ */ __name((data, columnsConfig) => {
2408
+ const filteredData = columnsConfig ? data.map((item) => {
2409
+ return Object.fromEntries(
2410
+ Object.entries(item).filter(
2411
+ ([key]) => columnsConfig?.includes(key)
2412
+ )
2413
+ );
2414
+ }) : data;
2415
+ const cols = Object.keys(filteredData[0] || {});
2416
+ const columns = cols.map((column, index) => ({
2417
+ name: column,
2418
+ index
2419
+ }));
2420
+ return { data: filteredData, columns };
2421
+ }, "processTableData");
2412
2422
 
2413
2423
  // src/flows/ui/elements/select/one.ts
2414
2424
  var selectOne = /* @__PURE__ */ __name((name, options) => {
@@ -2433,24 +2443,28 @@ var selectOne = /* @__PURE__ */ __name((name, options) => {
2433
2443
  async function page(options, data, action) {
2434
2444
  const content = options.content;
2435
2445
  let hasValidationErrors = false;
2436
- if (options.actions) {
2446
+ let validationError;
2447
+ if (options.actions && action !== null) {
2437
2448
  const isValidAction = options.actions.some((a) => {
2438
2449
  if (typeof a === "string") return a === action;
2439
2450
  return a && typeof a === "object" && "value" in a && a.value === action;
2440
2451
  });
2441
- hasValidationErrors = !isValidAction;
2452
+ if (!isValidAction) {
2453
+ hasValidationErrors = true;
2454
+ validationError = "invalid action";
2455
+ }
2442
2456
  }
2443
2457
  const contentUiConfig = await Promise.all(
2444
2458
  content.map(async (c) => {
2445
2459
  const isInput = "__type" in c && c.__type == "input";
2446
2460
  const hasData = data && c.uiConfig.name in data;
2447
2461
  if (isInput && hasData && c.validate) {
2448
- const validationError = await c.validate(data[c.uiConfig.name]);
2449
- if (typeof validationError === "string") {
2462
+ const validationError2 = await c.validate(data[c.uiConfig.name]);
2463
+ if (typeof validationError2 === "string") {
2450
2464
  hasValidationErrors = true;
2451
2465
  return {
2452
2466
  ...c.uiConfig,
2453
- validationError
2467
+ validationError: validationError2
2454
2468
  };
2455
2469
  }
2456
2470
  }
@@ -2471,7 +2485,9 @@ async function page(options, data, action) {
2471
2485
  a.mode = a.mode || "primary";
2472
2486
  }
2473
2487
  return a;
2474
- })
2488
+ }),
2489
+ hasValidationErrors,
2490
+ validationError
2475
2491
  },
2476
2492
  hasValidationErrors
2477
2493
  };
@@ -2595,6 +2611,90 @@ var header = /* @__PURE__ */ __name((options) => {
2595
2611
  };
2596
2612
  }, "header");
2597
2613
 
2614
+ // src/flows/ui/elements/display/keyValue.ts
2615
+ var keyValue = /* @__PURE__ */ __name((options) => {
2616
+ return {
2617
+ uiConfig: {
2618
+ __type: "ui.display.keyValue",
2619
+ data: options?.data || [],
2620
+ mode: options?.mode || "list"
2621
+ }
2622
+ };
2623
+ }, "keyValue");
2624
+
2625
+ // src/flows/ui/elements/select/table.ts
2626
+ var selectTable = /* @__PURE__ */ __name((name, options) => {
2627
+ const { data, columns } = processTableData(options.data, options.columns);
2628
+ return {
2629
+ __type: "input",
2630
+ uiConfig: {
2631
+ __type: "ui.select.table",
2632
+ name,
2633
+ data,
2634
+ columns,
2635
+ mode: options?.mode || "multi",
2636
+ optional: options?.optional || false,
2637
+ disabled: options?.disabled || false,
2638
+ helpText: options?.helpText
2639
+ },
2640
+ validate: options?.validate,
2641
+ getData: /* @__PURE__ */ __name((x) => x, "getData")
2642
+ };
2643
+ }, "selectTable");
2644
+
2645
+ // src/flows/ui/elements/input/dataGrid.ts
2646
+ import { sentenceCase } from "change-case";
2647
+ var dataGridInput = /* @__PURE__ */ __name((name, options) => {
2648
+ const { data } = processTableData(
2649
+ options.data,
2650
+ options.columns?.map((c) => c.key)
2651
+ );
2652
+ const inferType = /* @__PURE__ */ __name((key) => {
2653
+ const inferredTypeRaw = typeof data[0][key];
2654
+ const inferredTypeMap = {
2655
+ string: "text",
2656
+ number: "number",
2657
+ boolean: "boolean",
2658
+ bigint: "number",
2659
+ symbol: "text",
2660
+ undefined: "text",
2661
+ object: "text",
2662
+ function: "text"
2663
+ };
2664
+ return inferredTypeMap[inferredTypeRaw] ?? "text";
2665
+ }, "inferType");
2666
+ const columns = options.columns ? options.columns?.map((column, idx) => ({
2667
+ key: column.key,
2668
+ label: column.label || column.key,
2669
+ index: idx,
2670
+ type: column.type || inferType(column.key),
2671
+ editable: column.editable === void 0 ? column.type === "id" ? false : true : column.editable
2672
+ })) : Object.keys(data[0]).map((key, idx) => {
2673
+ return {
2674
+ index: idx,
2675
+ key,
2676
+ label: sentenceCase(key),
2677
+ type: inferType(key),
2678
+ editable: true
2679
+ };
2680
+ });
2681
+ return {
2682
+ __type: "input",
2683
+ uiConfig: {
2684
+ __type: "ui.input.dataGrid",
2685
+ name,
2686
+ data,
2687
+ columns,
2688
+ helpText: options?.helpText,
2689
+ allowAddRows: options?.allowAddRows ?? false,
2690
+ allowDeleteRows: options?.allowDeleteRows ?? false
2691
+ },
2692
+ validate: options?.validate,
2693
+ // TODO have some built in validation that checks the types of the response
2694
+ getData: /* @__PURE__ */ __name((x) => x, "getData")
2695
+ };
2696
+ }, "dataGridInput");
2697
+
2598
2698
  // src/flows/index.ts
2599
2699
  var STEP_STATUS = /* @__PURE__ */ ((STEP_STATUS2) => {
2600
2700
  STEP_STATUS2["NEW"] = "NEW";
@@ -2622,7 +2722,12 @@ function createFlowContext(runId, data, action, spanId, ctx) {
2622
2722
  env: ctx.env,
2623
2723
  now: ctx.now,
2624
2724
  secrets: ctx.secrets,
2625
- complete: /* @__PURE__ */ __name((options) => options, "complete"),
2725
+ complete: /* @__PURE__ */ __name((options) => {
2726
+ return {
2727
+ __type: "ui.complete",
2728
+ ...options
2729
+ };
2730
+ }, "complete"),
2626
2731
  step: /* @__PURE__ */ __name(async (name, optionsOrFn, fn) => {
2627
2732
  const options = typeof optionsOrFn === "function" ? {} : optionsOrFn;
2628
2733
  const actualFn = typeof optionsOrFn === "function" ? optionsOrFn : fn;
@@ -2769,7 +2874,8 @@ function createFlowContext(runId, data, action, spanId, ctx) {
2769
2874
  inputs: {
2770
2875
  text: textInput,
2771
2876
  number: numberInput,
2772
- boolean: booleanInput
2877
+ boolean: booleanInput,
2878
+ dataGrid: dataGridInput
2773
2879
  },
2774
2880
  display: {
2775
2881
  divider,
@@ -2780,10 +2886,12 @@ function createFlowContext(runId, data, action, spanId, ctx) {
2780
2886
  image,
2781
2887
  code,
2782
2888
  grid,
2783
- list
2889
+ list,
2890
+ keyValue
2784
2891
  },
2785
2892
  select: {
2786
- one: selectOne
2893
+ one: selectOne,
2894
+ table: selectTable
2787
2895
  }
2788
2896
  }
2789
2897
  };
@@ -2805,26 +2913,25 @@ __name(withTimeout, "withTimeout");
2805
2913
 
2806
2914
  // src/flows/ui/complete.ts
2807
2915
  async function complete(options) {
2808
- const content = options.content;
2916
+ const content = options.content || [];
2809
2917
  const contentUiConfig = await Promise.all(
2810
2918
  content.map(async (c) => {
2811
2919
  return c.uiConfig;
2812
2920
  })
2813
2921
  );
2814
2922
  return {
2815
- complete: {
2816
- __type: "ui.complete",
2817
- stage: options.stage,
2818
- title: options.title,
2819
- description: options.description,
2820
- content: contentUiConfig
2821
- }
2923
+ __type: "ui.complete",
2924
+ stage: options.stage,
2925
+ title: options.title,
2926
+ description: options.description,
2927
+ content: contentUiConfig || [],
2928
+ autoClose: options.autoClose
2822
2929
  };
2823
2930
  }
2824
2931
  __name(complete, "complete");
2825
2932
 
2826
2933
  // src/handleFlow.ts
2827
- import { sentenceCase } from "change-case";
2934
+ import { sentenceCase as sentenceCase2 } from "change-case";
2828
2935
  async function handleFlow(request, config) {
2829
2936
  const activeContext = opentelemetry6.propagation.extract(
2830
2937
  opentelemetry6.context.active(),
@@ -2868,7 +2975,7 @@ async function handleFlow(request, config) {
2868
2975
  const rawFlowConfig = flows[request.method].config;
2869
2976
  flowConfig = {
2870
2977
  ...rawFlowConfig,
2871
- title: rawFlowConfig.title || sentenceCase(request.method || "flow"),
2978
+ title: rawFlowConfig.title || sentenceCase2(request.method || "flow"),
2872
2979
  stages: rawFlowConfig.stages?.map((stage) => {
2873
2980
  if (typeof stage === "string") {
2874
2981
  return {
@@ -2923,7 +3030,8 @@ async function handleFlow(request, config) {
2923
3030
  }
2924
3031
  let ui = null;
2925
3032
  let data = null;
2926
- if (response && typeof response == "object" && "content" in response) {
3033
+ if (response && typeof response == "object" && "__type" in response && response.__type === "ui.complete") {
3034
+ ui = await complete(response);
2927
3035
  const completeStep = await db.selectFrom("keel.flow_step").where("run_id", "=", runId).where("type", "=", "COMPLETE" /* COMPLETE */).selectAll().executeTakeFirst();
2928
3036
  if (!completeStep) {
2929
3037
  await db.insertInto("keel.flow_step").values({
@@ -2933,10 +3041,10 @@ async function handleFlow(request, config) {
2933
3041
  status: "COMPLETED" /* COMPLETED */,
2934
3042
  type: "COMPLETE" /* COMPLETE */,
2935
3043
  startTime: /* @__PURE__ */ new Date(),
2936
- endTime: /* @__PURE__ */ new Date()
3044
+ endTime: /* @__PURE__ */ new Date(),
3045
+ ui: JSON.stringify(ui)
2937
3046
  }).returningAll().executeTakeFirst();
2938
3047
  }
2939
- ui = (await complete(response)).complete;
2940
3048
  data = response.data;
2941
3049
  } else if (response) {
2942
3050
  data = response;
@@ -2945,8 +3053,7 @@ async function handleFlow(request, config) {
2945
3053
  runId,
2946
3054
  runCompleted: true,
2947
3055
  data,
2948
- config: flowConfig,
2949
- ui
3056
+ config: flowConfig
2950
3057
  });
2951
3058
  } catch (e) {
2952
3059
  if (e instanceof Error) {