@botonic/plugin-flow-builder 0.58.0-alpha.0 → 0.58.0-alpha.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.
Files changed (94) hide show
  1. package/lib/cjs/action/first-interaction.js +1 -1
  2. package/lib/cjs/action/first-interaction.js.map +1 -1
  3. package/lib/cjs/action/get-contents.d.ts +2 -3
  4. package/lib/cjs/action/get-contents.js +6 -13
  5. package/lib/cjs/action/get-contents.js.map +1 -1
  6. package/lib/cjs/action/index.d.ts +0 -2
  7. package/lib/cjs/action/index.js +6 -16
  8. package/lib/cjs/action/index.js.map +1 -1
  9. package/lib/cjs/action/payload.d.ts +2 -2
  10. package/lib/cjs/action/payload.js +28 -12
  11. package/lib/cjs/action/payload.js.map +1 -1
  12. package/lib/cjs/api.d.ts +1 -1
  13. package/lib/cjs/api.js +2 -7
  14. package/lib/cjs/api.js.map +1 -1
  15. package/lib/cjs/content-fields/flow-do-nothing.js +1 -1
  16. package/lib/cjs/content-fields/flow-do-nothing.js.map +1 -1
  17. package/lib/cjs/content-fields/flow-update-variables.d.ts +15 -0
  18. package/lib/cjs/content-fields/flow-update-variables.js +137 -0
  19. package/lib/cjs/content-fields/flow-update-variables.js.map +1 -0
  20. package/lib/cjs/content-fields/hubtype-fields/node-types.d.ts +2 -1
  21. package/lib/cjs/content-fields/hubtype-fields/node-types.js +1 -0
  22. package/lib/cjs/content-fields/hubtype-fields/node-types.js.map +1 -1
  23. package/lib/cjs/content-fields/hubtype-fields/nodes.d.ts +2 -1
  24. package/lib/cjs/content-fields/hubtype-fields/update-variables.d.ts +9 -0
  25. package/lib/{esm/action/contents-result.js → cjs/content-fields/hubtype-fields/update-variables.js} +1 -1
  26. package/lib/cjs/content-fields/hubtype-fields/update-variables.js.map +1 -0
  27. package/lib/cjs/content-fields/index.d.ts +3 -2
  28. package/lib/cjs/content-fields/index.js +3 -1
  29. package/lib/cjs/content-fields/index.js.map +1 -1
  30. package/lib/cjs/flow-factory.js +2 -0
  31. package/lib/cjs/flow-factory.js.map +1 -1
  32. package/lib/cjs/services/contact-info-fields-api.d.ts +7 -0
  33. package/lib/cjs/services/contact-info-fields-api.js +28 -0
  34. package/lib/cjs/services/contact-info-fields-api.js.map +1 -0
  35. package/lib/esm/action/first-interaction.js +1 -1
  36. package/lib/esm/action/first-interaction.js.map +1 -1
  37. package/lib/esm/action/get-contents.d.ts +2 -3
  38. package/lib/esm/action/get-contents.js +6 -13
  39. package/lib/esm/action/get-contents.js.map +1 -1
  40. package/lib/esm/action/index.d.ts +0 -2
  41. package/lib/esm/action/index.js +6 -16
  42. package/lib/esm/action/index.js.map +1 -1
  43. package/lib/esm/action/payload.d.ts +2 -2
  44. package/lib/esm/action/payload.js +28 -12
  45. package/lib/esm/action/payload.js.map +1 -1
  46. package/lib/esm/api.d.ts +1 -1
  47. package/lib/esm/api.js +2 -7
  48. package/lib/esm/api.js.map +1 -1
  49. package/lib/esm/content-fields/flow-do-nothing.js +1 -1
  50. package/lib/esm/content-fields/flow-do-nothing.js.map +1 -1
  51. package/lib/esm/content-fields/flow-update-variables.d.ts +15 -0
  52. package/lib/esm/content-fields/flow-update-variables.js +137 -0
  53. package/lib/esm/content-fields/flow-update-variables.js.map +1 -0
  54. package/lib/esm/content-fields/hubtype-fields/node-types.d.ts +2 -1
  55. package/lib/esm/content-fields/hubtype-fields/node-types.js +1 -0
  56. package/lib/esm/content-fields/hubtype-fields/node-types.js.map +1 -1
  57. package/lib/esm/content-fields/hubtype-fields/nodes.d.ts +2 -1
  58. package/lib/esm/content-fields/hubtype-fields/update-variables.d.ts +9 -0
  59. package/lib/{cjs/action/contents-result.js → esm/content-fields/hubtype-fields/update-variables.js} +1 -1
  60. package/lib/esm/content-fields/hubtype-fields/update-variables.js.map +1 -0
  61. package/lib/esm/content-fields/index.d.ts +3 -2
  62. package/lib/esm/content-fields/index.js +3 -1
  63. package/lib/esm/content-fields/index.js.map +1 -1
  64. package/lib/esm/flow-factory.js +2 -0
  65. package/lib/esm/flow-factory.js.map +1 -1
  66. package/lib/esm/services/contact-info-fields-api.d.ts +7 -0
  67. package/lib/esm/services/contact-info-fields-api.js +28 -0
  68. package/lib/esm/services/contact-info-fields-api.js.map +1 -0
  69. package/package.json +2 -2
  70. package/src/action/first-interaction.ts +6 -7
  71. package/src/action/get-contents.ts +8 -17
  72. package/src/action/index.tsx +6 -40
  73. package/src/action/payload.ts +46 -16
  74. package/src/api.ts +3 -13
  75. package/src/content-fields/flow-do-nothing.tsx +1 -1
  76. package/src/content-fields/flow-update-variables.tsx +182 -0
  77. package/src/content-fields/hubtype-fields/node-types.ts +1 -0
  78. package/src/content-fields/hubtype-fields/nodes.ts +2 -0
  79. package/src/content-fields/hubtype-fields/update-variables.ts +10 -0
  80. package/src/content-fields/index.ts +3 -0
  81. package/src/flow-factory.ts +7 -0
  82. package/src/services/contact-info-fields-api.ts +36 -0
  83. package/lib/cjs/action/contents-result.d.ts +0 -5
  84. package/lib/cjs/action/contents-result.js.map +0 -1
  85. package/lib/cjs/action/push-flow-resolver.d.ts +0 -22
  86. package/lib/cjs/action/push-flow-resolver.js +0 -66
  87. package/lib/cjs/action/push-flow-resolver.js.map +0 -1
  88. package/lib/esm/action/contents-result.d.ts +0 -5
  89. package/lib/esm/action/contents-result.js.map +0 -1
  90. package/lib/esm/action/push-flow-resolver.d.ts +0 -22
  91. package/lib/esm/action/push-flow-resolver.js +0 -66
  92. package/lib/esm/action/push-flow-resolver.js.map +0 -1
  93. package/src/action/contents-result.ts +0 -6
  94. package/src/action/push-flow-resolver.ts +0 -101
@@ -0,0 +1,182 @@
1
+ import {
2
+ type BotContext,
3
+ EventAction,
4
+ type EventUpdateVariables,
5
+ type Session,
6
+ } from '@botonic/core'
7
+
8
+ import { FLOW_BUILDER_API_URL_PROD } from '../constants'
9
+ import { ContactInfoFieldsClient } from '../services/contact-info-fields-api'
10
+ import {
11
+ getCommonFlowContentEventArgsForContentId,
12
+ trackEvent,
13
+ } from '../tracking'
14
+ import { getFlowBuilderPlugin } from '../utils/get-flow-builder-plugin'
15
+ import { ContentFieldsBase } from './content-fields-base'
16
+ import type { HtUpdateVariablesNode } from './hubtype-fields/update-variables'
17
+
18
+ const SESSION_CONTACT_INFO_PREFIX = 'session.user.contact_info.'
19
+
20
+ export class FlowUpdateVariables extends ContentFieldsBase {
21
+ public setVariables: Record<string, string | number | boolean> = {}
22
+ public unsetVariables: string[] = []
23
+
24
+ static async fromHubtypeCMS(
25
+ cmsUpdateVariables: HtUpdateVariablesNode,
26
+ botContext: BotContext
27
+ ): Promise<FlowUpdateVariables> {
28
+ const newUpdateVariables = new FlowUpdateVariables(cmsUpdateVariables.id)
29
+ newUpdateVariables.setVariables = cmsUpdateVariables.content.set_variables
30
+ newUpdateVariables.unsetVariables =
31
+ cmsUpdateVariables.content.unset_variables
32
+ await newUpdateVariables.applyVariablesAndSyncContactInfo(botContext)
33
+ return newUpdateVariables
34
+ }
35
+
36
+ private async applyVariablesAndSyncContactInfo(
37
+ botContext: BotContext
38
+ ): Promise<void> {
39
+ const contactInfoUpdates: {
40
+ fieldName: string
41
+ value: string | number | boolean | undefined
42
+ }[] = []
43
+
44
+ for (const [keyPath, value] of Object.entries(this.setVariables)) {
45
+ const fieldName = this.getContactInfoFieldName(keyPath)
46
+ if (fieldName) {
47
+ this.updateSessionContactInfoField(botContext, fieldName, value)
48
+ contactInfoUpdates.push({ fieldName, value })
49
+ } else {
50
+ this.setSessionValueFromKeyPath(botContext, keyPath, value)
51
+ }
52
+ }
53
+
54
+ for (const keyPath of this.unsetVariables) {
55
+ const fieldName = this.getContactInfoFieldName(keyPath)
56
+ if (fieldName) {
57
+ this.updateSessionContactInfoField(botContext, fieldName, undefined)
58
+ contactInfoUpdates.push({ fieldName, value: undefined })
59
+ } else {
60
+ this.setSessionValueFromKeyPath(botContext, keyPath, undefined)
61
+ }
62
+ }
63
+
64
+ if (contactInfoUpdates.length === 0) {
65
+ return
66
+ }
67
+
68
+ const hubtypeApiUrl =
69
+ botContext.session._hubtype_api || FLOW_BUILDER_API_URL_PROD
70
+ const flowBuilderPlugin = getFlowBuilderPlugin(botContext.plugins)
71
+ const accessToken = flowBuilderPlugin.getAccessToken(botContext.session)
72
+ const chatId = botContext.session.user.id
73
+
74
+ const contactInfoFieldsClient = new ContactInfoFieldsClient(
75
+ hubtypeApiUrl,
76
+ accessToken
77
+ )
78
+
79
+ await Promise.all(
80
+ contactInfoUpdates.map(({ fieldName, value }) => {
81
+ if (value === undefined) {
82
+ return contactInfoFieldsClient.delete(chatId, fieldName)
83
+ }
84
+ return contactInfoFieldsClient.update(chatId, fieldName, value)
85
+ })
86
+ )
87
+ }
88
+
89
+ private setSessionValueFromKeyPath(
90
+ botContext: BotContext,
91
+ keyPath: string,
92
+ value: string | number | boolean | undefined
93
+ ): void {
94
+ const keys = keyPath.split('.')
95
+ if (keys.shift() !== 'session') {
96
+ return
97
+ }
98
+
99
+ const lastKey = keys.pop()
100
+ if (!lastKey) {
101
+ return
102
+ }
103
+
104
+ let current: Session = botContext.session
105
+ for (const key of keys) {
106
+ if (current[key] === undefined || current[key] === null) {
107
+ current[key] = {}
108
+ }
109
+ current = current[key]
110
+ }
111
+ current[lastKey] = value
112
+ }
113
+
114
+ private getContactInfoFieldName(keyPath: string): string | undefined {
115
+ if (!keyPath.startsWith(SESSION_CONTACT_INFO_PREFIX)) {
116
+ return undefined
117
+ }
118
+ const fieldName = keyPath.slice(SESSION_CONTACT_INFO_PREFIX.length)
119
+ return fieldName || undefined
120
+ }
121
+
122
+ private updateSessionContactInfoField(
123
+ botContext: BotContext,
124
+ fieldName: string,
125
+ value: string | number | boolean | undefined
126
+ ): void {
127
+ if (!botContext.session.user.contact_info) {
128
+ botContext.session.user.contact_info = []
129
+ }
130
+
131
+ const contactInfo = botContext.session.user.contact_info
132
+ const index = contactInfo.findIndex(field => field.name === fieldName)
133
+
134
+ if (value === undefined) {
135
+ if (index >= 0) {
136
+ contactInfo.splice(index, 1)
137
+ }
138
+ return
139
+ }
140
+
141
+ const stringValue = String(value)
142
+ const valueType = typeof value
143
+
144
+ if (index >= 0) {
145
+ contactInfo[index].value = stringValue
146
+ contactInfo[index].type = valueType
147
+ return
148
+ }
149
+
150
+ contactInfo.push({
151
+ name: fieldName,
152
+ type: valueType,
153
+ value: stringValue,
154
+ })
155
+ }
156
+
157
+ async trackFlow(botContext: BotContext): Promise<void> {
158
+ const { flowThreadId, flowId, flowName, flowNodeId, flowNodeContentId } =
159
+ getCommonFlowContentEventArgsForContentId(botContext, this.id)
160
+ const eventUpdateVariables: EventUpdateVariables = {
161
+ action: EventAction.UpdateVariables,
162
+ flowThreadId,
163
+ flowId,
164
+ flowName,
165
+ flowNodeId,
166
+ flowNodeContentId,
167
+ flowNodeIsMeaningful: false,
168
+ setVariables: this.setVariables,
169
+ unsetVariables: this.unsetVariables,
170
+ }
171
+ const { action, ...eventArgs } = eventUpdateVariables
172
+ await trackEvent(botContext, action, eventArgs)
173
+ }
174
+
175
+ async processContent(botContext: BotContext): Promise<void> {
176
+ await this.trackFlow(botContext)
177
+ }
178
+
179
+ toBotonic() {
180
+ return <></>
181
+ }
182
+ }
@@ -22,6 +22,7 @@ export enum HtNodeWithContentType {
22
22
  CUSTOM_CONDITION = 'custom-condition',
23
23
  DO_NOTHING = 'do-nothing',
24
24
  CONTACT_REASONS_CONDITION = 'contact-reasons-condition',
25
+ UPDATE_VARIABLES = 'update-variables',
25
26
  }
26
27
 
27
28
  export enum HtNodeWithoutContentType {
@@ -20,6 +20,7 @@ import type { HtPayloadNode } from './payload'
20
20
  import type { HtRatingNode } from './rating'
21
21
  import type { HtSmartIntentNode } from './smart-intent'
22
22
  import type { HtTextNode } from './text'
23
+ import type { HtUpdateVariablesNode } from './update-variables'
23
24
  import type { HtUrlNode } from './url'
24
25
  import type { HtVideoNode } from './video'
25
26
  import type { HtWebviewNode } from './webview'
@@ -52,6 +53,7 @@ export type HtNodeWithContent =
52
53
  | HtCustomConditionalV2Node
53
54
  | HtDoNothingNode
54
55
  | HtContactReasonsNode
56
+ | HtUpdateVariablesNode
55
57
  // | HtChannelConditionalNode
56
58
  // | HtCountryConditionalNode
57
59
  // | HtCustomConditionalNode
@@ -0,0 +1,10 @@
1
+ import type { HtBaseNode } from './common'
2
+ import type { HtNodeWithContentType } from './node-types'
3
+
4
+ export interface HtUpdateVariablesNode extends HtBaseNode {
5
+ type: HtNodeWithContentType.UPDATE_VARIABLES
6
+ content: {
7
+ set_variables: Record<string, string | number | boolean>
8
+ unset_variables: string[]
9
+ }
10
+ }
@@ -15,6 +15,7 @@ import { FlowImage } from './flow-image'
15
15
  import { FlowQueueStatusConditional } from './flow-queue-status-conditional'
16
16
  import { FlowRating } from './flow-rating'
17
17
  import { FlowText } from './flow-text'
18
+ import { FlowUpdateVariables } from './flow-update-variables'
18
19
  import { FlowVideo } from './flow-video'
19
20
  import { FlowWhatsappCtaUrlButtonNode } from './flow-whatsapp-cta-url-button'
20
21
  import { FlowWhatsappRequestContactInfoNode } from './flow-whatsapp-request-contact-info'
@@ -46,6 +47,7 @@ export {
46
47
  FlowQueueStatusConditional,
47
48
  FlowRating,
48
49
  FlowText,
50
+ FlowUpdateVariables,
49
51
  FlowVideo,
50
52
  FlowWhatsappButtonList,
51
53
  FlowWhatsappButtonListRow,
@@ -77,4 +79,5 @@ export type FlowContent =
77
79
  | FlowAiAgentRouter
78
80
  | FlowCustomConditionalV2
79
81
  | FlowDoNothing
82
+ | FlowUpdateVariables
80
83
  | FlowContactReasonsConditional
@@ -19,6 +19,7 @@ import {
19
19
  FlowQueueStatusConditional,
20
20
  FlowRating,
21
21
  FlowText,
22
+ FlowUpdateVariables,
22
23
  FlowVideo,
23
24
  FlowWhatsappButtonList,
24
25
  FlowWhatsappCtaUrlButtonNode,
@@ -123,6 +124,12 @@ export class FlowFactory {
123
124
  case HtNodeWithContentType.DO_NOTHING:
124
125
  return FlowDoNothing.fromHubtypeCMS(hubtypeContent)
125
126
 
127
+ case HtNodeWithContentType.UPDATE_VARIABLES:
128
+ return FlowUpdateVariables.fromHubtypeCMS(
129
+ hubtypeContent,
130
+ this.botContext
131
+ )
132
+
126
133
  case HtNodeWithContentType.CONTACT_REASONS_CONDITION:
127
134
  return FlowContactReasonsConditional.fromHubtypeCMS(
128
135
  hubtypeContent,
@@ -0,0 +1,36 @@
1
+ import axios from 'axios'
2
+
3
+ export class ContactInfoFieldsClient {
4
+ constructor(
5
+ private readonly hubtypeApiUrl: string,
6
+ private readonly accessToken: string
7
+ ) {}
8
+
9
+ async update(
10
+ chatId: string,
11
+ fieldName: string,
12
+ value: string | number | boolean
13
+ ): Promise<void> {
14
+ await axios.put(
15
+ `${this.hubtypeApiUrl}/external/v1/chats/${chatId}/contact_info_fields/${encodeURIComponent(fieldName)}/`,
16
+ { value },
17
+ {
18
+ headers: {
19
+ 'Content-Type': 'application/json',
20
+ Authorization: `Bearer ${this.accessToken}`,
21
+ },
22
+ }
23
+ )
24
+ }
25
+
26
+ async delete(chatId: string, fieldName: string): Promise<void> {
27
+ await axios.delete(
28
+ `${this.hubtypeApiUrl}/external/v1/chats/${chatId}/contact_info_fields/${encodeURIComponent(fieldName)}/`,
29
+ {
30
+ headers: {
31
+ Authorization: `Bearer ${this.accessToken}`,
32
+ },
33
+ }
34
+ )
35
+ }
36
+ }
@@ -1,5 +0,0 @@
1
- import type { FlowContent } from '../content-fields';
2
- export type FlowBuilderContentsResult = {
3
- contents: FlowContent[];
4
- campaignFirstMessageId?: string;
5
- };
@@ -1 +0,0 @@
1
- {"version":3,"file":"contents-result.js","sourceRoot":"","sources":["../../../src/action/contents-result.ts"],"names":[],"mappings":""}
@@ -1,22 +0,0 @@
1
- import type { FlowBuilderContentsResult } from './contents-result';
2
- import type { FlowBuilderContext } from './context';
3
- export declare enum PushFlowErrorCode {
4
- NoInputPayload = "NoInputPayload",
5
- NoPushFlowId = "NoPushFlowId",
6
- NoCampaignStartNode = "NoCampaignStartNode",
7
- NoCampaignId = "NoCampaignId"
8
- }
9
- export declare class PushFlowError extends Error {
10
- readonly code: PushFlowErrorCode;
11
- constructor(code: PushFlowErrorCode, reason: string);
12
- }
13
- export declare class PushFlowResolver {
14
- private botContext;
15
- private cmsApi;
16
- private flowBuilderPlugin;
17
- constructor(context: FlowBuilderContext);
18
- getContents(): Promise<FlowBuilderContentsResult>;
19
- private getPushFlowId;
20
- private getPushFlowNode;
21
- private getCampaignId;
22
- }
@@ -1,66 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PushFlowResolver = exports.PushFlowError = exports.PushFlowErrorCode = void 0;
4
- const constants_1 = require("../constants");
5
- var PushFlowErrorCode;
6
- (function (PushFlowErrorCode) {
7
- PushFlowErrorCode["NoInputPayload"] = "NoInputPayload";
8
- PushFlowErrorCode["NoPushFlowId"] = "NoPushFlowId";
9
- PushFlowErrorCode["NoCampaignStartNode"] = "NoCampaignStartNode";
10
- PushFlowErrorCode["NoCampaignId"] = "NoCampaignId";
11
- })(PushFlowErrorCode || (exports.PushFlowErrorCode = PushFlowErrorCode = {}));
12
- class PushFlowError extends Error {
13
- constructor(code, reason) {
14
- super(`push-flow failed: ${reason}`);
15
- this.code = code;
16
- this.name = 'PushFlowError';
17
- }
18
- }
19
- exports.PushFlowError = PushFlowError;
20
- class PushFlowResolver {
21
- constructor(context) {
22
- this.botContext = context.request;
23
- this.cmsApi = context.cmsApi;
24
- this.flowBuilderPlugin = context.flowBuilderPlugin;
25
- }
26
- async getContents() {
27
- const pushFlowId = this.getPushFlowId();
28
- const pushFlowNode = this.getPushFlowNode(pushFlowId);
29
- const campaignId = this.getCampaignId();
30
- return {
31
- contents: await this.flowBuilderPlugin.getContentsByNode(pushFlowNode),
32
- campaignFirstMessageId: campaignId,
33
- };
34
- }
35
- getPushFlowId() {
36
- const payload = this.botContext.input.payload;
37
- if (!payload) {
38
- throw new PushFlowError(PushFlowErrorCode.NoInputPayload, 'No payload found in input');
39
- }
40
- const parts = payload.split(constants_1.SEPARATOR);
41
- const pushFlowId = parts.length > 1 ? parts[1] : '';
42
- if (!pushFlowId) {
43
- throw new PushFlowError(PushFlowErrorCode.NoPushFlowId, 'No push flow id found in input payload');
44
- }
45
- return pushFlowId;
46
- }
47
- getPushFlowNode(pushFlowId) {
48
- const pushFlowNode = this.cmsApi.getNodeByCampaignId(pushFlowId);
49
- if (!pushFlowNode) {
50
- throw new PushFlowError(PushFlowErrorCode.NoCampaignStartNode, 'No campaign start node found');
51
- }
52
- return pushFlowNode;
53
- }
54
- getCampaignId() {
55
- const campaignId = this.botContext.input.context &&
56
- 'campaign_id' in this.botContext.input.context
57
- ? this.botContext.input.context.campaign_id
58
- : undefined;
59
- if (!campaignId) {
60
- throw new PushFlowError(PushFlowErrorCode.NoCampaignId, 'No campaign id found in input context');
61
- }
62
- return campaignId;
63
- }
64
- }
65
- exports.PushFlowResolver = PushFlowResolver;
66
- //# sourceMappingURL=push-flow-resolver.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"push-flow-resolver.js","sourceRoot":"","sources":["../../../src/action/push-flow-resolver.ts"],"names":[],"mappings":";;;AAEA,4CAAwC;AAMxC,IAAY,iBAKX;AALD,WAAY,iBAAiB;IAC3B,sDAAiC,CAAA;IACjC,kDAA6B,CAAA;IAC7B,gEAA2C,CAAA;IAC3C,kDAA6B,CAAA;AAC/B,CAAC,EALW,iBAAiB,iCAAjB,iBAAiB,QAK5B;AAED,MAAa,aAAc,SAAQ,KAAK;IAGtC,YAAY,IAAuB,EAAE,MAAc;QACjD,KAAK,CAAC,qBAAqB,MAAM,EAAE,CAAC,CAAA;QACpC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,IAAI,GAAG,eAAe,CAAA;IAC7B,CAAC;CACF;AARD,sCAQC;AAED,MAAa,gBAAgB;IAK3B,YAAY,OAA2B;QACrC,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,OAAO,CAAA;QACjC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;QAC5B,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAA;IACpD,CAAC;IAED,KAAK,CAAC,WAAW;QACf,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,EAAE,CAAA;QACvC,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,CAAA;QACrD,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,EAAE,CAAA;QAEvC,OAAO;YACL,QAAQ,EAAE,MAAM,IAAI,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,YAAY,CAAC;YACtE,sBAAsB,EAAE,UAAU;SACnC,CAAA;IACH,CAAC;IAEO,aAAa;QACnB,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAA;QAE7C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,aAAa,CACrB,iBAAiB,CAAC,cAAc,EAChC,2BAA2B,CAC5B,CAAA;QACH,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,qBAAS,CAAC,CAAA;QACtC,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QAEnD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,aAAa,CACrB,iBAAiB,CAAC,YAAY,EAC9B,wCAAwC,CACzC,CAAA;QACH,CAAC;QAED,OAAO,UAAU,CAAA;IACnB,CAAC;IAEO,eAAe,CAAC,UAAkB;QACxC,MAAM,YAAY,GAChB,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAoB,UAAU,CAAC,CAAA;QAEhE,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,IAAI,aAAa,CACrB,iBAAiB,CAAC,mBAAmB,EACrC,8BAA8B,CAC/B,CAAA;QACH,CAAC;QAED,OAAO,YAAY,CAAA;IACrB,CAAC;IAEO,aAAa;QACnB,MAAM,UAAU,GACd,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO;YAC7B,aAAa,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO;YAC5C,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW;YAC3C,CAAC,CAAC,SAAS,CAAA;QAEf,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,aAAa,CACrB,iBAAiB,CAAC,YAAY,EAC9B,uCAAuC,CACxC,CAAA;QACH,CAAC;QAED,OAAO,UAAU,CAAA;IACnB,CAAC;CACF;AA3ED,4CA2EC"}
@@ -1,5 +0,0 @@
1
- import type { FlowContent } from '../content-fields';
2
- export type FlowBuilderContentsResult = {
3
- contents: FlowContent[];
4
- campaignFirstMessageId?: string;
5
- };
@@ -1 +0,0 @@
1
- {"version":3,"file":"contents-result.js","sourceRoot":"","sources":["../../../src/action/contents-result.ts"],"names":[],"mappings":""}
@@ -1,22 +0,0 @@
1
- import type { FlowBuilderContentsResult } from './contents-result';
2
- import type { FlowBuilderContext } from './context';
3
- export declare enum PushFlowErrorCode {
4
- NoInputPayload = "NoInputPayload",
5
- NoPushFlowId = "NoPushFlowId",
6
- NoCampaignStartNode = "NoCampaignStartNode",
7
- NoCampaignId = "NoCampaignId"
8
- }
9
- export declare class PushFlowError extends Error {
10
- readonly code: PushFlowErrorCode;
11
- constructor(code: PushFlowErrorCode, reason: string);
12
- }
13
- export declare class PushFlowResolver {
14
- private botContext;
15
- private cmsApi;
16
- private flowBuilderPlugin;
17
- constructor(context: FlowBuilderContext);
18
- getContents(): Promise<FlowBuilderContentsResult>;
19
- private getPushFlowId;
20
- private getPushFlowNode;
21
- private getCampaignId;
22
- }
@@ -1,66 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PushFlowResolver = exports.PushFlowError = exports.PushFlowErrorCode = void 0;
4
- const constants_1 = require("../constants");
5
- var PushFlowErrorCode;
6
- (function (PushFlowErrorCode) {
7
- PushFlowErrorCode["NoInputPayload"] = "NoInputPayload";
8
- PushFlowErrorCode["NoPushFlowId"] = "NoPushFlowId";
9
- PushFlowErrorCode["NoCampaignStartNode"] = "NoCampaignStartNode";
10
- PushFlowErrorCode["NoCampaignId"] = "NoCampaignId";
11
- })(PushFlowErrorCode || (exports.PushFlowErrorCode = PushFlowErrorCode = {}));
12
- class PushFlowError extends Error {
13
- constructor(code, reason) {
14
- super(`push-flow failed: ${reason}`);
15
- this.code = code;
16
- this.name = 'PushFlowError';
17
- }
18
- }
19
- exports.PushFlowError = PushFlowError;
20
- class PushFlowResolver {
21
- constructor(context) {
22
- this.botContext = context.request;
23
- this.cmsApi = context.cmsApi;
24
- this.flowBuilderPlugin = context.flowBuilderPlugin;
25
- }
26
- async getContents() {
27
- const pushFlowId = this.getPushFlowId();
28
- const pushFlowNode = this.getPushFlowNode(pushFlowId);
29
- const campaignId = this.getCampaignId();
30
- return {
31
- contents: await this.flowBuilderPlugin.getContentsByNode(pushFlowNode),
32
- campaignFirstMessageId: campaignId,
33
- };
34
- }
35
- getPushFlowId() {
36
- const payload = this.botContext.input.payload;
37
- if (!payload) {
38
- throw new PushFlowError(PushFlowErrorCode.NoInputPayload, 'No payload found in input');
39
- }
40
- const parts = payload.split(constants_1.SEPARATOR);
41
- const pushFlowId = parts.length > 1 ? parts[1] : '';
42
- if (!pushFlowId) {
43
- throw new PushFlowError(PushFlowErrorCode.NoPushFlowId, 'No push flow id found in input payload');
44
- }
45
- return pushFlowId;
46
- }
47
- getPushFlowNode(pushFlowId) {
48
- const pushFlowNode = this.cmsApi.getNodeByCampaignId(pushFlowId);
49
- if (!pushFlowNode) {
50
- throw new PushFlowError(PushFlowErrorCode.NoCampaignStartNode, 'No campaign start node found');
51
- }
52
- return pushFlowNode;
53
- }
54
- getCampaignId() {
55
- const campaignId = this.botContext.input.context &&
56
- 'campaign_id' in this.botContext.input.context
57
- ? this.botContext.input.context.campaign_id
58
- : undefined;
59
- if (!campaignId) {
60
- throw new PushFlowError(PushFlowErrorCode.NoCampaignId, 'No campaign id found in input context');
61
- }
62
- return campaignId;
63
- }
64
- }
65
- exports.PushFlowResolver = PushFlowResolver;
66
- //# sourceMappingURL=push-flow-resolver.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"push-flow-resolver.js","sourceRoot":"","sources":["../../../src/action/push-flow-resolver.ts"],"names":[],"mappings":";;;AAEA,4CAAwC;AAMxC,IAAY,iBAKX;AALD,WAAY,iBAAiB;IAC3B,sDAAiC,CAAA;IACjC,kDAA6B,CAAA;IAC7B,gEAA2C,CAAA;IAC3C,kDAA6B,CAAA;AAC/B,CAAC,EALW,iBAAiB,iCAAjB,iBAAiB,QAK5B;AAED,MAAa,aAAc,SAAQ,KAAK;IAGtC,YAAY,IAAuB,EAAE,MAAc;QACjD,KAAK,CAAC,qBAAqB,MAAM,EAAE,CAAC,CAAA;QACpC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,IAAI,GAAG,eAAe,CAAA;IAC7B,CAAC;CACF;AARD,sCAQC;AAED,MAAa,gBAAgB;IAK3B,YAAY,OAA2B;QACrC,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,OAAO,CAAA;QACjC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;QAC5B,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAA;IACpD,CAAC;IAED,KAAK,CAAC,WAAW;QACf,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,EAAE,CAAA;QACvC,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,CAAA;QACrD,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,EAAE,CAAA;QAEvC,OAAO;YACL,QAAQ,EAAE,MAAM,IAAI,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,YAAY,CAAC;YACtE,sBAAsB,EAAE,UAAU;SACnC,CAAA;IACH,CAAC;IAEO,aAAa;QACnB,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAA;QAE7C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,aAAa,CACrB,iBAAiB,CAAC,cAAc,EAChC,2BAA2B,CAC5B,CAAA;QACH,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,qBAAS,CAAC,CAAA;QACtC,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QAEnD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,aAAa,CACrB,iBAAiB,CAAC,YAAY,EAC9B,wCAAwC,CACzC,CAAA;QACH,CAAC;QAED,OAAO,UAAU,CAAA;IACnB,CAAC;IAEO,eAAe,CAAC,UAAkB;QACxC,MAAM,YAAY,GAChB,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAoB,UAAU,CAAC,CAAA;QAEhE,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,IAAI,aAAa,CACrB,iBAAiB,CAAC,mBAAmB,EACrC,8BAA8B,CAC/B,CAAA;QACH,CAAC;QAED,OAAO,YAAY,CAAA;IACrB,CAAC;IAEO,aAAa;QACnB,MAAM,UAAU,GACd,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO;YAC7B,aAAa,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO;YAC5C,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW;YAC3C,CAAC,CAAC,SAAS,CAAA;QAEf,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,aAAa,CACrB,iBAAiB,CAAC,YAAY,EAC9B,uCAAuC,CACxC,CAAA;QACH,CAAC;QAED,OAAO,UAAU,CAAA;IACnB,CAAC;CACF;AA3ED,4CA2EC"}
@@ -1,6 +0,0 @@
1
- import type { FlowContent } from '../content-fields'
2
-
3
- export type FlowBuilderContentsResult = {
4
- contents: FlowContent[]
5
- campaignFirstMessageId?: string
6
- }
@@ -1,101 +0,0 @@
1
- import type { BotContext } from '@botonic/core'
2
- import type { FlowBuilderApi } from '../api'
3
- import { SEPARATOR } from '../constants'
4
- import type { HtNodeWithContent } from '../content-fields/hubtype-fields'
5
- import type BotonicPluginFlowBuilder from '../index'
6
- import type { FlowBuilderContentsResult } from './contents-result'
7
- import type { FlowBuilderContext } from './context'
8
-
9
- export enum PushFlowErrorCode {
10
- NoInputPayload = 'NoInputPayload',
11
- NoPushFlowId = 'NoPushFlowId',
12
- NoCampaignStartNode = 'NoCampaignStartNode',
13
- NoCampaignId = 'NoCampaignId',
14
- }
15
-
16
- export class PushFlowError extends Error {
17
- readonly code: PushFlowErrorCode
18
-
19
- constructor(code: PushFlowErrorCode, reason: string) {
20
- super(`push-flow failed: ${reason}`)
21
- this.code = code
22
- this.name = 'PushFlowError'
23
- }
24
- }
25
-
26
- export class PushFlowResolver {
27
- private botContext: BotContext
28
- private cmsApi: FlowBuilderApi
29
- private flowBuilderPlugin: BotonicPluginFlowBuilder
30
-
31
- constructor(context: FlowBuilderContext) {
32
- this.botContext = context.request
33
- this.cmsApi = context.cmsApi
34
- this.flowBuilderPlugin = context.flowBuilderPlugin
35
- }
36
-
37
- async getContents(): Promise<FlowBuilderContentsResult> {
38
- const pushFlowId = this.getPushFlowId()
39
- const pushFlowNode = this.getPushFlowNode(pushFlowId)
40
- const campaignId = this.getCampaignId()
41
-
42
- return {
43
- contents: await this.flowBuilderPlugin.getContentsByNode(pushFlowNode),
44
- campaignFirstMessageId: campaignId,
45
- }
46
- }
47
-
48
- private getPushFlowId(): string {
49
- const payload = this.botContext.input.payload
50
-
51
- if (!payload) {
52
- throw new PushFlowError(
53
- PushFlowErrorCode.NoInputPayload,
54
- 'No payload found in input'
55
- )
56
- }
57
-
58
- const parts = payload.split(SEPARATOR)
59
- const pushFlowId = parts.length > 1 ? parts[1] : ''
60
-
61
- if (!pushFlowId) {
62
- throw new PushFlowError(
63
- PushFlowErrorCode.NoPushFlowId,
64
- 'No push flow id found in input payload'
65
- )
66
- }
67
-
68
- return pushFlowId
69
- }
70
-
71
- private getPushFlowNode(pushFlowId: string): HtNodeWithContent {
72
- const pushFlowNode =
73
- this.cmsApi.getNodeByCampaignId<HtNodeWithContent>(pushFlowId)
74
-
75
- if (!pushFlowNode) {
76
- throw new PushFlowError(
77
- PushFlowErrorCode.NoCampaignStartNode,
78
- 'No campaign start node found'
79
- )
80
- }
81
-
82
- return pushFlowNode
83
- }
84
-
85
- private getCampaignId(): string {
86
- const campaignId =
87
- this.botContext.input.context &&
88
- 'campaign_id' in this.botContext.input.context
89
- ? this.botContext.input.context.campaign_id
90
- : undefined
91
-
92
- if (!campaignId) {
93
- throw new PushFlowError(
94
- PushFlowErrorCode.NoCampaignId,
95
- 'No campaign id found in input context'
96
- )
97
- }
98
-
99
- return campaignId
100
- }
101
- }