winsoroaks
winsoroaks•2w ago

How to properly combine a Convex query with an action?

I'm trying to implement a query that needs to fetch some encrypted data and decrypt it using AWS KMS. However, I'm running into a TypeScript error where ctx.runAction is not available in the query context. Here's a simplified version of what I'm trying to do:
export const queryEncryptedData = query({
args: { id: v.string() },
handler: async (ctx, args) => {
// 1. First fetch the encrypted data
const data = await ctx.db
.query("myTable")
.withIndex("by_id", q => q.eq("id", args.id))
.first()
if (!data) return undefined

// 2. Then try to decrypt the sensitive fields
// This is where we get the error:
// Property 'runAction' does not exist on type 'QueryCtx'
const decryptedItems = await Promise.all(
data.items.map(async (item) => ({
...item,
value: await ctx.runAction(internal.kms.decryptData, {
data: item.encryptedValue?.data,
key: item.encryptedValue?.key,
iv: item.encryptedValue?.iv,
})
}))
)

return {
items: data.items.map(item => ({
...item,
// Need to return the decrypted value here
}))
}
}
})
export const queryEncryptedData = query({
args: { id: v.string() },
handler: async (ctx, args) => {
// 1. First fetch the encrypted data
const data = await ctx.db
.query("myTable")
.withIndex("by_id", q => q.eq("id", args.id))
.first()
if (!data) return undefined

// 2. Then try to decrypt the sensitive fields
// This is where we get the error:
// Property 'runAction' does not exist on type 'QueryCtx'
const decryptedItems = await Promise.all(
data.items.map(async (item) => ({
...item,
value: await ctx.runAction(internal.kms.decryptData, {
data: item.encryptedValue?.data,
key: item.encryptedValue?.key,
iv: item.encryptedValue?.iv,
})
}))
)

return {
items: data.items.map(item => ({
...item,
// Need to return the decrypted value here
}))
}
}
})
is the only option to do useEffect in the front end component?
7 Replies
Convex Bot
Convex Bot•2w ago
Thanks for posting in <#1088161997662724167>. Reminder: If you have a Convex Pro account, use the Convex Dashboard to file support tickets. - Provide context: What are you trying to achieve, what is the end-user interaction, what are you seeing? (full error message, command output, etc.) - Use search.convex.dev to search Docs, Stack, and Discord all at once. - Additionally, you can post your questions in the Convex Community's <#1228095053885476985> channel to receive a response from AI. - Avoid tagging staff unless specifically instructed. Thank you!
erquhart
erquhart•2w ago
Yeah you'll want to run the action when the query changes, both from the client. An updatedAt timestamp field on the table with the encrypted data would help, so you can just query that and run the effect when it changes.
winsoroaks
winsoroaksOP•2w ago
thanks! this seems kinda messy 😦
erquhart
erquhart•2w ago
I can see that. But if you're fetching data on the server and you cannot store it anywhere due to it's sensitive nature, I don't know how much cleaner you're going to get than this in any reactive framework. If the reactivity isn't important you could just run an action to get everything at once, but guessing you want it reactive
winsoroaks
winsoroaksOP•2w ago
if i dont want it to be reactive, can i run the action without storing the decrypted data in the table for fetching?
erquhart
erquhart•2w ago
Yep, you would call the action from the client, and in the action you can await ctx.runQuery() for the encrypted data, decrypt it, and return queries can't await actions but actions can await anything
winsoroaks
winsoroaksOP•2w ago
got it. thanks!

Did you find this page helpful?