✨ Introducing Radar, fraud detection
This commit is contained in:
11
packages/env/env.ts
vendored
11
packages/env/env.ts
vendored
@@ -66,6 +66,16 @@ const baseEnv = {
|
||||
.default('FREE'),
|
||||
DEBUG: boolean.optional().default('false'),
|
||||
CHAT_API_TIMEOUT: z.coerce.number().optional(),
|
||||
RADAR_HIGH_RISK_KEYWORDS: z
|
||||
.string()
|
||||
.min(1)
|
||||
.transform((val) => val.split(','))
|
||||
.optional(),
|
||||
RADAR_INTERMEDIATE_RISK_KEYWORDS: z
|
||||
.string()
|
||||
.min(1)
|
||||
.transform((val) => val.split(','))
|
||||
.optional(),
|
||||
},
|
||||
client: {
|
||||
NEXT_PUBLIC_E2E_TEST: boolean.optional(),
|
||||
@@ -294,6 +304,7 @@ const telemetryEnv = {
|
||||
server: {
|
||||
TELEMETRY_WEBHOOK_URL: z.string().url().optional(),
|
||||
TELEMETRY_WEBHOOK_BEARER_TOKEN: z.string().min(1).optional(),
|
||||
MESSAGE_WEBHOOK_URL: z.string().url().optional(),
|
||||
USER_CREATED_WEBHOOK_URL: z.string().url().optional(),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ export const parseTestTypebot = (partialTypebot: Partial<Typebot>): Typebot => {
|
||||
isClosed: false,
|
||||
resultsTablePreferences: null,
|
||||
whatsAppCredentialsId: null,
|
||||
riskLevel: null,
|
||||
events:
|
||||
version === '6'
|
||||
? [
|
||||
|
||||
@@ -201,6 +201,7 @@ model Typebot {
|
||||
isArchived Boolean @default(false)
|
||||
isClosed Boolean @default(false)
|
||||
whatsAppCredentialsId String?
|
||||
riskLevel Int?
|
||||
|
||||
@@index([workspaceId])
|
||||
@@index([folderId])
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Typebot" ADD COLUMN "riskLevel" INTEGER;
|
||||
@@ -185,6 +185,7 @@ model Typebot {
|
||||
isArchived Boolean @default(false)
|
||||
isClosed Boolean @default(false)
|
||||
whatsAppCredentialsId String?
|
||||
riskLevel Int?
|
||||
|
||||
@@index([workspaceId])
|
||||
@@index([isArchived, createdAt(sort: Desc)])
|
||||
|
||||
56
packages/radar/index.ts
Normal file
56
packages/radar/index.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { Group } from '@typebot.io/schemas'
|
||||
import { env } from '@typebot.io/env'
|
||||
import { BubbleBlockType } from '@typebot.io/schemas/features/blocks/bubbles/constants'
|
||||
import { TDescendant, TElement, TText } from '@udecode/plate-common'
|
||||
|
||||
export const computeRiskLevel = ({
|
||||
name,
|
||||
groups,
|
||||
}: {
|
||||
name: string
|
||||
groups: Group[]
|
||||
}) => {
|
||||
if (!env.RADAR_HIGH_RISK_KEYWORDS) return 0
|
||||
if (
|
||||
env.RADAR_HIGH_RISK_KEYWORDS.some((keyword) =>
|
||||
name.toLowerCase().includes(keyword)
|
||||
)
|
||||
)
|
||||
return 100
|
||||
let hasSuspiciousKeywords = false
|
||||
for (const group of groups) {
|
||||
for (const block of group.blocks) {
|
||||
if (block.type !== BubbleBlockType.TEXT) continue
|
||||
for (const descendant of block.content?.richText as TDescendant[]) {
|
||||
if (
|
||||
env.RADAR_HIGH_RISK_KEYWORDS &&
|
||||
richTextElementContainsKeywords(env.RADAR_HIGH_RISK_KEYWORDS)(
|
||||
descendant
|
||||
)
|
||||
)
|
||||
return 100
|
||||
if (
|
||||
env.RADAR_INTERMEDIATE_RISK_KEYWORDS &&
|
||||
richTextElementContainsKeywords(env.RADAR_INTERMEDIATE_RISK_KEYWORDS)(
|
||||
descendant
|
||||
)
|
||||
)
|
||||
hasSuspiciousKeywords = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasSuspiciousKeywords ? 50 : 0
|
||||
}
|
||||
|
||||
const richTextElementContainsKeywords =
|
||||
(keywords: string[]) => (element: TElement | TText) => {
|
||||
if (element.text)
|
||||
return keywords.some((keyword) =>
|
||||
(element.text as string).toLowerCase().includes(keyword)
|
||||
)
|
||||
if (element.children)
|
||||
return (element.children as TDescendant[]).some(
|
||||
richTextElementContainsKeywords(keywords)
|
||||
)
|
||||
return false
|
||||
}
|
||||
18
packages/radar/package.json
Normal file
18
packages/radar/package.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "@typebot.io/radar",
|
||||
"version": "1.0.0",
|
||||
"main": "./index.ts",
|
||||
"types": "./index.ts",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@udecode/plate-common": "21.1.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typebot.io/schemas": "workspace:*",
|
||||
"@typebot.io/prisma": "workspace:*",
|
||||
"@typebot.io/tsconfig": "workspace:*",
|
||||
"@typebot.io/env": "workspace:*",
|
||||
"typescript": "5.3.2"
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,7 @@ export const typebotV5Schema = z.preprocess(
|
||||
isArchived: z.boolean(),
|
||||
isClosed: z.boolean(),
|
||||
whatsAppCredentialsId: z.string().nullable(),
|
||||
riskLevel: z.number().nullable(),
|
||||
}) satisfies z.ZodType<TypebotPrisma, z.ZodTypeDef, unknown>
|
||||
)
|
||||
export type TypebotV5 = z.infer<typeof typebotV5Schema>
|
||||
|
||||
Reference in New Issue
Block a user