winsoroaks
winsoroaks
CCConvex Community
Created by winsoroaks on 6/26/2024 in #support-community
tools to subscribe to websocket on the backend?
Hi team! I am planning to build an app that subscribes to some trading activities using convex, what’s the best way to do it? I currently just doing a while True loop, might not be the most efficient thing. Thanks! πŸ˜…
9 replies
CCConvex Community
Created by winsoroaks on 5/20/2024 in #support-community
is there a way to mock the ctx.db.system?
hi team! one of my mutation checks for the image size and store them in my table.
const metadata = await ctx.db.system.get(s.storageId as Id<"_storage">)
if (!metadata) throw new ConvexError("not found")
size += metadata.size
const metadata = await ctx.db.system.get(s.storageId as Id<"_storage">)
if (!metadata) throw new ConvexError("not found")
size += metadata.size
is there a way to handle this from the convex-test package? thanks!
11 replies
CCConvex Community
Created by winsoroaks on 5/14/2024 in #support-community
queryWithUser is not a function.
(not urgent) hi team! im working on some unit tests. the convex-test library is awesome and fun! however, im running into a weird scenario (not related to the lib perhaps).
// users.ts
import { LIMIT } from "./usage"

export const createUser = mutation({
...
await ctx.db.insert("usage", {
userId,
used: 0,
limit: LIMIT,
})

...

const addUser = customCtx(async (ctx: QueryCtx) => {
const userId = await getUserIdByTokenIdentifier(ctx)
if (!userId) {
throw new ConvexError("User ID not found")
}
return { userId }
})

export const queryWithUser = customQuery(query, addUser)
// users.ts
import { LIMIT } from "./usage"

export const createUser = mutation({
...
await ctx.db.insert("usage", {
userId,
used: 0,
limit: LIMIT,
})

...

const addUser = customCtx(async (ctx: QueryCtx) => {
const userId = await getUserIdByTokenIdentifier(ctx)
if (!userId) {
throw new ConvexError("User ID not found")
}
return { userId }
})

export const queryWithUser = customQuery(query, addUser)
and when i run vitest, im getting
TypeError: queryWithUser is not a function
❯ convex/usage.ts:24:25
22| })
23|
24| export const getUsage = queryWithUser({
| ^
25| handler: async (ctx) => {
26| const usage = await ctx.db
TypeError: queryWithUser is not a function
❯ convex/usage.ts:24:25
22| })
23|
24| export const getUsage = queryWithUser({
| ^
25| handler: async (ctx) => {
26| const usage = await ctx.db
but when i hard code the LIMIT to be 100, it works. any idea what's wrong? πŸ™
2 replies
CCConvex Community
Created by winsoroaks on 5/14/2024 in #support-community
query and update inside for-loop
(not urgent) hi team! im running into a weird situation. hopefully it's just that im blind to the logic implementation. i have the following code that "updates" the usage table with the image size the user uploaded
await Promise.all(
args.storageIds.map(async (s) => {
const metadata = await ctx.db.system.get(s.storageId as Id<"_storage">)
console.log(
"πŸš€ ~ file: images.ts:43 ~ args.storageIds.map ~ metadata:",
metadata.size
) // 93558, 68153, 68948

const usage = await ctx.db
.query("usage")
.withIndex("by_userId", (q) => q.eq("userId", ctx.userId))
.unique()
console.log(
"πŸš€ ~ file: images.ts:53 ~ args.storageIds.map ~ usage:",
usage.used
) // 0, 0, 0, should be 0, 93558, 93558 + 68153
await ctx.db.patch(usage._id, { used: usage.used + metadata.size })

await ctx.db.insert("images", {
userId: ctx.userId,
uploadedImageId: s.storageId,
})
})
)
await Promise.all(
args.storageIds.map(async (s) => {
const metadata = await ctx.db.system.get(s.storageId as Id<"_storage">)
console.log(
"πŸš€ ~ file: images.ts:43 ~ args.storageIds.map ~ metadata:",
metadata.size
) // 93558, 68153, 68948

const usage = await ctx.db
.query("usage")
.withIndex("by_userId", (q) => q.eq("userId", ctx.userId))
.unique()
console.log(
"πŸš€ ~ file: images.ts:53 ~ args.storageIds.map ~ usage:",
usage.used
) // 0, 0, 0, should be 0, 93558, 93558 + 68153
await ctx.db.patch(usage._id, { used: usage.used + metadata.size })

await ctx.db.insert("images", {
userId: ctx.userId,
uploadedImageId: s.storageId,
})
})
)
im not sure why the usage returned is 0, 0, 0 where i'd expect it to be 0, 93558, 93558 + 68153. i managed to change the implementation to the following:
let size = 0
await Promise.all(
args.storageIds.map(async (s) => {
const metadata = await ctx.db.system.get(s.storageId as Id<"_storage">)
size += metadata.size
await ctx.db.insert("images", {
userId: ctx.userId,
uploadedImageId: s.storageId,
})
})
)

const usage = await ctx.db
.query("usage")
.withIndex("by_userId", (q) => q.eq("userId", ctx.userId))
.unique()
await ctx.db.patch(usage._id, { used: usage.used + size })
let size = 0
await Promise.all(
args.storageIds.map(async (s) => {
const metadata = await ctx.db.system.get(s.storageId as Id<"_storage">)
size += metadata.size
await ctx.db.insert("images", {
userId: ctx.userId,
uploadedImageId: s.storageId,
})
})
)

const usage = await ctx.db
.query("usage")
.withIndex("by_userId", (q) => q.eq("userId", ctx.userId))
.unique()
await ctx.db.patch(usage._id, { used: usage.used + size })
which is def more efficient and worked. im just curious if there's some special case with my first implementation. thank you.
9 replies
CCConvex Community
Created by winsoroaks on 5/12/2024 in #support-community
running migration from dashboard
No description
10 replies
CCConvex Community
Created by winsoroaks on 5/11/2024 in #support-community
run migration on prod before pushing new schema?
i've added a new column to my table, after running a migration on local,
// schema.ts
rank: v.optional(v.number()),

export const addRankToImages = migration({
table: "images",
migrateOne: async (ctx, image) => {
if (!image.rank) {
await ctx.db.patch(image._id, { rank: 0 })
}
},
})
// schema.ts
rank: v.optional(v.number()),

export const addRankToImages = migration({
table: "images",
migrateOne: async (ctx, image) => {
if (!image.rank) {
await ctx.db.patch(image._id, { rank: 0 })
}
},
})
can i run the migration on production before pushing the new schema? i also have rank an optional field now
2 replies
CCConvex Community
Created by winsoroaks on 5/8/2024 in #support-community
suggestions on improving my architecture? (not really convex specific)
No description
37 replies
CCConvex Community
Created by winsoroaks on 5/6/2024 in #support-community
another copy of javascript when adding tsconfig.json
i just started to add a tsconfig.json to my /convex dir and im getting a copy of js file for every ts file i wrote. this hasnt been the case in the past and i wonder if i've configured something wrongly? here's my tsconfig.json:
{
/* This TypeScript project config describes the environment that
* Convex functions run in and is used to typecheck them.
* You can modify it, but some settings required to use Convex.
*/
"compilerOptions": {
/* These settings are not required by Convex and can be modified. */
"allowJs": true,
"strict": true,
"skipLibCheck": true,

/* These compiler options are required by Convex */
"target": "ESNext",
"lib": ["ES2021", "dom"],
"forceConsistentCasingInFileNames": true,
"allowSyntheticDefaultImports": true,
"module": "ESNext",
"moduleResolution": "Node",
"isolatedModules": true,
"noEmit": true,
"jsx": "react"
},
"include": ["./**/*"],
"exclude": ["./_generated"]
}
{
/* This TypeScript project config describes the environment that
* Convex functions run in and is used to typecheck them.
* You can modify it, but some settings required to use Convex.
*/
"compilerOptions": {
/* These settings are not required by Convex and can be modified. */
"allowJs": true,
"strict": true,
"skipLibCheck": true,

/* These compiler options are required by Convex */
"target": "ESNext",
"lib": ["ES2021", "dom"],
"forceConsistentCasingInFileNames": true,
"allowSyntheticDefaultImports": true,
"module": "ESNext",
"moduleResolution": "Node",
"isolatedModules": true,
"noEmit": true,
"jsx": "react"
},
"include": ["./**/*"],
"exclude": ["./_generated"]
}
thank you πŸ™‚
7 replies
CCConvex Community
Created by winsoroaks on 5/3/2024 in #support-community
when is the best time to create a user entry in the db?
hi all! im curious what's the best practice here. assume that i have a to-do list app and using clerk for auth. if i allow the user to sign in via google, there's no clear way to do "user has signed up" -> "i need to register user in db."
when should i create an entry of the user in the db? im thinking of when the user has created a to-do list and clicked on the save button, i can check if the user has existed in the users db and create the entry. is this reasonable? thank you
34 replies
CCConvex Community
Created by winsoroaks on 4/24/2024 in #support-community
can i do auth or run a function on the server side?
hi all! i have the following code,
"use client"

import { api } from "@/convex/_generated/api"
import { useConvexAuth, useQuery } from "convex/react"

import { Skeleton } from "@/components/ui/skeleton"

export function SideBar() {
const { isLoading } = useConvexAuth()

const username = useQuery(
api.db.username,
isLoading ? "skip" : {}
)

return <span className="capitalize">{username}</span>
}
"use client"

import { api } from "@/convex/_generated/api"
import { useConvexAuth, useQuery } from "convex/react"

import { Skeleton } from "@/components/ui/skeleton"

export function SideBar() {
const { isLoading } = useConvexAuth()

const username = useQuery(
api.db.username,
isLoading ? "skip" : {}
)

return <span className="capitalize">{username}</span>
}
and i've been running into the following error when i click on "logout"
ConvexError: [CONVEX Q(db:username)] [Request ID: 26f4c2ab052920a5] Server Error
Uncaught ConvexError: Unauthenticated call to function requiring authentication
at getClerkIdentity (../../convex/db/user.ts:18:6)
at async handler (../../convex/db/user.ts:166:17)

Called by client
ConvexError: [CONVEX Q(db:username)] [Request ID: 26f4c2ab052920a5] Server Error
Uncaught ConvexError: Unauthenticated call to function requiring authentication
at getClerkIdentity (../../convex/db/user.ts:18:6)
at async handler (../../convex/db/user.ts:166:17)

Called by client
is it possible to move api.db.username to the server side for this component? or am i taking a wrong path? thanks!
3 replies
CCConvex Community
Created by winsoroaks on 4/5/2024 in #support-community
ConvexChatMessageHistory schema for langchain
Hi @michal, im reading the article: https://stack.convex.dev/ai-chat-using-langchain-and-convex and im trying to understand how the messages schema is constructured and its relationship with ConvexChatMessageHistory. im currently using a RunnableSequence and it doesn't save to memory. i have to manually do
await memory.saveContext(
{
input: {
sessionId,
type: 'human',
content: message
}
},
{
content: response.content
}
)
await memory.saveContext(
{
input: {
sessionId,
type: 'human',
content: message
}
},
{
content: response.content
}
)
however, im running into the error below
Uncaught Error: Uncaught Error: Failed to insert or update a document in table "messages" because it does not match the schema: Object contains extra field `session_id` that is not in the validator.
Path: .message.data
Object: {additional_kwargs: {}, content: "what is an avocado?", response_metadata: {}, session_id: "34a48a99-e910-43e9-af24-8a9dbfddcc79", type: "human"}
Validator: v.object({additional_kwargs: v.optional(v.any()), content: v.string(), name: v.optional(v.string()), response_metadata: v.optional(v.any()), role: v.optional(v.string())})
Uncaught Error: Uncaught Error: Failed to insert or update a document in table "messages" because it does not match the schema: Object contains extra field `session_id` that is not in the validator.
Path: .message.data
Object: {additional_kwargs: {}, content: "what is an avocado?", response_metadata: {}, session_id: "34a48a99-e910-43e9-af24-8a9dbfddcc79", type: "human"}
Validator: v.object({additional_kwargs: v.optional(v.any()), content: v.string(), name: v.optional(v.string()), response_metadata: v.optional(v.any()), role: v.optional(v.string())})
to fix this, i had to modify the schema to
@@ -36,11 +36,14 @@ export default defineSchema({
sessionId: v.string(),
message: v.object({
type: v.string(),
data: v.object({
+ type: v.optional(v.string()),
content: v.string(),
role: v.optional(v.string()),
name: v.optional(v.string()),
additional_kwargs: v.optional(v.any()),
+ session_id: v.optional(v.any()),
response_metadata: v.optional(v.any())
})
})
@@ -36,11 +36,14 @@ export default defineSchema({
sessionId: v.string(),
message: v.object({
type: v.string(),
data: v.object({
+ type: v.optional(v.string()),
content: v.string(),
role: v.optional(v.string()),
name: v.optional(v.string()),
additional_kwargs: v.optional(v.any()),
+ session_id: v.optional(v.any()),
response_metadata: v.optional(v.any())
})
})
any idea why the input is having a diff structure when it tries to write to the db? thank you πŸ™‚
2 replies
CCConvex Community
Created by winsoroaks on 4/4/2024 in #support-community
Adding deps to node.externalPackages didn't resolve the error
Hi team! im running in to the error below
✘ [ERROR] Could not resolve "youtubei.js"

node_modules/langchain/dist/document_loaders/web/youtube.js:2:26:
2 β”‚ import { Innertube } from "youtubei.js";
✘ [ERROR] Could not resolve "youtubei.js"

node_modules/langchain/dist/document_loaders/web/youtube.js:2:26:
2 β”‚ import { Innertube } from "youtubei.js";
tried a few variations
// convex.json
{
"node": {
"externalPackages": [
"langchain" // "youtube-transcript", "youtubei.js"
]
}
}
// convex.json
{
"node": {
"externalPackages": [
"langchain" // "youtube-transcript", "youtubei.js"
]
}
}
but didnt fix the issue
Uncaught Failed to analyze ingest/load.js: Cannot find package 'youtube-transcript' imported from /tmp/external_deps/e9a05690-196f-40ed-88a7-cd46f4362a76/node_modules/langchain/dist/document_loaders/web/youtube.js
Uncaught Failed to analyze ingest/load.js: Cannot find package 'youtubei.js' imported from /tmp/external_deps/834ceee9-83db-4a8b-9907-c6805d171626/node_modules/langchain/dist/document_loaders/web/youtube.js
Uncaught Failed to analyze ingest/load.js: Cannot find package 'youtube-transcript' imported from /tmp/external_deps/e9a05690-196f-40ed-88a7-cd46f4362a76/node_modules/langchain/dist/document_loaders/web/youtube.js
Uncaught Failed to analyze ingest/load.js: Cannot find package 'youtubei.js' imported from /tmp/external_deps/834ceee9-83db-4a8b-9907-c6805d171626/node_modules/langchain/dist/document_loaders/web/youtube.js
any idea what's wrong? thank you.
11 replies
CCConvex Community
Created by winsoroaks on 4/2/2024 in #support-community
Uncaught Error: Failed to insert or update a document in table "messages" because it does not match
πŸ‘‹ was the ConvexVectorStore updated recently? im following the example from https://stack.convex.dev/ai-chat-using-langchain-and-convex and ran into the error above. was able to fix it by adding response_metadata: v.optional(v.any()) to the schema
2 replies
CCConvex Community
Created by winsoroaks on 3/10/2024 in #support-community
recommended logger for convex functions?
hi team, i've been using tslog as my logger for my front end stuff. apparently when i try to import it to my convex functions, im getting weird stuff, sth like some byte arrays?
'\x1B[37m2024-03-10 06:36:32.902\x1B[39m\x1B[0m\x1B[0m\t\x1B[34m\x1B[1mINFO\x1B[22m\x1B[39m\x1B[0m\x1B[0m\t[\x1B[37m/user/client.js:1280\x1B[39m\x1B[0m\x1B[0m\x1B[1m\x1B[37m\x1B[39m\x1B[22m\x1B[0m\x1B[0m]\tUpdating ...'
'\x1B[37m2024-03-10 06:36:32.902\x1B[39m\x1B[0m\x1B[0m\t\x1B[34m\x1B[1mINFO\x1B[22m\x1B[39m\x1B[0m\x1B[0m\t[\x1B[37m/user/client.js:1280\x1B[39m\x1B[0m\x1B[0m\x1B[1m\x1B[37m\x1B[39m\x1B[22m\x1B[0m\x1B[0m]\tUpdating ...'
i think i can go with console.log, just wondering if there's some known limitation with my current approach. thanks!
2 replies
CCConvex Community
Created by winsoroaks on 3/7/2024 in #support-community
loading protos
Hi team. im trying to load some protos into the convex backend but couldnt figure out how
// client.js
"use node"

import grpc from "@grpc/grpc-js"
import { loadSync } from "@grpc/proto-loader"

export class Client {
constructor(address) {
var PROTO_PATH = "./../../src/protos/client.proto"
const packageDefinition = loadSync(PROTO_PATH, {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
})
// client.js
"use node"

import grpc from "@grpc/grpc-js"
import { loadSync } from "@grpc/proto-loader"

export class Client {
constructor(address) {
var PROTO_PATH = "./../../src/protos/client.proto"
const packageDefinition = loadSync(PROTO_PATH, {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
})
my directory looks sth like
.
β”œβ”€β”€ convex
β”‚Β Β  β”œβ”€β”€ client
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ client.js
β”œβ”€β”€ src
β”‚Β Β  β”œβ”€β”€ protos
β”‚Β Β  β”‚Β Β  └── client.proto
.
β”œβ”€β”€ convex
β”‚Β Β  β”œβ”€β”€ client
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ client.js
β”œβ”€β”€ src
β”‚Β Β  β”œβ”€β”€ protos
β”‚Β Β  β”‚Β Β  └── client.proto
tried a few variations but keep running into
Uncaught Error: ENOENT: no such file or directory, open '../../src/protos/client.proto'
Uncaught Error: ENOENT: no such file or directory, open '../../src/protos/client.proto'
i also tried moving the protos/client.proto into the convex dir/ but got an error like
✘ [ERROR] No loader is configured for ".proto" files: convex/client/protos/client.proto
✘ [ERROR] No loader is configured for ".proto" files: convex/client/protos/client.proto
i'd apprecate any tips on how to debug the error. thanks!
15 replies
CCConvex Community
Created by winsoroaks on 1/16/2024 in #support-community
resend lib started to fail
when i configured my resend clients on 11/27, it was working perfectly. i havent touched the email components until the past weekend and the same code has been failing. i upgraded my convex to 1.7 on 12/30. it's unlikely that this is breaking my resend code. im quite baffled and started reaching out to resend support today. i wonder if others around still have their resend clients working with convex 1.7. after some trial and error, the resend.emails.send func that hits the POST /emails endpoint only fails when im using a template.
// fails
await resend.emails.send({
from: "onboarding@resend.dev",
to: process.env.MY_TEST_EMAIL!,
subject: "Hello World",
react: TestResendEmail({ url: "John" }) as React.ReactElement,
})

// success
await resend.emails.send({
from: "onboarding@resend.dev",
to: process.env.MY_TEST_EMAIL!,
subject: "Hello World",
html: "<strong>It works!</strong>",
})
// fails
await resend.emails.send({
from: "onboarding@resend.dev",
to: process.env.MY_TEST_EMAIL!,
subject: "Hello World",
react: TestResendEmail({ url: "John" }) as React.ReactElement,
})

// success
await resend.emails.send({
from: "onboarding@resend.dev",
to: process.env.MY_TEST_EMAIL!,
subject: "Hello World",
html: "<strong>It works!</strong>",
})
fwiw, here's the error i see in the logs from resend
{
"name": "application_error",
"message": "Something went wrong while saving email",
"statusCode": 500
}
{
"name": "application_error",
"message": "Something went wrong while saving email",
"statusCode": 500
}
would appreciate any insights. thanks!
4 replies
CCConvex Community
Created by winsoroaks on 1/9/2024 in #support-community
how do LOWER(q.field("name") LIKE LOWER('%name%')
hi team! tried searching the docs but to no avail. any idea how can i do sth like
.filter((q) => q.eq(q.field("name"), args.name))
.filter((q) => q.eq(q.field("name"), args.name))
but ignoring the case? πŸ˜…
4 replies
CCConvex Community
Created by winsoroaks on 1/7/2024 in #support-community
what's the proper way to query an SDK client in node env?
whenever a user navigates to the billing page, i want to check stripe if they have cancelled the pay, essentially, im trying to do
const plan: Stripe.Subscription = await stripe.subscriptions.retrieve(
stripeSubscriptionId
)
const plan: Stripe.Subscription = await stripe.subscriptions.retrieve(
stripeSubscriptionId
)
since stripe SDK is in the node env, i need to wrap it in an "action"
export const getStripePlan = action({
handler: async (ctx) => {
const stripe = new Stripe(process.env.STRIPE_KEY!, {
apiVersion: "2023-10-16",
typescript: true,
})

const stripeSubscriptionId = ...

const plan: Stripe.Subscription = await stripe.subscriptions.retrieve(
stripeSubscriptionId
)
return plan.cancel_at_period_end
},
})
export const getStripePlan = action({
handler: async (ctx) => {
const stripe = new Stripe(process.env.STRIPE_KEY!, {
apiVersion: "2023-10-16",
typescript: true,
})

const stripeSubscriptionId = ...

const plan: Stripe.Subscription = await stripe.subscriptions.retrieve(
stripeSubscriptionId
)
return plan.cancel_at_period_end
},
})
and i was thinking that i could do
// /api/stripe/route.ts
export async function GET(req: NextApiRequest, res: NextApiResponse) {
const plan = await convex.query(api.stripe.actions.getStripePlan, {})
res.status(200).json({ plan })
}
// /api/stripe/route.ts
export async function GET(req: NextApiRequest, res: NextApiResponse) {
const plan = await convex.query(api.stripe.actions.getStripePlan, {})
res.status(200).json({ plan })
}
and on the page.tsx, do a fetch to my API above. but im running into
formatDate
Argument of type 'FunctionReference<"action", "public", EmptyObject, boolean>' is not assignable to parameter of type 'FunctionReference<"query">'.
formatDate
Argument of type 'FunctionReference<"action", "public", EmptyObject, boolean>' is not assignable to parameter of type 'FunctionReference<"query">'.
or is there a better approach to what im trying to achieve? thanks!
13 replies
CCConvex Community
Created by winsoroaks on 1/3/2024 in #support-community
long shot: debugging twilio API errors but cannot see logs
hi all! this is a long shot, but i'll try my luck. im trying to debug why my outbound call is successful only once out of the 10 times i try. i've added some log statements around the function but they dont show up in my convex dashboard logs. does anyone know why? im aware that this is using a node sdk and have add the "use node" pragma. it succeeded once miraculously. i am interested in getting more logs before i reach out to twilio's support.
export const outbound = action({
handler: async (ctx) => {
try {
const username = process.env.TWILIO_SID!
console.log("πŸš€ ~ file: say.ts:19 ~ handler: ~ username:", username) // has logs here

const password = process.env.TWILIO_AUTH_TOKEN!
const client = new twilio.Twilio(username, password, {
logLevel: "debug",
})

// no more logs starting here
client.calls
.create(
{
url: "http://demo.twilio.com/docs/voice.xml",
to: process.env.TO_MY_PHONE!,
from: process.env.FROM_TWILIO_PHONE!,
},
function (err, call) {
if (err) {
console.log("πŸš€ ~ file: say.ts:32 ~ handler: ~ err:", err)
} else {
console.log("πŸš€ ~ file: say.ts:32 ~ handler: ~ call:", call?.sid)
}
}
)
.then((call) => {
console.log(call.sid)
})
.catch((err) => {
console.log("πŸš€ ~ file: say.ts:32 ~ handler: ~ err:", err)
})
} catch (e) {
console.error(e)
throw e
}
},
})
export const outbound = action({
handler: async (ctx) => {
try {
const username = process.env.TWILIO_SID!
console.log("πŸš€ ~ file: say.ts:19 ~ handler: ~ username:", username) // has logs here

const password = process.env.TWILIO_AUTH_TOKEN!
const client = new twilio.Twilio(username, password, {
logLevel: "debug",
})

// no more logs starting here
client.calls
.create(
{
url: "http://demo.twilio.com/docs/voice.xml",
to: process.env.TO_MY_PHONE!,
from: process.env.FROM_TWILIO_PHONE!,
},
function (err, call) {
if (err) {
console.log("πŸš€ ~ file: say.ts:32 ~ handler: ~ err:", err)
} else {
console.log("πŸš€ ~ file: say.ts:32 ~ handler: ~ call:", call?.sid)
}
}
)
.then((call) => {
console.log(call.sid)
})
.catch((err) => {
console.log("πŸš€ ~ file: say.ts:32 ~ handler: ~ err:", err)
})
} catch (e) {
console.error(e)
throw e
}
},
})
thanks!
5 replies
CCConvex Community
Created by winsoroaks on 12/31/2023 in #support-community
dumb question on how to allow users to do analytics
hi team! im not there yet but im curious how can i offer analytics for my users. let's assume my user wants to click a button to generate a chart of the revenue per month for the past 12 months. after reading some threads, i see folks here talking bout airbyte, dagster, duckdb, etc.. what's the correct mental model to think about this? is it the case that i stream data out of convex via airbyte (cloud) to another server that hosts the duckdb? which means i can then set up my convex service to make an API call to the duckdb service for the revenue data? pls feel free to correct my wrong understanding. thanks!
13 replies