@whitewall/blip-sdk 0.0.192 → 0.0.193
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/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/flow.js +34 -1
- package/dist/cjs/types/flow.js.map +1 -1
- package/dist/cjs/utils/builder.js +9 -28
- package/dist/cjs/utils/builder.js.map +1 -1
- package/dist/cjs/utils/flow-rules.js +304 -0
- package/dist/cjs/utils/flow-rules.js.map +1 -0
- package/dist/cjs/utils/minifier.js +42 -92
- package/dist/cjs/utils/minifier.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/flow.js +29 -0
- package/dist/esm/types/flow.js.map +1 -1
- package/dist/esm/utils/builder.js +9 -27
- package/dist/esm/utils/builder.js.map +1 -1
- package/dist/esm/utils/flow-rules.js +297 -0
- package/dist/esm/utils/flow-rules.js.map +1 -0
- package/dist/esm/utils/minifier.js +40 -90
- package/dist/esm/utils/minifier.js.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/types/flow.d.ts +33 -0
- package/dist/types/types/flow.d.ts.map +1 -1
- package/dist/types/utils/builder.d.ts +16 -25
- package/dist/types/utils/builder.d.ts.map +1 -1
- package/dist/types/utils/flow-rules.d.ts +50 -0
- package/dist/types/utils/flow-rules.d.ts.map +1 -0
- package/dist/types/utils/minifier.d.ts +294 -2
- package/dist/types/utils/minifier.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/types/flow.ts +40 -0
- package/src/utils/builder.ts +29 -62
- package/src/utils/flow-rules.ts +453 -0
- package/src/utils/minifier.ts +46 -95
package/src/utils/minifier.ts
CHANGED
|
@@ -11,17 +11,19 @@ import {
|
|
|
11
11
|
actionTypeSchema,
|
|
12
12
|
baseActionSchema,
|
|
13
13
|
type CONTENT_TYPES,
|
|
14
|
+
CUSTOM_ACTION_LISTS,
|
|
14
15
|
conditionOutputSchema,
|
|
15
16
|
defaultOutputSchema,
|
|
16
17
|
type Flow,
|
|
17
18
|
type InputState,
|
|
18
19
|
inputStateSchema,
|
|
20
|
+
isChatStateSendMessage,
|
|
19
21
|
type MIME_TYPES,
|
|
20
22
|
ROOT_STATE_ID,
|
|
21
23
|
type State,
|
|
22
24
|
stateSchema,
|
|
23
25
|
} from '../types/flow.ts'
|
|
24
|
-
import {
|
|
26
|
+
import { checkFlow } from './flow-rules.ts'
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
29
|
* Everything `minifyFlow` removes, grouped by where it lives. Together these
|
|
@@ -35,19 +37,12 @@ const STATE_NOISE = [
|
|
|
35
37
|
'$invalidCustomActions',
|
|
36
38
|
'$invalid',
|
|
37
39
|
'id',
|
|
38
|
-
'root',
|
|
39
40
|
'$tags',
|
|
40
41
|
'$inputSuggestions',
|
|
41
42
|
'isAiGenerated',
|
|
42
43
|
'deskStateVersion',
|
|
43
44
|
] as const
|
|
44
45
|
|
|
45
|
-
const CUSTOM_ACTION_LISTS = [
|
|
46
|
-
'$enteringCustomActions',
|
|
47
|
-
'$leavingCustomActions',
|
|
48
|
-
'$afterStateChangedActions',
|
|
49
|
-
'$localCustomActions',
|
|
50
|
-
] as const
|
|
51
46
|
const CUSTOM_ACTION_NOISE = ['$id', '$title', '$invalid', '$typeOfContent'] as const
|
|
52
47
|
|
|
53
48
|
const CONTENT_ACTION_ITEM_NOISE = ['$invalid'] as const
|
|
@@ -144,32 +139,7 @@ function stripAngularKeys(target: unknown): void {
|
|
|
144
139
|
}
|
|
145
140
|
}
|
|
146
141
|
|
|
147
|
-
const minifiedActionSchema = z.intersection(baseActionSchema.partial({ $id: true }), actionTypeSchema)
|
|
148
|
-
// expandMinifiedFlow derives $typeOfContent from the settings mime type, so
|
|
149
|
-
// a SendMessage without one cannot be pushed. Rejecting it here keeps
|
|
150
|
-
// validation and push in agreement instead of failing halfway through.
|
|
151
|
-
const action = ctx.value
|
|
152
|
-
if (action.type === 'SendMessage' && !action.settings.type) {
|
|
153
|
-
ctx.issues.push({
|
|
154
|
-
code: 'custom',
|
|
155
|
-
input: action,
|
|
156
|
-
path: ['settings', 'type'],
|
|
157
|
-
message: 'A SendMessage action requires a settings.type',
|
|
158
|
-
})
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// The runtime deserializes the raw content as this media type and refuses to
|
|
162
|
-
// run the action without one, so a hand-written raw message that omits it
|
|
163
|
-
// would be accepted here and then fail in the conversation.
|
|
164
|
-
if (action.type === 'SendRawMessage' && !action.settings.type) {
|
|
165
|
-
ctx.issues.push({
|
|
166
|
-
code: 'custom',
|
|
167
|
-
input: action,
|
|
168
|
-
path: ['settings', 'type'],
|
|
169
|
-
message: 'A SendRawMessage action requires a settings.type',
|
|
170
|
-
})
|
|
171
|
-
}
|
|
172
|
-
})
|
|
142
|
+
const minifiedActionSchema = z.intersection(baseActionSchema.partial({ $id: true }), actionTypeSchema)
|
|
173
143
|
|
|
174
144
|
const minifiedInputSchema = inputStateSchema.partial({ $cardContent: true, $invalid: true }).strict()
|
|
175
145
|
|
|
@@ -205,50 +175,22 @@ export const minifiedStateSchema = stateSchema
|
|
|
205
175
|
.strict()
|
|
206
176
|
|
|
207
177
|
/**
|
|
208
|
-
* A push replaces the whole flow, so
|
|
209
|
-
*
|
|
178
|
+
* A push replaces the whole flow, so everything that decides whether the runtime
|
|
179
|
+
* loads it — the entry point, the outputs, the loops, every condition and every
|
|
180
|
+
* action — is a validation error here instead of a bot that does not start.
|
|
181
|
+
*
|
|
182
|
+
* The rules run from this one check, and never per state or per action: zod skips
|
|
183
|
+
* a check on a value that already has issues, so nesting them would report the
|
|
184
|
+
* innermost problem and hide the rest of the flow's.
|
|
210
185
|
*/
|
|
211
186
|
export const minifiedFlowSchema = z.record(z.string(), minifiedStateSchema).check((ctx) => {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
// A variable output is only resolved at runtime.
|
|
216
|
-
if (output.typeOfStateId === 'variable' || output.stateId in ctx.value) {
|
|
217
|
-
return
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
ctx.issues.push({
|
|
221
|
-
code: 'custom',
|
|
222
|
-
input: output.stateId,
|
|
223
|
-
path: [...path, 'stateId'],
|
|
224
|
-
message: `Output points at '${output.stateId}', which is not a state in this flow`,
|
|
225
|
-
})
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
for (const [stateId, state] of Object.entries(ctx.value)) {
|
|
229
|
-
// The builder addresses a state by its title, so a duplicate hides one.
|
|
230
|
-
const title = state.$title.toLowerCase()
|
|
231
|
-
const duplicate = titles.get(title)
|
|
232
|
-
|
|
233
|
-
if (duplicate) {
|
|
234
|
-
ctx.issues.push({
|
|
235
|
-
code: 'custom',
|
|
236
|
-
input: state.$title,
|
|
237
|
-
path: [stateId, '$title'],
|
|
238
|
-
message: `Duplicate state title '${state.$title}', already used by '${duplicate}'`,
|
|
239
|
-
})
|
|
240
|
-
} else {
|
|
241
|
-
titles.set(title, stateId)
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
checkOutput(state.$defaultOutput, [stateId, '$defaultOutput'])
|
|
245
|
-
|
|
246
|
-
for (const [index, output] of state.$conditionOutputs.entries()) {
|
|
247
|
-
checkOutput(output, [stateId, '$conditionOutputs', index])
|
|
248
|
-
}
|
|
249
|
-
}
|
|
187
|
+
checkFlow(ctx.value, (rule, path, message) => {
|
|
188
|
+
ctx.issues.push({ code: 'custom', input: ctx.value, path, message, params: { rule } })
|
|
189
|
+
})
|
|
250
190
|
})
|
|
251
191
|
|
|
192
|
+
export type MinifiedAction = z.infer<typeof minifiedActionSchema>
|
|
193
|
+
export type MinifiedInput = z.infer<typeof minifiedInputSchema>
|
|
252
194
|
export type MinifiedState = z.infer<typeof minifiedStateSchema>
|
|
253
195
|
export type MinifiedFlow = z.infer<typeof minifiedFlowSchema>
|
|
254
196
|
|
|
@@ -271,10 +213,14 @@ export function minifyFlow(flow: Flow): MinifiedFlow {
|
|
|
271
213
|
stripAngularKeys(minifiedState)
|
|
272
214
|
stripKeys(minifiedState.$defaultOutput, DEFAULT_OUTPUT_NOISE)
|
|
273
215
|
|
|
274
|
-
//
|
|
275
|
-
//
|
|
216
|
+
// Only the state that is the entry point, and only a plugin that is really
|
|
217
|
+
// configured, are worth carrying: expansion writes `false` on all the others.
|
|
218
|
+
if (!minifiedState.root) {
|
|
219
|
+
delete minifiedState.root
|
|
220
|
+
}
|
|
221
|
+
|
|
276
222
|
if (!minifiedState.$whiteWallIntegration) {
|
|
277
|
-
|
|
223
|
+
delete minifiedState.$whiteWallIntegration
|
|
278
224
|
}
|
|
279
225
|
|
|
280
226
|
for (const output of minifiedState.$conditionOutputs ?? []) {
|
|
@@ -307,6 +253,9 @@ export function minifyFlow(flow: Flow): MinifiedFlow {
|
|
|
307
253
|
|
|
308
254
|
export function expandMinifiedFlow(minifiedFlow: MinifiedFlow, staleFlow?: Flow): Flow {
|
|
309
255
|
const flow: Flow = {}
|
|
256
|
+
// All or nothing: mixing the flow's own entry point with the builder's would
|
|
257
|
+
// leave two states marked as root, which the runtime refuses.
|
|
258
|
+
const declaresRoot = Object.values(minifiedFlow).some((state) => state.root)
|
|
310
259
|
|
|
311
260
|
for (const [stateId, minifiedState] of Object.entries(minifiedFlow)) {
|
|
312
261
|
try {
|
|
@@ -318,10 +267,16 @@ export function expandMinifiedFlow(minifiedFlow: MinifiedFlow, staleFlow?: Flow)
|
|
|
318
267
|
state.$invalidCustomActions = false
|
|
319
268
|
state.$invalid = false
|
|
320
269
|
state.id = stateId
|
|
321
|
-
//
|
|
322
|
-
//
|
|
323
|
-
//
|
|
324
|
-
|
|
270
|
+
// The entry point is carried by the flow, because `Flow.Validate`
|
|
271
|
+
// asserts on the flag and nothing else can express "this state, not the
|
|
272
|
+
// one named `onboarding`". A flow that predates it falls back to what
|
|
273
|
+
// the builder already knows, then to the id convention, so a first push
|
|
274
|
+
// still gets an entry point either way.
|
|
275
|
+
state.root = declaresRoot
|
|
276
|
+
? Boolean(minifiedState.root)
|
|
277
|
+
: staleState
|
|
278
|
+
? staleState.root
|
|
279
|
+
: stateId === ROOT_STATE_ID || undefined
|
|
325
280
|
state.$tags = staleState?.$tags ?? []
|
|
326
281
|
state.$inputSuggestions = staleState?.$inputSuggestions ?? []
|
|
327
282
|
state.isAiGenerated = staleState?.isAiGenerated ?? false
|
|
@@ -330,7 +285,7 @@ export function expandMinifiedFlow(minifiedFlow: MinifiedFlow, staleFlow?: Flow)
|
|
|
330
285
|
// keeps a plugin configured before this was carried through.
|
|
331
286
|
state.$whiteWallIntegration =
|
|
332
287
|
minifiedState.$whiteWallIntegration ?? staleState?.$whiteWallIntegration ?? false
|
|
333
|
-
state.deskStateVersion = staleState?.deskStateVersion
|
|
288
|
+
state.deskStateVersion = staleState?.deskStateVersion
|
|
334
289
|
state.$defaultOutput.$invalid = false
|
|
335
290
|
|
|
336
291
|
// Reuse the ids the builder already knows so the canvas keeps its
|
|
@@ -342,11 +297,11 @@ export function expandMinifiedFlow(minifiedFlow: MinifiedFlow, staleFlow?: Flow)
|
|
|
342
297
|
|
|
343
298
|
conditionOutput.$id = staleConditionOutput?.$id ?? crypto.randomUUID()
|
|
344
299
|
conditionOutput.$invalid = false
|
|
345
|
-
conditionOutput.$connId = staleConditionOutput?.$connId
|
|
346
|
-
conditionOutput.$isDeskOutput = staleConditionOutput?.$isDeskOutput
|
|
347
|
-
conditionOutput.$isDeskCustomOutput = staleConditionOutput?.$isDeskCustomOutput
|
|
348
|
-
conditionOutput.$isDeskDefaultOutput = staleConditionOutput?.$isDeskDefaultOutput
|
|
349
|
-
conditionOutput.$contentId = staleConditionOutput?.$contentId
|
|
300
|
+
conditionOutput.$connId = staleConditionOutput?.$connId
|
|
301
|
+
conditionOutput.$isDeskOutput = staleConditionOutput?.$isDeskOutput
|
|
302
|
+
conditionOutput.$isDeskCustomOutput = staleConditionOutput?.$isDeskCustomOutput
|
|
303
|
+
conditionOutput.$isDeskDefaultOutput = staleConditionOutput?.$isDeskDefaultOutput
|
|
304
|
+
conditionOutput.$contentId = staleConditionOutput?.$contentId
|
|
350
305
|
}
|
|
351
306
|
|
|
352
307
|
for (const actionType of CUSTOM_ACTION_LISTS) {
|
|
@@ -358,7 +313,7 @@ export function expandMinifiedFlow(minifiedFlow: MinifiedFlow, staleFlow?: Flow)
|
|
|
358
313
|
action.$id = staleAction?.$id ?? crypto.randomUUID()
|
|
359
314
|
action.$invalid = false
|
|
360
315
|
action.$title = staleAction?.$title ?? createActionTitle(action)
|
|
361
|
-
action.$typeOfContent = staleAction?.$typeOfContent
|
|
316
|
+
action.$typeOfContent = staleAction?.$typeOfContent
|
|
362
317
|
}
|
|
363
318
|
}
|
|
364
319
|
|
|
@@ -416,13 +371,9 @@ export function expandMinifiedFlow(minifiedFlow: MinifiedFlow, staleFlow?: Flow)
|
|
|
416
371
|
}
|
|
417
372
|
}
|
|
418
373
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
if (state.$contentActions[index].action) {
|
|
423
|
-
state.$contentActions.splice(index, 0, createChatStateContentAction())
|
|
424
|
-
}
|
|
425
|
-
}
|
|
374
|
+
state.$contentActions = (state.$contentActions ?? []).flatMap((item) =>
|
|
375
|
+
item.action ? [createChatStateContentAction(), item] : [item],
|
|
376
|
+
)
|
|
426
377
|
|
|
427
378
|
flow[stateId] = state
|
|
428
379
|
} catch (err) {
|