kstulgys
kstulgys
Explore posts from servers
CCConvex Community
Created by kstulgys on 2/4/2025 in #show-and-tell
Your Crypto Payment Gateway for USDC & USDT Stablecoin Payments
I love convex ents and how fast I can move on the backend and frontend.
6 replies
CCConvex Community
Created by kstulgys on 2/4/2025 in #show-and-tell
Your Crypto Payment Gateway for USDC & USDT Stablecoin Payments
Hi Mikey, I think if the product will get enough users I will ask what they would like to pay and if they see value in a product. Not sure how other saas companies think, I think the strategy depends on the niche. Some products comes with exact price plans etc. In my case I don't know. I just thought I will build a product. I haven't even done much "product fit" research on it, but I worked with crypto payments integrations and I know it's not the easiest task to support different chains and networks. 🙂
6 replies
CCConvex Community
Created by kstulgys on 1/17/2025 in #support-community
Should I avoid this ent query?
Thanks for the response. I'm just generally thinking whether this is good/bad/can be better
10 replies
CCConvex Community
Created by kstulgys on 1/17/2025 in #support-community
Should I avoid this ent query?
That "map" function that could potentially go through many records. I guess it's a special ".map" in convex right?
10 replies
CCConvex Community
Created by kstulgys on 1/17/2025 in #support-community
Should I avoid this ent query?
ok here is more concrete example that I'm working on:
export const remove = authMutation({
args: {},
handler: async (ctx, args) => {
// Get user account
const account = await ctx.table("accounts").getX(ctx.user.currentAccountId);

// Find unpaid receipts
const unpaidBillingReceipts = await account
.edge("billings")
.map(async (b) => {
const billingReceipt = await b.edge("billingReceipt").doc();
// This is unpaid billing because no billingReceipt record with data property
if (!billingReceipt?.data) return true;
})
.filter(Boolean);

// Do not delete account that has unpaid billing
if (unpaidBillingReceipts.length > 0) return { unpaid: true };

// Delete account ...
export const remove = authMutation({
args: {},
handler: async (ctx, args) => {
// Get user account
const account = await ctx.table("accounts").getX(ctx.user.currentAccountId);

// Find unpaid receipts
const unpaidBillingReceipts = await account
.edge("billings")
.map(async (b) => {
const billingReceipt = await b.edge("billingReceipt").doc();
// This is unpaid billing because no billingReceipt record with data property
if (!billingReceipt?.data) return true;
})
.filter(Boolean);

// Do not delete account that has unpaid billing
if (unpaidBillingReceipts.length > 0) return { unpaid: true };

// Delete account ...
This is my ents database relations:
billings: defineEnt({
// fields ...
})
.edge("account")
.edge("billingReceipt", { ref: true })
.edge("feeTier"),

billingReceipts: defineEnt({
// fields ...
}).edge("billing"),
billings: defineEnt({
// fields ...
})
.edge("account")
.edge("billingReceipt", { ref: true })
.edge("feeTier"),

billingReceipts: defineEnt({
// fields ...
}).edge("billing"),
I'm trying to understand if there is a better way todo this query or this is completely fine.
10 replies
CCConvex Community
Created by kstulgys on 1/3/2025 in #support-community
Ents is in maintenance mode. Should I use it?
Thanks for the response. What caveats?
6 replies
CCConvex Community
Created by kstulgys on 9/27/2024 in #support-community
Is runMutation transactional?
I assume runAction is the same?
5 replies
CCConvex Community
Created by kstulgys on 9/17/2024 in #support-community
Whats the best practice/approach for saving and fetching convex images?
"If you have maximum of 5 images, its fine with array" What's the reasoning? "You should prefetch image url on the server, this will generate url for you that will work for 1 hour" - but this will take more time to respond right? because I need to fetch products and then all images for those products with urls
7 replies
CCConvex Community
Created by kstulgys on 8/24/2024 in #support-community
Is this is legit way to upload files? Haven't seen this in any example
Thank you for the insights!
8 replies
CCConvex Community
Created by kstulgys on 8/26/2024 in #support-community
how do I efficiently aggregate data?
thanks
3 replies
CCConvex Community
Created by kstulgys on 8/24/2024 in #support-community
Is this is legit way to upload files? Haven't seen this in any example
Is this suppose to be slower? faster? better? worse?
8 replies
CCConvex Community
Created by kstulgys on 8/24/2024 in #support-community
Is this is legit way to upload files? Haven't seen this in any example
backend image_node.ts
"use node";

import { v } from "convex/values";
import { internalAction } from "./_generated/server";

export const upload = internalAction({
args: {
base64: v.string(),
},
handler: async (ctx, args) => {
const mimeType = args.base64.match(/data:(.*?);base64/)?.[1];
const base64Data = args.base64.split(",")[1];

if (!mimeType || !base64Data) return null;

const buffer = Buffer.from(base64Data, "base64");

const uploadUrl = await ctx.storage.generateUploadUrl();

try {
const result = await fetch(uploadUrl, {
method: "POST",
headers: { "Content-Type": mimeType },
body: buffer,
});

const json = await result.json();
if (!result.ok) return null;

return json.storageId;
} catch (e) {
return null;
}
},
});
"use node";

import { v } from "convex/values";
import { internalAction } from "./_generated/server";

export const upload = internalAction({
args: {
base64: v.string(),
},
handler: async (ctx, args) => {
const mimeType = args.base64.match(/data:(.*?);base64/)?.[1];
const base64Data = args.base64.split(",")[1];

if (!mimeType || !base64Data) return null;

const buffer = Buffer.from(base64Data, "base64");

const uploadUrl = await ctx.storage.generateUploadUrl();

try {
const result = await fetch(uploadUrl, {
method: "POST",
headers: { "Content-Type": mimeType },
body: buffer,
});

const json = await result.json();
if (!result.ok) return null;

return json.storageId;
} catch (e) {
return null;
}
},
});
8 replies
CCConvex Community
Created by kstulgys on 8/24/2024 in #support-community
Is this is legit way to upload files? Haven't seen this in any example
backend image.ts
export const upload = authAction({
args: {
base64: v.string(),
table: v.union(v.literal("accounts"), v.literal("products")),
column: v.string(),
},
handler: async (ctx, args) => {
const rowId = // get row id here or from frontend

const storageId = await ctx.runAction(internal.image_node.upload, {
base64: args.base64,
});

if (!storageId) return;

await ctx.runMutation(internal.image.saveImage, {
storageId,
table: args.table,
column: args.column,
rowId,
});
},
});

export const saveImage = internalMutation({
args: {
storageId: v.id("_storage"),
table: v.union(v.literal("accounts"), v.literal("products")),
column: v.string(),
rowId: v.id("accounts"),
},
handler: async (ctx, args) => {
const entity = await ctx.table(args.table).getX(args.rowId);

const deleteStorageId = () => {
// @ts-expect-error
const previousStorageId = entity[args.column] as Id<"_storage"> | null;
if (!previousStorageId) return;
return ctx.storage.delete(previousStorageId);
};

await Promise.all([entity.patch({ [args.column]: args.storageId }), deleteStorageId()]);
},
});
export const upload = authAction({
args: {
base64: v.string(),
table: v.union(v.literal("accounts"), v.literal("products")),
column: v.string(),
},
handler: async (ctx, args) => {
const rowId = // get row id here or from frontend

const storageId = await ctx.runAction(internal.image_node.upload, {
base64: args.base64,
});

if (!storageId) return;

await ctx.runMutation(internal.image.saveImage, {
storageId,
table: args.table,
column: args.column,
rowId,
});
},
});

export const saveImage = internalMutation({
args: {
storageId: v.id("_storage"),
table: v.union(v.literal("accounts"), v.literal("products")),
column: v.string(),
rowId: v.id("accounts"),
},
handler: async (ctx, args) => {
const entity = await ctx.table(args.table).getX(args.rowId);

const deleteStorageId = () => {
// @ts-expect-error
const previousStorageId = entity[args.column] as Id<"_storage"> | null;
if (!previousStorageId) return;
return ctx.storage.delete(previousStorageId);
};

await Promise.all([entity.patch({ [args.column]: args.storageId }), deleteStorageId()]);
},
});
8 replies
CCConvex Community
Created by kstulgys on 8/21/2024 in #support-community
How do I extend convex auth with my custom auth provider?
Thank you sir, just one correction for those who will see this:
const userId = await ctx.db.runMutation(internal.users.create, userData)
return { userId }
const userId = await ctx.db.runMutation(internal.users.create, userData)
return { userId }
3 replies
CCConvex Community
Created by kstulgys on 1/20/2024 in #support-community
So close to make puppeteer working
nop, I think convex does not suport this, they mentioned on their docs as well
15 replies
CCConvex Community
Created by kstulgys on 8/12/2024 in #support-community
I want to deploy my website that uses convex development environment, how do I deal with SITE_URL?
thank you!
25 replies
CCConvex Community
Created by kstulgys on 8/14/2024 in #support-community
Am I doing this ent query correctly?
I guess this is better, right?
export const get = authQuery({
args: {
orderId: v.id("orders"),
},
handler: async (ctx, args) => {
if (!ctx.user?.currentAccountId) return null;
const order = await ctx.table("orders").getX(args.orderId)
const account = await order.edgeX("account");
if(account._id !== ctx.user.currentAccountId) return null;
return order;
},
});
export const get = authQuery({
args: {
orderId: v.id("orders"),
},
handler: async (ctx, args) => {
if (!ctx.user?.currentAccountId) return null;
const order = await ctx.table("orders").getX(args.orderId)
const account = await order.edgeX("account");
if(account._id !== ctx.user.currentAccountId) return null;
return order;
},
});
3 replies