@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.cjs +192 -166
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -6
- package/dist/index.d.ts +35 -6
- package/dist/index.js +192 -166
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
469
|
+
type ListOptions<T> = {
|
|
466
470
|
data: T[];
|
|
467
471
|
render: (data: T) => ListItem;
|
|
468
472
|
};
|
|
469
|
-
type UiElementList = <T extends any>(options: ListOptions
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
469
|
+
type ListOptions<T> = {
|
|
466
470
|
data: T[];
|
|
467
471
|
render: (data: T) => ListItem;
|
|
468
472
|
};
|
|
469
|
-
type UiElementList = <T extends any>(options: ListOptions
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
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: "
|
|
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
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
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 (
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
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 (
|
|
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
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
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
|
-
|
|
3154
|
-
|
|
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
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
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
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
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
|
-
|
|
3174
|
-
|
|
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: "
|
|
3207
|
+
status: "COMPLETED" /* COMPLETED */,
|
|
3208
|
+
value: JSON.stringify(data),
|
|
3209
|
+
action,
|
|
3179
3210
|
spanId,
|
|
3180
|
-
endTime: /* @__PURE__ */ new Date()
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
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
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
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,
|