@teamkeel/functions-runtime 0.413.9 → 0.414.1

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.cjs CHANGED
@@ -2454,9 +2454,16 @@ var selectOne = /* @__PURE__ */ __name((name, options) => {
2454
2454
  }, "selectOne");
2455
2455
 
2456
2456
  // src/flows/ui/page.ts
2457
- async function page(options, data) {
2457
+ async function page(options, data, action) {
2458
2458
  const content = options.content;
2459
2459
  let hasValidationErrors = false;
2460
+ if (options.actions) {
2461
+ const isValidAction = options.actions.some((a) => {
2462
+ if (typeof a === "string") return a === action;
2463
+ return a && typeof a === "object" && "value" in a && a.value === action;
2464
+ });
2465
+ hasValidationErrors = !isValidAction;
2466
+ }
2460
2467
  const contentUiConfig = await Promise.all(
2461
2468
  content.map(async (c) => {
2462
2469
  const isInput = "__type" in c && c.__type == "input";
@@ -2481,7 +2488,14 @@ async function page(options, data) {
2481
2488
  title: options.title,
2482
2489
  description: options.description,
2483
2490
  content: contentUiConfig,
2484
- actions: options.actions
2491
+ actions: options.actions?.map((a) => {
2492
+ if (typeof a === "string") {
2493
+ return { label: a, value: a, mode: "primary" };
2494
+ } else if (typeof a === "object") {
2495
+ a.mode = a.mode || "primary";
2496
+ }
2497
+ return a;
2498
+ })
2485
2499
  },
2486
2500
  hasValidationErrors
2487
2501
  };
@@ -2607,15 +2621,33 @@ var header = /* @__PURE__ */ __name((options) => {
2607
2621
 
2608
2622
  // src/flows/index.ts
2609
2623
  var defaultOpts = {
2610
- maxRetries: 5,
2611
- timeoutInMs: 6e4
2624
+ retries: 5,
2625
+ timeout: 6e4
2612
2626
  };
2613
- function createFlowContext(runId, data, spanId) {
2627
+ function createFlowContext(runId, data, action, spanId, ctx) {
2628
+ const usedNames = /* @__PURE__ */ new Set();
2614
2629
  return {
2630
+ env: ctx.env,
2631
+ now: ctx.now,
2632
+ secrets: ctx.secrets,
2615
2633
  step: /* @__PURE__ */ __name(async (name, optionsOrFn, fn) => {
2616
2634
  const options = typeof optionsOrFn === "function" ? {} : optionsOrFn;
2617
2635
  const actualFn = typeof optionsOrFn === "function" ? optionsOrFn : fn;
2618
2636
  const db = useDatabase();
2637
+ if (usedNames.has(name)) {
2638
+ await db.insertInto("keel.flow_step").values({
2639
+ run_id: runId,
2640
+ name,
2641
+ stage: options.stage,
2642
+ status: "FAILED" /* FAILED */,
2643
+ type: "FUNCTION" /* FUNCTION */,
2644
+ error: `Duplicate step name: ${name}`,
2645
+ startTime: /* @__PURE__ */ new Date(),
2646
+ endTime: /* @__PURE__ */ new Date()
2647
+ }).returningAll().executeTakeFirst();
2648
+ throw new Error(`Duplicate step name: ${name}`);
2649
+ }
2650
+ usedNames.add(name);
2619
2651
  const past = await db.selectFrom("keel.flow_step").where("run_id", "=", runId).where("name", "=", name).selectAll().execute();
2620
2652
  const newSteps = past.filter((step) => step.status === "NEW" /* NEW */);
2621
2653
  const completedSteps = past.filter(
@@ -2646,7 +2678,7 @@ function createFlowContext(runId, data, spanId) {
2646
2678
  try {
2647
2679
  result = await withTimeout(
2648
2680
  actualFn(),
2649
- options.timeoutInMs ?? defaultOpts.timeoutInMs
2681
+ options.timeout ?? defaultOpts.timeout
2650
2682
  );
2651
2683
  } catch (e) {
2652
2684
  await db.updateTable("keel.flow_step").set({
@@ -2655,7 +2687,7 @@ function createFlowContext(runId, data, spanId) {
2655
2687
  endTime: /* @__PURE__ */ new Date(),
2656
2688
  error: e instanceof Error ? e.message : "An error occurred"
2657
2689
  }).where("id", "=", newSteps[0].id).returningAll().executeTakeFirst();
2658
- if (failedSteps.length + 1 >= (options.maxRetries ?? defaultOpts.maxRetries)) {
2690
+ if (failedSteps.length + 1 >= (options.retries ?? defaultOpts.retries)) {
2659
2691
  throw new ExhuastedRetriesDisrupt();
2660
2692
  }
2661
2693
  await db.insertInto("keel.flow_step").values({
@@ -2687,8 +2719,25 @@ function createFlowContext(runId, data, spanId) {
2687
2719
  ui: {
2688
2720
  page: /* @__PURE__ */ __name(async (name, options) => {
2689
2721
  const db = useDatabase();
2722
+ if (usedNames.has(name)) {
2723
+ await db.insertInto("keel.flow_step").values({
2724
+ run_id: runId,
2725
+ name,
2726
+ stage: options.stage,
2727
+ status: "FAILED" /* FAILED */,
2728
+ type: "UI" /* UI */,
2729
+ error: `Duplicate step name: ${name}`,
2730
+ startTime: /* @__PURE__ */ new Date(),
2731
+ endTime: /* @__PURE__ */ new Date()
2732
+ }).returningAll().executeTakeFirst();
2733
+ throw new Error(`Duplicate step name: ${name}`);
2734
+ }
2735
+ usedNames.add(name);
2690
2736
  let step = await db.selectFrom("keel.flow_step").where("run_id", "=", runId).where("name", "=", name).selectAll().executeTakeFirst();
2691
2737
  if (step && step.status === "COMPLETED" /* COMPLETED */) {
2738
+ if (step.action) {
2739
+ return { data: step.value, action: step.action };
2740
+ }
2692
2741
  return step.value;
2693
2742
  }
2694
2743
  if (!step) {
@@ -2700,22 +2749,29 @@ function createFlowContext(runId, data, spanId) {
2700
2749
  type: "UI" /* UI */,
2701
2750
  startTime: /* @__PURE__ */ new Date()
2702
2751
  }).returningAll().executeTakeFirst();
2703
- throw new UIRenderDisrupt(step?.id, (await page(options, null)).page);
2752
+ throw new UIRenderDisrupt(
2753
+ step?.id,
2754
+ (await page(options, null, null)).page
2755
+ );
2704
2756
  }
2705
2757
  if (!data) {
2706
- throw new UIRenderDisrupt(step?.id, (await page(options, null)).page);
2758
+ throw new UIRenderDisrupt(
2759
+ step?.id,
2760
+ (await page(options, null, null)).page
2761
+ );
2707
2762
  }
2708
- const p = await page(options, data);
2763
+ const p = await page(options, data, action);
2709
2764
  if (p.hasValidationErrors) {
2710
2765
  throw new UIRenderDisrupt(step?.id, p.page);
2711
2766
  }
2712
2767
  await db.updateTable("keel.flow_step").set({
2713
2768
  status: "COMPLETED" /* COMPLETED */,
2714
2769
  value: JSON.stringify(data),
2770
+ action,
2715
2771
  spanId,
2716
2772
  endTime: /* @__PURE__ */ new Date()
2717
2773
  }).where("id", "=", step.id).returningAll().executeTakeFirst();
2718
- return data;
2774
+ return { data, action };
2719
2775
  }, "page"),
2720
2776
  inputs: {
2721
2777
  text: textInput,
@@ -2770,7 +2826,7 @@ async function handleFlow(request, config) {
2770
2826
  if (!runId) {
2771
2827
  throw new Error("no runId provided");
2772
2828
  }
2773
- const { flows } = config;
2829
+ const { flows, createFlowContextAPI } = config;
2774
2830
  if (!(request.method in flows)) {
2775
2831
  const message = `no corresponding flow found for '${request.method}'`;
2776
2832
  span.setStatus({
@@ -2789,7 +2845,11 @@ async function handleFlow(request, config) {
2789
2845
  const ctx = createFlowContext(
2790
2846
  request.meta.runId,
2791
2847
  request.meta.data,
2792
- span.spanContext().spanId
2848
+ request.meta.action,
2849
+ span.spanContext().spanId,
2850
+ createFlowContextAPI({
2851
+ meta: request.meta
2852
+ })
2793
2853
  );
2794
2854
  const flowFunction = flows[request.method].fn;
2795
2855
  const rawFlowConfig = flows[request.method].config;