jamalsoueidan
jamalsoueidanā€¢4mo ago

union of two types

how do i typeguard in convex? in typescript i usually do type guards to handle this situtation, how to do that in convex? function isText(invoice: args ): invoice is object1 { return invoice.type === "text"; }
export const webhooks = internalAction({
args: {
object: v.string(),
entry: v.array(
v.object({
id: v.string(),
changes: v.array(
v.object({
field: v.string(),
value: v.object({
messaging_product: v.string(),
metadata: v.object({
phone_number_id: v.string(),
display_phone_number: v.string(),
}),
contacts: v.array(
v.object({
profile: v.object({
name: v.string(),
}),
wa_id: v.string(),
})
),
messages: v.array(
v.union(
v.object({
from: v.string(),
id: v.string(),
timestamp: v.string(),
type: v.literal("text"),
text: v.object({
body: v.string(),
preview_url: v.optional(v.boolean()),
}),
}),
v.object({
from: v.string(),
id: v.string(),
timestamp: v.string(),
type: v.literal("image"),
image: v.object({
mime_type: v.string(),
sha256: v.string(),
id: v.string(),
}),
})
..
},
handler: async (ctx, args) => {
..
const type = value.messages[0].type;

if (type === "text") {
await ctx.runAction(internal.datatypes.text.run, args);
} ...
await ctx.runMutation(internal.data.insert, args);
},
});
export const webhooks = internalAction({
args: {
object: v.string(),
entry: v.array(
v.object({
id: v.string(),
changes: v.array(
v.object({
field: v.string(),
value: v.object({
messaging_product: v.string(),
metadata: v.object({
phone_number_id: v.string(),
display_phone_number: v.string(),
}),
contacts: v.array(
v.object({
profile: v.object({
name: v.string(),
}),
wa_id: v.string(),
})
),
messages: v.array(
v.union(
v.object({
from: v.string(),
id: v.string(),
timestamp: v.string(),
type: v.literal("text"),
text: v.object({
body: v.string(),
preview_url: v.optional(v.boolean()),
}),
}),
v.object({
from: v.string(),
id: v.string(),
timestamp: v.string(),
type: v.literal("image"),
image: v.object({
mime_type: v.string(),
sha256: v.string(),
id: v.string(),
}),
})
..
},
handler: async (ctx, args) => {
..
const type = value.messages[0].type;

if (type === "text") {
await ctx.runAction(internal.datatypes.text.run, args);
} ...
await ctx.runMutation(internal.data.insert, args);
},
});
10 Replies
ballingt
ballingtā€¢4mo ago
args is an object with properties, it should be typed based on the args validator so this should be normal TypeScript syntax. What's value here?
jamalsoueidan
jamalsoueidanOPā€¢4mo ago
I needed up with more simple solution:
const args = v.union(text, media);

type Args = Infer<typeof args>;
type Text = Infer<typeof text>;

function isTextMessage(args: Args): args is Text {
return args.entry[0].changes[0].value.messages[0].type === "text";
}

export const webhooks = internalAction({
args,
handler: async (ctx, args) => {
if (isTextMessage(args)) {
await ctx.runAction(internal.datatypes.text.run, args);
} /*else if (type === "interactive") {
//await ctx.runAction(internal.datatypes.interactiveReply.run, args);
} else if (value.statuses) {
//await ctx.runAction(internal.datatypes.status.run, args);
} else {
//unspported
}*/

await ctx.runMutation(internal.data.insert, args);
},
});
const args = v.union(text, media);

type Args = Infer<typeof args>;
type Text = Infer<typeof text>;

function isTextMessage(args: Args): args is Text {
return args.entry[0].changes[0].value.messages[0].type === "text";
}

export const webhooks = internalAction({
args,
handler: async (ctx, args) => {
if (isTextMessage(args)) {
await ctx.runAction(internal.datatypes.text.run, args);
} /*else if (type === "interactive") {
//await ctx.runAction(internal.datatypes.interactiveReply.run, args);
} else if (value.statuses) {
//await ctx.runAction(internal.datatypes.status.run, args);
} else {
//unspported
}*/

await ctx.runMutation(internal.data.insert, args);
},
});
āœ– Error fetching POST https://proper-gnu-660.convex.cloud/api/push_config 400 Bad Request: InvalidModules: Hit an error while pushing: Loading the pushed modules encountered the following error: Unable to parse JSON from exportArgs: Args validator must be an object or any ok this is not working...
ballingt
ballingtā€¢4mo ago
What are text and media? The top-level args value needs to be an object
jamalsoueidan
jamalsoueidanOPā€¢4mo ago
they are objects in other files... export const text = v.object({...});
ballingt
ballingtā€¢4mo ago
@jamalsoueidan and media?
jamalsoueidan
jamalsoueidanOPā€¢4mo ago
same in another file
ballingt
ballingtā€¢4mo ago
Ah you're right, the top level can't be a union! you'll have make your union validator a property of the top-level arguments object, e.g. ```ts const args = v.union(text, media); type Args = Infer<typeof args>; type Text = Infer<typeof text>; function isTextMessage(args: Args): args is Text { return args.entry[0].changes[0].value.messages[0].type === "text"; } export const webhooks = internalAction({ { args }, handler: async (ctx, { args }) => { if (isTextMessage(args)) { await ctx.runAction(internal.datatypes.text.run, args); Sounds like a bug that this isn't a TypeScript error, you have to wait until runtime
jamalsoueidan
jamalsoueidanOPā€¢4mo ago
okay first day first bug... my room blinking red,,, i get flashback from the past when i used bit.cloud damn it was the worst experience in my life...i was fighting against the system full of bugs hahah...but im sure convex is not like that
ballingt
ballingtā€¢4mo ago
ooof, we absolutely aim for it not to be like that! If you report something here and it's part of the core of Convex like this we will get it fixed.
jamalsoueidan
jamalsoueidanOPā€¢4mo ago
thank you...i can already feel its good community here šŸ˜„