feat: initial commit — storefront, convex backend, and shared packages
Completes the first milestone of The Pet Loft ecommerce platform: - apps/storefront: full customer-facing Next.js app with HeroUI (cart, checkout, orders, wishlist, product detail, shop, search, auth) - convex/: serverless backend with schema, queries, mutations, actions, HTTP routes, Stripe/Shippo integrations, and co-located tests - packages/types, packages/utils, packages/convex: shared workspace packages Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
38
convex/model/users.ts
Normal file
38
convex/model/users.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { QueryCtx, MutationCtx } from "../_generated/server";
|
||||
import type { Id } from "../_generated/dataModel";
|
||||
|
||||
type AuthCtx = QueryCtx | MutationCtx;
|
||||
|
||||
export async function getCurrentUser(ctx: QueryCtx) {
|
||||
const identity = await ctx.auth.getUserIdentity();
|
||||
if (!identity) return null;
|
||||
return await ctx.db
|
||||
.query("users")
|
||||
.withIndex("by_external_id", (q) => q.eq("externalId", identity.subject))
|
||||
.unique();
|
||||
}
|
||||
|
||||
export async function getCurrentUserOrThrow(ctx: AuthCtx) {
|
||||
const user = await getCurrentUser(ctx as QueryCtx);
|
||||
if (!user) throw new Error("Unauthenticated");
|
||||
return user;
|
||||
}
|
||||
|
||||
export async function requireAdmin(ctx: QueryCtx) {
|
||||
const user = await getCurrentUserOrThrow(ctx);
|
||||
if (user.role !== "admin" && user.role !== "super_admin") {
|
||||
throw new Error("Unauthorized: admin access required");
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
export async function requireOwnership(
|
||||
ctx: AuthCtx,
|
||||
resourceUserId: Id<"users">,
|
||||
) {
|
||||
const user = await getCurrentUserOrThrow(ctx);
|
||||
if (resourceUserId !== user._id) {
|
||||
throw new Error("Unauthorized: resource does not belong to you");
|
||||
}
|
||||
return user;
|
||||
}
|
||||
Reference in New Issue
Block a user