server_message: Create zod schema to parse message recieved from server.

The commit creates a `server_message.ts` module which
will home our `zod` schema for the messages received
from server. We can then import the schema to parse
the data in needed modules at the API boundaries.
This will also help us write better tests.
This commit is contained in:
Varun Singh 2024-07-16 00:11:08 +05:30 committed by Tim Abbott
parent bdd39f4c67
commit 884317e407
3 changed files with 90 additions and 0 deletions

View File

@ -120,6 +120,7 @@ js_rules = RuleList(
"web/src/types.ts",
"web/src/util.ts",
"web/src/message_helper.ts",
"web/src/server_message.ts",
"web/tests/",
},
"exclude_pattern": "emails",

View File

@ -204,6 +204,7 @@ EXEMPT_FILES = make_set(
"web/src/sent_messages.ts",
"web/src/sentry.ts",
"web/src/server_events.js",
"web/src/server_message.ts",
"web/src/settings.js",
"web/src/settings_account.js",
"web/src/settings_bots.js",

88
web/src/server_message.ts Normal file
View File

@ -0,0 +1,88 @@
import {z} from "zod";
const display_recipient_users_schema = z.object({
id: z.number(),
email: z.string(),
full_name: z.string(),
is_mirror_dummy: z.boolean(),
});
export const message_edit_history_schema = z.array(
z.object({
prev_content: z.optional(z.string()),
prev_rendered_content: z.optional(z.string()),
prev_rendered_content_version: z.optional(z.number()),
prev_stream: z.optional(z.number()),
prev_topic: z.optional(z.string()),
stream: z.optional(z.number()),
timestamp: z.number(),
topic: z.optional(z.string()),
user_id: z.number().nullable(),
}),
);
const message_reaction_schema = z.array(
z.object({
emoji_name: z.string(),
emoji_code: z.string(),
reaction_type: z.enum(["unicode_emoji", "realm_emoji", "zulip_extra_emoji"]),
user_id: z.number(),
user: z.object({
id: z.number(),
email: z.string(),
full_name: z.string(),
is_mirror_dummy: z.boolean().nullish(),
}),
}),
);
const submessage_schema = z.array(
z.object({
msg_type: z.string(),
content: z.string(),
message_id: z.number(),
sender_id: z.number(),
id: z.number(),
}),
);
export const server_message_schema = z
.object({
avatar_url: z.string().nullish(),
client: z.string(),
content: z.string(),
content_type: z.enum(["text/html", "text/x-markdown"]),
display_recipient: z.union([z.string(), z.array(display_recipient_users_schema)]),
edit_history: z.optional(message_edit_history_schema),
id: z.number(),
is_me_message: z.boolean(),
last_edit_timestamp: z.number().optional(),
reactions: message_reaction_schema,
recipient_id: z.number(),
sender_email: z.string(),
sender_full_name: z.string(),
sender_id: z.number(),
sender_realm_str: z.string(),
submessages: submessage_schema,
timestamp: z.number(),
})
.and(
z.discriminatedUnion("type", [
z.object({
type: z.literal("stream"),
subject: z.string(),
stream_id: z.number(),
topic_links: z.array(
z.object({
text: z.string(),
url: z.string(),
}),
),
}),
z.object({
type: z.literal("private"),
subject: z.literal(""),
topic_links: z.array(z.never()),
}),
]),
);