Rewrite cart as client-only guest cart per AI_PROMPT.md spec

Replaces the previous server-cart implementation (which wrongly called
the customer-dashboard-only /businesses/{id}/cart* API) with the
documented guest-cart architecture:

- src/lib/guestCart.ts: storage key/cookie name, cookie attributes,
  line shape, and encodeGuestCart() copied verbatim from AI_PROMPT.md
- CartProvider/CartButton: pure client state (localStorage + mirrored
  cookie), no bearer auth, no businessId
- CartButton's "ادامه" builds the exact documented Continue URL,
  branching on hasCustomerSessionCookie() to either
  customer.<domain>/checkout/cart?guestCart=<encoded> or
  .../login?redirect=<encoded checkout path>
- Auth cookie corrected to the real documented name
  (meshkee_customer_access_token, possibly chunked) via a shared
  reassembleChunkedCookie() helper used by both auth.ts (server) and
  authUser.ts (client)
- ProductBuyPanel/product pages switched to the documented
  GET .../store-items/by-product/{id} endpoint (getStoreItemByProduct)
- isInStock() treats stockQuantity === null as unlimited stock, not
  out-of-stock, per spec
- AGENTS.md updated to describe this architecture and remove the
  incorrect server-cart documentation

Manually verified in-browser: badge count, popup lines/qty/remove/
total all update correctly against injected guest-cart data; tsc,
eslint, and next build all pass clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
amirhosein.ashourloo
2026-09-06 13:29:30 +03:30
co-authored by Claude Sonnet 5
parent d624ad8a32
commit 4ffdf03727
17 changed files with 434 additions and 381 deletions
+9 -6
View File
@@ -1,18 +1,21 @@
import { cookies } from "next/headers";
import { getMe, safe } from "./api";
import { AUTH_TOKEN_COOKIE } from "./config";
import { reassembleChunkedCookie } from "./authUser";
import type { AuthUser } from "./types";
export { displayName, isAdmin } from "./authUser";
// Server-side "am I logged in" check for the header/account menu. See the
// AUTH_TOKEN_COOKIE comment in config.ts for the one external dependency
// this relies on. Resolves to null whenever the cookie is absent or /auth/me
// fails — never throws, so a missing session degrades to the anonymous view.
// Server-side "am I logged in" check for the header/account menu. Reads the
// cookie the customer dashboard writes on login (see AUTH_TOKEN_COOKIE in
// config.ts and AI_PROMPT.md "Shared login") — this storefront never issues
// it. Resolves to null whenever the cookie is absent or /auth/me fails —
// never throws, so a missing session degrades to the anonymous view.
export async function getSession(): Promise<AuthUser | null> {
const store = await cookies();
const token = store.get(AUTH_TOKEN_COOKIE)?.value;
if (!token) return null;
const raw = reassembleChunkedCookie((name) => store.get(name)?.value, AUTH_TOKEN_COOKIE);
if (!raw) return null;
const token = decodeURIComponent(raw);
const result = await safe(getMe(token), null);
return result?.user ?? null;