entropy
entropy
CCConvex Community
Created by entropy on 12/11/2024 in #support-community
Next build error when ran in github action
this is without the testing I did with pulling env vars from vercel before building
8 replies
CCConvex Community
Created by entropy on 12/11/2024 in #support-community
Next build error when ran in github action
Here's my action as well
name: Continuous Integration

on:
push:
branches:
- main

jobs:
build:
name: Lint, typecheck, and build
timeout-minutes: 15
runs-on: ubuntu-latest
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}

steps:
- name: Check Out Code
uses: actions/checkout@v4

- name: Cache Turbo Build Setup
uses: actions/cache@v4
with:
path: .turbo
key: ${{ runner.os }}-turbo-${{ github.sha }}
restore-keys: |
${{ runner.os }}-turbo-

- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.1.36

- name: Install Dependencies
run: bun install

- name: Check Linting
run: bun lint

- name: Check TypeScript Types
run: bun typecheck

- name: Build
run: bun run build
name: Continuous Integration

on:
push:
branches:
- main

jobs:
build:
name: Lint, typecheck, and build
timeout-minutes: 15
runs-on: ubuntu-latest
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}

steps:
- name: Check Out Code
uses: actions/checkout@v4

- name: Cache Turbo Build Setup
uses: actions/cache@v4
with:
path: .turbo
key: ${{ runner.os }}-turbo-${{ github.sha }}
restore-keys: |
${{ runner.os }}-turbo-

- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.1.36

- name: Install Dependencies
run: bun install

- name: Check Linting
run: bun lint

- name: Check TypeScript Types
run: bun typecheck

- name: Build
run: bun run build
8 replies
CCConvex Community
Created by entropy on 12/11/2024 in #support-community
Next build error when ran in github action
root package.json "build": "turbo build --parallel" next app package.json "build": "next build" turbo.json
"build": {
"env": ["CONVEX_DEPLOY_KEY", "CLERK_SECRET_KEY", "OPENPANEL_SECRET_KEY"],
"inputs": ["$TURBO_DEFAULT$", ".env"],
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**", "next-env.d.ts", ".expo/**"]
}
"build": {
"env": ["CONVEX_DEPLOY_KEY", "CLERK_SECRET_KEY", "OPENPANEL_SECRET_KEY"],
"inputs": ["$TURBO_DEFAULT$", ".env"],
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**", "next-env.d.ts", ".expo/**"]
}
8 replies
CCConvex Community
Created by entropy on 12/11/2024 in #support-community
Next build error when ran in github action
I was trying to just build my frontend to make sure it can complete successfully as a part of my CI. For actually deploying to vercel I haven't had issues using the below build command. I assumed that maybe this issue was that the convex url was missing, but even when pulling my env vars from vercel before the build step in my CI it still throws the error above. cd ../../packages/backend && npx convex deploy --cmd 'cd ../../apps/web && turbo run build' --cmd-url-env-var-name NEXT_PUBLIC_CONVEX_URL
8 replies
CCConvex Community
Created by entropy on 12/3/2024 in #support-community
Calculating average rating across a large dataset
Sorry for the late reply but thanks for the suggestions! I wasn't able to figure out how to get the [Id<'anime>, boolean] method working so I ended up going with just do a check before inserting into the aggregate (I'm also looking into triggers). I was wondering if this was a good approach overall? convex/lib/aggregates.ts
export const animeStatsByEntry = new TableAggregate<{
Namespace: Id<'anime'>
Key: null
DataModel: DataModel
TableName: 'anime_entries'
}>(components.aggregateByAnime, {
namespace: doc => doc.animeId,
sortKey: _ => null,
// biome-ignore lint/style/noNonNullAssertion:
sumValue: doc => doc.rating!
})
export const animeStatsByEntry = new TableAggregate<{
Namespace: Id<'anime'>
Key: null
DataModel: DataModel
TableName: 'anime_entries'
}>(components.aggregateByAnime, {
namespace: doc => doc.animeId,
sortKey: _ => null,
// biome-ignore lint/style/noNonNullAssertion:
sumValue: doc => doc.rating!
})
convex/functions/anime.ts
export const getBySlug = query({
args: { slug: v.string },
handler: async (ctx, args) => {
const anime = await ctx.db
.query('anime')
.withIndex('by_slug', q => q.eq('slug', args.slug))
.first()

if (!anime) return null

const opts = {
namespace: anime._id,
bounds: {
lower: undefined,
upper: undefined
}
}

return {
...anime,
rating:
(await animeStatsByEntry.sum(ctx, opts)) /
(await animeStatsByEntry.count(ctx, opts))
}
}
})
export const getBySlug = query({
args: { slug: v.string },
handler: async (ctx, args) => {
const anime = await ctx.db
.query('anime')
.withIndex('by_slug', q => q.eq('slug', args.slug))
.first()

if (!anime) return null

const opts = {
namespace: anime._id,
bounds: {
lower: undefined,
upper: undefined
}
}

return {
...anime,
rating:
(await animeStatsByEntry.sum(ctx, opts)) /
(await animeStatsByEntry.count(ctx, opts))
}
}
})
convex/functions/anime_entries.ts
async function insertRatingAggregate(
ctx: MutationCtx,
entryId: Id<'anime_entries'>
) {
const createdEntry = await ctx.db.get(entryId)
if (!createdEntry) throw new ConvexError('Failed to get created entry')
await animeStatsByEntry.insert(ctx, createdEntry)
}

export const createEditorEntry = authRLSMutation({
args: {
lists: v.array(v.id('lists')),
entry: v.object(AnimeEntries.withoutSystemFields)
},
handler: async (ctx, args) => {
const { lists, entry } = args
const entryId = await ctx.db.insert('anime_entries', entry)

if (entry.rating) await insertRatingAggregate(ctx, entryId)

return await Promise.all(
lists.map(list =>
ctx.db.insert('anime_lists_entries', {
entryId,
listId: list
})
)
)
}
})
async function insertRatingAggregate(
ctx: MutationCtx,
entryId: Id<'anime_entries'>
) {
const createdEntry = await ctx.db.get(entryId)
if (!createdEntry) throw new ConvexError('Failed to get created entry')
await animeStatsByEntry.insert(ctx, createdEntry)
}

export const createEditorEntry = authRLSMutation({
args: {
lists: v.array(v.id('lists')),
entry: v.object(AnimeEntries.withoutSystemFields)
},
handler: async (ctx, args) => {
const { lists, entry } = args
const entryId = await ctx.db.insert('anime_entries', entry)

if (entry.rating) await insertRatingAggregate(ctx, entryId)

return await Promise.all(
lists.map(list =>
ctx.db.insert('anime_lists_entries', {
entryId,
listId: list
})
)
)
}
})
6 replies
CCConvex Community
Created by entropy on 11/29/2024 in #support-community
useQuery different return types
Thanks for the help!
9 replies
CCConvex Community
Created by entropy on 11/29/2024 in #support-community
useQuery different return types
Ahh that was it. One was imported from convex/react and the other from convex-helpers/react.
9 replies
CCConvex Community
Created by entropy on 11/29/2024 in #support-community
useQuery different return types
Sure anime_entries.authSingleById
export const authSingleById = authRLSQuery({
args: { id: v.id('anime') },
handler: async (ctx, args) => {
return await ctx.db
.query('anime_entries')
.withIndex('by_animeId', q => q.eq('animeId', args.id))
.first()
}
})
export const authSingleById = authRLSQuery({
args: { id: v.id('anime') },
handler: async (ctx, args) => {
return await ctx.db
.query('anime_entries')
.withIndex('by_animeId', q => q.eq('animeId', args.id))
.first()
}
})
lists.authAll
export const authAll = authRLSQuery({
handler: async ctx => {
return await ctx.db
.query('lists')
.withIndex('by_userId', q => q.eq('userId', ctx.user._id))
.collect()
}
})
export const authAll = authRLSQuery({
handler: async ctx => {
return await ctx.db
.query('lists')
.withIndex('by_userId', q => q.eq('userId', ctx.user._id))
.collect()
}
})
9 replies
CCConvex Community
Created by entropy on 11/29/2024 in #support-community
useQuery different return types
For example with entry, I want to display an error if there was a problem fetching the data. Though if there just isn't an entry yet I know to create one.
9 replies
CCConvex Community
Created by entropy on 11/29/2024 in #support-community
useQuery different return types
Preferably it would always return the object including information on the query status.
9 replies
CCConvex Community
Created by entropy on 8/25/2024 in #support-community
Best way of querying documents when using Clerk
as a quick example something like this would be best if I decided to go the seperate user route?
export const getByUser = authRLSQuery({
args: { mediaId: union(id('anime')) },
handler: async (ctx, args) => {
return await ctx.db
.query('entries')
.withIndex('by_userId_mediaId', q =>
q.eq('userId', ctx.user._id).eq('mediaId', args.mediaId)
)
.first()
}
})
export const getByUser = authRLSQuery({
args: { mediaId: union(id('anime')) },
handler: async (ctx, args) => {
return await ctx.db
.query('entries')
.withIndex('by_userId_mediaId', q =>
q.eq('userId', ctx.user._id).eq('mediaId', args.mediaId)
)
.first()
}
})
export const authRLSQuery = customQuery(query, {
args: {},
input: async (ctx, args) => {
const identity = await ctx.auth.getUserIdentity()
if (!identity) {
throw new ConvexError({
code: 'UNAUTHORIZED',
message: 'Sorry, you must be logged in to perform this action'
})
}

const user = await getUser(ctx, identity.subject)
if (!user) {
throw new ConvexError({ message: 'No user found for this identifier.' })
}

const db = wrapDatabaseReader({ identity }, ctx.db, {
users: {
read: async (ctx, user) => ctx.identity.subject === user.clerkId
}
})
return { ctx: { ...ctx, db, identity, user }, args }
}
})
export const authRLSQuery = customQuery(query, {
args: {},
input: async (ctx, args) => {
const identity = await ctx.auth.getUserIdentity()
if (!identity) {
throw new ConvexError({
code: 'UNAUTHORIZED',
message: 'Sorry, you must be logged in to perform this action'
})
}

const user = await getUser(ctx, identity.subject)
if (!user) {
throw new ConvexError({ message: 'No user found for this identifier.' })
}

const db = wrapDatabaseReader({ identity }, ctx.db, {
users: {
read: async (ctx, user) => ctx.identity.subject === user.clerkId
}
})
return { ctx: { ...ctx, db, identity, user }, args }
}
})
8 replies
CCConvex Community
Created by entropy on 8/25/2024 in #support-community
Best way of querying documents when using Clerk
I see that makes sense and thank you for the insight!
8 replies
CCConvex Community
Created by entropy on 8/25/2024 in #support-community
Best way of querying documents when using Clerk
For example if I have a relationship like this where an entry belongs to a user I could either: one use the _id field of the user but then that means I have to query a user by their clerk id to get their user id, or two use the clerk id as the field for relationship and always query by the clerk id. I feel like either there's something I'm missing or there's a better way.
8 replies
CCConvex Community
Created by entropy on 8/25/2024 in #support-community
Best way of querying documents when using Clerk
So in that case I should use ctx.identity.subject passed from my RLS and then query the user for their user id? The main thing is it feels a bit weird having two main id fields with the clerkId field allowing my to avoid querying the user for their id.
8 replies
CCConvex Community
Created by entropy on 7/8/2024 in #support-community
ip whitelist with httpRouter
Thanks for the info! I ended up just doing this:
const requestIp = headerPayload.get('x-forwarded-for') ?? ''
const validIps = String(process.env.SVIX_REQUEST_IPS).split(',')

if (!validIps.includes(requestIp)) {
return new Response('Forbidden', {
status: 403
})
}
const requestIp = headerPayload.get('x-forwarded-for') ?? ''
const validIps = String(process.env.SVIX_REQUEST_IPS).split(',')

if (!validIps.includes(requestIp)) {
return new Response('Forbidden', {
status: 403
})
}
9 replies
CCConvex Community
Created by entropy on 5/29/2024 in #support-community
Implementing non OpenID custom auth
Gotcha thanks for the info. The self signing trick looks interesting so I'll look into that.
5 replies
CCConvex Community
Created by entropy on 5/29/2024 in #support-community
Implementing non OpenID custom auth
here's the code from my previous implementation with supabase for reference
5 replies
CCConvex Community
Created by entropy on 5/16/2024 in #support-community
preloaded data with paginated query
Yep that works perfectly, thank you for the great suggestion!
9 replies