2
0
Files
bot/packages/scripts/fixTypebots.ts
2023-03-15 08:35:16 +01:00

204 lines
5.8 KiB
TypeScript

import { PrismaClient } from '@typebot.io/prisma'
import { writeFileSync } from 'fs'
import {
Block,
BlockOptions,
BlockType,
defaultEmailInputOptions,
Group,
InputBlockType,
PublicTypebot,
publicTypebotSchema,
Theme,
Typebot,
} from '@typebot.io/schemas'
import { isDefined, isNotDefined } from '@typebot.io/lib'
import { promptAndSetEnvironment } from './utils'
import { detailedDiff } from 'deep-object-diff'
const fixTypebot = (brokenTypebot: Typebot | PublicTypebot) =>
({
...brokenTypebot,
theme: fixTheme(brokenTypebot.theme),
groups: fixGroups(brokenTypebot.groups),
} satisfies Typebot | PublicTypebot)
const fixTheme = (brokenTheme: Theme) =>
({
...brokenTheme,
chat: {
...brokenTheme.chat,
hostAvatar: brokenTheme.chat.hostAvatar
? {
isEnabled: brokenTheme.chat.hostAvatar.isEnabled,
url: brokenTheme.chat.hostAvatar.url ?? undefined,
}
: undefined,
},
} satisfies Theme)
const fixGroups = (brokenGroups: Group[]) =>
brokenGroups.map(
(brokenGroup, index) =>
({
...brokenGroup,
graphCoordinates: {
...brokenGroup.graphCoordinates,
x: brokenGroup.graphCoordinates.x ?? 0,
y: brokenGroup.graphCoordinates.y ?? 0,
},
blocks: fixBlocks(brokenGroup.blocks, brokenGroup.id, index),
} satisfies Group)
)
const fixBlocks = (
brokenBlocks: Block[],
groupId: string,
groupIndex: number
) => {
if (groupIndex === 0 && brokenBlocks.length > 1) return [brokenBlocks[0]]
return brokenBlocks
.filter((block) => block && Object.keys(block).length > 0)
.map((brokenBlock) => {
return removeUndefinedFromObject({
...brokenBlock,
webhookId:
('webhookId' in brokenBlock ? brokenBlock.webhookId : undefined) ??
('webhook' in brokenBlock && brokenBlock.webhook
? //@ts-ignore
brokenBlock.webhook.id
: undefined),
webhook: undefined,
groupId: brokenBlock.groupId ?? groupId,
options:
brokenBlock && 'options' in brokenBlock && brokenBlock.options
? fixBrokenBlockOption(brokenBlock.options, brokenBlock.type)
: undefined,
})
}) as Block[]
}
const fixBrokenBlockOption = (options: BlockOptions, blockType: BlockType) =>
removeUndefinedFromObject({
...options,
sheetId:
'sheetId' in options && isDefined(options.sheetId)
? options.sheetId.toString()
: undefined,
step:
'step' in options && isDefined(options.step) ? options.step : undefined,
value:
'value' in options && isDefined(options.value)
? options.value
: undefined,
retryMessageContent: fixRetryMessageContent(
//@ts-ignore
options.retryMessageContent,
blockType
),
}) as BlockOptions
const fixRetryMessageContent = (
retryMessageContent: string | undefined,
blockType: BlockType
) => {
if (isNotDefined(retryMessageContent) && blockType === InputBlockType.EMAIL)
return defaultEmailInputOptions.retryMessageContent
if (isNotDefined(retryMessageContent)) return undefined
return retryMessageContent
}
const removeUndefinedFromObject = (obj: any) => {
Object.keys(obj).forEach((key) => obj[key] === undefined && delete obj[key])
return obj
}
const resolve = (path: string, obj: object, separator = '.') => {
const properties = Array.isArray(path) ? path : path.split(separator)
//@ts-ignore
return properties.reduce((prev, curr) => prev?.[curr], obj)
}
const fixTypebots = async () => {
await promptAndSetEnvironment()
const prisma = new PrismaClient({
log: [{ emit: 'event', level: 'query' }, 'info', 'warn', 'error'],
})
const typebots = await prisma.publicTypebot.findMany({
where: {
updatedAt: {
gte: new Date('2023-01-01T00:00:00.000Z'),
},
},
})
writeFileSync('logs/typebots.json', JSON.stringify(typebots))
const total = typebots.length
let totalFixed = 0
let progress = 0
const fixedTypebots: (Typebot | PublicTypebot)[] = []
const diffs: any[] = []
for (const typebot of typebots) {
progress += 1
console.log(
`Progress: ${progress}/${total} (${Math.round(
(progress / total) * 100
)}%) (${totalFixed} fixed typebots)`
)
const parser = publicTypebotSchema.safeParse({
...typebot,
updatedAt: new Date(typebot.updatedAt),
createdAt: new Date(typebot.createdAt),
})
if ('error' in parser) {
const fixedTypebot = {
...fixTypebot(typebot as Typebot | PublicTypebot),
updatedAt: new Date(),
createdAt: new Date(typebot.createdAt),
}
publicTypebotSchema.parse(fixedTypebot)
fixedTypebots.push(fixedTypebot)
totalFixed += 1
diffs.push({
id: typebot.id,
failedObject: resolve(parser.error.issues[0].path.join('.'), typebot),
...detailedDiff(typebot, fixedTypebot),
})
}
}
writeFileSync('logs/fixedTypebots.json', JSON.stringify(fixedTypebots))
writeFileSync(
'logs/diffs.json',
JSON.stringify(diffs.reverse().slice(0, 100))
)
const queries = fixedTypebots.map((fixedTypebot) =>
prisma.publicTypebot.updateMany({
where: { id: fixedTypebot.id },
data: {
...fixedTypebot,
// theme: fixedTypebot.theme ?? undefined,
// settings: fixedTypebot.settings ?? undefined,
// resultsTablePreferences:
// 'resultsTablePreferences' in fixedTypebot &&
// fixedTypebot.resultsTablePreferences
// ? fixedTypebot.resultsTablePreferences
// : undefined,
} as any,
})
)
const totalQueries = queries.length
progress = 0
prisma.$on('query', () => {
progress += 1
console.log(`Progress: ${progress}/${totalQueries}`)
})
await prisma.$transaction(queries)
}
fixTypebots()