286 lines
8.4 KiB
TypeScript
286 lines
8.4 KiB
TypeScript
import { TemplateStyle, TemplateType } from "@prisma/client";
|
|
import { z } from "zod";
|
|
|
|
const email = z
|
|
.string({ invalid_type_error: "Email needs to be a string", required_error: "Email is required" })
|
|
.email({ message: "Invalid email address" })
|
|
.transform((e) => e.toLowerCase());
|
|
|
|
const password = z.string().min(6, "Password needs to be at least 6 characters long");
|
|
|
|
const id = z
|
|
.string({ invalid_type_error: "ID needs to be a string", required_error: "ID is required" })
|
|
.uuid({ message: "Id needs to be a valid UUID" });
|
|
|
|
export const UtilitySchemas = {
|
|
id: z.object({
|
|
id,
|
|
}),
|
|
email: z.object({
|
|
email,
|
|
}),
|
|
pagination: z.object({
|
|
page: z
|
|
.number({
|
|
invalid_type_error: "Page needs to be a number",
|
|
required_error: "Page is required",
|
|
})
|
|
.min(1, "Page needs to be at least 1")
|
|
.default(1)
|
|
.or(
|
|
z.string().transform((s) => {
|
|
return Number(s);
|
|
}),
|
|
),
|
|
}),
|
|
};
|
|
|
|
export const UserSchemas = {
|
|
credentials: z.object({
|
|
email: email,
|
|
password: password,
|
|
}),
|
|
};
|
|
|
|
const zodSchema = z.record(
|
|
z.union(
|
|
[
|
|
z
|
|
.string({
|
|
invalid_type_error:
|
|
"Metadata can only be a string, array of strings or a non-persistent object (https://docs.useplunk.com/working-with-contacts/metadata#non-persistent-metadata)",
|
|
})
|
|
.transform((s) => {
|
|
return { persistent: true, value: s };
|
|
}),
|
|
z
|
|
.array(
|
|
z.string({
|
|
invalid_type_error:
|
|
"Metadata can only be a string, array of strings or a non-persistent object (https://docs.useplunk.com/working-with-contacts/metadata#non-persistent-metadata)",
|
|
}),
|
|
)
|
|
.transform((s) => {
|
|
return { persistent: true, value: s };
|
|
}),
|
|
z.object(
|
|
{
|
|
persistent: z.boolean({ invalid_type_error: "Persistent should be a boolean" }).optional().default(true),
|
|
value: z.union([z.string(), z.array(z.string())], {
|
|
invalid_type_error:
|
|
"Metadata can only be a string, array of strings or a non-persistent object (https://docs.useplunk.com/working-with-contacts/metadata#non-persistent-metadata)",
|
|
}),
|
|
},
|
|
{
|
|
invalid_type_error:
|
|
"Metadata can only be a string, array of strings or a non-persistent object (https://docs.useplunk.com/working-with-contacts/metadata#non-persistent-metadata)",
|
|
},
|
|
),
|
|
],
|
|
{
|
|
invalid_type_error:
|
|
"Metadata can only be a string, array of strings or a non-persistent object (https://docs.useplunk.com/working-with-contacts/metadata#non-persistent-metadata)",
|
|
},
|
|
),
|
|
{ invalid_type_error: "Metadata should be an object (https://docs.useplunk.com/working-with-contacts/metadata)" },
|
|
);
|
|
export const EventSchemas = {
|
|
post: z.object({
|
|
email,
|
|
subscribed: z
|
|
.boolean({
|
|
invalid_type_error:
|
|
"Subscribed should be a boolean. Read more: https://docs.useplunk.com/api-reference/actions/track",
|
|
})
|
|
.nullish(),
|
|
event: z
|
|
.string({
|
|
required_error: "Event is required. Read more: https://docs.useplunk.com/api-reference/actions/track",
|
|
invalid_type_error: "Event can only be a string. Read more: https://docs.useplunk.com/api-reference/actions/track",
|
|
})
|
|
.transform((n) => n.toLowerCase())
|
|
.transform((n) => n.replace(/ /g, "-")),
|
|
data: zodSchema.nullish(),
|
|
}),
|
|
send: z.object({
|
|
subscribed: z.boolean({ invalid_type_error: "Subscribed should be a boolean" }).nullish(),
|
|
from: email.nullish(),
|
|
name: z.string().nullish(),
|
|
reply: email.nullish(),
|
|
to: z
|
|
.array(email)
|
|
.max(5, "You can only send transactional emails to 5 people at a time")
|
|
.or(email.transform((e) => [e])),
|
|
subject: z.string({
|
|
required_error: "Subject is required. Read more: https://docs.useplunk.com/api-reference/transactional/send",
|
|
}),
|
|
body: z.string({
|
|
required_error: "Body is required. Read more: https://docs.useplunk.com/api-reference/transactional/send",
|
|
}),
|
|
headers: z.record(z.string()).nullish(),
|
|
}),
|
|
};
|
|
|
|
export const CampaignSchemas = {
|
|
send: z.object({
|
|
id,
|
|
live: z.boolean().default(false),
|
|
delay: z.number().int("Delay needs to be a whole number").nonnegative("Delay needs to be a positive number"),
|
|
}),
|
|
create: z.object({
|
|
subject: z
|
|
.string()
|
|
.min(1, "Subject needs to be at least 1 character long")
|
|
.max(70, "Subject needs to be less than 70 characters long"),
|
|
body: z.string().min(1, "Body needs to be at least 1 character long"),
|
|
email: email.nullish().or(z.literal("")),
|
|
from: z.string().nullish(),
|
|
recipients: z.array(z.string()),
|
|
style: z.nativeEnum(TemplateStyle).default("PLUNK"),
|
|
}),
|
|
update: z.object({
|
|
id,
|
|
subject: z
|
|
.string()
|
|
.min(1, "Subject needs to be at least 1 character long")
|
|
.max(70, "Subject needs to be less than 70 characters long"),
|
|
body: z.string().min(1, "Body needs to be at least 1 character long"),
|
|
email: email.nullish().or(z.literal("")),
|
|
from: z.string().nullish(),
|
|
recipients: z.array(z.string()),
|
|
style: z.nativeEnum(TemplateStyle).default("PLUNK"),
|
|
}),
|
|
};
|
|
|
|
export const ActionSchemas = {
|
|
create: z.object({
|
|
name: z.string().min(1, "Name needs to be at least 1 character long"),
|
|
runOnce: z.boolean().default(false),
|
|
delay: z.number().int("Delay needs to be a whole number").nonnegative("Delay needs to be a positive number"),
|
|
template: id,
|
|
events: z.array(id).min(1, "Select at least one event"),
|
|
notevents: z.array(id).optional().default([]),
|
|
}),
|
|
update: z.object({
|
|
id,
|
|
name: z.string().min(1, "Name needs to be at least 1 character long"),
|
|
runOnce: z.boolean().default(false),
|
|
delay: z.number().int("Delay needs to be a whole number").nonnegative("Delay needs to be a positive number"),
|
|
template: id,
|
|
events: z.array(id).default([]),
|
|
notevents: z.array(id).optional().default([]),
|
|
}),
|
|
};
|
|
|
|
export const ContactSchemas = {
|
|
create: z.object({
|
|
email,
|
|
data: z
|
|
.object({})
|
|
.catchall(z.union([z.string(), z.array(z.string())]))
|
|
.or(z.string().transform((s) => (s === "" ? null : JSON.parse(s))))
|
|
.nullish(),
|
|
subscribed: z.boolean(),
|
|
}),
|
|
manage: z
|
|
.object({
|
|
id: id.optional(),
|
|
email: email.optional(),
|
|
data: z
|
|
.object({})
|
|
.catchall(z.union([z.string(), z.array(z.string()), z.null()]))
|
|
.or(z.string().transform((s) => (s === "" ? null : JSON.parse(s))))
|
|
.nullish(),
|
|
subscribed: z.boolean().nullish(),
|
|
})
|
|
.refine(
|
|
(data) => {
|
|
return data.id || data.email;
|
|
},
|
|
{ message: "Either id or email should be specified" },
|
|
)
|
|
.refine(
|
|
(data) => {
|
|
// if id and email are both present
|
|
return !(data.id && data.email);
|
|
},
|
|
{ message: "Either id or email should be specified" },
|
|
),
|
|
};
|
|
|
|
export const TemplateSchemas = {
|
|
create: z.object({
|
|
subject: z.string().min(1, "Subject can't be empty").max(70, "Subject needs to be less than 70 characters long"),
|
|
body: z.string().min(1, "Body can't be empty"),
|
|
email: email.nullish().or(z.literal("")),
|
|
from: z.string().nullish(),
|
|
type: z.nativeEnum(TemplateType).default("MARKETING"),
|
|
style: z.nativeEnum(TemplateStyle).default("PLUNK"),
|
|
}),
|
|
update: z.object({
|
|
id,
|
|
subject: z.string().min(1, "Subject can't be empty").max(70, "Subject needs to be less than 70 characters long"),
|
|
body: z.string().min(1, "Body can't be empty"),
|
|
email: email.nullish().or(z.literal("")),
|
|
from: z.string().nullish(),
|
|
type: z.nativeEnum(TemplateType).default("MARKETING"),
|
|
style: z.nativeEnum(TemplateStyle).default("PLUNK"),
|
|
}),
|
|
};
|
|
|
|
export const MembershipSchemas = {
|
|
invite: z.object({
|
|
id,
|
|
email,
|
|
role: z.enum(["MEMBER", "ADMIN"]).default("MEMBER"),
|
|
}),
|
|
kick: z.object({
|
|
id,
|
|
email,
|
|
}),
|
|
};
|
|
|
|
export const ProjectSchemas = {
|
|
secret: z.object({
|
|
secret: z.string(),
|
|
}),
|
|
create: z.object({
|
|
name: z.string().min(1, "Name can't be empty"),
|
|
|
|
url: z
|
|
.string()
|
|
.regex(/^(?:(?:https?):\/\/)?(?:[\w-]+\.)+[a-z]{2,}(?:\/[^\s]*)?$/)
|
|
.transform((u) => (u.startsWith("http") ? u : `https://${u}`)),
|
|
}),
|
|
update: z.object({
|
|
id: id,
|
|
name: z.string().min(1, "Name can't be empty"),
|
|
|
|
url: z
|
|
.string()
|
|
.regex(/^(?:(?:https?):\/\/)?(?:[\w-]+\.)+[a-z]{2,}(?:\/[^\s]*)?$/)
|
|
.transform((u) => (u.startsWith("http") ? u : `https://${u}`)),
|
|
}),
|
|
analytics: z.object({
|
|
method: z.enum(["week", "month", "year"]).default("week"),
|
|
}),
|
|
};
|
|
|
|
export const IdentitySchemas = {
|
|
create: z.object({
|
|
id: id,
|
|
email: email.refine(
|
|
(e) => {
|
|
return !["gmail.com", "outlook.com", "hotmail.com", "yahoo.com", "useplunk.com", "useplunk.dev"].includes(
|
|
e.split("@")[1],
|
|
);
|
|
},
|
|
{ message: "Please use your own domain" },
|
|
),
|
|
}),
|
|
update: z.object({
|
|
id: id,
|
|
from: z.string().min(1, "Name can't be empty"),
|
|
}),
|
|
};
|