@teamkeel/functions-runtime 0.421.2 → 0.421.4

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
@@ -216,14 +216,18 @@ declare function withSpan(name: any, fn: any): Promise<any>;
216
216
  declare function init(): void;
217
217
  declare function forceFlush(): Promise<void>;
218
218
  declare function spanNameForModelAPI(modelName: any, action: any): string;
219
+ declare const KEEL_INTERNAL_ATTR: "keel_internal";
220
+ declare const KEEL_INTERNAL_CHILDREN: "includeChildrenSpans";
219
221
 
222
+ declare const tracing_KEEL_INTERNAL_ATTR: typeof KEEL_INTERNAL_ATTR;
223
+ declare const tracing_KEEL_INTERNAL_CHILDREN: typeof KEEL_INTERNAL_CHILDREN;
220
224
  declare const tracing_forceFlush: typeof forceFlush;
221
225
  declare const tracing_getTracer: typeof getTracer;
222
226
  declare const tracing_init: typeof init;
223
227
  declare const tracing_spanNameForModelAPI: typeof spanNameForModelAPI;
224
228
  declare const tracing_withSpan: typeof withSpan;
225
229
  declare namespace tracing {
226
- export { tracing_forceFlush as forceFlush, tracing_getTracer as getTracer, tracing_init as init, tracing_spanNameForModelAPI as spanNameForModelAPI, tracing_withSpan as withSpan };
230
+ export { tracing_KEEL_INTERNAL_ATTR as KEEL_INTERNAL_ATTR, tracing_KEEL_INTERNAL_CHILDREN as KEEL_INTERNAL_CHILDREN, tracing_forceFlush as forceFlush, tracing_getTracer as getTracer, tracing_init as init, tracing_spanNameForModelAPI as spanNameForModelAPI, tracing_withSpan as withSpan };
227
231
  }
228
232
 
229
233
  type MimeType = "application/json" | "application/gzip" | "application/pdf" | "application/rtf" | "application/vnd.openxmlformats-officedocument.wordprocessingml.document" | "application/vnd.openxmlformats-officedocument.presentationml.presentation" | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | "application/vnd.ms-excel" | "application/vnd.ms-powerpoint" | "application/msword" | "application/zip" | "application/xml" | "application/x-7z-compressed" | "application/x-tar" | "image/gif" | "image/jpeg" | "image/svg+xml" | "image/png" | "text/html" | "text/csv" | "text/javascript" | "text/plain" | "text/calendar" | (string & {});
@@ -462,11 +466,11 @@ type ListItem = {
462
466
  description?: string;
463
467
  image?: ImageConfig;
464
468
  };
465
- type ListOptions$1<T> = {
469
+ type ListOptions<T> = {
466
470
  data: T[];
467
471
  render: (data: T) => ListItem;
468
472
  };
469
- type UiElementList = <T extends any>(options: ListOptions$1<T>) => DisplayElementResponse;
473
+ type UiElementList = <T extends any>(options: ListOptions<T>) => DisplayElementResponse;
470
474
  interface UiElementListApiResponse extends BaseUiDisplayResponse<"ui.display.list"> {
471
475
  data: ListItem[];
472
476
  }
@@ -620,7 +624,10 @@ interface UiElementPrintApiResponse extends BaseUiDisplayResponse<"ui.interactiv
620
624
  autoPrint: boolean;
621
625
  }
622
626
 
623
- type UiElementPickList = <N extends string, T extends Record<string, any>>(name: N, options: ListOptions<T>) => InputElementResponse<N, {
627
+ type UiElementPickList = <N extends string, T extends Record<string, any>, const M extends PickListInputModes = {
628
+ scanner: true;
629
+ manual: true;
630
+ }>(name: N, options: PickListOptions<M, T>) => InputElementResponse<N, {
624
631
  items: PickListResponseItem[];
625
632
  }>;
626
633
  type PickListResponseItem = {
@@ -637,13 +644,35 @@ type PickListItem = {
637
644
  image?: ImageConfig;
638
645
  barcodes?: string[];
639
646
  };
640
- type ListOptions<T> = {
647
+ /**
648
+ * Defines how duplicate scans should be handled.
649
+ * @default "increaseQuantity"
650
+ */
651
+ type ScanDuplicateMode$1 =
652
+ /** Increase quantity when duplicates are scanned */
653
+ "increaseQuantity"
654
+ /** Reject duplicate scans with an error message */
655
+ | "rejectDuplicates";
656
+ /**
657
+ * Defines how picking items should be handled. By default, all modes are enabled.
658
+ */
659
+ type PickListInputModes = {
660
+ /** Picking items can be done by scanning barcodes */
661
+ scanner: boolean;
662
+ /** Picking items can be done by using the add/remove buttons */
663
+ manual: boolean;
664
+ };
665
+ type PickListOptions<M extends PickListInputModes, T> = {
641
666
  data: T[];
642
667
  render: (data: T) => PickListItem;
643
- validate?: ValidateFn<PickListResponseItem[]>;
668
+ supportedInputs?: M;
669
+ validate?: ValidateFn<PickListResponseItem>;
670
+ duplicateHandling?: ScanDuplicateMode$1 | undefined;
644
671
  };
645
672
  interface UiElementPickListApiResponse extends BaseUiMinimalInputResponse<"ui.interactive.pickList"> {
646
673
  data: PickListItem[];
674
+ supportedInputs: PickListInputModes;
675
+ duplicateHandling?: ScanDuplicateMode$1 | undefined;
647
676
  }
648
677
 
649
678
  type UiElementScan = <N extends string, const M extends scanMode = "single", const D extends ScanDuplicateMode = "none">(name: N, options?: ScanOptions<M, D>) => InputElementResponse<N, M extends "single" ? string : ScanResponseItem<D>[]>;
package/dist/index.d.ts CHANGED
@@ -216,14 +216,18 @@ declare function withSpan(name: any, fn: any): Promise<any>;
216
216
  declare function init(): void;
217
217
  declare function forceFlush(): Promise<void>;
218
218
  declare function spanNameForModelAPI(modelName: any, action: any): string;
219
+ declare const KEEL_INTERNAL_ATTR: "keel_internal";
220
+ declare const KEEL_INTERNAL_CHILDREN: "includeChildrenSpans";
219
221
 
222
+ declare const tracing_KEEL_INTERNAL_ATTR: typeof KEEL_INTERNAL_ATTR;
223
+ declare const tracing_KEEL_INTERNAL_CHILDREN: typeof KEEL_INTERNAL_CHILDREN;
220
224
  declare const tracing_forceFlush: typeof forceFlush;
221
225
  declare const tracing_getTracer: typeof getTracer;
222
226
  declare const tracing_init: typeof init;
223
227
  declare const tracing_spanNameForModelAPI: typeof spanNameForModelAPI;
224
228
  declare const tracing_withSpan: typeof withSpan;
225
229
  declare namespace tracing {
226
- export { tracing_forceFlush as forceFlush, tracing_getTracer as getTracer, tracing_init as init, tracing_spanNameForModelAPI as spanNameForModelAPI, tracing_withSpan as withSpan };
230
+ export { tracing_KEEL_INTERNAL_ATTR as KEEL_INTERNAL_ATTR, tracing_KEEL_INTERNAL_CHILDREN as KEEL_INTERNAL_CHILDREN, tracing_forceFlush as forceFlush, tracing_getTracer as getTracer, tracing_init as init, tracing_spanNameForModelAPI as spanNameForModelAPI, tracing_withSpan as withSpan };
227
231
  }
228
232
 
229
233
  type MimeType = "application/json" | "application/gzip" | "application/pdf" | "application/rtf" | "application/vnd.openxmlformats-officedocument.wordprocessingml.document" | "application/vnd.openxmlformats-officedocument.presentationml.presentation" | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | "application/vnd.ms-excel" | "application/vnd.ms-powerpoint" | "application/msword" | "application/zip" | "application/xml" | "application/x-7z-compressed" | "application/x-tar" | "image/gif" | "image/jpeg" | "image/svg+xml" | "image/png" | "text/html" | "text/csv" | "text/javascript" | "text/plain" | "text/calendar" | (string & {});
@@ -462,11 +466,11 @@ type ListItem = {
462
466
  description?: string;
463
467
  image?: ImageConfig;
464
468
  };
465
- type ListOptions$1<T> = {
469
+ type ListOptions<T> = {
466
470
  data: T[];
467
471
  render: (data: T) => ListItem;
468
472
  };
469
- type UiElementList = <T extends any>(options: ListOptions$1<T>) => DisplayElementResponse;
473
+ type UiElementList = <T extends any>(options: ListOptions<T>) => DisplayElementResponse;
470
474
  interface UiElementListApiResponse extends BaseUiDisplayResponse<"ui.display.list"> {
471
475
  data: ListItem[];
472
476
  }
@@ -620,7 +624,10 @@ interface UiElementPrintApiResponse extends BaseUiDisplayResponse<"ui.interactiv
620
624
  autoPrint: boolean;
621
625
  }
622
626
 
623
- type UiElementPickList = <N extends string, T extends Record<string, any>>(name: N, options: ListOptions<T>) => InputElementResponse<N, {
627
+ type UiElementPickList = <N extends string, T extends Record<string, any>, const M extends PickListInputModes = {
628
+ scanner: true;
629
+ manual: true;
630
+ }>(name: N, options: PickListOptions<M, T>) => InputElementResponse<N, {
624
631
  items: PickListResponseItem[];
625
632
  }>;
626
633
  type PickListResponseItem = {
@@ -637,13 +644,35 @@ type PickListItem = {
637
644
  image?: ImageConfig;
638
645
  barcodes?: string[];
639
646
  };
640
- type ListOptions<T> = {
647
+ /**
648
+ * Defines how duplicate scans should be handled.
649
+ * @default "increaseQuantity"
650
+ */
651
+ type ScanDuplicateMode$1 =
652
+ /** Increase quantity when duplicates are scanned */
653
+ "increaseQuantity"
654
+ /** Reject duplicate scans with an error message */
655
+ | "rejectDuplicates";
656
+ /**
657
+ * Defines how picking items should be handled. By default, all modes are enabled.
658
+ */
659
+ type PickListInputModes = {
660
+ /** Picking items can be done by scanning barcodes */
661
+ scanner: boolean;
662
+ /** Picking items can be done by using the add/remove buttons */
663
+ manual: boolean;
664
+ };
665
+ type PickListOptions<M extends PickListInputModes, T> = {
641
666
  data: T[];
642
667
  render: (data: T) => PickListItem;
643
- validate?: ValidateFn<PickListResponseItem[]>;
668
+ supportedInputs?: M;
669
+ validate?: ValidateFn<PickListResponseItem>;
670
+ duplicateHandling?: ScanDuplicateMode$1 | undefined;
644
671
  };
645
672
  interface UiElementPickListApiResponse extends BaseUiMinimalInputResponse<"ui.interactive.pickList"> {
646
673
  data: PickListItem[];
674
+ supportedInputs: PickListInputModes;
675
+ duplicateHandling?: ScanDuplicateMode$1 | undefined;
647
676
  }
648
677
 
649
678
  type UiElementScan = <N extends string, const M extends scanMode = "single", const D extends ScanDuplicateMode = "none">(name: N, options?: ScanOptions<M, D>) => InputElementResponse<N, M extends "single" ? string : ScanResponseItem<D>[]>;
package/dist/index.js CHANGED
@@ -193,6 +193,8 @@ import { Pool as Pool2, Client, types as pgTypes } from "pg";
193
193
  // src/tracing.js
194
194
  var tracing_exports = {};
195
195
  __export(tracing_exports, {
196
+ KEEL_INTERNAL_ATTR: () => KEEL_INTERNAL_ATTR,
197
+ KEEL_INTERNAL_CHILDREN: () => KEEL_INTERNAL_CHILDREN,
196
198
  forceFlush: () => forceFlush,
197
199
  getTracer: () => getTracer,
198
200
  init: () => init,
@@ -209,11 +211,13 @@ async function withSpan(name, fn) {
209
211
  try {
210
212
  return await fn(span);
211
213
  } catch (err) {
212
- span.recordException(err);
213
- span.setStatus({
214
- code: opentelemetry.SpanStatusCode.ERROR,
215
- message: err.message
216
- });
214
+ if (err instanceof Error) {
215
+ span.recordException(err);
216
+ span.setStatus({
217
+ code: opentelemetry.SpanStatusCode.ERROR,
218
+ message: err.message
219
+ });
220
+ }
217
221
  throw err;
218
222
  } finally {
219
223
  span.end();
@@ -351,6 +355,8 @@ function spanNameForModelAPI(modelName, action) {
351
355
  return `Database ${modelName}.${action}`;
352
356
  }
353
357
  __name(spanNameForModelAPI, "spanNameForModelAPI");
358
+ var KEEL_INTERNAL_ATTR = "keel_internal";
359
+ var KEEL_INTERNAL_CHILDREN = "includeChildrenSpans";
354
360
 
355
361
  // src/database.ts
356
362
  import WebSocket from "ws";
@@ -419,6 +425,7 @@ var InstrumentedPool = class extends Pool2 {
419
425
  const _super = super.connect.bind(this);
420
426
  return withSpan("Database Connect", function(span) {
421
427
  span.setAttribute("dialect", process.env["KEEL_DB_CONN_TYPE"]);
428
+ span.setAttribute(KEEL_INTERNAL_ATTR, true);
422
429
  return _super.apply(null, args);
423
430
  });
424
431
  }
@@ -431,6 +438,7 @@ var InstrumentedNeonServerlessPool = class extends neon.Pool {
431
438
  const _super = super.connect.bind(this);
432
439
  return withSpan("Database Connect", function(span) {
433
440
  span.setAttribute("dialect", process.env["KEEL_DB_CONN_TYPE"]);
441
+ span.setAttribute(KEEL_INTERNAL_ATTR, true);
434
442
  return _super.apply(null, args);
435
443
  });
436
444
  }
@@ -2875,6 +2883,11 @@ var pickList = /* @__PURE__ */ __name((name, options) => {
2875
2883
  uiConfig: {
2876
2884
  __type: "ui.interactive.pickList",
2877
2885
  name,
2886
+ supportedInputs: options.supportedInputs || {
2887
+ scanner: true,
2888
+ manual: true
2889
+ },
2890
+ duplicateHandling: options.duplicateHandling,
2878
2891
  data: options.data.map((item) => {
2879
2892
  const rendered = options.render(item);
2880
2893
  return {
@@ -3006,112 +3019,19 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
3006
3019
  };
3007
3020
  }, "complete"),
3008
3021
  step: /* @__PURE__ */ __name(async (name, optionsOrFn, fn) => {
3009
- const options = typeof optionsOrFn === "function" ? {} : optionsOrFn;
3010
- const actualFn = typeof optionsOrFn === "function" ? optionsOrFn : fn;
3011
- options.retries = options.retries ?? defaultOpts.retries;
3012
- options.timeout = options.timeout ?? defaultOpts.timeout;
3013
- const db = useDatabase();
3014
- if (usedNames.has(name)) {
3015
- await db.insertInto("keel.flow_step").values({
3016
- run_id: runId,
3017
- name,
3018
- stage: options.stage,
3019
- status: "FAILED" /* FAILED */,
3020
- type: "FUNCTION" /* FUNCTION */,
3021
- error: `Duplicate step name: ${name}`,
3022
- startTime: /* @__PURE__ */ new Date(),
3023
- endTime: /* @__PURE__ */ new Date()
3024
- }).returningAll().executeTakeFirst();
3025
- throw new Error(`Duplicate step name: ${name}`);
3026
- }
3027
- usedNames.add(name);
3028
- const past = await db.selectFrom("keel.flow_step").where("run_id", "=", runId).where("name", "=", name).selectAll().execute();
3029
- const newSteps = past.filter((step) => step.status === "NEW" /* NEW */);
3030
- const completedSteps = past.filter(
3031
- (step) => step.status === "COMPLETED" /* COMPLETED */
3032
- );
3033
- const failedSteps = past.filter(
3034
- (step) => step.status === "FAILED" /* FAILED */
3035
- );
3036
- if (newSteps.length > 1) {
3037
- throw new Error("Multiple NEW steps found for the same step");
3038
- }
3039
- if (completedSteps.length > 1) {
3040
- throw new Error("Multiple completed steps found for the same step");
3041
- }
3042
- if (completedSteps.length > 1 && newSteps.length > 1) {
3043
- throw new Error(
3044
- "Multiple completed and new steps found for the same step"
3045
- );
3046
- }
3047
- if (completedSteps.length === 1) {
3048
- return completedSteps[0].value;
3049
- }
3050
- if (newSteps.length === 1) {
3051
- let result = null;
3052
- await db.updateTable("keel.flow_step").set({
3053
- startTime: /* @__PURE__ */ new Date()
3054
- }).where("id", "=", newSteps[0].id).returningAll().executeTakeFirst();
3055
- try {
3056
- const stepArgs = {
3057
- attempt: failedSteps.length + 1,
3058
- stepOptions: options
3059
- };
3060
- result = await withTimeout(actualFn(stepArgs), options.timeout);
3061
- } catch (e) {
3062
- await db.updateTable("keel.flow_step").set({
3063
- status: "FAILED" /* FAILED */,
3064
- spanId,
3065
- endTime: /* @__PURE__ */ new Date(),
3066
- error: e instanceof Error ? e.message : "An error occurred"
3067
- }).where("id", "=", newSteps[0].id).returningAll().executeTakeFirst();
3068
- if (failedSteps.length >= options.retries || e instanceof NonRetriableError) {
3069
- if (options.onFailure) {
3070
- await options.onFailure();
3071
- }
3072
- throw new ExhuastedRetriesDisrupt();
3073
- }
3074
- await db.insertInto("keel.flow_step").values({
3075
- run_id: runId,
3076
- name,
3077
- stage: options.stage,
3078
- status: "NEW" /* NEW */,
3079
- type: "FUNCTION" /* FUNCTION */
3080
- }).returningAll().executeTakeFirst();
3081
- throw new StepCreatedDisrupt(
3082
- options.retryPolicy ? new Date(
3083
- Date.now() + options.retryPolicy(failedSteps.length + 1)
3084
- ) : void 0
3085
- );
3086
- }
3087
- await db.updateTable("keel.flow_step").set({
3088
- status: "COMPLETED" /* COMPLETED */,
3089
- value: JSON.stringify(result),
3090
- spanId,
3091
- endTime: /* @__PURE__ */ new Date()
3092
- }).where("id", "=", newSteps[0].id).returningAll().executeTakeFirst();
3093
- return result;
3094
- }
3095
- await db.insertInto("keel.flow_step").values({
3096
- run_id: runId,
3097
- name,
3098
- stage: options.stage,
3099
- status: "NEW" /* NEW */,
3100
- type: "FUNCTION" /* FUNCTION */
3101
- }).returningAll().executeTakeFirst();
3102
- throw new StepCreatedDisrupt();
3103
- }, "step"),
3104
- ui: {
3105
- page: /* @__PURE__ */ __name(async (name, options) => {
3022
+ return withSpan(`Step - ${name}`, async (span) => {
3023
+ const options = typeof optionsOrFn === "function" ? {} : optionsOrFn;
3024
+ const actualFn = typeof optionsOrFn === "function" ? optionsOrFn : fn;
3025
+ options.retries = options.retries ?? defaultOpts.retries;
3026
+ options.timeout = options.timeout ?? defaultOpts.timeout;
3106
3027
  const db = useDatabase();
3107
- const isCallback = element && callback;
3108
3028
  if (usedNames.has(name)) {
3109
3029
  await db.insertInto("keel.flow_step").values({
3110
3030
  run_id: runId,
3111
3031
  name,
3112
3032
  stage: options.stage,
3113
3033
  status: "FAILED" /* FAILED */,
3114
- type: "UI" /* UI */,
3034
+ type: "FUNCTION" /* FUNCTION */,
3115
3035
  error: `Duplicate step name: ${name}`,
3116
3036
  startTime: /* @__PURE__ */ new Date(),
3117
3037
  endTime: /* @__PURE__ */ new Date()
@@ -3119,77 +3039,179 @@ function createFlowContext(runId, data, action, callback, element, spanId, ctx)
3119
3039
  throw new Error(`Duplicate step name: ${name}`);
3120
3040
  }
3121
3041
  usedNames.add(name);
3122
- let step = await db.selectFrom("keel.flow_step").where("run_id", "=", runId).where("name", "=", name).selectAll().executeTakeFirst();
3123
- if (step && step.status === "COMPLETED" /* COMPLETED */) {
3124
- if (step.action) {
3125
- return { data: step.value, action: step.action };
3126
- }
3127
- return step.value;
3042
+ const past = await db.selectFrom("keel.flow_step").where("run_id", "=", runId).where("name", "=", name).selectAll().execute();
3043
+ const newSteps = past.filter((step) => step.status === "NEW" /* NEW */);
3044
+ const completedSteps = past.filter(
3045
+ (step) => step.status === "COMPLETED" /* COMPLETED */
3046
+ );
3047
+ const failedSteps = past.filter(
3048
+ (step) => step.status === "FAILED" /* FAILED */
3049
+ );
3050
+ if (newSteps.length > 1) {
3051
+ throw new Error("Multiple NEW steps found for the same step");
3128
3052
  }
3129
- if (!step) {
3130
- step = await db.insertInto("keel.flow_step").values({
3131
- run_id: runId,
3132
- name,
3133
- stage: options.stage,
3134
- status: "PENDING" /* PENDING */,
3135
- type: "UI" /* UI */,
3136
- startTime: /* @__PURE__ */ new Date()
3137
- }).returningAll().executeTakeFirst();
3138
- throw new UIRenderDisrupt(
3139
- step?.id,
3140
- (await page(options, null, null)).page
3053
+ if (completedSteps.length > 1) {
3054
+ throw new Error("Multiple completed steps found for the same step");
3055
+ }
3056
+ if (completedSteps.length > 1 && newSteps.length > 1) {
3057
+ throw new Error(
3058
+ "Multiple completed and new steps found for the same step"
3141
3059
  );
3142
3060
  }
3143
- if (isCallback) {
3061
+ if (completedSteps.length === 1) {
3062
+ span.setAttribute(KEEL_INTERNAL_ATTR, KEEL_INTERNAL_CHILDREN);
3063
+ return completedSteps[0].value;
3064
+ }
3065
+ if (newSteps.length === 1) {
3066
+ let result = null;
3067
+ await db.updateTable("keel.flow_step").set({
3068
+ startTime: /* @__PURE__ */ new Date()
3069
+ }).where("id", "=", newSteps[0].id).returningAll().executeTakeFirst();
3144
3070
  try {
3145
- const response = await callbackFn(
3146
- options.content,
3147
- element,
3148
- callback,
3149
- data
3150
- );
3151
- throw new CallbackDisrupt(response, false);
3071
+ const stepArgs = {
3072
+ attempt: failedSteps.length + 1,
3073
+ stepOptions: options
3074
+ };
3075
+ result = await withTimeout(actualFn(stepArgs), options.timeout);
3152
3076
  } catch (e) {
3153
- if (e instanceof CallbackDisrupt) {
3154
- throw e;
3077
+ await db.updateTable("keel.flow_step").set({
3078
+ status: "FAILED" /* FAILED */,
3079
+ spanId,
3080
+ endTime: /* @__PURE__ */ new Date(),
3081
+ error: e instanceof Error ? e.message : "An error occurred"
3082
+ }).where("id", "=", newSteps[0].id).returningAll().executeTakeFirst();
3083
+ if (failedSteps.length >= options.retries || e instanceof NonRetriableError) {
3084
+ if (options.onFailure) {
3085
+ await options.onFailure();
3086
+ }
3087
+ throw new ExhuastedRetriesDisrupt();
3155
3088
  }
3156
- throw new CallbackDisrupt(
3157
- e instanceof Error ? e.message : `An error occurred`,
3158
- true
3089
+ await db.insertInto("keel.flow_step").values({
3090
+ run_id: runId,
3091
+ name,
3092
+ stage: options.stage,
3093
+ status: "NEW" /* NEW */,
3094
+ type: "FUNCTION" /* FUNCTION */
3095
+ }).returningAll().executeTakeFirst();
3096
+ throw new StepCreatedDisrupt(
3097
+ options.retryPolicy ? new Date(
3098
+ Date.now() + options.retryPolicy(failedSteps.length + 1)
3099
+ ) : void 0
3159
3100
  );
3160
3101
  }
3102
+ await db.updateTable("keel.flow_step").set({
3103
+ status: "COMPLETED" /* COMPLETED */,
3104
+ value: JSON.stringify(result),
3105
+ spanId,
3106
+ endTime: /* @__PURE__ */ new Date()
3107
+ }).where("id", "=", newSteps[0].id).returningAll().executeTakeFirst();
3108
+ return result;
3161
3109
  }
3162
- if (!data) {
3163
- throw new UIRenderDisrupt(
3164
- step?.id,
3165
- (await page(options, null, null)).page
3166
- );
3167
- }
3168
- try {
3169
- const p = await page(options, data, action);
3170
- if (p.hasValidationErrors) {
3171
- throw new UIRenderDisrupt(step?.id, p.page);
3110
+ await db.insertInto("keel.flow_step").values({
3111
+ run_id: runId,
3112
+ name,
3113
+ stage: options.stage,
3114
+ status: "NEW" /* NEW */,
3115
+ type: "FUNCTION" /* FUNCTION */
3116
+ }).returningAll().executeTakeFirst();
3117
+ span.setAttribute(KEEL_INTERNAL_ATTR, KEEL_INTERNAL_CHILDREN);
3118
+ throw new StepCreatedDisrupt();
3119
+ });
3120
+ }, "step"),
3121
+ ui: {
3122
+ page: /* @__PURE__ */ __name(async (name, options) => {
3123
+ return withSpan(`Page - ${name}`, async (span) => {
3124
+ const db = useDatabase();
3125
+ const isCallback = element && callback;
3126
+ if (usedNames.has(name)) {
3127
+ await db.insertInto("keel.flow_step").values({
3128
+ run_id: runId,
3129
+ name,
3130
+ stage: options.stage,
3131
+ status: "FAILED" /* FAILED */,
3132
+ type: "UI" /* UI */,
3133
+ error: `Duplicate step name: ${name}`,
3134
+ startTime: /* @__PURE__ */ new Date(),
3135
+ endTime: /* @__PURE__ */ new Date()
3136
+ }).returningAll().executeTakeFirst();
3137
+ throw new Error(`Duplicate step name: ${name}`);
3172
3138
  }
3173
- } catch (e) {
3174
- if (e instanceof UIRenderDisrupt) {
3139
+ usedNames.add(name);
3140
+ let step = await db.selectFrom("keel.flow_step").where("run_id", "=", runId).where("name", "=", name).selectAll().executeTakeFirst();
3141
+ if (step && step.status === "COMPLETED" /* COMPLETED */) {
3142
+ span.setAttribute(KEEL_INTERNAL_ATTR, KEEL_INTERNAL_CHILDREN);
3143
+ if (step.action) {
3144
+ return { data: step.value, action: step.action };
3145
+ }
3146
+ return step.value;
3147
+ }
3148
+ if (!step) {
3149
+ step = await db.insertInto("keel.flow_step").values({
3150
+ run_id: runId,
3151
+ name,
3152
+ stage: options.stage,
3153
+ status: "PENDING" /* PENDING */,
3154
+ type: "UI" /* UI */,
3155
+ startTime: /* @__PURE__ */ new Date()
3156
+ }).returningAll().executeTakeFirst();
3157
+ span.setAttribute("rendered", true);
3158
+ throw new UIRenderDisrupt(
3159
+ step?.id,
3160
+ (await page(options, null, null)).page
3161
+ );
3162
+ }
3163
+ if (isCallback) {
3164
+ span.setAttribute("callback", callback);
3165
+ try {
3166
+ const response = await callbackFn(
3167
+ options.content,
3168
+ element,
3169
+ callback,
3170
+ data
3171
+ );
3172
+ throw new CallbackDisrupt(response, false);
3173
+ } catch (e) {
3174
+ if (e instanceof CallbackDisrupt) {
3175
+ throw e;
3176
+ }
3177
+ throw new CallbackDisrupt(
3178
+ e instanceof Error ? e.message : `An error occurred`,
3179
+ true
3180
+ );
3181
+ }
3182
+ }
3183
+ if (!data) {
3184
+ throw new UIRenderDisrupt(
3185
+ step?.id,
3186
+ (await page(options, null, null)).page
3187
+ );
3188
+ }
3189
+ try {
3190
+ const p = await page(options, data, action);
3191
+ if (p.hasValidationErrors) {
3192
+ throw new UIRenderDisrupt(step?.id, p.page);
3193
+ }
3194
+ } catch (e) {
3195
+ if (e instanceof UIRenderDisrupt) {
3196
+ throw e;
3197
+ }
3198
+ await db.updateTable("keel.flow_step").set({
3199
+ status: "FAILED" /* FAILED */,
3200
+ spanId,
3201
+ endTime: /* @__PURE__ */ new Date(),
3202
+ error: e instanceof Error ? e.message : "An error occurred"
3203
+ }).where("id", "=", step?.id).returningAll().executeTakeFirst();
3175
3204
  throw e;
3176
3205
  }
3177
3206
  await db.updateTable("keel.flow_step").set({
3178
- status: "FAILED" /* FAILED */,
3207
+ status: "COMPLETED" /* COMPLETED */,
3208
+ value: JSON.stringify(data),
3209
+ action,
3179
3210
  spanId,
3180
- endTime: /* @__PURE__ */ new Date(),
3181
- error: e instanceof Error ? e.message : "An error occurred"
3182
- }).where("id", "=", step?.id).returningAll().executeTakeFirst();
3183
- throw e;
3184
- }
3185
- await db.updateTable("keel.flow_step").set({
3186
- status: "COMPLETED" /* COMPLETED */,
3187
- value: JSON.stringify(data),
3188
- action,
3189
- spanId,
3190
- endTime: /* @__PURE__ */ new Date()
3191
- }).where("id", "=", step.id).returningAll().executeTakeFirst();
3192
- return { data, action };
3211
+ endTime: /* @__PURE__ */ new Date()
3212
+ }).where("id", "=", step.id).returningAll().executeTakeFirst();
3213
+ return { data, action };
3214
+ });
3193
3215
  }, "page"),
3194
3216
  inputs: {
3195
3217
  text: textInput,
@@ -3268,6 +3290,7 @@ async function handleFlow(request, config) {
3268
3290
  );
3269
3291
  return opentelemetry6.context.with(activeContext, () => {
3270
3292
  return withSpan(request.method, async (span) => {
3293
+ span.setAttribute(KEEL_INTERNAL_ATTR, true);
3271
3294
  let db = null;
3272
3295
  let flowConfig = null;
3273
3296
  const runId = request.meta?.runId;
@@ -3325,6 +3348,7 @@ async function handleFlow(request, config) {
3325
3348
  });
3326
3349
  } catch (e) {
3327
3350
  if (e instanceof StepCreatedDisrupt) {
3351
+ span.setAttribute(KEEL_INTERNAL_ATTR, KEEL_INTERNAL_CHILDREN);
3328
3352
  return createJSONRPCSuccessResponse5(request.id, {
3329
3353
  runId,
3330
3354
  runCompleted: false,
@@ -3346,11 +3370,13 @@ async function handleFlow(request, config) {
3346
3370
  ui: e.contents
3347
3371
  });
3348
3372
  }
3349
- span.recordException(e);
3350
- span.setStatus({
3351
- code: opentelemetry6.SpanStatusCode.ERROR,
3352
- message: e instanceof Error ? e.message : "unknown error"
3353
- });
3373
+ if (e instanceof Error) {
3374
+ span.recordException(e);
3375
+ span.setStatus({
3376
+ code: opentelemetry6.SpanStatusCode.ERROR,
3377
+ message: e instanceof Error ? e.message : "unknown error"
3378
+ });
3379
+ }
3354
3380
  if (e instanceof ExhuastedRetriesDisrupt) {
3355
3381
  return createJSONRPCSuccessResponse5(request.id, {
3356
3382
  runId,