2
0
Files
bot/packages/forge/core/index.ts

198 lines
5.1 KiB
TypeScript
Raw Normal View History

import { ZodRawShape, ZodTypeAny } from 'zod'
import { AuthDefinition, BlockDefinition, ActionDefinition } from './types'
import { ZodLayoutMetadata, z } from './zod'
export const variableStringSchema = z.custom<`{{${string}}}`>((val) =>
/^{{.+}}$/g.test(val as string)
)
export const createAuth = <A extends AuthDefinition>(authDefinition: A) =>
authDefinition
export const createBlock = <
Id extends string,
A extends AuthDefinition,
O extends z.ZodObject<any>
>(
blockDefinition: BlockDefinition<Id, A, O>
): BlockDefinition<Id, A, O> => blockDefinition
export const createVersionedBlock = <
Blocks extends Record<
string,
BlockDefinition<string, AuthDefinition, z.ZodObject<any>>
>
>(
blocks: Blocks
): Blocks => blocks
export const createAction = <
A extends AuthDefinition,
2024-01-11 12:39:58 +05:30
BaseOptions extends z.ZodObject<ZodRawShape> = z.ZodObject<{}>,
O extends z.ZodObject<ZodRawShape> = z.ZodObject<{}>
>(
actionDefinition: {
auth?: A
baseOptions?: BaseOptions
} & ActionDefinition<A, BaseOptions, O>
) => actionDefinition
export const parseBlockSchema = <
I extends string,
A extends AuthDefinition,
O extends z.ZodObject<any>
>(
blockDefinition: BlockDefinition<I, A, O>
) => {
const options = z.discriminatedUnion('action', [
blockDefinition.options
? blockDefinition.options.extend({
credentialsId: z.string().optional(),
action: z.undefined(),
})
: z.object({
credentialsId: z.string().optional(),
action: z.undefined(),
}),
...blockDefinition.actions.map((action) =>
blockDefinition.options
? (blockDefinition.options
.extend({
credentialsId: z.string().optional(),
})
.extend({
action: z.literal(action.name),
})
.merge(action.options ?? z.object({})) as any)
: z
.object({
credentialsId: z.string().optional(),
})
.extend({
action: z.literal(action.name),
})
.merge(action.options ?? z.object({}))
),
])
return z.object({
id: z.string(),
outgoingEdgeId: z.string().optional(),
type: z.literal(blockDefinition.id),
options: options.optional(),
})
}
export const parseBlockCredentials = <I extends string>(
blockId: I,
authSchema: z.ZodObject<any>
) => {
return z.object({
id: z.string(),
type: z.literal(blockId),
createdAt: z.date(),
workspaceId: z.string(),
name: z.string(),
iv: z.string(),
data: authSchema,
})
}
export const option = {
object: <T extends z.ZodRawShape>(schema: T) => z.object(schema),
literal: <T extends string>(value: T) => z.literal(value),
string: z.string().optional(),
2024-01-03 16:29:41 +01:00
boolean: z.boolean().optional(),
enum: <T extends string>(values: readonly [T, ...T[]]) =>
z.enum(values).optional(),
number: z.number().or(variableStringSchema).optional(),
array: <T extends z.ZodTypeAny>(schema: T) => z.array(schema).optional(),
discriminatedUnion: <
T extends string,
J extends [
z.ZodDiscriminatedUnionOption<T>,
...z.ZodDiscriminatedUnionOption<T>[]
]
>(
field: T,
schemas: J
) =>
// @ts-expect-error
z.discriminatedUnion<T, J>(field, [
z.object({ [field]: z.undefined() }),
...schemas,
]),
saveResponseArray: <I extends readonly [string, ...string[]]>(
items: I,
layouts?: {
item?: ZodLayoutMetadata<ZodTypeAny>
variableId?: ZodLayoutMetadata<ZodTypeAny>
}
) =>
z
.array(
z.object({
item: z
.enum(items)
.optional()
.layout({
...(layouts?.item ?? {}),
placeholder: 'Select a response',
defaultValue: items[0],
}),
variableId: z
.string()
.optional()
.layout({
...(layouts?.variableId ?? {}),
inputType: 'variableDropdown',
}),
})
)
.optional(),
filter: ({
operators = defaultFilterOperators,
isJoinerHidden,
}: {
operators?: readonly [string, ...string[]]
isJoinerHidden: (currentObj: Record<string, any>) => boolean
}) =>
z
.object({
comparisons: z.array(
z.object({
input: z.string().optional().layout({ label: 'Enter a field ' }),
operator: z
.enum(operators)
.optional()
.layout({ defaultValue: 'Equal to' }),
value: z
.string()
.optional()
.layout({ placeholder: 'Enter a value' }),
})
),
joiner: z.enum(['AND', 'OR']).optional().layout({
placeholder: 'Select joiner',
isHidden: isJoinerHidden,
}),
})
.optional(),
}
const defaultFilterOperators = [
'Equal to',
'Not equal',
'Contains',
'Does not contain',
'Greater than',
'Less than',
'Is set',
'Is empty',
'Starts with',
'Ends with',
'Matches regex',
'Does not match regex',
] as const
export type * from './types'