@whitewall/blip-sdk 0.0.173 → 0.0.175

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 (131) hide show
  1. package/README.md +13 -6
  2. package/dist/cjs/client.js +3 -0
  3. package/dist/cjs/client.js.map +1 -1
  4. package/dist/cjs/index.js +3 -0
  5. package/dist/cjs/index.js.map +1 -1
  6. package/dist/cjs/namespaces/account.js +23 -11
  7. package/dist/cjs/namespaces/account.js.map +1 -1
  8. package/dist/cjs/namespaces/analytics.js +54 -0
  9. package/dist/cjs/namespaces/analytics.js.map +1 -1
  10. package/dist/cjs/namespaces/desk.js +264 -45
  11. package/dist/cjs/namespaces/desk.js.map +1 -1
  12. package/dist/cjs/namespaces/plugins.js +1 -0
  13. package/dist/cjs/namespaces/plugins.js.map +1 -1
  14. package/dist/cjs/namespaces/portal.js +45 -0
  15. package/dist/cjs/namespaces/portal.js.map +1 -1
  16. package/dist/cjs/namespaces/tunnel.js +46 -0
  17. package/dist/cjs/namespaces/tunnel.js.map +1 -0
  18. package/dist/cjs/namespaces/whatsapp.js +2 -23
  19. package/dist/cjs/namespaces/whatsapp.js.map +1 -1
  20. package/dist/cjs/sender/multi/multisender.js +28 -9
  21. package/dist/cjs/sender/multi/multisender.js.map +1 -1
  22. package/dist/cjs/sender/sessionnegotiator.js +1 -1
  23. package/dist/cjs/sender/sessionnegotiator.js.map +1 -1
  24. package/dist/cjs/sender/tcp/tcpsender.js +35 -2
  25. package/dist/cjs/sender/tcp/tcpsender.js.map +1 -1
  26. package/dist/cjs/sender/websocket/websocketsender.js +1 -1
  27. package/dist/cjs/sender/websocket/websocketsender.js.map +1 -1
  28. package/dist/cjs/types/desk.js.map +1 -1
  29. package/dist/cjs/types/flow.js +344 -0
  30. package/dist/cjs/types/flow.js.map +1 -1
  31. package/dist/cjs/utils/desk.js +65 -0
  32. package/dist/cjs/utils/desk.js.map +1 -0
  33. package/dist/cjs/utils/thread.js +84 -0
  34. package/dist/cjs/utils/thread.js.map +1 -0
  35. package/dist/cjs/utils/whatsapp.js +268 -0
  36. package/dist/cjs/utils/whatsapp.js.map +1 -0
  37. package/dist/esm/client.js +3 -0
  38. package/dist/esm/client.js.map +1 -1
  39. package/dist/esm/index.js +3 -0
  40. package/dist/esm/index.js.map +1 -1
  41. package/dist/esm/namespaces/account.js +19 -10
  42. package/dist/esm/namespaces/account.js.map +1 -1
  43. package/dist/esm/namespaces/analytics.js +54 -0
  44. package/dist/esm/namespaces/analytics.js.map +1 -1
  45. package/dist/esm/namespaces/desk.js +264 -45
  46. package/dist/esm/namespaces/desk.js.map +1 -1
  47. package/dist/esm/namespaces/plugins.js +1 -0
  48. package/dist/esm/namespaces/plugins.js.map +1 -1
  49. package/dist/esm/namespaces/portal.js +45 -0
  50. package/dist/esm/namespaces/portal.js.map +1 -1
  51. package/dist/esm/namespaces/tunnel.js +42 -0
  52. package/dist/esm/namespaces/tunnel.js.map +1 -0
  53. package/dist/esm/namespaces/whatsapp.js +2 -23
  54. package/dist/esm/namespaces/whatsapp.js.map +1 -1
  55. package/dist/esm/sender/multi/multisender.js +28 -9
  56. package/dist/esm/sender/multi/multisender.js.map +1 -1
  57. package/dist/esm/sender/sessionnegotiator.js +1 -1
  58. package/dist/esm/sender/sessionnegotiator.js.map +1 -1
  59. package/dist/esm/sender/tcp/tcpsender.js +1 -1
  60. package/dist/esm/sender/tcp/tcpsender.js.map +1 -1
  61. package/dist/esm/sender/websocket/websocketsender.js +1 -1
  62. package/dist/esm/sender/websocket/websocketsender.js.map +1 -1
  63. package/dist/esm/types/desk.js.map +1 -1
  64. package/dist/esm/types/flow.js +343 -1
  65. package/dist/esm/types/flow.js.map +1 -1
  66. package/dist/esm/utils/desk.js +59 -0
  67. package/dist/esm/utils/desk.js.map +1 -0
  68. package/dist/esm/utils/thread.js +80 -0
  69. package/dist/esm/utils/thread.js.map +1 -0
  70. package/dist/esm/utils/whatsapp.js +263 -0
  71. package/dist/esm/utils/whatsapp.js.map +1 -0
  72. package/dist/types/client.d.ts +2 -0
  73. package/dist/types/client.d.ts.map +1 -1
  74. package/dist/types/index.d.ts +3 -0
  75. package/dist/types/index.d.ts.map +1 -1
  76. package/dist/types/namespaces/account.d.ts +1791 -3
  77. package/dist/types/namespaces/account.d.ts.map +1 -1
  78. package/dist/types/namespaces/analytics.d.ts +60 -0
  79. package/dist/types/namespaces/analytics.d.ts.map +1 -1
  80. package/dist/types/namespaces/desk.d.ts +124 -4
  81. package/dist/types/namespaces/desk.d.ts.map +1 -1
  82. package/dist/types/namespaces/plugins.d.ts +1 -0
  83. package/dist/types/namespaces/plugins.d.ts.map +1 -1
  84. package/dist/types/namespaces/portal.d.ts +45 -0
  85. package/dist/types/namespaces/portal.d.ts.map +1 -1
  86. package/dist/types/namespaces/tunnel.d.ts +28 -0
  87. package/dist/types/namespaces/tunnel.d.ts.map +1 -0
  88. package/dist/types/namespaces/whatsapp.d.ts +3 -2
  89. package/dist/types/namespaces/whatsapp.d.ts.map +1 -1
  90. package/dist/types/schemas/webhook.d.ts +2 -2
  91. package/dist/types/sender/gateway/customgatewaysender.d.ts +1 -1
  92. package/dist/types/sender/http/httpsender.d.ts +1 -1
  93. package/dist/types/sender/multi/multisender.d.ts +1 -0
  94. package/dist/types/sender/multi/multisender.d.ts.map +1 -1
  95. package/dist/types/sender/sender.d.ts +1 -1
  96. package/dist/types/sender/tcp/tcpsender.d.ts +1 -1
  97. package/dist/types/sender/websocket/websocketsender.d.ts +1 -1
  98. package/dist/types/types/desk.d.ts +57 -1
  99. package/dist/types/types/desk.d.ts.map +1 -1
  100. package/dist/types/types/flow.d.ts +3269 -142
  101. package/dist/types/types/flow.d.ts.map +1 -1
  102. package/dist/types/types/message.d.ts +1 -1
  103. package/dist/types/types/whatsapp.d.ts +10 -2
  104. package/dist/types/types/whatsapp.d.ts.map +1 -1
  105. package/dist/types/utils/desk.d.ts +6 -0
  106. package/dist/types/utils/desk.d.ts.map +1 -0
  107. package/dist/types/utils/thread.d.ts +4 -0
  108. package/dist/types/utils/thread.d.ts.map +1 -0
  109. package/dist/types/utils/whatsapp.d.ts +103 -0
  110. package/dist/types/utils/whatsapp.d.ts.map +1 -0
  111. package/package.json +8 -11
  112. package/src/client.ts +3 -0
  113. package/src/index.ts +3 -0
  114. package/src/namespaces/account.ts +27 -13
  115. package/src/namespaces/analytics.ts +154 -0
  116. package/src/namespaces/desk.ts +428 -77
  117. package/src/namespaces/plugins.ts +2 -0
  118. package/src/namespaces/portal.ts +110 -0
  119. package/src/namespaces/tunnel.ts +58 -0
  120. package/src/namespaces/whatsapp.ts +4 -39
  121. package/src/sender/multi/multisender.ts +38 -14
  122. package/src/sender/sessionnegotiator.ts +1 -1
  123. package/src/sender/tcp/tcpsender.ts +1 -1
  124. package/src/sender/websocket/websocketsender.ts +1 -1
  125. package/src/types/desk.ts +66 -1
  126. package/src/types/flow.ts +387 -246
  127. package/src/types/message.ts +1 -1
  128. package/src/types/whatsapp.ts +11 -2
  129. package/src/utils/desk.ts +78 -0
  130. package/src/utils/thread.ts +119 -0
  131. package/src/utils/whatsapp.ts +530 -0
package/src/types/flow.ts CHANGED
@@ -1,254 +1,393 @@
1
- import type { MessageTypesContent } from './message.ts'
1
+ import { z } from 'zod'
2
2
 
3
- type SendMessageActionSettings = {
4
- $invalid?: boolean
5
- id: string
6
- type: keyof MessageTypesContent
7
- content: MessageTypesContent[keyof MessageTypesContent]
8
- }
3
+ const VALIDATION_RULES = ['text', 'number', 'date', 'regex', 'type'] as const
4
+ export const CONTENT_TYPES = [
5
+ 'text',
6
+ 'select-immediate',
7
+ 'select',
8
+ 'media',
9
+ 'media-audio',
10
+ 'media-video',
11
+ 'media-document',
12
+ 'chat-state',
13
+ 'web-link',
14
+ 'raw-content',
15
+ '',
16
+ ] as const
17
+ export const MIME_TYPES = [
18
+ 'text/plain',
19
+ 'application/vnd.lime.media-link+json',
20
+ 'application/vnd.lime.select+json',
21
+ 'application/vnd.lime.chatstate+json',
22
+ 'application/vnd.lime.web-link+json',
23
+ ] as const
24
+ const HTTP_METHODS = ['POST', 'GET', 'PUT', 'DELETE'] as const
25
+ const COMPARISON_OPERATORS = [
26
+ 'equals',
27
+ 'notEquals',
28
+ 'contains',
29
+ 'startsWith',
30
+ 'endsWith',
31
+ 'greaterThan',
32
+ 'lessThan',
33
+ 'greaterThanOrEquals',
34
+ 'lessThanOrEquals',
35
+ 'matches',
36
+ 'approximateTo',
37
+ 'exists',
38
+ 'notExists',
39
+ ] as const
40
+ const SELECT_SCOPES = ['immediate', 'persistent'] as const
41
+ const LINK_TARGETS = ['blank', 'self', 'selfCompact', 'selfTall'] as const
42
+ const COMMAND_METHODS = ['get', 'set', 'merge', 'delete'] as const
43
+ const CONDITION_SOURCES = ['input', 'context'] as const
44
+ const LOGICAL_OPERATORS = ['or', 'and'] as const
45
+ const TYPE_OF_STATE_ID = ['state', 'variable'] as const
9
46
 
10
- type ProcessHttpActionSettings = {
11
- $invalid?: boolean
12
- method: 'POST' | 'GET' | 'PUT' | 'DELETE'
13
- // The URL to be called, you can use variables in the URL, for example: https://api.example.com/{{contact.email}}
14
- uri: string
15
- // The headers to be sent in the request. You can use variables in the headers, for example: Authorization: Bearer {{config.token}}
16
- headers: Record<string, string>
17
- // The body of the request. You can use variables in the body, for example: { "email": "{{contact.email}}" }
18
- body: string
19
- responseBodyVariable: string
20
- responseStatusVariable: string
21
- }
47
+ const createVariableNameSchema = (description: string) => z.string().describe(description)
22
48
 
23
- type TrackEventActionSettings = {
24
- $invalid?: boolean
25
- category: string
26
- action: string
27
- extras: Record<string, string>
28
- }
49
+ const plainTextSchema = z.string()
29
50
 
30
- type MergeContactActionSettings = {
31
- $invalid?: boolean
32
- name: string
33
- email: string
34
- city: string
35
- extras: Record<string, string>
36
- }
51
+ const mediaLinkSchema = z.object({
52
+ title: z.string().optional(),
53
+ text: z.string().optional(),
54
+ // Mime type of the linked content.
55
+ type: z.string().describe('Mime type of the content'),
56
+ uri: z.string(),
57
+ })
37
58
 
38
- type ExecuteScriptActionSettings = {
39
- $invalid?: boolean
40
- function: 'run'
41
- // It should be a valid ES5 code
42
- source: string
43
- // The input variables that will be passed to the function, you must not use the {{ variableName }} syntax or @ syntax here, just the variable name
44
- // Can be a context variable or any other special variable
45
- inputVariables: Array<string>
46
- // The context variable name to store the returned result of the function
47
- outputVariable: string
48
- }
59
+ const selectSchema = z.object({
60
+ text: z.string(),
61
+ scope: z.enum(SELECT_SCOPES).nullish(),
62
+ // Builder accepts both simple string options and object options.
63
+ options: z.array(z.string()).or(
64
+ z.array(
65
+ z.object({
66
+ text: z.string(),
67
+ }),
68
+ ),
69
+ ),
70
+ })
49
71
 
50
- type SendRawMessageActionSettings = {
51
- $invalid?: boolean
52
- type: 'application/json'
53
- // Useful to send raw content to the user, like raw whatsapp messages
54
- // Example: {"recipient_type": "individual","type": "interactive","interactive": {"type": "button","body": {"text": "..."},"action": {"buttons": [...]}}}
55
- rawContent: string
56
- }
72
+ const chatstateSchema = z.object({
73
+ state: z.string(),
74
+ interval: z.union([z.number(), z.string()]).optional(),
75
+ })
57
76
 
58
- type SetVariableActionSettings = {
59
- $invalid?: boolean
60
- variable: string
61
- value: string
62
- // Expiration time of the variable in seconds, if unsure, don't set it
63
- expiration?: number
64
- }
77
+ const webLinkSchema = z.object({
78
+ title: z.string().nullish(),
79
+ text: z.string(),
80
+ target: z.enum(LINK_TARGETS).nullish(),
81
+ uri: z.string(),
82
+ })
65
83
 
66
- type TypeOfStateId = 'state' | 'variable'
67
-
68
- export type Condition = {
69
- source: 'input' | 'context'
70
- // The variable name of the conversation context to be evaluated, if the 'source' value is 'context'
71
- variable?: string
72
- // The type of the comparison. Optional. The default value is 'equals'
73
- comparison:
74
- | 'equals'
75
- | 'notEquals'
76
- | 'contains'
77
- | 'startsWith'
78
- | 'endsWith'
79
- | 'greaterThan'
80
- | 'lessThan'
81
- | 'greaterThanOrEquals'
82
- | 'lessThanOrEquals'
83
- | 'matches'
84
- | 'approximateTo'
85
- | 'exists'
86
- | 'notExists'
87
- // The operator for comparison with the provided values. The default value is 'or'
88
- operator?: 'or' | 'and'
89
- values: Array<string>
90
- }
84
+ const flowMessageContentSchema = plainTextSchema
85
+ .or(mediaLinkSchema)
86
+ .or(selectSchema)
87
+ .or(webLinkSchema)
88
+ .or(chatstateSchema)
91
89
 
92
- export type Action = {
93
- $id: string
94
- // The type of content should only exists if the action is of type SendMessage or SendRawMessage
95
- // It should match the content type of the action settings
96
- $typeOfContent?: // if don`t exists is set with empty string in GET
97
- | ''
98
- // type = text/plain
99
- | 'text'
100
- // type = application/vnd.lime.select+json
101
- // content.scope = immediate
102
- | 'select-immediate'
103
- // content.scope = persistent
104
- | 'select'
105
- // type = application/vnd.lime.media-link+json
106
- // content.type = image/png, image/jpeg, image/gif
107
- | 'media'
108
- // content.type = audio/mpeg, audio/wav, audio/ogg
109
- | 'media-audio'
110
- // content.type = video/mp4
111
- | 'media-video'
112
- // content.type = application/pdf
113
- | 'media-document'
114
- // type = application/vnd.lime.chatstate+json
115
- | 'chat-state'
116
- // type = application/vnd.lime.web-link+json
117
- | 'web-link'
118
- // type = application/json
119
- // Should be used only for SendRawMessage action
120
- | 'raw-content'
121
- // The type of the action to be executed
122
- type: // Send a message to the user
123
- | 'SendMessage'
124
- // Send a raw message to the user, useful to send whatsapp content
125
- | 'SendRawMessage'
126
- // Track an event in the conversation
127
- | 'TrackEvent'
128
- // Process an HTTP request
129
- | 'ProcessHttp'
130
- // Update the contact information of the user
131
- | 'MergeContact'
132
- // Execute a ES5 script
133
- | 'ExecuteScript'
134
- // Set a variable in the context
135
- | 'SetVariable'
136
- | 'ForwardToDesk'
137
- | 'LeavingFromDesk'
138
- $title?: string
139
- $invalid?: boolean
140
- // The matching settings of the action type
141
- settings:
142
- | SendMessageActionSettings
143
- | SendRawMessageActionSettings
144
- | TrackEventActionSettings
145
- | ProcessHttpActionSettings
146
- | MergeContactActionSettings
147
- | ExecuteScriptActionSettings
148
- | SetVariableActionSettings
149
- | Record<string, never>
150
- // Must always be set if the action is of type SendMessage or SendRawMessage
151
- // If other action type, it must be null
152
- $cardContent?: {
153
- document: {
154
- id: string
155
- // Should always be the same of settings.type
156
- type: keyof MessageTypesContent | 'application/json'
157
- // The content of the message, it should be the same of settings.content
158
- content: MessageTypesContent[keyof MessageTypesContent] | string
159
- textContent?: string
160
- }
161
- editable: boolean
162
- deletable: boolean
163
- position: 'left'
164
- }
165
- conditions?: Array<Condition>
166
- }
90
+ const processHttpActionSettingsSchema = z.object({
91
+ $invalid: z.boolean().optional(),
92
+ method: z.enum(HTTP_METHODS),
93
+ // The URL to be called. Variables can be interpolated, for example:
94
+ // https://api.example.com/{{contact.email}}
95
+ uri: z.string(),
96
+ // The headers to be sent in the request. Variables can be interpolated too.
97
+ headers: z.record(z.string(), z.string()).nullish(),
98
+ // The body of the request. Variables can be interpolated in the body too.
99
+ body: z.string(),
100
+ // Context variable used to store the response body.
101
+ responseBodyVariable: createVariableNameSchema('Response body variable name'),
102
+ // Context variable used to store the response status.
103
+ responseStatusVariable: createVariableNameSchema('Response status variable name'),
104
+ })
167
105
 
168
- type InputState = {
169
- // Always same values, except for the document.id
170
- $cardContent: {
171
- document: {
172
- id: string
173
- type: 'text/plain'
174
- content?: 'Entrada do usuário'
175
- // Should always be the same of the variable name
176
- textContent?: string
177
- }
178
- editable: boolean
179
- editing: boolean
180
- deletable: boolean
181
- position: 'right'
182
- }
183
- $invalid: boolean
184
- bypass: boolean
185
- validation?: {
186
- // Gets or sets the validation rule to be used
187
- rule: 'text' | 'number' | 'date' | 'regex' | 'type'
188
- // The regular expression to be used in case of the 'rule' value is regex'
189
- regex?: string
190
- // The type to be used in case of the 'rule' value is 'type'
191
- type?: string
192
- // The error message text to be returned to the user in case of the input value is not valid accordingly to the defined rule
193
- error: string
194
- }
195
- // Input expiration time in minutes. If not set, the input will never expire. If unsure, don't set it
196
- expiration?: string
197
- variable?: string
198
- conditions?: Array<Condition>
199
- }
106
+ const trackEventActionSettingsSchema = z.object({
107
+ $invalid: z.boolean().optional(),
108
+ category: z.string(),
109
+ action: z.string(),
110
+ extras: z.record(z.string(), z.string()).nullish(),
111
+ })
200
112
 
201
- type Output = {
202
- // Id of the state to redirect
203
- stateId: string
204
- typeOfStateId?: TypeOfStateId
205
- $id?: string
206
- conditions: Array<Condition>
207
- $invalid?: boolean
208
- $isDeskOutput?: boolean
209
- $isDeskDefaultOutput?: boolean
210
- }
113
+ const mergeContactActionSettingsSchema = z.object({
114
+ $invalid: z.boolean().optional(),
115
+ name: z.string().nullish(),
116
+ email: z.string().nullish(),
117
+ city: z.string().nullish(),
118
+ extras: z.record(z.string(), z.string()).nullish(),
119
+ })
211
120
 
212
- export type State = {
213
- $contentActions: Array<{
214
- // The actions that would be executed after entering actions
215
- // All the actions here should be of type SendMessage
216
- // This is the only place that can have the SendMessage action
217
- action?: Action
218
- // If the state should have a user input, it should be defined here
219
- input?: InputState
220
- }>
221
- $conditionOutputs: Array<Output>
222
- // The actions that would be executed after entering the state
223
- $enteringCustomActions: Array<Action>
224
- // The actions that would be executed after leaving the state, before the output conditions
225
- $leavingCustomActions: Array<Action>
226
- $localCustomActions: Array<Action>
227
- $inputSuggestions: []
228
- $defaultOutput: Output
229
- isAiGenerated?: boolean
230
- deskStateVersion?: string
231
- $afterStateChangedActions?: Array<Action>
232
- $tags: Array<{
233
- id: string
234
- label: string
235
- // Hexadecimal color code of the tag, with # prefix
236
- background: string
237
- canChangeBackground: boolean
238
- }>
239
- id?: string
240
- // Only the special state with id "onbarding" has root as boolean
241
- root?: boolean
242
- $title: string
243
- $position?: {
244
- top: string
245
- left: string
246
- }
247
- $invalidContentActions: boolean
248
- $invalidOutputs: boolean
249
- $invalidCustomActions: boolean
250
- $invalid?: boolean
251
- }
121
+ const executeScriptActionSettingsSchema = z.object({
122
+ $invalid: z.boolean().optional(),
123
+ // Builder executes a function called "run".
124
+ function: z.literal('run').optional(),
125
+ // Must be valid ES5 source code.
126
+ source: z.string(),
127
+ // Variables are passed to the function in this declared order. Do not use
128
+ // the {{ variableName }} syntax here, only the plain variable name.
129
+ inputVariables: z.array(createVariableNameSchema('Variable name')),
130
+ // Context variable used to store the returned result.
131
+ outputVariable: createVariableNameSchema('Output variable name'),
132
+ })
133
+
134
+ const sendMessageActionSettingsSchema = z.object({
135
+ $invalid: z.boolean().optional(),
136
+ type: z.enum(MIME_TYPES).optional(),
137
+ content: flowMessageContentSchema,
138
+ // Message id generated by the builder.
139
+ id: z.string().optional(),
140
+ metadata: z.record(z.string(), z.string()).optional(),
141
+ })
142
+
143
+ const sendRawMessageActionSettingsSchema = z.object({
144
+ $invalid: z.boolean().optional(),
145
+ type: z.literal('application/json').optional(),
146
+ // Useful to send raw channel payloads, such as WhatsApp interactive content.
147
+ rawContent: z.string(),
148
+ })
149
+
150
+ const setVariableActionSettingsSchema = z.object({
151
+ $invalid: z.boolean().optional(),
152
+ variable: createVariableNameSchema('Name of the variable to be set in the context'),
153
+ value: z.union([z.string(), z.number()]).optional(),
154
+ // Expiration time in seconds.
155
+ expiration: z.number().nullish(),
156
+ })
157
+
158
+ const processCommandActionSettingsSchema = z.object({
159
+ $invalid: z.boolean().optional(),
160
+ to: z.string(),
161
+ method: z.enum(COMMAND_METHODS),
162
+ uri: z.string(),
163
+ variable: createVariableNameSchema('Variable name'),
164
+ from: z.string().optional(),
165
+ })
166
+
167
+ const forwardToDeskActionSettingsSchema = z.object({
168
+ $invalid: z.boolean().optional(),
169
+ })
170
+
171
+ const leavingFromDeskActionSettingsSchema = z.object({
172
+ $invalid: z.boolean().optional(),
173
+ })
174
+
175
+ const redirectActionSettingsSchema = z.object({
176
+ $invalid: z.boolean().optional(),
177
+ address: z.string(),
178
+ context: z.object({
179
+ type: z.literal('text/plain'),
180
+ value: z.string(),
181
+ }),
182
+ })
183
+
184
+ export const conditionSchema = z.object({
185
+ source: z.enum(CONDITION_SOURCES),
186
+ // Used only when source is "context".
187
+ variable: createVariableNameSchema('Context variable name').nullish(),
188
+ comparison: z.enum(COMPARISON_OPERATORS),
189
+ operator: z.enum(LOGICAL_OPERATORS).optional(),
190
+ values: z.array(z.string()),
191
+ })
192
+
193
+ const baseActionSchema = z.object({
194
+ $id: z.string(),
195
+ // Should only exist for SendMessage and SendRawMessage actions. When it is
196
+ // omitted, GET responses usually return an empty string.
197
+ $typeOfContent: z.enum(CONTENT_TYPES).optional(),
198
+ $title: z.string().optional(),
199
+ $invalid: z.boolean().optional(),
200
+ // The action runs only when its conditions are met.
201
+ conditions: z.array(conditionSchema).optional(),
202
+ $cardContent: z
203
+ .object({
204
+ editable: z.boolean(),
205
+ deletable: z.boolean(),
206
+ position: z.literal('left'),
207
+ document: z.object({
208
+ id: z.string(),
209
+ // Must match the type defined in the action settings.
210
+ type: z.enum(MIME_TYPES).or(z.literal('application/json')),
211
+ // Must match the content defined in the action settings.
212
+ content: flowMessageContentSchema.or(z.string()),
213
+ textContent: z.string().optional(),
214
+ }),
215
+ })
216
+ .nullish(),
217
+ // When true, execution continues even if the action fails.
218
+ continueOnError: z.boolean().optional(),
219
+ })
220
+
221
+ const actionTypeSchema = z.discriminatedUnion('type', [
222
+ z.object({
223
+ type: z.literal('SendMessage'),
224
+ settings: sendMessageActionSettingsSchema,
225
+ }),
226
+ z.object({
227
+ type: z.literal('SendRawMessage'),
228
+ settings: sendRawMessageActionSettingsSchema,
229
+ }),
230
+ z.object({
231
+ type: z.literal('TrackEvent'),
232
+ settings: trackEventActionSettingsSchema,
233
+ }),
234
+ z.object({
235
+ type: z.literal('ProcessHttp'),
236
+ settings: processHttpActionSettingsSchema,
237
+ }),
238
+ z.object({
239
+ type: z.literal('MergeContact'),
240
+ settings: mergeContactActionSettingsSchema,
241
+ }),
242
+ z.object({
243
+ type: z.literal('ExecuteScript'),
244
+ settings: executeScriptActionSettingsSchema,
245
+ }),
246
+ z.object({
247
+ type: z.literal('ExecuteScriptV2'),
248
+ settings: executeScriptActionSettingsSchema,
249
+ }),
250
+ z.object({
251
+ type: z.literal('SetVariable'),
252
+ settings: setVariableActionSettingsSchema,
253
+ }),
254
+ z.object({
255
+ type: z.literal('ProcessCommand'),
256
+ settings: processCommandActionSettingsSchema,
257
+ }),
258
+ z.object({
259
+ type: z.literal('ForwardToDesk'),
260
+ settings: forwardToDeskActionSettingsSchema,
261
+ }),
262
+ z.object({
263
+ type: z.literal('LeavingFromDesk'),
264
+ settings: leavingFromDeskActionSettingsSchema,
265
+ }),
266
+ z.object({
267
+ type: z.literal('Redirect'),
268
+ settings: redirectActionSettingsSchema,
269
+ }),
270
+ ])
271
+
272
+ export const actionSchema = z.intersection(baseActionSchema, actionTypeSchema)
273
+
274
+ const inputValidationSchema = z.object({
275
+ // Validation rule applied to the captured input.
276
+ rule: z.enum(VALIDATION_RULES),
277
+ regex: z.string().nullish(),
278
+ type: z.string().nullish(),
279
+ // Message shown when validation fails.
280
+ error: z.string(),
281
+ })
282
+
283
+ export const inputStateSchema = z.object({
284
+ // Builder card metadata shown in the editor. The values are usually fixed
285
+ // except for the nested document id.
286
+ $cardContent: z.object({
287
+ document: z.object({
288
+ id: z.string(),
289
+ type: z.literal('text/plain'),
290
+ // Builder commonly renders "Entrada do usuario" here.
291
+ content: z.string().optional(),
292
+ // Should usually match the variable name where the input is stored.
293
+ textContent: z.string().optional(),
294
+ }),
295
+ editable: z.boolean(),
296
+ editing: z.boolean(),
297
+ deletable: z.boolean(),
298
+ position: z.literal('right'),
299
+ }),
300
+ $invalid: z.boolean(),
301
+ // When true, the input step is skipped.
302
+ bypass: z.boolean(),
303
+ validation: inputValidationSchema.nullish(),
304
+ // Input expiration time in minutes.
305
+ expiration: z.string().nullish(),
306
+ variable: createVariableNameSchema('Input variable name').nullish(),
307
+ conditions: z.array(conditionSchema).optional(),
308
+ })
309
+
310
+ const baseOutputSchema = z.object({
311
+ // Id of the target state, or a variable id when typeOfStateId is "variable".
312
+ stateId: z.string(),
313
+ typeOfStateId: z.enum(TYPE_OF_STATE_ID).optional(),
314
+ })
315
+
316
+ export const conditionOutputSchema = baseOutputSchema.extend({
317
+ $id: z.string().optional(),
318
+ $invalid: z.boolean().optional(),
319
+ $connId: z.string().optional(),
320
+ $contentId: z.string().optional(),
321
+ $isDeskOutput: z.boolean().optional(),
322
+ $isDeskCustomOutput: z.boolean().optional(),
323
+ $isDeskDefaultOutput: z.boolean().optional(),
324
+ conditions: z.array(conditionSchema),
325
+ })
326
+
327
+ export const defaultOutputSchema = baseOutputSchema.extend({
328
+ $invalid: z.boolean().optional(),
329
+ })
330
+
331
+ export const contentActionItemSchema = z.object({
332
+ // Actions executed after entering actions. In practice, this is where
333
+ // builder stores SendMessage cards.
334
+ action: actionSchema.optional(),
335
+ // If the state expects user input, it should be defined here.
336
+ input: inputStateSchema.optional(),
337
+ $invalid: z.boolean().optional(),
338
+ })
339
+
340
+ export const stateSchema = z.object({
341
+ $contentActions: z.array(contentActionItemSchema),
342
+ $conditionOutputs: z.array(conditionOutputSchema),
343
+ // Actions executed when entering the state.
344
+ $enteringCustomActions: z.array(actionSchema),
345
+ // Actions executed when leaving the state, before output evaluation.
346
+ $leavingCustomActions: z.array(actionSchema),
347
+ $localCustomActions: z.array(actionSchema).optional(),
348
+ $inputSuggestions: z.array(z.string()),
349
+ // Output used when none of the conditional outputs are matched.
350
+ $defaultOutput: defaultOutputSchema,
351
+ isAiGenerated: z.boolean().optional(),
352
+ deskStateVersion: z.string().optional(),
353
+ $afterStateChangedActions: z.array(actionSchema).optional(),
354
+ $tags: z.array(
355
+ z.object({
356
+ id: z.string(),
357
+ label: z.string(),
358
+ // Hexadecimal color code including the "#" prefix.
359
+ background: z.string(),
360
+ canChangeBackground: z.boolean(),
361
+ }),
362
+ ),
363
+ id: z.string().optional(),
364
+ // Only the special state with id "onboarding" is usually marked as root.
365
+ root: z.boolean().optional(),
366
+ $title: z.string(),
367
+ $position: z
368
+ .object({
369
+ top: z.string(),
370
+ left: z.string(),
371
+ })
372
+ .optional(),
373
+ $invalidContentActions: z.boolean(),
374
+ $invalidOutputs: z.boolean(),
375
+ $invalidCustomActions: z.boolean(),
376
+ $invalid: z.boolean().optional(),
377
+ $whiteWallIntegration: z.unknown().optional(),
378
+ })
379
+
380
+ export const flowSchema = z.record(z.string(), stateSchema)
381
+
382
+ export type Condition = z.infer<typeof conditionSchema>
383
+ export type Action = z.infer<typeof actionSchema>
384
+ export type InputState = z.infer<typeof inputStateSchema>
385
+ export type ConditionOutput = z.infer<typeof conditionOutputSchema>
386
+ export type DefaultOutput = z.infer<typeof defaultOutputSchema>
387
+ export type ContentActionItem = z.infer<typeof contentActionItemSchema>
388
+ export type State = z.infer<typeof stateSchema>
389
+ export type Flow = z.infer<typeof flowSchema>
390
+ export type BuilderFlow = Flow
252
391
 
253
392
  export type BuilderConfiguration = {
254
393
  'builder:minimumIntentScore'?: string
@@ -256,9 +395,7 @@ export type BuilderConfiguration = {
256
395
  'builder:#localTimeZone'?: string
257
396
  } & Record<string, string | number>
258
397
 
259
- export type BuilderFlow = Record<'onboarding' | 'fallback' | string, State>
260
-
261
- // The history index is a number from 1 to 10, representing the last 10 publications
398
+ // The history index is a number from 1 to 10, representing the last 10 publications.
262
399
  export type HistoryIndex = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
263
400
 
264
401
  export type Publication = {
@@ -267,7 +404,7 @@ export type Publication = {
267
404
  }
268
405
 
269
406
  export type BuilderLatestPublications = {
270
- // The last publication its a rotate of 10
407
+ // The publication index rotates from 1 to 10.
271
408
  lastInsertedIndex: HistoryIndex
272
409
  isMoreOptionsActive: string
273
410
  publications: Array<Publication & { publishedAt: string; index: HistoryIndex }>
@@ -280,21 +417,25 @@ export type BuilderLatestPublication = {
280
417
  }
281
418
 
282
419
  type RecursivelyRemoveDollar<T> = T extends object
283
- ? T extends Array<infer U>
284
- ? Array<RecursivelyRemoveDollar<U>>
285
- : { [K in keyof T as K extends `$${string}` ? never : K]: RecursivelyRemoveDollar<T[K]> }
420
+ ? T extends Array<infer Item>
421
+ ? Array<RecursivelyRemoveDollar<Item>>
422
+ : { [Key in keyof T as Key extends `$${string}` ? never : Key]: RecursivelyRemoveDollar<T[Key]> }
286
423
  : T
287
424
 
425
+ type TypeOfStateId = (typeof TYPE_OF_STATE_ID)[number]
426
+
288
427
  export type StateApplication = {
289
428
  id: string
290
429
  root?: boolean
291
430
  name: string
431
+ deskStateVersion?: string
292
432
  inputActions: RecursivelyRemoveDollar<Array<Action>>
293
433
  input: RecursivelyRemoveDollar<InputState>
294
434
  outputActions: RecursivelyRemoveDollar<Array<Action>>
295
435
  afterStateChangedActions: RecursivelyRemoveDollar<Array<Action>>
296
436
  outputs: Array<{
297
437
  stateId: string
438
+ typeOfStateId?: TypeOfStateId
298
439
  conditions?: RecursivelyRemoveDollar<Array<Condition>>
299
440
  }>
300
441
  }