diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c53bda..2ff67a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to Epicure are documented here. This file is mirrored in-app at `/changelog` (and in the admin dashboard) via `apps/web/lib/changelog.ts` — update both together. +## 0.44.1 — 2026-07-17 17:00 + +### Fixed +- Every recipe page was broken (server error) since 0.41.0 — the new followers-visibility check referenced the user_follows table incorrectly inside a query the ORM rewrites in a way that silently produces invalid SQL for cross-table references. Fixed by using a literal table reference instead. + ## 0.44.0 — 2026-07-17 16:15 ### Added diff --git a/apps/web/lib/changelog.ts b/apps/web/lib/changelog.ts index 0a3bd85..5d8f133 100644 --- a/apps/web/lib/changelog.ts +++ b/apps/web/lib/changelog.ts @@ -1,5 +1,5 @@ // Mirrors CHANGELOG.md at the repo root — update both together. -export const APP_VERSION = "0.44.0"; +export const APP_VERSION = "0.44.1"; export type ChangelogEntry = { version: string; @@ -11,6 +11,13 @@ export type ChangelogEntry = { }; export const CHANGELOG: ChangelogEntry[] = [ + { + version: "0.44.1", + date: "2026-07-17 17:00", + fixed: [ + "Every recipe page was broken (server error) since 0.41.0 — the new followers-visibility check referenced the user_follows table incorrectly inside a query the ORM rewrites in a way that silently produces invalid SQL for cross-table references. Fixed by using a literal table reference instead.", + ], + }, { version: "0.44.0", date: "2026-07-17 16:15", diff --git a/apps/web/lib/visibility.ts b/apps/web/lib/visibility.ts index b3461b8..042bcec 100644 --- a/apps/web/lib/visibility.ts +++ b/apps/web/lib/visibility.ts @@ -1,4 +1,4 @@ -import { recipes, userFollows, eq, or, and, inArray, sql } from "@epicure/db"; +import { recipes, eq, or, and, inArray, sql } from "@epicure/db"; /** * Drizzle condition: true when `viewerId` may view a given recipe row — the @@ -6,6 +6,14 @@ import { recipes, userFollows, eq, or, and, inArray, sql } from "@epicure/db"; * recipes, only to viewers who follow the author. Meant to be `and()`ed with * an `eq(recipes.id, id)` (or similar) in a single query, so the DB does the * filtering rather than fetching content the viewer can't see. + * + * Uses a literal `user_follows` identifier rather than a Drizzle column + * proxy for that table — inside `db.query.recipes.findFirst`/`findMany`'s + * `where`, the relational query builder rewrites embedded column refs to + * the outer query's own table alias regardless of which table they actually + * belong to (same issue documented in recipes/page.tsx's search filter), + * which would otherwise silently produce broken SQL referencing a column + * that doesn't exist on `recipes`. */ export function visibleToViewer(viewerId: string) { return or( @@ -13,7 +21,7 @@ export function visibleToViewer(viewerId: string) { inArray(recipes.visibility, ["public", "unlisted"]), and( eq(recipes.visibility, "followers"), - sql`exists (select 1 from ${userFollows} where ${userFollows.followerId} = ${viewerId} and ${userFollows.followingId} = ${recipes.authorId})` + sql`exists (select 1 from user_follows where user_follows.follower_id = ${viewerId} and user_follows.following_id = ${recipes.authorId})` ) ); } diff --git a/apps/web/package.json b/apps/web/package.json index f9e4edd..cc64315 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@epicure/web", - "version": "0.44.0", + "version": "0.44.1", "private": true, "scripts": { "dev": "next dev", diff --git a/package.json b/package.json index 67f57cf..524880d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "epicure", - "version": "0.44.0", + "version": "0.44.1", "private": true, "scripts": { "dev": "pnpm --filter web dev",