migrate from queuedEdgeIds to queuedEdges

This commit is contained in:
Alexis Falaise 2025-04-09 12:03:26 +02:00
parent f79f92b817
commit e2964b56c4
9 changed files with 70 additions and 51 deletions

View File

@ -4,7 +4,7 @@ import type { Edge } from "@typebot.io/typebot/schemas/edge";
export const addPortalEdge = (
id: string,
state: SessionState,
{ to, condition }: Pick<Edge, "to" | "condition">,
{ to }: Pick<Edge, "to">,
): SessionState => {
const existingEdge = state.typebotsQueue[0].typebot.edges.find(
(e) => e.id === id,
@ -26,10 +26,7 @@ export const addPortalEdge = (
? queue.typebot.edges.map((e) =>
e.id === id ? { ...e, to } : e,
)
: [
...queue.typebot.edges,
createPortalEdge({ id, to, condition }),
],
: [...queue.typebot.edges, createPortalEdge({ id, to })],
},
}
: queue,
@ -38,13 +35,8 @@ export const addPortalEdge = (
return newSessionState;
};
const createPortalEdge = ({
id,
to,
condition,
}: Pick<Edge, "to" | "id" | "condition">) => ({
const createPortalEdge = ({ id, to }: Pick<Edge, "to" | "id">) => ({
id,
from: { blockId: "", groupId: "" },
to,
condition,
});

View File

@ -101,7 +101,7 @@ const addSameTypebotToState = async ({
...newSessionState.typebotsQueue[0].typebot,
},
resultId: newSessionState.typebotsQueue[0].resultId,
queuedEdgeIds: edgeIdToQueue ? [edgeIdToQueue] : undefined,
queuedEdges: edgeIdToQueue ? [{ id: edgeIdToQueue }] : undefined,
answers: newSessionState.typebotsQueue[0].answers,
isMergingWithParent: true,
},
@ -161,7 +161,7 @@ const addLinkedTypebotToState = async (
: shouldMergeResults
? newSessionState.typebotsQueue[0].resultId
: createId(),
queuedEdgeIds: edgeIdToQueue ? [edgeIdToQueue] : undefined,
queuedEdges: edgeIdToQueue ? [{ id: edgeIdToQueue }] : undefined,
answers: shouldMergeResults
? newSessionState.typebotsQueue[0].answers
: [],

View File

@ -93,8 +93,8 @@ const computePossibleNextInputBlocks = ({
if (outgoingEdgeIds.length > 0 || group.blocks.length !== blockIndex + 1)
return possibleNextInputBlocks;
if (typebotsQueue.length > 1 || typebotsQueue[0].queuedEdgeIds?.length) {
const nextEdgeId = typebotsQueue[0].queuedEdgeIds?.[0];
if (typebotsQueue.length > 1 || typebotsQueue[0].queuedEdges?.length) {
const nextEdgeId = typebotsQueue[0].queuedEdges?.[0]?.id;
const to = typebotsQueue[1].typebot.edges.find(byId(nextEdgeId))?.to;
if (!to) return possibleNextInputBlocks;
const blockId =

View File

@ -217,7 +217,7 @@ export const continueBotFlow = async (
if (
!nextEdgeId &&
newSessionState.typebotsQueue.length === 1 &&
(newSessionState.typebotsQueue[0].queuedEdgeIds ?? []).length === 0
(newSessionState.typebotsQueue[0].queuedEdges ?? []).length === 0
)
return {
messages: [],

View File

@ -83,30 +83,28 @@ export const connectEdgeToNextBlock = async ({
if (!resumeMetadata) return state;
let newSessionState = state;
let condition: Condition | undefined;
if (event.type === EventType.REPLY) {
condition = event.options?.exitCondition?.condition;
}
const virtualEdgeId = `virtual-${event.id}`;
const { group, block } = resumeMetadata;
newSessionState = addPortalEdge(`virtual-${event.id}`, newSessionState, {
newSessionState = addPortalEdge(virtualEdgeId, newSessionState, {
to: { groupId: group.id, blockId: block.id },
condition,
});
const virtualEdge = { id: virtualEdgeId, condition };
newSessionState = {
...newSessionState,
typebotsQueue: [
{
...newSessionState.typebotsQueue[0],
queuedEdgeIds: newSessionState.typebotsQueue[0].queuedEdgeIds
? [
`virtual-${event.id}`,
...newSessionState.typebotsQueue[0].queuedEdgeIds,
]
: [`virtual-${event.id}`],
queuedEdges: newSessionState.typebotsQueue[0].queuedEdges
? [virtualEdge, ...newSessionState.typebotsQueue[0].queuedEdges]
: [virtualEdge],
},
...newSessionState.typebotsQueue.slice(1),
],

View File

@ -243,7 +243,7 @@ export const executeGroup = async (
if (
!nextEdgeId &&
newSessionState.typebotsQueue.length === 1 &&
(newSessionState.typebotsQueue[0].queuedEdgeIds ?? []).length === 0
(newSessionState.typebotsQueue[0].queuedEdges ?? []).length === 0
)
return {
messages,

View File

@ -1,7 +1,8 @@
import type { Block } from "@typebot.io/blocks-core/schemas/schema";
import type { SessionState } from "@typebot.io/chat-session/schemas";
import type {
QueuedEdge,
SessionState,
} from "@typebot.io/chat-session/schemas";
import { executeCondition } from "@typebot.io/conditions/executeCondition";
import { getBlockById } from "@typebot.io/groups/helpers/getBlockById";
import type { Group } from "@typebot.io/groups/schemas";
import { byId, isDefined, isNotDefined } from "@typebot.io/lib/utils";
import type { Prisma } from "@typebot.io/prisma/types";
@ -27,17 +28,12 @@ export const getNextGroup = async ({
}): Promise<NextGroup> => {
const nextEdge = state.typebotsQueue[0].typebot.edges.find(byId(edgeId));
if (!nextEdge) {
const nextEdgeResponse = popQueuedEdge(state);
const poppedEdgeId = nextEdgeResponse.edgeId;
const poppedEdge =
nextEdgeResponse.state.typebotsQueue[0].typebot.edges.find(
byId(poppedEdgeId),
);
const queuedEdgeResponse = popQueuedEdge(state);
const exitConditionMet =
poppedEdge?.condition &&
executeCondition(poppedEdge.condition, {
variables: nextEdgeResponse.state.typebotsQueue[0].typebot.variables,
queuedEdgeResponse.queuedEdge?.condition &&
executeCondition(queuedEdgeResponse.queuedEdge.condition, {
variables: state.typebotsQueue[0].typebot.variables,
sessionStore,
});
@ -47,7 +43,7 @@ export const getNextGroup = async ({
};
}
let newSessionState = nextEdgeResponse.state;
let newSessionState = queuedEdgeResponse.state;
if (newSessionState.typebotsQueue.length > 1) {
const isMergingWithParent =
newSessionState.typebotsQueue[0].isMergingWithParent;
@ -112,10 +108,10 @@ export const getNextGroup = async ({
newSessionState.typebotsQueue[0].answers.length,
};
}
if (nextEdgeResponse.edgeId)
if (queuedEdgeResponse.queuedEdge?.id)
return getNextGroup({
state: newSessionState,
edgeId: nextEdgeResponse.edgeId,
edgeId: queuedEdgeResponse.queuedEdge.id,
isOffDefaultPath,
sessionStore,
});
@ -168,17 +164,17 @@ export const getNextGroup = async ({
const popQueuedEdge = (
state: SessionState,
): { edgeId?: string; state: SessionState } => {
const edgeId = state.typebotsQueue[0].queuedEdgeIds?.[0];
if (!edgeId) return { state };
): { queuedEdge?: QueuedEdge; state: SessionState } => {
const queuedEdge = state.typebotsQueue[0].queuedEdges?.[0];
if (!queuedEdge) return { state };
return {
edgeId,
queuedEdge,
state: {
...state,
typebotsQueue: [
{
...state.typebotsQueue[0],
queuedEdgeIds: state.typebotsQueue[0].queuedEdgeIds?.slice(1),
queuedEdges: state.typebotsQueue[0].queuedEdges?.slice(1),
},
...state.typebotsQueue.slice(1),
],

View File

@ -1,4 +1,5 @@
import { isInputBlock } from "@typebot.io/blocks-core/helpers";
import { conditionSchema } from "@typebot.io/conditions/schemas";
import type { Prisma } from "@typebot.io/prisma/types";
import {
answerInSessionStateSchemaV2,
@ -124,6 +125,12 @@ const sessionStateSchemaV2 = z.object({
.optional(),
});
const queuedEdgeSchema = z.object({
id: z.string(),
condition: conditionSchema.optional(),
});
export type QueuedEdge = z.infer<typeof queuedEdgeSchema>;
const sessionStateSchemaV3 = sessionStateSchemaV2
.omit({ currentBlock: true })
.extend({
@ -150,19 +157,33 @@ const sessionStateSchemaV3 = sessionStateSchemaV2
.optional(),
});
export type SessionState = z.infer<typeof sessionStateSchemaV3>;
const sessionStateSchemaV4 = sessionStateSchemaV3.extend({
version: z.literal("4"),
typebotsQueue: z.array(
sessionStateSchemaV2.shape.typebotsQueue.element.extend({
queuedEdges: z.array(queuedEdgeSchema).optional(),
}),
),
});
export type SessionState = z.infer<typeof sessionStateSchemaV4>;
export const sessionStateSchema = z
.discriminatedUnion("version", [
sessionStateSchemaV1,
sessionStateSchemaV2,
sessionStateSchemaV3,
sessionStateSchemaV4,
])
.transform((state): SessionState => {
if (state.version === "3") return state;
if (state.version === "4") return state;
let migratedState: any = state;
if (!state.version) migratedState = migrateFromV1ToV2(state);
return migrateFromV2ToV3(migratedState);
if (migratedState.version === "2")
migratedState = migrateFromV2ToV3(migratedState);
if (migratedState.version === "3")
migratedState = migrateFromV3ToV4(migratedState);
return migratedState;
}) as z.ZodType<SessionState>;
const migrateFromV1ToV2 = (
@ -246,6 +267,20 @@ const migrateFromV2ToV3 = (
workspaceId: "",
});
const migrateFromV3ToV4 = (
state: z.infer<typeof sessionStateSchemaV3>,
): z.infer<typeof sessionStateSchemaV4> => ({
...state,
version: "4",
typebotsQueue: state.typebotsQueue.map((typebot) => ({
...typebot,
queuedEdges: typebot.queuedEdgeIds?.map((id) => ({
id,
})),
queuedEdgeIds: undefined,
})),
});
const chatSessionSchema = z.object({
id: z.string(),
createdAt: z.date(),

View File

@ -1,4 +1,3 @@
import { conditionSchema } from "@typebot.io/conditions/schemas";
import { z } from "@typebot.io/zod";
const blockSourceSchema = z.object({
@ -24,6 +23,5 @@ export const edgeSchema = z.object({
id: z.string(),
from: sourceSchema,
to: targetSchema,
condition: conditionSchema.optional(),
});
export type Edge = z.infer<typeof edgeSchema>;