@botonic/plugin-flow-builder 0.50.2 → 0.51.0

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.
Files changed (63) hide show
  1. package/lib/cjs/content-fields/custom-conditional/custom-conditional-v2-evaluators.d.ts +15 -0
  2. package/lib/cjs/content-fields/custom-conditional/custom-conditional-v2-evaluators.js +71 -0
  3. package/lib/cjs/content-fields/custom-conditional/custom-conditional-v2-evaluators.js.map +1 -0
  4. package/lib/cjs/content-fields/custom-conditional/custom-conditional-v2-resolver.d.ts +9 -0
  5. package/lib/cjs/content-fields/custom-conditional/custom-conditional-v2-resolver.js +58 -0
  6. package/lib/cjs/content-fields/custom-conditional/custom-conditional-v2-resolver.js.map +1 -0
  7. package/lib/cjs/content-fields/custom-conditional/flow-custom-condition-v2.d.ts +17 -0
  8. package/lib/cjs/content-fields/custom-conditional/flow-custom-condition-v2.js +79 -0
  9. package/lib/cjs/content-fields/custom-conditional/flow-custom-condition-v2.js.map +1 -0
  10. package/lib/cjs/content-fields/flow-custom-conditional.js +1 -0
  11. package/lib/cjs/content-fields/flow-custom-conditional.js.map +1 -1
  12. package/lib/cjs/content-fields/hubtype-fields/custom-conditional-v2.d.ts +56 -0
  13. package/lib/cjs/content-fields/hubtype-fields/custom-conditional-v2.js +36 -0
  14. package/lib/cjs/content-fields/hubtype-fields/custom-conditional-v2.js.map +1 -0
  15. package/lib/cjs/content-fields/hubtype-fields/index.d.ts +1 -0
  16. package/lib/cjs/content-fields/hubtype-fields/index.js +1 -0
  17. package/lib/cjs/content-fields/hubtype-fields/index.js.map +1 -1
  18. package/lib/cjs/content-fields/hubtype-fields/node-types.d.ts +2 -1
  19. package/lib/cjs/content-fields/hubtype-fields/node-types.js +1 -0
  20. package/lib/cjs/content-fields/hubtype-fields/node-types.js.map +1 -1
  21. package/lib/cjs/content-fields/hubtype-fields/nodes.d.ts +2 -1
  22. package/lib/cjs/content-fields/index.d.ts +3 -2
  23. package/lib/cjs/content-fields/index.js +3 -1
  24. package/lib/cjs/content-fields/index.js.map +1 -1
  25. package/lib/cjs/flow-factory.js +2 -0
  26. package/lib/cjs/flow-factory.js.map +1 -1
  27. package/lib/esm/content-fields/custom-conditional/custom-conditional-v2-evaluators.d.ts +15 -0
  28. package/lib/esm/content-fields/custom-conditional/custom-conditional-v2-evaluators.js +71 -0
  29. package/lib/esm/content-fields/custom-conditional/custom-conditional-v2-evaluators.js.map +1 -0
  30. package/lib/esm/content-fields/custom-conditional/custom-conditional-v2-resolver.d.ts +9 -0
  31. package/lib/esm/content-fields/custom-conditional/custom-conditional-v2-resolver.js +58 -0
  32. package/lib/esm/content-fields/custom-conditional/custom-conditional-v2-resolver.js.map +1 -0
  33. package/lib/esm/content-fields/custom-conditional/flow-custom-condition-v2.d.ts +17 -0
  34. package/lib/esm/content-fields/custom-conditional/flow-custom-condition-v2.js +79 -0
  35. package/lib/esm/content-fields/custom-conditional/flow-custom-condition-v2.js.map +1 -0
  36. package/lib/esm/content-fields/flow-custom-conditional.js +1 -0
  37. package/lib/esm/content-fields/flow-custom-conditional.js.map +1 -1
  38. package/lib/esm/content-fields/hubtype-fields/custom-conditional-v2.d.ts +56 -0
  39. package/lib/esm/content-fields/hubtype-fields/custom-conditional-v2.js +36 -0
  40. package/lib/esm/content-fields/hubtype-fields/custom-conditional-v2.js.map +1 -0
  41. package/lib/esm/content-fields/hubtype-fields/index.d.ts +1 -0
  42. package/lib/esm/content-fields/hubtype-fields/index.js +1 -0
  43. package/lib/esm/content-fields/hubtype-fields/index.js.map +1 -1
  44. package/lib/esm/content-fields/hubtype-fields/node-types.d.ts +2 -1
  45. package/lib/esm/content-fields/hubtype-fields/node-types.js +1 -0
  46. package/lib/esm/content-fields/hubtype-fields/node-types.js.map +1 -1
  47. package/lib/esm/content-fields/hubtype-fields/nodes.d.ts +2 -1
  48. package/lib/esm/content-fields/index.d.ts +3 -2
  49. package/lib/esm/content-fields/index.js +3 -1
  50. package/lib/esm/content-fields/index.js.map +1 -1
  51. package/lib/esm/flow-factory.js +2 -0
  52. package/lib/esm/flow-factory.js.map +1 -1
  53. package/package.json +2 -2
  54. package/src/content-fields/custom-conditional/custom-conditional-v2-evaluators.ts +124 -0
  55. package/src/content-fields/custom-conditional/custom-conditional-v2-resolver.ts +92 -0
  56. package/src/content-fields/custom-conditional/flow-custom-condition-v2.tsx +136 -0
  57. package/src/content-fields/flow-custom-conditional.tsx +1 -0
  58. package/src/content-fields/hubtype-fields/custom-conditional-v2.ts +68 -0
  59. package/src/content-fields/hubtype-fields/index.ts +1 -0
  60. package/src/content-fields/hubtype-fields/node-types.ts +1 -0
  61. package/src/content-fields/hubtype-fields/nodes.ts +2 -0
  62. package/src/content-fields/index.ts +3 -0
  63. package/src/flow-factory.ts +7 -0
@@ -0,0 +1,124 @@
1
+ import {
2
+ BooleanConditionOperator,
3
+ type HtBooleanCondition,
4
+ type HtNumberCondition,
5
+ type HtStringCondition,
6
+ NumberConditionOperator,
7
+ StringConditionOperator,
8
+ } from '../hubtype-fields'
9
+
10
+ type StringEvaluator = (variable: string, value: string) => boolean
11
+
12
+ type NumberEvaluator = (
13
+ variable: number,
14
+ value: number,
15
+ condition: HtNumberCondition
16
+ ) => boolean
17
+
18
+ type BooleanEvaluator = (variable: boolean) => boolean
19
+
20
+ export function getMinAndMax(condition: HtNumberCondition): {
21
+ min: number
22
+ max: number
23
+ } {
24
+ if (condition.min !== undefined && condition.max !== undefined) {
25
+ return { min: condition.min, max: condition.max }
26
+ }
27
+ throw new Error(
28
+ `Min or max not found for number condition ${condition.operator}`
29
+ )
30
+ }
31
+
32
+ export const STRING_CONDITION_EVALUATORS: Record<
33
+ StringConditionOperator,
34
+ StringEvaluator
35
+ > = {
36
+ [StringConditionOperator.Contains]: (variable, value) =>
37
+ variable.includes(value),
38
+ [StringConditionOperator.NotContains]: (variable, value) =>
39
+ !variable.includes(value),
40
+ [StringConditionOperator.EqualsTo]: (variable, value) => variable === value,
41
+ [StringConditionOperator.NotEqualsTo]: (variable, value) =>
42
+ variable !== value,
43
+ [StringConditionOperator.StartsWith]: (variable, value) =>
44
+ variable.startsWith(value),
45
+ [StringConditionOperator.NotStartsWith]: (variable, value) =>
46
+ !variable.startsWith(value),
47
+ [StringConditionOperator.EndsWith]: (variable, value) =>
48
+ variable.endsWith(value),
49
+ [StringConditionOperator.NotEndsWith]: (variable, value) =>
50
+ !variable.endsWith(value),
51
+ }
52
+
53
+ export const NUMBER_CONDITION_EVALUATORS: Record<
54
+ NumberConditionOperator,
55
+ NumberEvaluator
56
+ > = {
57
+ [NumberConditionOperator.EqualsTo]: (variable, value) => variable === value,
58
+ [NumberConditionOperator.NotEqualsTo]: (variable, value) =>
59
+ variable !== value,
60
+ [NumberConditionOperator.GreaterThan]: (variable, value) => variable > value,
61
+ [NumberConditionOperator.LessThan]: (variable, value) => variable < value,
62
+ [NumberConditionOperator.GreaterThanOrEqualTo]: (variable, value) =>
63
+ variable >= value,
64
+ [NumberConditionOperator.LessThanOrEqualTo]: (variable, value) =>
65
+ variable <= value,
66
+ [NumberConditionOperator.Between]: (variable, _value, condition) => {
67
+ const { min, max } = getMinAndMax(condition)
68
+ return variable >= min && variable <= max
69
+ },
70
+ [NumberConditionOperator.NotBetween]: (variable, _value, condition) => {
71
+ const { min, max } = getMinAndMax(condition)
72
+ return variable < min || variable > max
73
+ },
74
+ }
75
+
76
+ export const BOOLEAN_CONDITION_EVALUATORS: Record<
77
+ BooleanConditionOperator,
78
+ BooleanEvaluator
79
+ > = {
80
+ [BooleanConditionOperator.IsTruthy]: variable => !!variable,
81
+ }
82
+
83
+ export function evaluateStringCondition(
84
+ variable: string,
85
+ condition: HtStringCondition
86
+ ): boolean {
87
+ if (condition.value === undefined) {
88
+ throw new Error(
89
+ `Value not found for string condition ${condition.operator}`
90
+ )
91
+ }
92
+ const evaluator = STRING_CONDITION_EVALUATORS[condition.operator]
93
+ if (!evaluator) {
94
+ throw new Error(`Invalid string condition operator ${condition.operator}`)
95
+ }
96
+ return evaluator(variable, condition.value)
97
+ }
98
+
99
+ export function evaluateNumberCondition(
100
+ variable: number,
101
+ condition: HtNumberCondition
102
+ ): boolean {
103
+ if (condition.value === undefined) {
104
+ throw new Error(
105
+ `Value not found for number condition ${condition.operator}`
106
+ )
107
+ }
108
+ const evaluator = NUMBER_CONDITION_EVALUATORS[condition.operator]
109
+ if (!evaluator) {
110
+ throw new Error(`Invalid number condition operator ${condition.operator}`)
111
+ }
112
+ return evaluator(variable, condition.value, condition)
113
+ }
114
+
115
+ export function evaluateBooleanCondition(
116
+ variable: boolean,
117
+ condition: HtBooleanCondition
118
+ ): boolean {
119
+ const evaluator = BOOLEAN_CONDITION_EVALUATORS[condition.operator]
120
+ if (!evaluator) {
121
+ throw new Error(`Invalid boolean condition operator ${condition.operator}`)
122
+ }
123
+ return evaluator(variable)
124
+ }
@@ -0,0 +1,92 @@
1
+ import {
2
+ type HtCondition,
3
+ type HtNodeLink,
4
+ type HtNumberCondition,
5
+ type HtStringCondition,
6
+ NumberConditionOperator,
7
+ VariableFormat,
8
+ } from '../hubtype-fields'
9
+
10
+ export type ConditionMatch = {
11
+ customResult: string
12
+ target: HtNodeLink
13
+ operator: string
14
+ }
15
+
16
+ export function getConditionCustomResult(
17
+ condition: HtCondition,
18
+ variableFormat: VariableFormat
19
+ ): string {
20
+ switch (variableFormat) {
21
+ case VariableFormat.String:
22
+ return String((condition as HtStringCondition).value)
23
+ case VariableFormat.Number:
24
+ return getNumberConditionCustomResult(condition as HtNumberCondition)
25
+ case VariableFormat.Boolean:
26
+ // Only reached after evaluateBooleanCondition succeeds; today that is isTruthy → 'true'
27
+ return 'true'
28
+ default:
29
+ throw new Error(`Invalid variable format ${variableFormat}`)
30
+ }
31
+ }
32
+
33
+ function getNumberConditionCustomResult(condition: HtNumberCondition): string {
34
+ const numberCondition = condition as HtNumberCondition
35
+ if (
36
+ numberCondition.operator === NumberConditionOperator.Between ||
37
+ numberCondition.operator === NumberConditionOperator.NotBetween
38
+ ) {
39
+ return `min: ${numberCondition.min} - max: ${numberCondition.max}`
40
+ }
41
+ return String(numberCondition.value)
42
+ }
43
+
44
+ export function findLastMatchingCondition<T extends HtCondition>(
45
+ conditions: T[],
46
+ variable: unknown,
47
+ variableFormat: VariableFormat,
48
+ evaluate: (variable: unknown, condition: T) => boolean
49
+ ): ConditionMatch | undefined {
50
+ let lastMatch: ConditionMatch | undefined
51
+
52
+ for (const condition of conditions) {
53
+ if (!evaluate(variable, condition)) {
54
+ continue
55
+ }
56
+
57
+ if (!condition.target) {
58
+ continue
59
+ }
60
+
61
+ lastMatch = {
62
+ customResult: getConditionCustomResult(condition, variableFormat),
63
+ target: condition.target,
64
+ operator: condition.operator,
65
+ }
66
+ }
67
+
68
+ return lastMatch
69
+ }
70
+
71
+ export function resolveWithDefaultTarget(
72
+ match: ConditionMatch | undefined,
73
+ defaultTarget: HtNodeLink,
74
+ nodeCode: string,
75
+ defaultCustomResult: string = 'default'
76
+ ): ConditionMatch {
77
+ if (match) {
78
+ return match
79
+ }
80
+
81
+ if (!defaultTarget) {
82
+ throw new Error(
83
+ `Default target not found for custom condition node ${nodeCode}`
84
+ )
85
+ }
86
+
87
+ return {
88
+ customResult: defaultCustomResult,
89
+ target: defaultTarget,
90
+ operator: '',
91
+ }
92
+ }
@@ -0,0 +1,136 @@
1
+ import {
2
+ type BotContext,
3
+ EventAction,
4
+ type EventConditionalCustom,
5
+ } from '@botonic/core'
6
+ import {
7
+ getCommonFlowContentEventArgsForContentId,
8
+ trackEvent,
9
+ } from '../../tracking'
10
+ import { ContentFieldsBase } from '../content-fields-base'
11
+ import {
12
+ type HtBooleanCondition,
13
+ type HtCondition,
14
+ type HtCustomConditionalV2Node,
15
+ type HtNodeLink,
16
+ type HtNumberCondition,
17
+ type HtStringCondition,
18
+ VariableFormat,
19
+ } from '../hubtype-fields'
20
+ import {
21
+ evaluateBooleanCondition,
22
+ evaluateNumberCondition,
23
+ evaluateStringCondition,
24
+ } from './custom-conditional-v2-evaluators'
25
+ import {
26
+ type ConditionMatch,
27
+ findLastMatchingCondition,
28
+ resolveWithDefaultTarget,
29
+ } from './custom-conditional-v2-resolver'
30
+
31
+ export class FlowCustomConditionalV2 extends ContentFieldsBase {
32
+ public variableFormat: VariableFormat
33
+ public keyPath: string
34
+ public conditions: HtCondition[]
35
+ public defaultTarget: HtNodeLink
36
+ public customResult = ''
37
+ public resolvedOperator = ''
38
+
39
+ static fromHubtypeCMS(
40
+ component: HtCustomConditionalV2Node,
41
+ botContext: BotContext
42
+ ): FlowCustomConditionalV2 {
43
+ const newCustomConditionalV2 = new FlowCustomConditionalV2(component.id)
44
+ newCustomConditionalV2.code = component.code
45
+ newCustomConditionalV2.variableFormat = component.content.type
46
+ newCustomConditionalV2.keyPath = component.content.key_path
47
+ newCustomConditionalV2.conditions = component.content.conditions
48
+ newCustomConditionalV2.defaultTarget = component.content.default_target
49
+ newCustomConditionalV2.setFollowUp(botContext)
50
+
51
+ return newCustomConditionalV2
52
+ }
53
+
54
+ private setFollowUp(botContext: BotContext): void {
55
+ const botVariable = this.getValueFromKeyPath(botContext, this.keyPath)
56
+ const resolved = this.evaluateConditions(botVariable)
57
+
58
+ this.customResult = resolved.customResult
59
+ this.resolvedOperator = resolved.operator
60
+ this.followUp = resolved.target
61
+ }
62
+
63
+ private evaluateConditions(botVariable: unknown): ConditionMatch {
64
+ switch (this.variableFormat) {
65
+ case VariableFormat.String: {
66
+ const match = findLastMatchingCondition(
67
+ this.conditions as HtStringCondition[],
68
+ botVariable,
69
+ this.variableFormat,
70
+ (variable, condition) =>
71
+ evaluateStringCondition(variable as string, condition)
72
+ )
73
+ return resolveWithDefaultTarget(match, this.defaultTarget, this.code)
74
+ }
75
+ case VariableFormat.Number: {
76
+ const match = findLastMatchingCondition(
77
+ this.conditions as HtNumberCondition[],
78
+ botVariable,
79
+ this.variableFormat,
80
+ (variable, condition) =>
81
+ evaluateNumberCondition(variable as number, condition)
82
+ )
83
+ return resolveWithDefaultTarget(match, this.defaultTarget, this.code)
84
+ }
85
+ case VariableFormat.Boolean: {
86
+ const match = findLastMatchingCondition(
87
+ this.conditions as HtBooleanCondition[],
88
+ botVariable,
89
+ this.variableFormat,
90
+ (variable, condition) =>
91
+ evaluateBooleanCondition(variable as boolean, condition)
92
+ )
93
+ return resolveWithDefaultTarget(
94
+ match,
95
+ this.defaultTarget,
96
+ this.code,
97
+ 'false'
98
+ )
99
+ }
100
+ default:
101
+ throw new Error(
102
+ `Invalid variable format ${this.variableFormat} for custom condition node ${this.code}`
103
+ )
104
+ }
105
+ }
106
+
107
+ async trackFlow(botContext: BotContext): Promise<void> {
108
+ const { flowThreadId, flowId, flowName, flowNodeId, flowNodeContentId } =
109
+ getCommonFlowContentEventArgsForContentId(botContext, this.id)
110
+
111
+ const eventCustomConditional: EventConditionalCustom = {
112
+ action: EventAction.ConditionalCustom,
113
+ flowThreadId,
114
+ flowId,
115
+ flowName,
116
+ flowNodeId,
117
+ flowNodeContentId,
118
+ flowNodeIsMeaningful: false,
119
+ conditionalVariable: this.customResult,
120
+ variableFormat: this.variableFormat,
121
+ operator: this.resolvedOperator,
122
+ }
123
+ const { action, ...eventArgs } = eventCustomConditional
124
+ await trackEvent(botContext, action, eventArgs)
125
+ }
126
+
127
+ async processContent(botContext: BotContext): Promise<void> {
128
+ await this.filterContent(botContext, this)
129
+ await this.trackFlow(botContext)
130
+ return
131
+ }
132
+
133
+ toBotonic() {
134
+ return <></>
135
+ }
136
+ }
@@ -101,6 +101,7 @@ export class FlowCustomConditional extends ContentFieldsBase {
101
101
  flowNodeIsMeaningful: false,
102
102
  conditionalVariable: this.customResult.toString(),
103
103
  variableFormat: this.variableFormat,
104
+ operator: '',
104
105
  }
105
106
  const { action, ...eventArgs } = eventCustomConditional
106
107
  await trackEvent(botContext, action, eventArgs)
@@ -0,0 +1,68 @@
1
+ import type { HtBaseNode, HtNodeLink } from './common'
2
+ import type { HtNodeWithContentType } from './node-types'
3
+
4
+ export enum VariableFormat {
5
+ Boolean = 'boolean',
6
+ Number = 'number',
7
+ String = 'string',
8
+ }
9
+
10
+ export enum StringConditionOperator {
11
+ Contains = 'contains',
12
+ NotContains = 'notContains',
13
+ EqualsTo = 'equalsTo',
14
+ NotEqualsTo = 'notEqualsTo',
15
+ StartsWith = 'startsWith',
16
+ NotStartsWith = 'notStartsWith',
17
+ EndsWith = 'endsWith',
18
+ NotEndsWith = 'notEndsWith',
19
+ }
20
+
21
+ export interface HtStringCondition {
22
+ operator: StringConditionOperator
23
+ value?: string
24
+ target?: HtNodeLink
25
+ }
26
+
27
+ export enum NumberConditionOperator {
28
+ EqualsTo = 'equalsTo',
29
+ NotEqualsTo = 'notEqualsTo',
30
+ GreaterThan = 'greaterThan',
31
+ LessThan = 'lessThan',
32
+ GreaterThanOrEqualTo = 'greaterThanOrEqualTo',
33
+ LessThanOrEqualTo = 'lessThanOrEqualTo',
34
+ Between = 'between',
35
+ NotBetween = 'notBetween',
36
+ }
37
+
38
+ export interface HtNumberCondition {
39
+ operator: NumberConditionOperator
40
+ value?: number
41
+ min?: number
42
+ max?: number
43
+ target?: HtNodeLink
44
+ }
45
+
46
+ export enum BooleanConditionOperator {
47
+ IsTruthy = 'isTruthy',
48
+ }
49
+
50
+ export interface HtBooleanCondition {
51
+ operator: BooleanConditionOperator
52
+ target?: HtNodeLink
53
+ }
54
+
55
+ export type HtCondition =
56
+ | HtStringCondition
57
+ | HtNumberCondition
58
+ | HtBooleanCondition
59
+
60
+ export interface HtCustomConditionalV2Node extends HtBaseNode {
61
+ type: HtNodeWithContentType.CUSTOM_CONDITION
62
+ content: {
63
+ type: VariableFormat
64
+ key_path: string
65
+ conditions: HtCondition[]
66
+ default_target: HtNodeLink
67
+ }
68
+ }
@@ -5,6 +5,7 @@ export * from './button'
5
5
  export * from './capture-user-input'
6
6
  export * from './carousel'
7
7
  export * from './common'
8
+ export * from './custom-conditional-v2'
8
9
  export * from './fallback'
9
10
  export * from './function'
10
11
  export * from './go-to-flow'
@@ -19,6 +19,7 @@ export enum HtNodeWithContentType {
19
19
  WEBVIEW = 'webview',
20
20
  GO_TO_FLOW = 'go-to-flow',
21
21
  CAPTURE_USER_INPUT = 'capture-user-input',
22
+ CUSTOM_CONDITION = 'custom-condition',
22
23
  }
23
24
 
24
25
  export enum HtNodeWithoutContentType {
@@ -3,6 +3,7 @@ import type { HtAiAgentRouterNode } from './ai-agent-router'
3
3
  import type { HtBotActionNode } from './bot-action'
4
4
  import type { HtCaptureUserInputNode } from './capture-user-input'
5
5
  import type { HtCarouselNode } from './carousel'
6
+ import type { HtCustomConditionalV2Node } from './custom-conditional-v2'
6
7
  // import { HtChannelConditionalNode } from './channel-conditional'
7
8
  // import { HtCountryConditionalNode } from './country-conditional'
8
9
  // import { HtCustomConditionalNode } from './custom-conditional'
@@ -46,6 +47,7 @@ export type HtNodeWithContent =
46
47
  | HtGoToFlow
47
48
  | HtWhatsappTemplateNode
48
49
  | HtCaptureUserInputNode
50
+ | HtCustomConditionalV2Node
49
51
  // | HtChannelConditionalNode
50
52
  // | HtCountryConditionalNode
51
53
  // | HtCustomConditionalNode
@@ -1,3 +1,4 @@
1
+ import { FlowCustomConditionalV2 } from './custom-conditional/flow-custom-condition-v2'
1
2
  import { FlowAiAgent } from './flow-ai-agent'
2
3
  import { FlowAiAgentRouter } from './flow-ai-agent-router'
3
4
  import { FlowBotAction } from './flow-bot-action'
@@ -44,6 +45,7 @@ export {
44
45
  FlowWhatsappButtonList,
45
46
  FlowWhatsappCtaUrlButtonNode,
46
47
  FlowWhatsappTemplate,
48
+ FlowCustomConditionalV2,
47
49
  }
48
50
 
49
51
  export type FlowContent =
@@ -66,5 +68,6 @@ export type FlowContent =
66
68
  | FlowGoToFlow
67
69
  | FlowCaptureUserInput
68
70
  | FlowAiAgentRouter
71
+ | FlowCustomConditionalV2
69
72
 
70
73
  export { DISABLED_MEMORY_LENGTH }
@@ -10,6 +10,7 @@ import {
10
10
  type FlowContent,
11
11
  FlowCountryConditional,
12
12
  FlowCustomConditional,
13
+ FlowCustomConditionalV2,
13
14
  FlowGoToFlow,
14
15
  FlowHandoff,
15
16
  FlowImage,
@@ -102,6 +103,12 @@ export class FlowFactory {
102
103
  case HtNodeWithContentType.CAPTURE_USER_INPUT:
103
104
  return FlowCaptureUserInput.fromHubtypeCMS(hubtypeContent)
104
105
 
106
+ case HtNodeWithContentType.CUSTOM_CONDITION:
107
+ return FlowCustomConditionalV2.fromHubtypeCMS(
108
+ hubtypeContent,
109
+ this.botContext
110
+ )
111
+
105
112
  default:
106
113
  return undefined
107
114
  }