♻️ (viewer) Remove barrel exports and flatten folder arch
This commit is contained in:
@ -13,7 +13,7 @@
|
||||
"write-translations": "docusaurus write-translations",
|
||||
"write-heading-ids": "docusaurus write-heading-ids",
|
||||
"update-search": "docker run -it --rm --env-file=.env -e \"CONFIG=$(cat docsearch-scrapper-config.json | jq -r tostring)\" algolia/docsearch-scraper",
|
||||
"api:generate": "tsx --tsconfig ../builder/tsconfig.json ../builder/src/helpers/server/generateOpenApi.ts && tsx --tsconfig ../viewer/openapi.tsconfig.json ../viewer/src/utils/server/generateOpenApi.ts"
|
||||
"api:generate": "tsx --tsconfig ../builder/tsconfig.json ../builder/src/helpers/server/generateOpenApi.ts && tsx --tsconfig ../viewer/openapi.tsconfig.json ../viewer/src/helpers/server/generateOpenApi.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.3.1",
|
||||
|
@ -15,13 +15,14 @@ import {
|
||||
} from '@typebot.io/lib'
|
||||
import { SEO } from './Seo'
|
||||
import { ErrorPage } from './ErrorPage'
|
||||
import { createResultQuery, updateResultQuery } from '@/features/results'
|
||||
import { upsertAnswerQuery } from '@/features/answers'
|
||||
import { gtmBodyElement } from '@/lib/google-tag-manager'
|
||||
import {
|
||||
getExistingResultFromSession,
|
||||
setResultInSession,
|
||||
} from '@/utils/sessionStorage'
|
||||
} from '@/helpers/sessionStorage'
|
||||
import { upsertAnswerQuery } from '@/features/answers/queries/upsertAnswerQuery'
|
||||
import { createResultQuery } from '@/features/results/queries/createResultQuery'
|
||||
import { updateResultQuery } from '@/features/results/queries/updateResultQuery'
|
||||
|
||||
export type TypebotPageProps = {
|
||||
publishedTypebot: Omit<PublicTypebot, 'createdAt' | 'updatedAt'> & {
|
||||
|
@ -1 +0,0 @@
|
||||
export { upsertAnswerQuery } from './queries/upsertAnswerQuery'
|
@ -1 +0,0 @@
|
||||
export { authenticateUser } from './authenticateUser'
|
@ -1,4 +1,3 @@
|
||||
import { deepParseVariable } from '@/features/variables/utils'
|
||||
import {
|
||||
SessionState,
|
||||
VariableWithValue,
|
||||
@ -6,6 +5,7 @@ import {
|
||||
ItemType,
|
||||
} from '@typebot.io/schemas'
|
||||
import { isDefined } from '@typebot.io/lib'
|
||||
import { deepParseVariables } from '@/features/variables/deepParseVariable'
|
||||
|
||||
export const injectVariableValuesInButtonsInputBlock =
|
||||
(variables: SessionState['typebot']['variables']) =>
|
||||
@ -27,5 +27,5 @@ export const injectVariableValuesInButtonsInputBlock =
|
||||
})),
|
||||
}
|
||||
}
|
||||
return deepParseVariable(variables)(block)
|
||||
return deepParseVariables(variables)(block)
|
||||
}
|
@ -1 +0,0 @@
|
||||
export * from './utils'
|
@ -1 +0,0 @@
|
||||
export * from './parseReadableDate'
|
@ -1 +0,0 @@
|
||||
export * from './utils'
|
@ -1 +0,0 @@
|
||||
export * from './validateEmail'
|
@ -1 +0,0 @@
|
||||
export * from './utils'
|
@ -1 +0,0 @@
|
||||
export * from './computePaymentInputRuntimeOptions'
|
@ -1,4 +1,4 @@
|
||||
import { parseVariables } from '@/features/variables'
|
||||
import { parseVariables } from '@/features/variables/parseVariables'
|
||||
import prisma from '@/lib/prisma'
|
||||
import { TRPCError } from '@trpc/server'
|
||||
import {
|
@ -1 +0,0 @@
|
||||
export * from './utils'
|
@ -1,2 +0,0 @@
|
||||
export * from './formatPhoneNumber'
|
||||
export * from './validatePhoneNumber'
|
@ -1 +0,0 @@
|
||||
export { validateUrl } from './utils/validateUrl'
|
@ -1 +0,0 @@
|
||||
export * from './utils/executeChatwootBlock'
|
@ -1,9 +1,7 @@
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat'
|
||||
import {
|
||||
parseVariables,
|
||||
parseCorrectValueType,
|
||||
extractVariablesFromText,
|
||||
} from '@/features/variables'
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat/types'
|
||||
import { extractVariablesFromText } from '@/features/variables/extractVariablesFromText'
|
||||
import { parseGuessedValueType } from '@/features/variables/parseGuessedValueType'
|
||||
import { parseVariables } from '@/features/variables/parseVariables'
|
||||
import {
|
||||
ChatwootBlock,
|
||||
ChatwootOptions,
|
||||
@ -85,7 +83,7 @@ export const executeChatwootBlock = (
|
||||
args: extractVariablesFromText(variables)(chatwootCode).map(
|
||||
(variable) => ({
|
||||
id: variable.id,
|
||||
value: parseCorrectValueType(variable.value),
|
||||
value: parseGuessedValueType(variable.value),
|
||||
})
|
||||
),
|
||||
},
|
@ -1 +0,0 @@
|
||||
export { executeGoogleAnalyticsBlock } from './utils/executeGoogleAnalyticsBlock'
|
@ -1,5 +1,5 @@
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat'
|
||||
import { deepParseVariable } from '@/features/variables'
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat/types'
|
||||
import { deepParseVariables } from '@/features/variables/deepParseVariable'
|
||||
import { GoogleAnalyticsBlock, SessionState } from '@typebot.io/schemas'
|
||||
|
||||
export const executeGoogleAnalyticsBlock = (
|
||||
@ -10,7 +10,7 @@ export const executeGoogleAnalyticsBlock = (
|
||||
outgoingEdgeId: block.outgoingEdgeId,
|
||||
clientSideActions: [
|
||||
{
|
||||
googleAnalytics: deepParseVariable(variables)(block.options),
|
||||
googleAnalytics: deepParseVariables(variables)(block.options),
|
||||
lastBubbleBlockId,
|
||||
},
|
||||
],
|
@ -1 +0,0 @@
|
||||
export * from './utils'
|
@ -1 +0,0 @@
|
||||
export * from './executeGoogleSheetBlock'
|
@ -1,12 +1,12 @@
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat'
|
||||
import {
|
||||
GoogleSheetsBlock,
|
||||
GoogleSheetsAction,
|
||||
SessionState,
|
||||
} from '@typebot.io/schemas'
|
||||
import { getRow } from './getRow'
|
||||
import { insertRow } from './insertRow'
|
||||
import { updateRow } from './updateRow'
|
||||
import { getRow } from './getRow'
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat/types'
|
||||
|
||||
export const executeGoogleSheetBlock = async (
|
||||
state: SessionState,
|
@ -6,12 +6,13 @@ import {
|
||||
LogicalOperator,
|
||||
ReplyLog,
|
||||
} from '@typebot.io/schemas'
|
||||
import { saveErrorLog } from '@/features/logs/api'
|
||||
import { getAuthenticatedGoogleDoc } from './helpers'
|
||||
import { deepParseVariable, updateVariables } from '@/features/variables'
|
||||
import { isNotEmpty, byId, isDefined } from '@typebot.io/lib'
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat'
|
||||
import type { GoogleSpreadsheetRow } from 'google-spreadsheet'
|
||||
import { getAuthenticatedGoogleDoc } from './helpers/getAuthenticatedGoogleDoc'
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat/types'
|
||||
import { saveErrorLog } from '@/features/logs/saveErrorLog'
|
||||
import { updateVariables } from '@/features/variables/updateVariables'
|
||||
import { deepParseVariables } from '@/features/variables/deepParseVariable'
|
||||
|
||||
export const getRow = async (
|
||||
state: SessionState,
|
||||
@ -20,7 +21,7 @@ export const getRow = async (
|
||||
options,
|
||||
}: { outgoingEdgeId?: string; options: GoogleSheetsGetOptions }
|
||||
): Promise<ExecuteIntegrationResponse> => {
|
||||
const { sheetId, cellsToExtract, referenceCell, filter } = deepParseVariable(
|
||||
const { sheetId, cellsToExtract, referenceCell, filter } = deepParseVariables(
|
||||
state.typebot.variables
|
||||
)(options)
|
||||
if (!sheetId) return { outgoingEdgeId }
|
@ -1,20 +1,6 @@
|
||||
import { parseVariables } from '@/features/variables'
|
||||
import { getAuthenticatedGoogleClient } from '@/lib/google-sheets'
|
||||
import { TRPCError } from '@trpc/server'
|
||||
import { GoogleSpreadsheet } from 'google-spreadsheet'
|
||||
import { Variable, Cell } from '@typebot.io/schemas'
|
||||
|
||||
export const parseCellValues =
|
||||
(variables: Variable[]) =>
|
||||
(cells: Cell[]): { [key: string]: string } =>
|
||||
cells.reduce((row, cell) => {
|
||||
return !cell.column || !cell.value
|
||||
? row
|
||||
: {
|
||||
...row,
|
||||
[cell.column]: parseVariables(variables)(cell.value),
|
||||
}
|
||||
}, {})
|
||||
|
||||
export const getAuthenticatedGoogleDoc = async ({
|
||||
credentialsId,
|
@ -0,0 +1,14 @@
|
||||
import { parseVariables } from '@/features/variables/parseVariables'
|
||||
import { Variable, Cell } from '@typebot.io/schemas'
|
||||
|
||||
export const parseCellValues =
|
||||
(variables: Variable[]) =>
|
||||
(cells: Cell[]): { [key: string]: string } =>
|
||||
cells.reduce((row, cell) => {
|
||||
return !cell.column || !cell.value
|
||||
? row
|
||||
: {
|
||||
...row,
|
||||
[cell.column]: parseVariables(variables)(cell.value),
|
||||
}
|
||||
}, {})
|
@ -3,9 +3,11 @@ import {
|
||||
GoogleSheetsInsertRowOptions,
|
||||
ReplyLog,
|
||||
} from '@typebot.io/schemas'
|
||||
import { saveErrorLog, saveSuccessLog } from '@/features/logs/api'
|
||||
import { getAuthenticatedGoogleDoc, parseCellValues } from './helpers'
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat'
|
||||
import { parseCellValues } from './helpers/parseCellValues'
|
||||
import { getAuthenticatedGoogleDoc } from './helpers/getAuthenticatedGoogleDoc'
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat/types'
|
||||
import { saveErrorLog } from '@/features/logs/saveErrorLog'
|
||||
import { saveSuccessLog } from '@/features/logs/saveSuccessLog'
|
||||
|
||||
export const insertRow = async (
|
||||
{ result, typebot: { variables } }: SessionState,
|
@ -3,11 +3,13 @@ import {
|
||||
GoogleSheetsUpdateRowOptions,
|
||||
ReplyLog,
|
||||
} from '@typebot.io/schemas'
|
||||
import { saveErrorLog, saveSuccessLog } from '@/features/logs/api'
|
||||
import { getAuthenticatedGoogleDoc, parseCellValues } from './helpers'
|
||||
import { TRPCError } from '@trpc/server'
|
||||
import { deepParseVariable } from '@/features/variables'
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat'
|
||||
import { parseCellValues } from './helpers/parseCellValues'
|
||||
import { getAuthenticatedGoogleDoc } from './helpers/getAuthenticatedGoogleDoc'
|
||||
import { deepParseVariables } from '@/features/variables/deepParseVariable'
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat/types'
|
||||
import { saveErrorLog } from '@/features/logs/saveErrorLog'
|
||||
import { saveSuccessLog } from '@/features/logs/saveSuccessLog'
|
||||
|
||||
export const updateRow = async (
|
||||
{ result, typebot: { variables } }: SessionState,
|
||||
@ -16,7 +18,7 @@ export const updateRow = async (
|
||||
options,
|
||||
}: { outgoingEdgeId?: string; options: GoogleSheetsUpdateRowOptions }
|
||||
): Promise<ExecuteIntegrationResponse> => {
|
||||
const { sheetId, referenceCell } = deepParseVariable(variables)(options)
|
||||
const { sheetId, referenceCell } = deepParseVariables(variables)(options)
|
||||
if (!options.cellsToUpsert || !sheetId || !referenceCell)
|
||||
return { outgoingEdgeId }
|
||||
|
@ -1,7 +1,5 @@
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat/types'
|
||||
import { saveErrorLog } from '@/features/logs/api'
|
||||
import { transformStringVariablesToList } from '@/features/variables/transformVariablesToList'
|
||||
import { parseVariables, updateVariables } from '@/features/variables/utils'
|
||||
import prisma from '@/lib/prisma'
|
||||
import {
|
||||
SessionState,
|
||||
@ -16,6 +14,9 @@ import {
|
||||
import { OpenAIApi, Configuration, ChatCompletionRequestMessage } from 'openai'
|
||||
import { isDefined, byId, isNotEmpty } from '@typebot.io/lib'
|
||||
import { decrypt } from '@typebot.io/lib/api/encryption'
|
||||
import { saveErrorLog } from '@/features/logs/saveErrorLog'
|
||||
import { updateVariables } from '@/features/variables/updateVariables'
|
||||
import { parseVariables } from 'bot-engine'
|
||||
|
||||
export const createChatCompletionOpenAI = async (
|
||||
state: SessionState,
|
||||
|
@ -1 +0,0 @@
|
||||
export { executeSendEmailBlock } from './utils/executeSendEmailBlock'
|
@ -1,6 +1,4 @@
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat'
|
||||
import { saveErrorLog, saveSuccessLog } from '@/features/logs/api'
|
||||
import { parseVariables } from '@/features/variables'
|
||||
import { parseVariables } from '@/features/variables/parseVariables'
|
||||
import prisma from '@/lib/prisma'
|
||||
import { render } from '@faire/mjml-react/utils/render'
|
||||
import { DefaultBotNotificationEmail } from '@typebot.io/emails'
|
||||
@ -17,7 +15,10 @@ import Mail from 'nodemailer/lib/mailer'
|
||||
import { byId, isEmpty, isNotDefined, omit } from '@typebot.io/lib'
|
||||
import { parseAnswers } from '@typebot.io/lib/results'
|
||||
import { decrypt } from '@typebot.io/lib/api'
|
||||
import { defaultFrom, defaultTransportOptions } from '../constants'
|
||||
import { defaultFrom, defaultTransportOptions } from './constants'
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat/types'
|
||||
import { saveErrorLog } from '@/features/logs/saveErrorLog'
|
||||
import { saveSuccessLog } from '@/features/logs/saveSuccessLog'
|
||||
|
||||
export const executeSendEmailBlock = async (
|
||||
{ result, typebot }: SessionState,
|
@ -1 +0,0 @@
|
||||
export * from './utils'
|
@ -1,2 +0,0 @@
|
||||
export * from './executeWebhookBlock'
|
||||
export * from './parseSampleResult'
|
@ -1,6 +1,3 @@
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat'
|
||||
import { saveErrorLog, saveSuccessLog } from '@/features/logs/api'
|
||||
import { parseVariables, updateVariables } from '@/features/variables'
|
||||
import prisma from '@/lib/prisma'
|
||||
import {
|
||||
WebhookBlock,
|
||||
@ -26,6 +23,11 @@ import { byId, omit } from '@typebot.io/lib'
|
||||
import { parseAnswers } from '@typebot.io/lib/results'
|
||||
import got, { Method, Headers, HTTPError } from 'got'
|
||||
import { parseSampleResult } from './parseSampleResult'
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat/types'
|
||||
import { saveErrorLog } from '@/features/logs/saveErrorLog'
|
||||
import { saveSuccessLog } from '@/features/logs/saveSuccessLog'
|
||||
import { updateVariables } from '@/features/variables/updateVariables'
|
||||
import { parseVariables } from 'bot-engine'
|
||||
|
||||
export const executeWebhookBlock = async (
|
||||
state: SessionState,
|
@ -1 +0,0 @@
|
||||
export { executeCondition } from './utils/executeCondition'
|
@ -1,5 +1,3 @@
|
||||
import { ExecuteLogicResponse } from '@/features/chat'
|
||||
import { findUniqueVariableValue, parseVariables } from '@/features/variables'
|
||||
import {
|
||||
Comparison,
|
||||
ComparisonOperators,
|
||||
@ -9,6 +7,9 @@ import {
|
||||
Variable,
|
||||
} from '@typebot.io/schemas'
|
||||
import { isNotDefined, isDefined } from '@typebot.io/lib'
|
||||
import { ExecuteLogicResponse } from '@/features/chat/types'
|
||||
import { findUniqueVariableValue } from '@/features/variables/findUniqueVariableValue'
|
||||
import { parseVariables } from 'bot-engine'
|
||||
|
||||
export const executeCondition = (
|
||||
{ typebot: { variables } }: SessionState,
|
@ -1,8 +1,8 @@
|
||||
import { ExecuteLogicResponse } from '@/features/chat'
|
||||
import {
|
||||
addEdgeToTypebot,
|
||||
createPortalEdge,
|
||||
} from '@/features/chat/api/utils/addEdgeToTypebot'
|
||||
} from '@/features/chat/helpers/addEdgeToTypebot'
|
||||
import { ExecuteLogicResponse } from '@/features/chat/types'
|
||||
import { TRPCError } from '@trpc/server'
|
||||
import { SessionState } from '@typebot.io/schemas'
|
||||
import { JumpBlock } from '@typebot.io/schemas/features/blocks/logic/jump'
|
||||
|
@ -1 +0,0 @@
|
||||
export { executeRedirect } from './utils/executeRedirect'
|
@ -1,7 +1,7 @@
|
||||
import { ExecuteLogicResponse } from '@/features/chat'
|
||||
import { parseVariables } from '@/features/variables'
|
||||
import { parseVariables } from '@/features/variables/parseVariables'
|
||||
import { RedirectBlock, SessionState } from '@typebot.io/schemas'
|
||||
import { sanitizeUrl } from '@typebot.io/lib'
|
||||
import { ExecuteLogicResponse } from '@/features/chat/types'
|
||||
|
||||
export const executeRedirect = (
|
||||
{ typebot: { variables } }: SessionState,
|
@ -1,9 +1,7 @@
|
||||
import { ExecuteLogicResponse } from '@/features/chat'
|
||||
import {
|
||||
parseVariables,
|
||||
parseCorrectValueType,
|
||||
extractVariablesFromText,
|
||||
} from '@/features/variables'
|
||||
import { ExecuteLogicResponse } from '@/features/chat/types'
|
||||
import { extractVariablesFromText } from '@/features/variables/extractVariablesFromText'
|
||||
import { parseGuessedValueType } from '@/features/variables/parseGuessedValueType'
|
||||
import { parseVariables } from '@/features/variables/parseVariables'
|
||||
import { ScriptBlock, SessionState } from '@typebot.io/schemas'
|
||||
|
||||
export const executeScript = (
|
||||
@ -19,7 +17,7 @@ export const executeScript = (
|
||||
const args = extractVariablesFromText(variables)(block.options.content).map(
|
||||
(variable) => ({
|
||||
id: variable.id,
|
||||
value: parseCorrectValueType(variable.value),
|
||||
value: parseGuessedValueType(variable.value),
|
||||
})
|
||||
)
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
export { executeSetVariable } from './utils/executeSetVariable'
|
@ -1,11 +1,9 @@
|
||||
import { SessionState, SetVariableBlock, Variable } from '@typebot.io/schemas'
|
||||
import { byId } from '@typebot.io/lib'
|
||||
import {
|
||||
parseVariables,
|
||||
parseCorrectValueType,
|
||||
updateVariables,
|
||||
} from '@/features/variables'
|
||||
import { ExecuteLogicResponse } from '@/features/chat'
|
||||
import { ExecuteLogicResponse } from '@/features/chat/types'
|
||||
import { updateVariables } from '@/features/variables/updateVariables'
|
||||
import { parseVariables } from '@/features/variables/parseVariables'
|
||||
import { parseGuessedValueType } from '@/features/variables/parseGuessedValueType'
|
||||
|
||||
export const executeSetVariable = async (
|
||||
state: SessionState,
|
||||
@ -45,7 +43,7 @@ const evaluateSetVariableExpression =
|
||||
)
|
||||
try {
|
||||
const func = Function(...variables.map((v) => v.id), evaluating)
|
||||
return func(...variables.map((v) => parseCorrectValueType(v.value)))
|
||||
return func(...variables.map((v) => parseGuessedValueType(v.value)))
|
||||
} catch (err) {
|
||||
return parseVariables(variables)(str)
|
||||
}
|
@ -1 +0,0 @@
|
||||
export * from './utils'
|
@ -1,3 +0,0 @@
|
||||
export * from './executeTypebotLink'
|
||||
export * from './getLinkedTypebots'
|
||||
export * from './getLinkedTypebotsChildren'
|
@ -1,9 +1,7 @@
|
||||
import { ExecuteLogicResponse } from '@/features/chat'
|
||||
import {
|
||||
addEdgeToTypebot,
|
||||
createPortalEdge,
|
||||
} from '@/features/chat/api/utils/addEdgeToTypebot'
|
||||
import { saveErrorLog } from '@/features/logs/api'
|
||||
} from '@/features/chat/helpers/addEdgeToTypebot'
|
||||
import prisma from '@/lib/prisma'
|
||||
import {
|
||||
TypebotLinkBlock,
|
||||
@ -12,6 +10,8 @@ import {
|
||||
Variable,
|
||||
} from '@typebot.io/schemas'
|
||||
import { byId } from '@typebot.io/lib'
|
||||
import { ExecuteLogicResponse } from '@/features/chat/types'
|
||||
import { saveErrorLog } from '@/features/logs/saveErrorLog'
|
||||
|
||||
export const executeTypebotLink = async (
|
||||
state: SessionState,
|
@ -1,5 +1,5 @@
|
||||
import prisma from '@/lib/prisma'
|
||||
import { canReadTypebots } from '@/utils/api/dbRules'
|
||||
import { canReadTypebots } from '@/helpers/api/dbRules'
|
||||
import { User } from '@typebot.io/prisma'
|
||||
import {
|
||||
LogicBlockType,
|
@ -1,5 +1,5 @@
|
||||
import { ExecuteLogicResponse } from '@/features/chat'
|
||||
import { parseVariables } from '@/features/variables'
|
||||
import { ExecuteLogicResponse } from '@/features/chat/types'
|
||||
import { parseVariables } from '@/features/variables/parseVariables'
|
||||
import { SessionState, WaitBlock } from '@typebot.io/schemas'
|
||||
|
||||
export const executeWait = async (
|
@ -1,6 +0,0 @@
|
||||
import { router } from '@/utils/server/trpc'
|
||||
import { sendMessageProcedure } from './procedures'
|
||||
|
||||
export const chatRouter = router({
|
||||
sendMessage: sendMessageProcedure,
|
||||
})
|
@ -1,2 +0,0 @@
|
||||
export * from './chatRouter'
|
||||
export { getSession } from './utils'
|
@ -1 +0,0 @@
|
||||
export * from './sendMessageProcedure'
|
6
apps/viewer/src/features/chat/api/router.ts
Normal file
6
apps/viewer/src/features/chat/api/router.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { router } from '@/helpers/server/trpc'
|
||||
import { sendMessage } from './sendMessage'
|
||||
|
||||
export const chatRouter = router({
|
||||
sendMessage,
|
||||
})
|
@ -1,12 +1,5 @@
|
||||
import { checkChatsUsage } from '@/features/usage'
|
||||
import {
|
||||
prefillVariables,
|
||||
deepParseVariable,
|
||||
parseVariables,
|
||||
injectVariablesFromExistingResult,
|
||||
} from '@/features/variables'
|
||||
import prisma from '@/lib/prisma'
|
||||
import { publicProcedure } from '@/utils/server/trpc'
|
||||
import { publicProcedure } from '@/helpers/server/trpc'
|
||||
import { TRPCError } from '@trpc/server'
|
||||
import { Prisma } from '@typebot.io/prisma'
|
||||
import {
|
||||
@ -28,10 +21,15 @@ import {
|
||||
getSession,
|
||||
setResultAsCompleted,
|
||||
startBotFlow,
|
||||
} from '../utils'
|
||||
} from '../helpers'
|
||||
import { env, isDefined, omit } from '@typebot.io/lib'
|
||||
import { prefillVariables } from '@/features/variables/prefillVariables'
|
||||
import { checkChatsUsage } from '@/features/usage/checkChatsUsage'
|
||||
import { injectVariablesFromExistingResult } from '@/features/variables/injectVariablesFromExistingResult'
|
||||
import { deepParseVariables } from '@/features/variables/deepParseVariable'
|
||||
import { parseVariables } from '@/features/variables/parseVariables'
|
||||
|
||||
export const sendMessageProcedure = publicProcedure
|
||||
export const sendMessage = publicProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
method: 'POST',
|
||||
@ -165,10 +163,10 @@ const startSession = async (startParams?: StartParams, userId?: string) => {
|
||||
clientSideActions,
|
||||
typebot: {
|
||||
id: typebot.id,
|
||||
settings: deepParseVariable(newInitialState.typebot.variables)(
|
||||
settings: deepParseVariables(newInitialState.typebot.variables)(
|
||||
typebot.settings
|
||||
),
|
||||
theme: deepParseVariable(newInitialState.typebot.variables)(
|
||||
theme: deepParseVariables(newInitialState.typebot.variables)(
|
||||
typebot.theme
|
||||
),
|
||||
},
|
||||
@ -195,10 +193,10 @@ const startSession = async (startParams?: StartParams, userId?: string) => {
|
||||
sessionId: session.id,
|
||||
typebot: {
|
||||
id: typebot.id,
|
||||
settings: deepParseVariable(newInitialState.typebot.variables)(
|
||||
settings: deepParseVariables(newInitialState.typebot.variables)(
|
||||
typebot.settings
|
||||
),
|
||||
theme: deepParseVariable(newInitialState.typebot.variables)(
|
||||
theme: deepParseVariables(newInitialState.typebot.variables)(
|
||||
typebot.theme
|
||||
),
|
||||
},
|
@ -1,10 +1,3 @@
|
||||
import { validateEmail } from '@/features/blocks/inputs/email/api'
|
||||
import {
|
||||
formatPhoneNumber,
|
||||
validatePhoneNumber,
|
||||
} from '@/features/blocks/inputs/phone/api'
|
||||
import { validateUrl } from '@/features/blocks/inputs/url/api'
|
||||
import { parseVariables, updateVariables } from '@/features/variables'
|
||||
import prisma from '@/lib/prisma'
|
||||
import { TRPCError } from '@trpc/server'
|
||||
import { Prisma } from '@typebot.io/prisma'
|
||||
@ -22,6 +15,12 @@ import {
|
||||
import { isInputBlock, isNotDefined } from '@typebot.io/lib'
|
||||
import { executeGroup } from './executeGroup'
|
||||
import { getNextGroup } from './getNextGroup'
|
||||
import { validateEmail } from '@/features/blocks/inputs/email/validateEmail'
|
||||
import { formatPhoneNumber } from '@/features/blocks/inputs/phone/formatPhoneNumber'
|
||||
import { validatePhoneNumber } from '@/features/blocks/inputs/phone/validatePhoneNumber'
|
||||
import { validateUrl } from '@/features/blocks/inputs/url/validateUrl'
|
||||
import { updateVariables } from '@/features/variables/updateVariables'
|
||||
import { parseVariables } from '@/features/variables/parseVariables'
|
||||
|
||||
export const continueBotFlow =
|
||||
(state: SessionState) =>
|
@ -1,4 +1,3 @@
|
||||
import { deepParseVariable } from '@/features/variables'
|
||||
import {
|
||||
BubbleBlock,
|
||||
BubbleBlockType,
|
||||
@ -19,8 +18,9 @@ import {
|
||||
import { executeLogic } from './executeLogic'
|
||||
import { getNextGroup } from './getNextGroup'
|
||||
import { executeIntegration } from './executeIntegration'
|
||||
import { computePaymentInputRuntimeOptions } from '@/features/blocks/inputs/payment/api'
|
||||
import { injectVariableValuesInButtonsInputBlock } from '@/features/blocks/inputs/buttons/api/utils/injectVariableValuesInButtonsInputBlock'
|
||||
import { injectVariableValuesInButtonsInputBlock } from '@/features/blocks/inputs/buttons/injectVariableValuesInButtonsInputBlock'
|
||||
import { deepParseVariables } from '@/features/variables/deepParseVariable'
|
||||
import { computePaymentInputRuntimeOptions } from '@/features/blocks/inputs/payment/computePaymentInputRuntimeOptions'
|
||||
|
||||
export const executeGroup =
|
||||
(
|
||||
@ -137,7 +137,7 @@ const parseBubbleBlock =
|
||||
(block: BubbleBlock): ChatReply['messages'][0] => {
|
||||
switch (block.type) {
|
||||
case BubbleBlockType.EMBED: {
|
||||
const message = deepParseVariable(variables)(block)
|
||||
const message = deepParseVariables(variables)(block)
|
||||
return {
|
||||
...message,
|
||||
content: {
|
||||
@ -150,7 +150,7 @@ const parseBubbleBlock =
|
||||
}
|
||||
}
|
||||
default:
|
||||
return deepParseVariable(variables)(block)
|
||||
return deepParseVariables(variables)(block)
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,7 +164,7 @@ const injectVariablesValueInBlock =
|
||||
)
|
||||
}
|
||||
default: {
|
||||
return deepParseVariable(state.typebot.variables)({
|
||||
return deepParseVariables(state.typebot.variables)({
|
||||
...block,
|
||||
runtimeOptions: await computeRuntimeOptions(state)(block),
|
||||
prefilledValue: getPrefilledInputValue(state.typebot.variables)(
|
@ -1,15 +1,15 @@
|
||||
import { executeChatwootBlock } from '@/features/blocks/integrations/chatwoot/api'
|
||||
import { executeGoogleAnalyticsBlock } from '@/features/blocks/integrations/googleAnalytics/api'
|
||||
import { executeGoogleSheetBlock } from '@/features/blocks/integrations/googleSheets/api'
|
||||
import { executeOpenAIBlock } from '@/features/blocks/integrations/openai/executeOpenAIBlock'
|
||||
import { executeSendEmailBlock } from '@/features/blocks/integrations/sendEmail/api'
|
||||
import { executeWebhookBlock } from '@/features/blocks/integrations/webhook/api'
|
||||
import { executeSendEmailBlock } from '@/features/blocks/integrations/sendEmail/executeSendEmailBlock'
|
||||
import { executeWebhookBlock } from '@/features/blocks/integrations/webhook/executeWebhookBlock'
|
||||
import { executeChatwootBlock } from '@/features/blocks/integrations/chatwoot/executeChatwootBlock'
|
||||
import { executeGoogleAnalyticsBlock } from '@/features/blocks/integrations/googleAnalytics/executeGoogleAnalyticsBlock'
|
||||
import { executeGoogleSheetBlock } from '@/features/blocks/integrations/googleSheets/executeGoogleSheetBlock'
|
||||
import {
|
||||
IntegrationBlock,
|
||||
IntegrationBlockType,
|
||||
SessionState,
|
||||
} from '@typebot.io/schemas'
|
||||
import { ExecuteIntegrationResponse } from '../../types'
|
||||
import { ExecuteIntegrationResponse } from '../types'
|
||||
|
||||
export const executeIntegration =
|
||||
(state: SessionState, lastBubbleBlockId?: string) =>
|
@ -1,12 +1,12 @@
|
||||
import { executeCondition } from '@/features/blocks/logic/condition/api'
|
||||
import { executeRedirect } from '@/features/blocks/logic/redirect/api'
|
||||
import { executeSetVariable } from '@/features/blocks/logic/setVariable/api'
|
||||
import { executeTypebotLink } from '@/features/blocks/logic/typebotLink/api'
|
||||
import { executeWait } from '@/features/blocks/logic/wait/api/utils/executeWait'
|
||||
import { executeWait } from '@/features/blocks/logic/wait/executeWait'
|
||||
import { LogicBlock, LogicBlockType, SessionState } from '@typebot.io/schemas'
|
||||
import { ExecuteLogicResponse } from '../../types'
|
||||
import { ExecuteLogicResponse } from '../types'
|
||||
import { executeScript } from '@/features/blocks/logic/script/executeScript'
|
||||
import { executeJumpBlock } from '@/features/blocks/logic/jump/executeJumpBlock'
|
||||
import { executeRedirect } from '@/features/blocks/logic/redirect/executeRedirect'
|
||||
import { executeCondition } from '@/features/blocks/logic/condition/executeCondition'
|
||||
import { executeSetVariable } from '@/features/blocks/logic/setVariable/executeSetVariable'
|
||||
import { executeTypebotLink } from '@/features/blocks/logic/typebotLink/executeTypebotLink'
|
||||
|
||||
export const executeLogic =
|
||||
(state: SessionState, lastBubbleBlockId?: string) =>
|
@ -1 +0,0 @@
|
||||
export * from './types'
|
@ -1,2 +0,0 @@
|
||||
export * from './saveErrorLog'
|
||||
export * from './saveSuccessLog'
|
@ -1,4 +1,4 @@
|
||||
import { saveLog } from './utils'
|
||||
import { saveLog } from './saveLog'
|
||||
|
||||
export const saveErrorLog = ({
|
||||
resultId,
|
@ -1,4 +1,4 @@
|
||||
import { saveLog } from './utils'
|
||||
import { saveLog } from './saveLog'
|
||||
|
||||
export const saveSuccessLog = ({
|
||||
resultId,
|
@ -1 +0,0 @@
|
||||
export { createResultQuery, updateResultQuery } from './queries'
|
@ -1,2 +0,0 @@
|
||||
export * from './createResultQuery'
|
||||
export * from './updateResultQuery'
|
@ -1 +0,0 @@
|
||||
export * from './utils'
|
@ -1 +0,0 @@
|
||||
export * from './checkChatsUsage'
|
28
apps/viewer/src/features/variables/deepParseVariable.ts
Normal file
28
apps/viewer/src/features/variables/deepParseVariable.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { Variable } from '@typebot.io/schemas'
|
||||
import { parseVariables } from './parseVariables'
|
||||
|
||||
export const deepParseVariables =
|
||||
(variables: Variable[]) =>
|
||||
<T extends Record<string, unknown>>(object: T): T =>
|
||||
Object.keys(object).reduce<T>((newObj, key) => {
|
||||
const currentValue = object[key]
|
||||
|
||||
if (typeof currentValue === 'string')
|
||||
return { ...newObj, [key]: parseVariables(variables)(currentValue) }
|
||||
|
||||
if (currentValue instanceof Object && currentValue.constructor === Object)
|
||||
return {
|
||||
...newObj,
|
||||
[key]: deepParseVariables(variables)(
|
||||
currentValue as Record<string, unknown>
|
||||
),
|
||||
}
|
||||
|
||||
if (currentValue instanceof Array)
|
||||
return {
|
||||
...newObj,
|
||||
[key]: currentValue.map(deepParseVariables(variables)),
|
||||
}
|
||||
|
||||
return { ...newObj, [key]: currentValue }
|
||||
}, {} as T)
|
@ -0,0 +1,15 @@
|
||||
import { Variable } from '@typebot.io/schemas'
|
||||
|
||||
export const extractVariablesFromText =
|
||||
(variables: Variable[]) =>
|
||||
(text: string): Variable[] => {
|
||||
const matches = [...text.matchAll(/\{\{(.*?)\}\}/g)]
|
||||
return matches.reduce<Variable[]>((acc, match) => {
|
||||
const variableName = match[1]
|
||||
const variable = variables.find(
|
||||
(variable) => variable.name === variableName
|
||||
)
|
||||
if (!variable) return acc
|
||||
return [...acc, variable]
|
||||
}, [])
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
import { Variable } from '@typebot.io/schemas'
|
||||
|
||||
export const findUniqueVariableValue =
|
||||
(variables: Variable[]) =>
|
||||
(value: string | undefined): string | string[] | null => {
|
||||
if (!value || !value.startsWith('{{') || !value.endsWith('}}')) return null
|
||||
const variableName = value.slice(2, -2)
|
||||
const variable = variables.find(
|
||||
(variable) => variable.name === variableName
|
||||
)
|
||||
return variable?.value ?? null
|
||||
}
|
1
apps/viewer/src/features/variables/hasVariable.ts
Normal file
1
apps/viewer/src/features/variables/hasVariable.ts
Normal file
@ -0,0 +1 @@
|
||||
export const hasVariable = (str: string): boolean => /\{\{(.*?)\}\}/g.test(str)
|
@ -1 +0,0 @@
|
||||
export * from './utils'
|
@ -0,0 +1,17 @@
|
||||
import { Result, Variable } from '@typebot.io/schemas'
|
||||
|
||||
export const injectVariablesFromExistingResult = (
|
||||
variables: Variable[],
|
||||
resultVariables: Result['variables']
|
||||
): Variable[] =>
|
||||
variables.map((variable) => {
|
||||
const resultVariable = resultVariables.find(
|
||||
(resultVariable) =>
|
||||
resultVariable.name === variable.name && !variable.value
|
||||
)
|
||||
if (!resultVariable) return variable
|
||||
return {
|
||||
...variable,
|
||||
value: resultVariable.value,
|
||||
}
|
||||
})
|
20
apps/viewer/src/features/variables/parseGuessedValueType.ts
Normal file
20
apps/viewer/src/features/variables/parseGuessedValueType.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { Variable } from '@typebot.io/schemas'
|
||||
|
||||
export const parseGuessedValueType = (
|
||||
value: Variable['value']
|
||||
): string | string[] | boolean | number | null | undefined => {
|
||||
if (value === null) return null
|
||||
if (value === undefined) return undefined
|
||||
if (typeof value !== 'string') return value
|
||||
const isNumberStartingWithZero =
|
||||
value.startsWith('0') && !value.startsWith('0.') && value.length > 1
|
||||
if (typeof value === 'string' && isNumberStartingWithZero) return value
|
||||
if (typeof value === 'number') return value
|
||||
if (value === 'true') return true
|
||||
if (value === 'false') return false
|
||||
if (value === 'null') return null
|
||||
if (value === 'undefined') return undefined
|
||||
// isNaN works with strings
|
||||
if (isNaN(value as unknown as number)) return value
|
||||
return Number(value)
|
||||
}
|
40
apps/viewer/src/features/variables/parseVariables.ts
Normal file
40
apps/viewer/src/features/variables/parseVariables.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { isDefined } from '@typebot.io/lib'
|
||||
import { Variable, VariableWithValue } from '@typebot.io/schemas'
|
||||
import { safeStringify } from './safeStringify'
|
||||
|
||||
export const parseVariables =
|
||||
(
|
||||
variables: Variable[],
|
||||
options: { fieldToParse?: 'value' | 'id'; escapeForJson?: boolean } = {
|
||||
fieldToParse: 'value',
|
||||
escapeForJson: false,
|
||||
}
|
||||
) =>
|
||||
(text: string | undefined): string => {
|
||||
if (!text || text === '') return ''
|
||||
return text.replace(/\{\{(.*?)\}\}/g, (_, fullVariableString) => {
|
||||
const matchedVarName = fullVariableString.replace(/{{|}}/g, '')
|
||||
const variable = variables.find((variable) => {
|
||||
return (
|
||||
matchedVarName === variable.name &&
|
||||
(options.fieldToParse === 'id' || isDefined(variable.value))
|
||||
)
|
||||
}) as VariableWithValue | undefined
|
||||
if (!variable) return ''
|
||||
if (options.fieldToParse === 'id') return variable.id
|
||||
const { value } = variable
|
||||
if (options.escapeForJson)
|
||||
return jsonParse(
|
||||
typeof value !== 'string' ? JSON.stringify(value) : value
|
||||
)
|
||||
const parsedValue = safeStringify(value)
|
||||
if (!parsedValue) return ''
|
||||
return parsedValue
|
||||
})
|
||||
}
|
||||
|
||||
const jsonParse = (str: string) =>
|
||||
str
|
||||
.replace(/\n/g, `\\n`)
|
||||
.replace(/"/g, `\\"`)
|
||||
.replace(/\\[^n"]/g, `\\\\ `)
|
15
apps/viewer/src/features/variables/prefillVariables.ts
Normal file
15
apps/viewer/src/features/variables/prefillVariables.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { StartParams, Variable } from '@typebot.io/schemas'
|
||||
import { safeStringify } from './safeStringify'
|
||||
|
||||
export const prefillVariables = (
|
||||
variables: Variable[],
|
||||
prefilledVariables: NonNullable<StartParams['prefilledVariables']>
|
||||
): Variable[] =>
|
||||
variables.map((variable) => {
|
||||
const prefilledVariable = prefilledVariables[variable.name]
|
||||
if (!prefilledVariable) return variable
|
||||
return {
|
||||
...variable,
|
||||
value: safeStringify(prefilledVariable),
|
||||
}
|
||||
})
|
12
apps/viewer/src/features/variables/safeStringify.ts
Normal file
12
apps/viewer/src/features/variables/safeStringify.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { isNotDefined } from '@typebot.io/lib'
|
||||
|
||||
export const safeStringify = (val: unknown): string | null => {
|
||||
if (isNotDefined(val)) return null
|
||||
if (typeof val === 'string') return val
|
||||
try {
|
||||
return JSON.stringify(val)
|
||||
} catch {
|
||||
console.warn('Failed to safely stringify variable value', val)
|
||||
return null
|
||||
}
|
||||
}
|
77
apps/viewer/src/features/variables/updateVariables.ts
Normal file
77
apps/viewer/src/features/variables/updateVariables.ts
Normal file
@ -0,0 +1,77 @@
|
||||
import prisma from '@/lib/prisma'
|
||||
import { isDefined } from '@typebot.io/lib'
|
||||
import {
|
||||
SessionState,
|
||||
VariableWithUnknowValue,
|
||||
VariableWithValue,
|
||||
Variable,
|
||||
} from '@typebot.io/schemas'
|
||||
import { safeStringify } from './safeStringify'
|
||||
|
||||
export const updateVariables =
|
||||
(state: SessionState) =>
|
||||
async (newVariables: VariableWithUnknowValue[]): Promise<SessionState> => ({
|
||||
...state,
|
||||
typebot: {
|
||||
...state.typebot,
|
||||
variables: updateTypebotVariables(state)(newVariables),
|
||||
},
|
||||
result: {
|
||||
...state.result,
|
||||
variables: await updateResultVariables(state)(newVariables),
|
||||
},
|
||||
})
|
||||
|
||||
const updateResultVariables =
|
||||
({ result }: Pick<SessionState, 'result' | 'typebot'>) =>
|
||||
async (
|
||||
newVariables: VariableWithUnknowValue[]
|
||||
): Promise<VariableWithValue[]> => {
|
||||
const serializedNewVariables = newVariables.map((variable) => ({
|
||||
...variable,
|
||||
value: Array.isArray(variable.value)
|
||||
? variable.value.map(safeStringify).filter(isDefined)
|
||||
: safeStringify(variable.value),
|
||||
}))
|
||||
|
||||
const updatedVariables = [
|
||||
...result.variables.filter((existingVariable) =>
|
||||
serializedNewVariables.every(
|
||||
(newVariable) => existingVariable.id !== newVariable.id
|
||||
)
|
||||
),
|
||||
...serializedNewVariables,
|
||||
].filter((variable) => isDefined(variable.value)) as VariableWithValue[]
|
||||
|
||||
if (result.id)
|
||||
await prisma.result.update({
|
||||
where: {
|
||||
id: result.id,
|
||||
},
|
||||
data: {
|
||||
variables: updatedVariables,
|
||||
},
|
||||
})
|
||||
|
||||
return updatedVariables
|
||||
}
|
||||
|
||||
const updateTypebotVariables =
|
||||
({ typebot }: Pick<SessionState, 'result' | 'typebot'>) =>
|
||||
(newVariables: VariableWithUnknowValue[]): Variable[] => {
|
||||
const serializedNewVariables = newVariables.map((variable) => ({
|
||||
...variable,
|
||||
value: Array.isArray(variable.value)
|
||||
? variable.value.map(safeStringify).filter(isDefined)
|
||||
: safeStringify(variable.value),
|
||||
}))
|
||||
|
||||
return [
|
||||
...typebot.variables.filter((existingVariable) =>
|
||||
serializedNewVariables.every(
|
||||
(newVariable) => existingVariable.id !== newVariable.id
|
||||
)
|
||||
),
|
||||
...serializedNewVariables,
|
||||
]
|
||||
}
|
@ -1,229 +0,0 @@
|
||||
import prisma from '@/lib/prisma'
|
||||
import {
|
||||
Result,
|
||||
SessionState,
|
||||
StartParams,
|
||||
Typebot,
|
||||
Variable,
|
||||
VariableWithUnknowValue,
|
||||
VariableWithValue,
|
||||
} from '@typebot.io/schemas'
|
||||
import { isDefined, isNotDefined } from '@typebot.io/lib'
|
||||
|
||||
export const stringContainsVariable = (str: string): boolean =>
|
||||
/\{\{(.*?)\}\}/g.test(str)
|
||||
|
||||
export const parseVariables =
|
||||
(
|
||||
variables: Variable[],
|
||||
options: { fieldToParse?: 'value' | 'id'; escapeForJson?: boolean } = {
|
||||
fieldToParse: 'value',
|
||||
escapeForJson: false,
|
||||
}
|
||||
) =>
|
||||
(text: string | undefined): string => {
|
||||
if (!text || text === '') return ''
|
||||
return text.replace(/\{\{(.*?)\}\}/g, (_, fullVariableString) => {
|
||||
const matchedVarName = fullVariableString.replace(/{{|}}/g, '')
|
||||
const variable = variables.find((variable) => {
|
||||
return (
|
||||
matchedVarName === variable.name &&
|
||||
(options.fieldToParse === 'id' || isDefined(variable.value))
|
||||
)
|
||||
}) as VariableWithValue | undefined
|
||||
if (!variable) return ''
|
||||
if (options.fieldToParse === 'id') return variable.id
|
||||
const { value } = variable
|
||||
if (options.escapeForJson)
|
||||
return jsonParse(
|
||||
typeof value !== 'string' ? JSON.stringify(value) : value
|
||||
)
|
||||
const parsedValue = safeStringify(value)
|
||||
if (!parsedValue) return ''
|
||||
return parsedValue
|
||||
})
|
||||
}
|
||||
|
||||
export const extractVariablesFromText =
|
||||
(variables: Variable[]) =>
|
||||
(text: string): Variable[] => {
|
||||
const matches = [...text.matchAll(/\{\{(.*?)\}\}/g)]
|
||||
return matches.reduce<Variable[]>((acc, match) => {
|
||||
const variableName = match[1]
|
||||
const variable = variables.find(
|
||||
(variable) => variable.name === variableName
|
||||
)
|
||||
if (!variable) return acc
|
||||
return [...acc, variable]
|
||||
}, [])
|
||||
}
|
||||
|
||||
export const safeStringify = (val: unknown): string | null => {
|
||||
if (isNotDefined(val)) return null
|
||||
if (typeof val === 'string') return val
|
||||
try {
|
||||
return JSON.stringify(val)
|
||||
} catch {
|
||||
console.warn('Failed to safely stringify variable value', val)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export const parseCorrectValueType = (
|
||||
value: Variable['value']
|
||||
): string | string[] | boolean | number | null | undefined => {
|
||||
if (value === null) return null
|
||||
if (value === undefined) return undefined
|
||||
if (typeof value !== 'string') return value
|
||||
const isNumberStartingWithZero =
|
||||
value.startsWith('0') && !value.startsWith('0.') && value.length > 1
|
||||
if (typeof value === 'string' && isNumberStartingWithZero) return value
|
||||
if (typeof value === 'number') return value
|
||||
if (value === 'true') return true
|
||||
if (value === 'false') return false
|
||||
if (value === 'null') return null
|
||||
if (value === 'undefined') return undefined
|
||||
// isNaN works with strings
|
||||
if (isNaN(value as unknown as number)) return value
|
||||
return Number(value)
|
||||
}
|
||||
|
||||
const jsonParse = (str: string) =>
|
||||
str
|
||||
.replace(/\n/g, `\\n`)
|
||||
.replace(/"/g, `\\"`)
|
||||
.replace(/\\[^n"]/g, `\\\\ `)
|
||||
|
||||
export const deepParseVariable =
|
||||
(variables: Variable[]) =>
|
||||
<T extends Record<string, unknown>>(object: T): T =>
|
||||
Object.keys(object).reduce<T>((newObj, key) => {
|
||||
const currentValue = object[key]
|
||||
|
||||
if (typeof currentValue === 'string')
|
||||
return { ...newObj, [key]: parseVariables(variables)(currentValue) }
|
||||
|
||||
if (currentValue instanceof Object && currentValue.constructor === Object)
|
||||
return {
|
||||
...newObj,
|
||||
[key]: deepParseVariable(variables)(
|
||||
currentValue as Record<string, unknown>
|
||||
),
|
||||
}
|
||||
|
||||
if (currentValue instanceof Array)
|
||||
return {
|
||||
...newObj,
|
||||
[key]: currentValue.map(deepParseVariable(variables)),
|
||||
}
|
||||
|
||||
return { ...newObj, [key]: currentValue }
|
||||
}, {} as T)
|
||||
|
||||
export const prefillVariables = (
|
||||
variables: Typebot['variables'],
|
||||
prefilledVariables: NonNullable<StartParams['prefilledVariables']>
|
||||
): Variable[] =>
|
||||
variables.map((variable) => {
|
||||
const prefilledVariable = prefilledVariables[variable.name]
|
||||
if (!prefilledVariable) return variable
|
||||
return {
|
||||
...variable,
|
||||
value: safeStringify(prefilledVariable),
|
||||
}
|
||||
})
|
||||
|
||||
export const injectVariablesFromExistingResult = (
|
||||
variables: Typebot['variables'],
|
||||
resultVariables: Result['variables']
|
||||
): Variable[] =>
|
||||
variables.map((variable) => {
|
||||
const resultVariable = resultVariables.find(
|
||||
(resultVariable) =>
|
||||
resultVariable.name === variable.name && !variable.value
|
||||
)
|
||||
if (!resultVariable) return variable
|
||||
return {
|
||||
...variable,
|
||||
value: resultVariable.value,
|
||||
}
|
||||
})
|
||||
|
||||
export const updateVariables =
|
||||
(state: SessionState) =>
|
||||
async (newVariables: VariableWithUnknowValue[]): Promise<SessionState> => ({
|
||||
...state,
|
||||
typebot: {
|
||||
...state.typebot,
|
||||
variables: updateTypebotVariables(state)(newVariables),
|
||||
},
|
||||
result: {
|
||||
...state.result,
|
||||
variables: await updateResultVariables(state)(newVariables),
|
||||
},
|
||||
})
|
||||
|
||||
const updateResultVariables =
|
||||
({ result }: Pick<SessionState, 'result' | 'typebot'>) =>
|
||||
async (
|
||||
newVariables: VariableWithUnknowValue[]
|
||||
): Promise<VariableWithValue[]> => {
|
||||
const serializedNewVariables = newVariables.map((variable) => ({
|
||||
...variable,
|
||||
value: Array.isArray(variable.value)
|
||||
? variable.value.map(safeStringify).filter(isDefined)
|
||||
: safeStringify(variable.value),
|
||||
}))
|
||||
|
||||
const updatedVariables = [
|
||||
...result.variables.filter((existingVariable) =>
|
||||
serializedNewVariables.every(
|
||||
(newVariable) => existingVariable.id !== newVariable.id
|
||||
)
|
||||
),
|
||||
...serializedNewVariables,
|
||||
].filter((variable) => isDefined(variable.value)) as VariableWithValue[]
|
||||
|
||||
if (result.id)
|
||||
await prisma.result.update({
|
||||
where: {
|
||||
id: result.id,
|
||||
},
|
||||
data: {
|
||||
variables: updatedVariables,
|
||||
},
|
||||
})
|
||||
|
||||
return updatedVariables
|
||||
}
|
||||
|
||||
const updateTypebotVariables =
|
||||
({ typebot }: Pick<SessionState, 'result' | 'typebot'>) =>
|
||||
(newVariables: VariableWithUnknowValue[]): Variable[] => {
|
||||
const serializedNewVariables = newVariables.map((variable) => ({
|
||||
...variable,
|
||||
value: Array.isArray(variable.value)
|
||||
? variable.value.map(safeStringify).filter(isDefined)
|
||||
: safeStringify(variable.value),
|
||||
}))
|
||||
|
||||
return [
|
||||
...typebot.variables.filter((existingVariable) =>
|
||||
serializedNewVariables.every(
|
||||
(newVariable) => existingVariable.id !== newVariable.id
|
||||
)
|
||||
),
|
||||
...serializedNewVariables,
|
||||
]
|
||||
}
|
||||
|
||||
export const findUniqueVariableValue =
|
||||
(variables: Variable[]) =>
|
||||
(value: string | undefined): string | string[] | null => {
|
||||
if (!value || !value.startsWith('{{') || !value.endsWith('}}')) return null
|
||||
const variableName = value.slice(2, -2)
|
||||
const variable = variables.find(
|
||||
(variable) => variable.name === variableName
|
||||
)
|
||||
return variable?.value ?? null
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { chatRouter } from '@/features/chat/api'
|
||||
import { chatRouter } from '@/features/chat/api/router'
|
||||
import { router } from '../../trpc'
|
||||
|
||||
export const appRouter = router({
|
@ -17,7 +17,8 @@ import {
|
||||
} from '@typebot.io/schemas'
|
||||
import Cors from 'cors'
|
||||
import { getAuthenticatedGoogleClient } from '@/lib/google-sheets'
|
||||
import { saveErrorLog, saveSuccessLog } from '@/features/logs/api'
|
||||
import { saveErrorLog } from '@/features/logs/saveErrorLog'
|
||||
import { saveSuccessLog } from '@/features/logs/saveSuccessLog'
|
||||
|
||||
const cors = initMiddleware(Cors())
|
||||
|
||||
|
@ -15,7 +15,7 @@ import {
|
||||
Variable,
|
||||
} from '@typebot.io/schemas'
|
||||
import prisma from '@/lib/prisma'
|
||||
import { parseVariables } from '@/features/variables'
|
||||
import { parseVariables } from '@/features/variables/parseVariables'
|
||||
|
||||
const cors = initMiddleware(Cors())
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { authenticateUser } from '@/features/auth/api'
|
||||
import { authenticateUser } from '@/helpers/authenticateUser'
|
||||
import prisma from '@/lib/prisma'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import { methodNotAllowed } from '@typebot.io/lib/api'
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user