made pretty and fixed message posting

This commit is contained in:
Kevin Puig
2025-09-27 15:55:20 -04:00
parent 74f4e076ce
commit da1310b9c8
10 changed files with 415 additions and 390 deletions

View File

@@ -1,127 +1,126 @@
import { Context } from "hono"; import { Context } from "hono";
import { sendMessageToChannel, removeMessageFromChannel } from "../services/realtime.js" import {
sendMessageToChannel,
removeMessageFromChannel,
} from "../services/realtime.js";
import { success } from "zod"; import { success } from "zod";
export async function postMessageToChannel(io: any, c: Context) {
try {
io = c.get("io");
export async function postMessageToChannel( const instanceId = c.req.param("instanceId");
io: any, const categoryId = c.req.param("categoryId");
c: Context const channelId = c.req.param("channelId");
) { const message = await c.req.json();
try {
io = c.get("io");
const instanceId = c.req.param("instanceId"); const result = await sendMessageToChannel(
const categoryId = c.req.param("categoryId"); instanceId,
const channelId = c.req.param("channelId"); categoryId,
const message = await c.req.json(); channelId,
message,
"new_channel_message",
io,
);
const result = await sendMessageToChannel( if (result === "Event not implemented") {
instanceId, console.log(
categoryId, "controller::realtime::postMessageToChannel - Failed to send message",
channelId, );
message, return c.json({
"new_channel_message", success: false,
io message: "Event not implemented or recognized",
) status: 400,
});
if(result === "Event not implemented"){
console.log("controller::realtime::postMessageToChannel - Failed to send message")
return c.json({
success: false,
message: "Event not implemented or recognized",
status: 400
})
}
if(result === "no acknowledgment"){
console.log("controller::realtime::postMessageToChannel - No acknowledgment received from client")
return c.json({
success: false,
message: "No acknowledgment received from client",
status: 500
})
}
if(!result){
throw new Error("failed to send message");
}
return c.json({
success: true,
message: "Message sent successfully",
status: 200
})
} catch (err) {
const errMessage = err as Error;
console.log("controller::realtime::postMessageToChannel - ", errMessage);
return c.json({
success: false,
message: errMessage.message,
status: 500
});
} }
if (result === "no acknowledgment") {
console.log(
"controller::realtime::postMessageToChannel - No acknowledgment received from client",
);
return c.json({
success: false,
message: "No acknowledgment received from client",
status: 500,
});
}
if (!result) {
throw new Error("failed to send message");
}
return c.json({
success: true,
message: "Message sent successfully",
status: 200,
});
} catch (err) {
const errMessage = err as Error;
console.log("controller::realtime::postMessageToChannel - ", errMessage);
return c.json({
success: false,
message: errMessage.message,
status: 500,
});
}
} }
export async function deleteMessageFromChannel( export async function deleteMessageFromChannel(io: any, c: Context) {
io: any, try {
c: Context io = c.get("io");
){
try {
io = c.get("io"); const instanceId = c.req.param("instanceId");
const categoryId = c.req.param("categoryId");
const channelId = c.req.param("channelId");
const messageId = c.req.param("messageId");
const instanceId = c.req.param("instanceId"); const result = await removeMessageFromChannel(
const categoryId = c.req.param("categoryId"); instanceId,
const channelId = c.req.param("channelId"); categoryId,
const messageId = c.req.param("messageId"); channelId,
messageId,
"delete_channel_message",
io,
);
const result = await removeMessageFromChannel( if (result === "event not implemented") {
instanceId, console.log(
categoryId, "controller::realtime::deleteMessageFromChannel - Event not implemented",
channelId, );
messageId, return c.json({
"delete_channel_message", success: false,
io message: "Event not implemented or recognized",
) status: 400,
});
if(result === "event not implemented"){
console.log("controller::realtime::deleteMessageFromChannel - Event not implemented")
return c.json({
success: false,
message: "Event not implemented or recognized",
status: 400
});
}
if(result === "no acknowledgment"){
console.log("controller::realtime::deleteMessageFromChannel - No acknowledgment received from client")
return c.json({
success: false,
message: "No acknowledgment received from client",
status: 500
});
}
if(!result){
throw new Error("failed to delete message");
}
c.json({
success: true,
message: "Message deleted successfully",
status: 200
})
} catch (err) {
const errMessage = err as Error;
console.log("services::realtime::deleteMessageFromChannel - ", errMessage);
return c.json({
success: false,
message: errMessage.message,
status: 500
});
} }
if (result === "no acknowledgment") {
console.log(
"controller::realtime::deleteMessageFromChannel - No acknowledgment received from client",
);
return c.json({
success: false,
message: "No acknowledgment received from client",
status: 500,
});
}
if (!result) {
throw new Error("failed to delete message");
}
c.json({
success: true,
message: "Message deleted successfully",
status: 200,
});
} catch (err) {
const errMessage = err as Error;
console.log("services::realtime::deleteMessageFromChannel - ", errMessage);
return c.json({
success: false,
message: errMessage.message,
status: 500,
});
}
} }

View File

@@ -1,4 +1,8 @@
import { getAllUsersFrom, getUserInformation, createUser } from "../services/userService"; import {
getAllUsersFrom,
getUserInformation,
createUser,
} from "../services/userService";
import { CreateUserInput } from "../validators/userValidator"; import { CreateUserInput } from "../validators/userValidator";
export async function fetchUserData(id: string) { export async function fetchUserData(id: string) {

View File

@@ -1,5 +1,5 @@
import * as crypto from 'crypto'; import * as crypto from "crypto";
export default function shaHash(data:string, salt:string) : string { export default function shaHash(data: string, salt: string): string {
return crypto.createHmac('sha256', salt).update(data).digest('hex'); return crypto.createHmac("sha256", salt).update(data).digest("hex");
} }

View File

@@ -53,21 +53,19 @@ app.use(
app.route("/api", routes); app.route("/api", routes);
app.get( app.get(
'/openapi', "/openapi",
openAPIRouteHandler(app, { openAPIRouteHandler(app, {
documentation: { documentation: {
info: { info: {
title: 'Hono API', title: "Hono API",
version: '1.0.0', version: "1.0.0",
description: 'Greeting API', description: "Greeting API",
}, },
servers: [ servers: [{ url: "http://localhost:3000", description: "Local Server" }],
{ url: 'http://localhost:3000', description: 'Local Server' },
],
}, },
}) }),
) );
app.get('/scalar', Scalar({ url: '/openapi' })) app.get("/scalar", Scalar({ url: "/openapi" }));
export default app; export default app;

View File

@@ -1,28 +1,29 @@
import { Hono } from "hono"; import { Hono } from "hono";
import { zValidator } from "@hono/zod-validator"; import { zValidator } from "@hono/zod-validator";
import { describeRoute, resolver } from "hono-openapi"; import { describeRoute, resolver } from "hono-openapi";
import { postMessageToChannel, import {
deleteMessageFromChannel postMessageToChannel,
deleteMessageFromChannel,
} from "../controller/realtime"; } from "../controller/realtime";
const app = new Hono(); const app = new Hono();
app.post( app.post(
"message/", "message/",
zValidator({ zValidator({
body: z.object({ body: z.object({
content: z.string().min(1).max(500) content: z.string().min(1).max(500),
})
}), }),
async (c) => { }),
const { instanceId, categoryId, channelId } = c.req.params; async (c) => {
const { content } = c.req.body; const { instanceId, categoryId, channelId } = c.req.params;
const { content } = c.req.body;
return postMessageToChannel(c.get("io"), { return postMessageToChannel(c.get("io"), {
instanceId, instanceId,
categoryId, categoryId,
channelId, channelId,
content content,
}); });
} },
); );

View File

@@ -1,29 +1,38 @@
import { Hono } from "hono"; import { Hono } from "hono";
import { fetchAllUsers, fetchUserData, createNewUser } from "../controller/userController"; import {
import { createUserSchema, queryAllUsersByInstanceId, queryUserByIdSchema } from "../validators/userValidator"; fetchAllUsers,
fetchUserData,
createNewUser,
} from "../controller/userController";
import {
createUserSchema,
queryAllUsersByInstanceId,
queryUserByIdSchema,
} from "../validators/userValidator";
import { zValidator } from "@hono/zod-validator"; import { zValidator } from "@hono/zod-validator";
import { describeRoute, resolver } from "hono-openapi"; import { describeRoute, resolver } from "hono-openapi";
const actions = new Hono(); const actions = new Hono();
actions.get("user/:id", actions.get(
"user/:id",
describeRoute({ describeRoute({
description: "Get user by id", description: "Get user by id",
responses: { responses: {
200: { 200: {
description: "Success getting user", description: "Success getting user",
content: { content: {
"application/json": { schema: resolver(queryUserByIdSchema) } "application/json": { schema: resolver(queryUserByIdSchema) },
} },
}, },
404: { 404: {
description: "User id not found", description: "User id not found",
content: { content: {
"application/json": { schema: resolver(queryUserByIdSchema) } "application/json": { schema: resolver(queryUserByIdSchema) },
} },
} },
} },
}), }),
zValidator('param', queryUserByIdSchema), zValidator("param", queryUserByIdSchema),
async (c) => { async (c) => {
const id = c.req.param("id"); const id = c.req.param("id");
const userData = await fetchUserData(id); const userData = await fetchUserData(id);
@@ -32,22 +41,23 @@ actions.get("user/:id",
} else { } else {
return c.json({ error: "User not found" }, 404); return c.json({ error: "User not found" }, 404);
} }
} },
); );
actions.get("user", actions.get(
"user",
describeRoute({ describeRoute({
description: "Get all users by instance id", description: "Get all users by instance id",
responses: { responses: {
200: { 200: {
description: "Success getting all users in instance", description: "Success getting all users in instance",
content: { content: {
"application/json": { schema: resolver(queryAllUsersByInstanceId) } "application/json": { schema: resolver(queryAllUsersByInstanceId) },
} },
} },
} },
}), }),
zValidator('query', queryAllUsersByInstanceId), zValidator("query", queryAllUsersByInstanceId),
async (c) => { async (c) => {
const instanceId = c.req.query("instanceId"); const instanceId = c.req.query("instanceId");
if (!instanceId) { if (!instanceId) {
@@ -60,7 +70,7 @@ actions.get("user",
} else { } else {
return c.json({ error: "Error getting all users from instance" }, 500); return c.json({ error: "Error getting all users from instance" }, 500);
} }
} },
); );
actions.post( actions.post(
@@ -71,18 +81,18 @@ actions.post(
201: { 201: {
description: "Success", description: "Success",
content: { content: {
'application/json': { schema: resolver(createUserSchema) }, "application/json": { schema: resolver(createUserSchema) },
}, },
}, },
400: { 400: {
description: "Bad request (user exists)", description: "Bad request (user exists)",
content: { content: {
'application/json': { schema: resolver(createUserSchema) } "application/json": { schema: resolver(createUserSchema) },
} },
} },
} },
}), }),
zValidator('json', createUserSchema), zValidator("json", createUserSchema),
async (c) => { async (c) => {
try { try {
const data = await c.req.json(); const data = await c.req.json();
@@ -94,7 +104,7 @@ actions.post(
} catch (error) { } catch (error) {
return c.json({ error: "Error creating user" }, 500); return c.json({ error: "Error creating user" }, 500);
} }
} },
); );
export default actions; export default actions;

View File

@@ -3,75 +3,76 @@ import {
MessagePing, MessagePing,
PrismaClient, PrismaClient,
Role, Role,
Reply Reply,
} from "@prisma/client"; } from "@prisma/client";
import { CreateUserInput } from '../validators/userValidator'; import { CreateUserInput } from "../validators/userValidator";
const prisma = new PrismaClient(); const prisma = new PrismaClient();
class MessageService { export async function sendMessageToChannel(
public async function sendMessageToChannel( channelId: string,
channelId: string, userId: string,
userId: string, content: string,
content: string, repliedMessageId: string | null,
repliedMessageId: string | null ): Promise<{
): Promise<{ id: string;
id: string, channelId: string;
channelId: string, userId: string;
userId: string, text: string;
text: string, deleted: boolean;
deleted: boolean, replies: null | {
replies: null | { messageId: string;
messageId: string, repliesToId: string;
repliesToId: string, repliesToText: string;
repliesToText: string };
} } | null> {
} | null> { try {
try { const newMessage = await prisma.message.create({
data: {
channelId: channelId,
const newMessage = await prisma.message.create({ userId: userId,
data: { text: content,
channelId: channelId, deleted: false,
userId: userId, },
text: content, });
deleted: false,
}
})
let origMessage;
if(repliedMessageId){
origMessage = await prisma.message.findUnique({
where: {
id: repliedMessageId
}
})
if(!origMessage){
throw new Error("could not find original message to reply to");
}
await prisma.reply.create({
data: {
messageId: newMessage.id,
repliesToId: origMessage.id
}
})
}
return {
...newMessage,
replies: repliedMessageId ? {
messageId: newMessage.id,
repliesToId: origMessage?.id,
repliesToText: origMessage?.text
} : null
}
} catch (error) {
if (!newMessage) {
return null;
} }
let origMessage;
if (repliedMessageId) {
origMessage = await prisma.message.findUnique({
where: {
id: repliedMessageId,
},
});
if (!origMessage) {
throw new Error("could not find original message to reply to");
}
await prisma.reply.create({
data: {
messageId: newMessage.id,
repliesToId: origMessage.id,
},
});
}
return {
...newMessage,
channelId: newMessage.channelId!,
userId: newMessage.userId!,
replies: origMessage
? {
messageId: newMessage.id,
repliesToId: origMessage?.id,
repliesToText: origMessage?.text,
}
: null,
};
} catch (error) {
return null;
}
} }

View File

@@ -1,88 +1,90 @@
import { readonly } from "zod"; import { readonly } from "zod";
const EVENTS = { const EVENTS = {
NEW_CHANNEL_MESSAGE: "new_channel_message", NEW_CHANNEL_MESSAGE: "new_channel_message",
DELETE_CHANNEL_MESSAGE: "delete_channel_message", DELETE_CHANNEL_MESSAGE: "delete_channel_message",
} };
export async function sendMessageToChannel( export async function sendMessageToChannel(
instanceId: string, instanceId: string,
categoryId: string, categoryId: string,
channelId: string, channelId: string,
message: any, message: any,
event: string, event: string,
io: any, io: any,
): Promise<string | boolean> { ): Promise<string | boolean> {
try { try {
//TODO: implement middleware to replace this
//TODO: implement middleware to replace this if (EVENTS.NEW_CHANNEL_MESSAGE === event) {
if(EVENTS.NEW_CHANNEL_MESSAGE === event){ throw new Error("Event not implemented");
throw new Error("Event not implemented");
}
//TODO: add prisma to save channel message to DB
return new Promise((resolve) => {
io.to(instanceId).emit(event, message, (ack: any) => {
if (ack && ack.status === 'received') {
console.log(`Message ${ack.messageId} acknowledged by client.`);
resolve(true);
} else {
console.log('services::realtime::sendMessageToChannel No acknowledgment received from client.');
resolve("no acknowledgment");
}
});
});
} catch (err) {
const errMessage = err as Error;
if (errMessage.message === "Event not implemented") {
console.log(`services::realtime::sendMessageToChannel - Event not implemented. Attempted event: ${event}`)
return "event not implemented"
}
console.log("services::realtime::sendMessageToChannel - ", errMessage);
return false;
} }
//TODO: add prisma to save channel message to DB
return new Promise((resolve) => {
io.to(instanceId).emit(event, message, (ack: any) => {
if (ack && ack.status === "received") {
console.log(`Message ${ack.messageId} acknowledged by client.`);
resolve(true);
} else {
console.log(
"services::realtime::sendMessageToChannel No acknowledgment received from client.",
);
resolve("no acknowledgment");
}
});
});
} catch (err) {
const errMessage = err as Error;
if (errMessage.message === "Event not implemented") {
console.log(
`services::realtime::sendMessageToChannel - Event not implemented. Attempted event: ${event}`,
);
return "event not implemented";
}
console.log("services::realtime::sendMessageToChannel - ", errMessage);
return false;
}
} }
export async function removeMessageFromChannel( export async function removeMessageFromChannel(
instanceId: string, instanceId: string,
categoryId: string, categoryId: string,
channelId: string, channelId: string,
messageId: string, messageId: string,
event: string, event: string,
io: any io: any,
): Promise<string | boolean>{ ): Promise<string | boolean> {
try { try {
//TODO: implement middleware to replace this
//TODO: implement middleware to replace this if (EVENTS.DELETE_CHANNEL_MESSAGE === event) {
if(EVENTS.DELETE_CHANNEL_MESSAGE === event){ throw new Error("event not implemented");
throw new Error("event not implemented");
}
//TODO: add prisma to flag a channel message as deleted
return new Promise((resolve) => {
io.to(instanceId).emit(event, { messageId }, (ack: any) => {
if (ack && ack.status === 'received') {
console.log(`Message ${ack.messageId} acknowledged by client.`);
resolve(true);
} else {
console.log('services::realtime::deleteMessageFromChannel No acknowledgment received from client.');
resolve("no acknowledgment");
}
});
});
} catch (err) {
const errMessage = err as Error;
if (errMessage.message === "Event not implemented") {
console.log(`services::realtime::deleteMessageFromChannel - Event not implemented. Attempted event: ${event}`)
return false;
}
console.log("services::realtime::deleteMessageFromChannel - ", errMessage);
return false;
} }
//TODO: add prisma to flag a channel message as deleted
return new Promise((resolve) => {
io.to(instanceId).emit(event, { messageId }, (ack: any) => {
if (ack && ack.status === "received") {
console.log(`Message ${ack.messageId} acknowledged by client.`);
resolve(true);
} else {
console.log(
"services::realtime::deleteMessageFromChannel No acknowledgment received from client.",
);
resolve("no acknowledgment");
}
});
});
} catch (err) {
const errMessage = err as Error;
if (errMessage.message === "Event not implemented") {
console.log(
`services::realtime::deleteMessageFromChannel - Event not implemented. Attempted event: ${event}`,
);
return false;
}
console.log("services::realtime::deleteMessageFromChannel - ", errMessage);
return false;
}
} }

View File

@@ -5,31 +5,35 @@ import {
Role, Role,
UserAuth, UserAuth,
} from "@prisma/client"; } from "@prisma/client";
import { CreateUserInput } from '../validators/userValidator'; import { CreateUserInput } from "../validators/userValidator";
import shaHash from "../helper/hashing"; import shaHash from "../helper/hashing";
const prisma = new PrismaClient(); const prisma = new PrismaClient();
export async function createUser(data: CreateUserInput): Promise<{ export async function createUser(data: CreateUserInput): Promise<{
username: string, username: string;
nickname: string | null, nickname: string | null;
bio: string | null, bio: string | null;
picture: string | null, picture: string | null;
banner: string | null, banner: string | null;
status: string, status: string;
admin: boolean admin: boolean;
} | null> { } | null> {
const requestingUser = await getUserInformation(data.requestingUserId); const requestingUser = await getUserInformation(data.requestingUserId);
const requestingUserCredentials = await getUserCredentials(data.requestingUserId) const requestingUserCredentials = await getUserCredentials(
if (!requestingUser data.requestingUserId,
|| !requestingUserCredentials );
|| !requestingUser.admin if (
|| requestingUserCredentials.token == null !requestingUser ||
|| data.requestingUserToken != requestingUserCredentials.token) { !requestingUserCredentials ||
!requestingUser.admin ||
requestingUserCredentials.token == null ||
data.requestingUserToken != requestingUserCredentials.token
) {
return null; return null;
} }
if (await prisma.user.count({ where: { username: data.username }}) >= 1) { if ((await prisma.user.count({ where: { username: data.username } })) >= 1) {
return null; return null;
} }
@@ -45,13 +49,15 @@ export async function createUser(data: CreateUserInput): Promise<{
}, },
}); });
if (!(await prisma.userAuth.create({ if (
data: { !(await prisma.userAuth.create({
userId: userData.id, data: {
password: shaHash(data.passwordhash, userData.id), userId: userData.id,
token: null, password: shaHash(data.passwordhash, userData.id),
} token: null,
}))) { },
}))
) {
return null; return null;
} }
@@ -59,52 +65,52 @@ export async function createUser(data: CreateUserInput): Promise<{
} }
export async function getUserCredentials(userId: string): Promise<{ export async function getUserCredentials(userId: string): Promise<{
userId: string, userId: string;
password: string, password: string;
token: string | null token: string | null;
} | null> { } | null> {
try { try {
if (!userId) { if (!userId) {
throw new Error("missing userId"); throw new Error("missing userId");
} }
const userAuth = await prisma.userAuth.findUnique({ const userAuth = await prisma.userAuth.findUnique({
where: { where: {
userId: userId, userId: userId,
}, },
}); });
if (!userAuth) { if (!userAuth) {
throw new Error("could not find user credentials"); throw new Error("could not find user credentials");
} }
return { return {
userId: userAuth.userId, userId: userAuth.userId,
password: userAuth.password, password: userAuth.password,
token: userAuth.token, token: userAuth.token,
}; };
} catch (err) { } catch (err) {
const errMessage = err as Error; const errMessage = err as Error;
if (errMessage.message === "missing userId") { if (errMessage.message === "missing userId") {
console.log("services::actions::getUserCredentials - missing userId"); console.log("services::actions::getUserCredentials - missing userId");
return null; return null;
} }
if (errMessage.message === "could not find user credentials") {
console.log(
"services::actions::getUserCredentials - unable to find user credentials",
);
return null;
}
if (errMessage.message === "could not find user credentials") {
console.log( console.log(
"services::actions::getUserCredentials - unknown error", "services::actions::getUserCredentials - unable to find user credentials",
errMessage,
); );
return null; return null;
} }
console.log(
"services::actions::getUserCredentials - unknown error",
errMessage,
);
return null;
} }
}
export async function getUserInformation(userId: string): Promise<{ export async function getUserInformation(userId: string): Promise<{
id: string; id: string;
@@ -196,9 +202,9 @@ export async function getAllUsersFrom(instanceId: string): Promise<
try { try {
const instances = await prisma.instance.count({ const instances = await prisma.instance.count({
where: { where: {
id: instanceId id: instanceId,
} },
}) });
if (instances < 1) { if (instances < 1) {
throw new Error("could not find given instance id"); throw new Error("could not find given instance id");
} }
@@ -218,8 +224,8 @@ export async function getAllUsersFrom(instanceId: string): Promise<
const admins = await prisma.user.findMany({ const admins = await prisma.user.findMany({
where: { where: {
admin: true admin: true,
} },
}); });
if (!admins) { if (!admins) {
throw new Error("could not get all admins"); throw new Error("could not get all admins");
@@ -249,13 +255,13 @@ export async function getAllUsersFrom(instanceId: string): Promise<
).includes(u.status as any) ).includes(u.status as any)
? (u.status as "online" | "offline" | "dnd" | "idle" | "invis") ? (u.status as "online" | "offline" | "dnd" | "idle" | "invis")
: "offline", : "offline",
role: adminRoles.map(r => ({ role: adminRoles.map((r) => ({
userId: r.userId, userId: r.userId,
instanceId: r.instanceId, instanceId: r.instanceId,
})), })),
} };
}) }),
) );
const userData = await Promise.all( const userData = await Promise.all(
users.map(async (u) => { users.map(async (u) => {

View File

@@ -1,12 +1,12 @@
import { z } from 'zod' import { z } from "zod";
export const queryUserByIdSchema = z.object({ export const queryUserByIdSchema = z.object({
id: z.uuidv7() id: z.uuidv7(),
}) });
export const queryAllUsersByInstanceId = z.object({ export const queryAllUsersByInstanceId = z.object({
instanceId: z.uuidv7() instanceId: z.uuidv7(),
}) });
export const createUserSchema = z.object({ export const createUserSchema = z.object({
username: z.string().min(3).max(30), username: z.string().min(3).max(30),
@@ -14,13 +14,17 @@ export const createUserSchema = z.object({
bio: z.string().max(500).optional(), bio: z.string().max(500).optional(),
picture: z.url().optional(), picture: z.url().optional(),
banner: z.url().optional(), banner: z.url().optional(),
status: z.enum(['online', 'offline', 'dnd', 'idle', 'invis']).default('online'), status: z
.enum(["online", "offline", "dnd", "idle", "invis"])
.default("online"),
admin: z.boolean().default(false), admin: z.boolean().default(false),
requestingUserId: z.uuidv7(), requestingUserId: z.uuidv7(),
requestingUserToken: z.uuidv4(), requestingUserToken: z.uuidv4(),
passwordhash: z.string(), passwordhash: z.string(),
}) });
export type QueryUserByIdInput = z.infer<typeof queryUserByIdSchema> export type QueryUserByIdInput = z.infer<typeof queryUserByIdSchema>;
export type QueryAllUsersByInstanceIdInput = z.infer<typeof queryAllUsersByInstanceId> export type QueryAllUsersByInstanceIdInput = z.infer<
export type CreateUserInput = z.infer<typeof createUserSchema> typeof queryAllUsersByInstanceId
>;
export type CreateUserInput = z.infer<typeof createUserSchema>;