@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 +73 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -10
- package/dist/index.d.ts +34 -10
- package/dist/index.js +73 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -352,11 +352,12 @@ type PageOptions<C extends FlowConfig, A extends PageActions[], T extends UIElem
|
|
|
352
352
|
validate?: (data: ExtractFormData<T>) => Promise<true | string>;
|
|
353
353
|
actions?: A;
|
|
354
354
|
};
|
|
355
|
-
type UiPage<C extends FlowConfig> = <T extends UIElements, const A extends PageActions[] = []>(name: string, options: PageOptions<C, A, T>) => A["length"] extends 0 ? ExtractFormData<T> : {
|
|
355
|
+
type UiPage<C extends FlowConfig> = <T extends UIElements, const A extends PageActions[] = []>(name: string, options: PageOptions<C, A, T>) => Promise<A["length"] extends 0 ? ExtractFormData<T> : {
|
|
356
356
|
data: ExtractFormData<T>;
|
|
357
357
|
action: ActionValue<A[number]>;
|
|
358
|
-
}
|
|
359
|
-
type PageActions = string |
|
|
358
|
+
}>;
|
|
359
|
+
type PageActions = string | PageActionConfig;
|
|
360
|
+
type PageActionConfig = {
|
|
360
361
|
label: string;
|
|
361
362
|
value: string;
|
|
362
363
|
mode?: "primary" | "secondary" | "destructive";
|
|
@@ -545,19 +546,31 @@ type UIApiResponses = {
|
|
|
545
546
|
};
|
|
546
547
|
};
|
|
547
548
|
|
|
548
|
-
interface FlowContext<C extends FlowConfig> {
|
|
549
|
+
interface FlowContext<C extends FlowConfig, E = any, S = any> {
|
|
549
550
|
step: Step<C>;
|
|
550
551
|
ui: UI<C>;
|
|
552
|
+
env: E;
|
|
553
|
+
now: Date;
|
|
554
|
+
secrets: S;
|
|
551
555
|
}
|
|
552
556
|
type JsonSerializable = string | number | boolean | null | JsonSerializable[] | {
|
|
553
557
|
[key: string]: JsonSerializable;
|
|
554
558
|
};
|
|
555
559
|
type Step<C extends FlowConfig> = {
|
|
556
|
-
<R extends JsonSerializable | void>(
|
|
560
|
+
<R extends JsonSerializable | void>(
|
|
561
|
+
/** The unique name of this step. */
|
|
562
|
+
name: string,
|
|
563
|
+
/** Configuration options for the step. */
|
|
564
|
+
options: {
|
|
565
|
+
/** The stage this step belongs to. Used for organising steps in the UI. */
|
|
557
566
|
stage?: ExtractStageKeys<C>;
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
567
|
+
/** Number of times to retry the step if it fails. Defaults to 5. */
|
|
568
|
+
retries?: number;
|
|
569
|
+
/** Maximum time in milliseconds to wait for the step to complete. Defaults to 60000 (1 minute). */
|
|
570
|
+
timeout?: number;
|
|
571
|
+
},
|
|
572
|
+
/** The step function to execute. */
|
|
573
|
+
fn: () => Promise<R> & {
|
|
561
574
|
catch: (errorHandler: (err: Error) => Promise<void> | void) => Promise<any>;
|
|
562
575
|
}): Promise<R>;
|
|
563
576
|
<R extends JsonSerializable | void>(name: string, fn: () => Promise<R> & {
|
|
@@ -565,8 +578,11 @@ type Step<C extends FlowConfig> = {
|
|
|
565
578
|
}): Promise<R>;
|
|
566
579
|
};
|
|
567
580
|
interface FlowConfig {
|
|
581
|
+
/** The stages to organise the steps in the flow. */
|
|
568
582
|
stages?: StageConfig[];
|
|
583
|
+
/** The title of the flow as shown in the Console. */
|
|
569
584
|
title?: string;
|
|
585
|
+
/** The description of the flow as shown in the Console. */
|
|
570
586
|
description?: string;
|
|
571
587
|
}
|
|
572
588
|
interface FlowConfigAPI {
|
|
@@ -574,20 +590,28 @@ interface FlowConfigAPI {
|
|
|
574
590
|
title: string;
|
|
575
591
|
description?: string;
|
|
576
592
|
}
|
|
577
|
-
type FlowFunction<C extends FlowConfig, I extends any = {}> = (ctx: FlowContext<C>, inputs: I) => Promise<void>;
|
|
593
|
+
type FlowFunction<C extends FlowConfig, E extends any = {}, S extends any = {}, I extends any = {}> = (ctx: FlowContext<C, E, S>, inputs: I) => Promise<void>;
|
|
578
594
|
type ExtractStageKeys<T extends FlowConfig> = T extends {
|
|
579
595
|
stages: infer S;
|
|
580
596
|
} ? S extends ReadonlyArray<infer U> ? U extends string ? U : U extends {
|
|
581
597
|
key: infer K extends string;
|
|
582
598
|
} ? K : never : never : never;
|
|
583
599
|
type StageConfigObject = {
|
|
600
|
+
/** The unique key of the stage. */
|
|
584
601
|
key: string;
|
|
602
|
+
/** The name of the stage as shown in the Console. */
|
|
585
603
|
name: string;
|
|
604
|
+
/** The description of the stage as shown in the Console. */
|
|
586
605
|
description?: string;
|
|
606
|
+
/** Whether the stage is initially hidden in the Console. */
|
|
587
607
|
initiallyHidden?: boolean;
|
|
588
608
|
};
|
|
589
609
|
type StageConfig = string | StageConfigObject;
|
|
590
|
-
declare function createFlowContext<C extends FlowConfig>(runId: string, data: any, spanId: string
|
|
610
|
+
declare function createFlowContext<C extends FlowConfig, E = any, S = any>(runId: string, data: any, action: string | null, spanId: string, ctx: {
|
|
611
|
+
env: E;
|
|
612
|
+
now: Date;
|
|
613
|
+
secrets: S;
|
|
614
|
+
}): FlowContext<C, E, S>;
|
|
591
615
|
|
|
592
616
|
declare function ksuid(): string;
|
|
593
617
|
|
package/dist/index.d.ts
CHANGED
|
@@ -352,11 +352,12 @@ type PageOptions<C extends FlowConfig, A extends PageActions[], T extends UIElem
|
|
|
352
352
|
validate?: (data: ExtractFormData<T>) => Promise<true | string>;
|
|
353
353
|
actions?: A;
|
|
354
354
|
};
|
|
355
|
-
type UiPage<C extends FlowConfig> = <T extends UIElements, const A extends PageActions[] = []>(name: string, options: PageOptions<C, A, T>) => A["length"] extends 0 ? ExtractFormData<T> : {
|
|
355
|
+
type UiPage<C extends FlowConfig> = <T extends UIElements, const A extends PageActions[] = []>(name: string, options: PageOptions<C, A, T>) => Promise<A["length"] extends 0 ? ExtractFormData<T> : {
|
|
356
356
|
data: ExtractFormData<T>;
|
|
357
357
|
action: ActionValue<A[number]>;
|
|
358
|
-
}
|
|
359
|
-
type PageActions = string |
|
|
358
|
+
}>;
|
|
359
|
+
type PageActions = string | PageActionConfig;
|
|
360
|
+
type PageActionConfig = {
|
|
360
361
|
label: string;
|
|
361
362
|
value: string;
|
|
362
363
|
mode?: "primary" | "secondary" | "destructive";
|
|
@@ -545,19 +546,31 @@ type UIApiResponses = {
|
|
|
545
546
|
};
|
|
546
547
|
};
|
|
547
548
|
|
|
548
|
-
interface FlowContext<C extends FlowConfig> {
|
|
549
|
+
interface FlowContext<C extends FlowConfig, E = any, S = any> {
|
|
549
550
|
step: Step<C>;
|
|
550
551
|
ui: UI<C>;
|
|
552
|
+
env: E;
|
|
553
|
+
now: Date;
|
|
554
|
+
secrets: S;
|
|
551
555
|
}
|
|
552
556
|
type JsonSerializable = string | number | boolean | null | JsonSerializable[] | {
|
|
553
557
|
[key: string]: JsonSerializable;
|
|
554
558
|
};
|
|
555
559
|
type Step<C extends FlowConfig> = {
|
|
556
|
-
<R extends JsonSerializable | void>(
|
|
560
|
+
<R extends JsonSerializable | void>(
|
|
561
|
+
/** The unique name of this step. */
|
|
562
|
+
name: string,
|
|
563
|
+
/** Configuration options for the step. */
|
|
564
|
+
options: {
|
|
565
|
+
/** The stage this step belongs to. Used for organising steps in the UI. */
|
|
557
566
|
stage?: ExtractStageKeys<C>;
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
567
|
+
/** Number of times to retry the step if it fails. Defaults to 5. */
|
|
568
|
+
retries?: number;
|
|
569
|
+
/** Maximum time in milliseconds to wait for the step to complete. Defaults to 60000 (1 minute). */
|
|
570
|
+
timeout?: number;
|
|
571
|
+
},
|
|
572
|
+
/** The step function to execute. */
|
|
573
|
+
fn: () => Promise<R> & {
|
|
561
574
|
catch: (errorHandler: (err: Error) => Promise<void> | void) => Promise<any>;
|
|
562
575
|
}): Promise<R>;
|
|
563
576
|
<R extends JsonSerializable | void>(name: string, fn: () => Promise<R> & {
|
|
@@ -565,8 +578,11 @@ type Step<C extends FlowConfig> = {
|
|
|
565
578
|
}): Promise<R>;
|
|
566
579
|
};
|
|
567
580
|
interface FlowConfig {
|
|
581
|
+
/** The stages to organise the steps in the flow. */
|
|
568
582
|
stages?: StageConfig[];
|
|
583
|
+
/** The title of the flow as shown in the Console. */
|
|
569
584
|
title?: string;
|
|
585
|
+
/** The description of the flow as shown in the Console. */
|
|
570
586
|
description?: string;
|
|
571
587
|
}
|
|
572
588
|
interface FlowConfigAPI {
|
|
@@ -574,20 +590,28 @@ interface FlowConfigAPI {
|
|
|
574
590
|
title: string;
|
|
575
591
|
description?: string;
|
|
576
592
|
}
|
|
577
|
-
type FlowFunction<C extends FlowConfig, I extends any = {}> = (ctx: FlowContext<C>, inputs: I) => Promise<void>;
|
|
593
|
+
type FlowFunction<C extends FlowConfig, E extends any = {}, S extends any = {}, I extends any = {}> = (ctx: FlowContext<C, E, S>, inputs: I) => Promise<void>;
|
|
578
594
|
type ExtractStageKeys<T extends FlowConfig> = T extends {
|
|
579
595
|
stages: infer S;
|
|
580
596
|
} ? S extends ReadonlyArray<infer U> ? U extends string ? U : U extends {
|
|
581
597
|
key: infer K extends string;
|
|
582
598
|
} ? K : never : never : never;
|
|
583
599
|
type StageConfigObject = {
|
|
600
|
+
/** The unique key of the stage. */
|
|
584
601
|
key: string;
|
|
602
|
+
/** The name of the stage as shown in the Console. */
|
|
585
603
|
name: string;
|
|
604
|
+
/** The description of the stage as shown in the Console. */
|
|
586
605
|
description?: string;
|
|
606
|
+
/** Whether the stage is initially hidden in the Console. */
|
|
587
607
|
initiallyHidden?: boolean;
|
|
588
608
|
};
|
|
589
609
|
type StageConfig = string | StageConfigObject;
|
|
590
|
-
declare function createFlowContext<C extends FlowConfig>(runId: string, data: any, spanId: string
|
|
610
|
+
declare function createFlowContext<C extends FlowConfig, E = any, S = any>(runId: string, data: any, action: string | null, spanId: string, ctx: {
|
|
611
|
+
env: E;
|
|
612
|
+
now: Date;
|
|
613
|
+
secrets: S;
|
|
614
|
+
}): FlowContext<C, E, S>;
|
|
591
615
|
|
|
592
616
|
declare function ksuid(): string;
|
|
593
617
|
|
package/dist/index.js
CHANGED
|
@@ -2430,9 +2430,16 @@ var selectOne = /* @__PURE__ */ __name((name, options) => {
|
|
|
2430
2430
|
}, "selectOne");
|
|
2431
2431
|
|
|
2432
2432
|
// src/flows/ui/page.ts
|
|
2433
|
-
async function page(options, data) {
|
|
2433
|
+
async function page(options, data, action) {
|
|
2434
2434
|
const content = options.content;
|
|
2435
2435
|
let hasValidationErrors = false;
|
|
2436
|
+
if (options.actions) {
|
|
2437
|
+
const isValidAction = options.actions.some((a) => {
|
|
2438
|
+
if (typeof a === "string") return a === action;
|
|
2439
|
+
return a && typeof a === "object" && "value" in a && a.value === action;
|
|
2440
|
+
});
|
|
2441
|
+
hasValidationErrors = !isValidAction;
|
|
2442
|
+
}
|
|
2436
2443
|
const contentUiConfig = await Promise.all(
|
|
2437
2444
|
content.map(async (c) => {
|
|
2438
2445
|
const isInput = "__type" in c && c.__type == "input";
|
|
@@ -2457,7 +2464,14 @@ async function page(options, data) {
|
|
|
2457
2464
|
title: options.title,
|
|
2458
2465
|
description: options.description,
|
|
2459
2466
|
content: contentUiConfig,
|
|
2460
|
-
actions: options.actions
|
|
2467
|
+
actions: options.actions?.map((a) => {
|
|
2468
|
+
if (typeof a === "string") {
|
|
2469
|
+
return { label: a, value: a, mode: "primary" };
|
|
2470
|
+
} else if (typeof a === "object") {
|
|
2471
|
+
a.mode = a.mode || "primary";
|
|
2472
|
+
}
|
|
2473
|
+
return a;
|
|
2474
|
+
})
|
|
2461
2475
|
},
|
|
2462
2476
|
hasValidationErrors
|
|
2463
2477
|
};
|
|
@@ -2583,15 +2597,33 @@ var header = /* @__PURE__ */ __name((options) => {
|
|
|
2583
2597
|
|
|
2584
2598
|
// src/flows/index.ts
|
|
2585
2599
|
var defaultOpts = {
|
|
2586
|
-
|
|
2587
|
-
|
|
2600
|
+
retries: 5,
|
|
2601
|
+
timeout: 6e4
|
|
2588
2602
|
};
|
|
2589
|
-
function createFlowContext(runId, data, spanId) {
|
|
2603
|
+
function createFlowContext(runId, data, action, spanId, ctx) {
|
|
2604
|
+
const usedNames = /* @__PURE__ */ new Set();
|
|
2590
2605
|
return {
|
|
2606
|
+
env: ctx.env,
|
|
2607
|
+
now: ctx.now,
|
|
2608
|
+
secrets: ctx.secrets,
|
|
2591
2609
|
step: /* @__PURE__ */ __name(async (name, optionsOrFn, fn) => {
|
|
2592
2610
|
const options = typeof optionsOrFn === "function" ? {} : optionsOrFn;
|
|
2593
2611
|
const actualFn = typeof optionsOrFn === "function" ? optionsOrFn : fn;
|
|
2594
2612
|
const db = useDatabase();
|
|
2613
|
+
if (usedNames.has(name)) {
|
|
2614
|
+
await db.insertInto("keel.flow_step").values({
|
|
2615
|
+
run_id: runId,
|
|
2616
|
+
name,
|
|
2617
|
+
stage: options.stage,
|
|
2618
|
+
status: "FAILED" /* FAILED */,
|
|
2619
|
+
type: "FUNCTION" /* FUNCTION */,
|
|
2620
|
+
error: `Duplicate step name: ${name}`,
|
|
2621
|
+
startTime: /* @__PURE__ */ new Date(),
|
|
2622
|
+
endTime: /* @__PURE__ */ new Date()
|
|
2623
|
+
}).returningAll().executeTakeFirst();
|
|
2624
|
+
throw new Error(`Duplicate step name: ${name}`);
|
|
2625
|
+
}
|
|
2626
|
+
usedNames.add(name);
|
|
2595
2627
|
const past = await db.selectFrom("keel.flow_step").where("run_id", "=", runId).where("name", "=", name).selectAll().execute();
|
|
2596
2628
|
const newSteps = past.filter((step) => step.status === "NEW" /* NEW */);
|
|
2597
2629
|
const completedSteps = past.filter(
|
|
@@ -2622,7 +2654,7 @@ function createFlowContext(runId, data, spanId) {
|
|
|
2622
2654
|
try {
|
|
2623
2655
|
result = await withTimeout(
|
|
2624
2656
|
actualFn(),
|
|
2625
|
-
options.
|
|
2657
|
+
options.timeout ?? defaultOpts.timeout
|
|
2626
2658
|
);
|
|
2627
2659
|
} catch (e) {
|
|
2628
2660
|
await db.updateTable("keel.flow_step").set({
|
|
@@ -2631,7 +2663,7 @@ function createFlowContext(runId, data, spanId) {
|
|
|
2631
2663
|
endTime: /* @__PURE__ */ new Date(),
|
|
2632
2664
|
error: e instanceof Error ? e.message : "An error occurred"
|
|
2633
2665
|
}).where("id", "=", newSteps[0].id).returningAll().executeTakeFirst();
|
|
2634
|
-
if (failedSteps.length + 1 >= (options.
|
|
2666
|
+
if (failedSteps.length + 1 >= (options.retries ?? defaultOpts.retries)) {
|
|
2635
2667
|
throw new ExhuastedRetriesDisrupt();
|
|
2636
2668
|
}
|
|
2637
2669
|
await db.insertInto("keel.flow_step").values({
|
|
@@ -2663,8 +2695,25 @@ function createFlowContext(runId, data, spanId) {
|
|
|
2663
2695
|
ui: {
|
|
2664
2696
|
page: /* @__PURE__ */ __name(async (name, options) => {
|
|
2665
2697
|
const db = useDatabase();
|
|
2698
|
+
if (usedNames.has(name)) {
|
|
2699
|
+
await db.insertInto("keel.flow_step").values({
|
|
2700
|
+
run_id: runId,
|
|
2701
|
+
name,
|
|
2702
|
+
stage: options.stage,
|
|
2703
|
+
status: "FAILED" /* FAILED */,
|
|
2704
|
+
type: "UI" /* UI */,
|
|
2705
|
+
error: `Duplicate step name: ${name}`,
|
|
2706
|
+
startTime: /* @__PURE__ */ new Date(),
|
|
2707
|
+
endTime: /* @__PURE__ */ new Date()
|
|
2708
|
+
}).returningAll().executeTakeFirst();
|
|
2709
|
+
throw new Error(`Duplicate step name: ${name}`);
|
|
2710
|
+
}
|
|
2711
|
+
usedNames.add(name);
|
|
2666
2712
|
let step = await db.selectFrom("keel.flow_step").where("run_id", "=", runId).where("name", "=", name).selectAll().executeTakeFirst();
|
|
2667
2713
|
if (step && step.status === "COMPLETED" /* COMPLETED */) {
|
|
2714
|
+
if (step.action) {
|
|
2715
|
+
return { data: step.value, action: step.action };
|
|
2716
|
+
}
|
|
2668
2717
|
return step.value;
|
|
2669
2718
|
}
|
|
2670
2719
|
if (!step) {
|
|
@@ -2676,22 +2725,29 @@ function createFlowContext(runId, data, spanId) {
|
|
|
2676
2725
|
type: "UI" /* UI */,
|
|
2677
2726
|
startTime: /* @__PURE__ */ new Date()
|
|
2678
2727
|
}).returningAll().executeTakeFirst();
|
|
2679
|
-
throw new UIRenderDisrupt(
|
|
2728
|
+
throw new UIRenderDisrupt(
|
|
2729
|
+
step?.id,
|
|
2730
|
+
(await page(options, null, null)).page
|
|
2731
|
+
);
|
|
2680
2732
|
}
|
|
2681
2733
|
if (!data) {
|
|
2682
|
-
throw new UIRenderDisrupt(
|
|
2734
|
+
throw new UIRenderDisrupt(
|
|
2735
|
+
step?.id,
|
|
2736
|
+
(await page(options, null, null)).page
|
|
2737
|
+
);
|
|
2683
2738
|
}
|
|
2684
|
-
const p = await page(options, data);
|
|
2739
|
+
const p = await page(options, data, action);
|
|
2685
2740
|
if (p.hasValidationErrors) {
|
|
2686
2741
|
throw new UIRenderDisrupt(step?.id, p.page);
|
|
2687
2742
|
}
|
|
2688
2743
|
await db.updateTable("keel.flow_step").set({
|
|
2689
2744
|
status: "COMPLETED" /* COMPLETED */,
|
|
2690
2745
|
value: JSON.stringify(data),
|
|
2746
|
+
action,
|
|
2691
2747
|
spanId,
|
|
2692
2748
|
endTime: /* @__PURE__ */ new Date()
|
|
2693
2749
|
}).where("id", "=", step.id).returningAll().executeTakeFirst();
|
|
2694
|
-
return data;
|
|
2750
|
+
return { data, action };
|
|
2695
2751
|
}, "page"),
|
|
2696
2752
|
inputs: {
|
|
2697
2753
|
text: textInput,
|
|
@@ -2746,7 +2802,7 @@ async function handleFlow(request, config) {
|
|
|
2746
2802
|
if (!runId) {
|
|
2747
2803
|
throw new Error("no runId provided");
|
|
2748
2804
|
}
|
|
2749
|
-
const { flows } = config;
|
|
2805
|
+
const { flows, createFlowContextAPI } = config;
|
|
2750
2806
|
if (!(request.method in flows)) {
|
|
2751
2807
|
const message = `no corresponding flow found for '${request.method}'`;
|
|
2752
2808
|
span.setStatus({
|
|
@@ -2765,7 +2821,11 @@ async function handleFlow(request, config) {
|
|
|
2765
2821
|
const ctx = createFlowContext(
|
|
2766
2822
|
request.meta.runId,
|
|
2767
2823
|
request.meta.data,
|
|
2768
|
-
|
|
2824
|
+
request.meta.action,
|
|
2825
|
+
span.spanContext().spanId,
|
|
2826
|
+
createFlowContextAPI({
|
|
2827
|
+
meta: request.meta
|
|
2828
|
+
})
|
|
2769
2829
|
);
|
|
2770
2830
|
const flowFunction = flows[request.method].fn;
|
|
2771
2831
|
const rawFlowConfig = flows[request.method].config;
|