@cimplify/sdk 0.38.5 → 0.39.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/{chunk-JTU5P6GM.mjs → chunk-3WD6U5RD.mjs} +1 -83
  2. package/dist/chunk-BGCEKFLA.js +89 -0
  3. package/dist/chunk-IRJFDKFV.mjs +83 -0
  4. package/dist/{chunk-5VHKZTFJ.js → chunk-OMAP327U.js} +0 -87
  5. package/dist/index.js +34 -33
  6. package/dist/index.mjs +2 -1
  7. package/dist/react.js +47 -46
  8. package/dist/react.mjs +3 -2
  9. package/dist/server.d.mts +97 -0
  10. package/dist/server.d.ts +97 -0
  11. package/dist/server.js +107 -0
  12. package/dist/server.mjs +92 -0
  13. package/dist/styles.css +1 -1
  14. package/package.json +7 -1
  15. package/templates/storefront/app/about/page.tsx +61 -0
  16. package/templates/storefront/app/categories/[slug]/listing-client.tsx +19 -0
  17. package/templates/storefront/app/categories/[slug]/page.tsx +94 -57
  18. package/templates/storefront/app/collections/[slug]/listing-client.tsx +20 -0
  19. package/templates/storefront/app/collections/[slug]/page.tsx +94 -57
  20. package/templates/storefront/app/faq/page.tsx +122 -0
  21. package/templates/storefront/app/page.tsx +77 -45
  22. package/templates/storefront/app/privacy/page.tsx +88 -0
  23. package/templates/storefront/app/shop/page.tsx +25 -41
  24. package/templates/storefront/app/shop/shop-client.tsx +27 -0
  25. package/templates/storefront/app/terms/page.tsx +102 -0
  26. package/templates/storefront/components/cart-pill.tsx +32 -0
  27. package/templates/storefront/components/footer.tsx +186 -15
  28. package/templates/storefront/components/header.tsx +32 -22
  29. package/templates/storefront/components/nav-link.tsx +20 -0
  30. package/templates/storefront/components/store-product-card.tsx +9 -25
  31. package/templates/storefront/lib/server-client.ts +27 -0
  32. package/templates/storefront/next.config.ts +4 -0
@@ -0,0 +1,102 @@
1
+ import type { Metadata } from "next";
2
+
3
+ export const metadata: Metadata = {
4
+ title: "Terms of Service — Akua's Bakery",
5
+ description: "The rules of the road for ordering from Akua's Bakery.",
6
+ };
7
+
8
+ export default function TermsPage() {
9
+ return (
10
+ <article className="max-w-3xl mx-auto px-8 py-16 prose prose-lg max-w-none">
11
+ <p className="text-[11px] font-semibold uppercase tracking-[0.16em] text-primary mb-2 not-prose">
12
+ Terms of service
13
+ </p>
14
+ <h1 className="font-serif text-[clamp(2.25rem,5vw,3.5rem)] font-semibold mb-2 -tracking-[0.02em]">
15
+ Terms of Service
16
+ </h1>
17
+ <p className="text-sm text-muted-foreground not-prose mb-10">
18
+ Last updated: 1 May 2026
19
+ </p>
20
+
21
+ <section className="space-y-5 leading-relaxed text-foreground/90">
22
+ <h2 className="font-serif text-2xl font-semibold mt-0">1. Who we are</h2>
23
+ <p>
24
+ Akua's Bakery (&quot;we&quot;, &quot;us&quot;) is a bakery and pâtisserie operating
25
+ at 12 Independence Avenue, Accra, Ghana. By placing an order through this
26
+ website, you (&quot;you&quot;, &quot;customer&quot;) agree to these terms.
27
+ </p>
28
+
29
+ <h2 className="font-serif text-2xl font-semibold">2. Orders and acceptance</h2>
30
+ <p>
31
+ Placing an order constitutes an offer to buy. We confirm acceptance by
32
+ sending an order confirmation email or SMS. Until acceptance, we may
33
+ decline an order — we'll refund any payment in full, immediately.
34
+ </p>
35
+
36
+ <h2 className="font-serif text-2xl font-semibold">3. Pricing and payment</h2>
37
+ <p>
38
+ Prices are in Ghana Cedis (GH₵) and include VAT where applicable.
39
+ Payment is due at checkout via Mobile Money, card, or cash on delivery.
40
+ We reserve the right to correct typographical pricing errors before
41
+ fulfilment.
42
+ </p>
43
+
44
+ <h2 className="font-serif text-2xl font-semibold">4. Delivery and pickup</h2>
45
+ <p>
46
+ Delivery times are estimates, not guarantees. We're not liable for
47
+ delays caused by weather, traffic, or events outside our control. If
48
+ a rider can't reach you within 30 minutes of arrival, the order may be
49
+ returned to the kitchen — please make sure your address and phone are
50
+ correct.
51
+ </p>
52
+
53
+ <h2 className="font-serif text-2xl font-semibold">5. Custom cakes</h2>
54
+ <p>
55
+ Custom cake orders require a 50% deposit at booking and the balance
56
+ before pickup or dispatch. Cancellations more than 72 hours before the
57
+ event date receive a full refund of the deposit; within 72 hours,
58
+ the deposit is non-refundable.
59
+ </p>
60
+
61
+ <h2 className="font-serif text-2xl font-semibold">6. Allergens</h2>
62
+ <p>
63
+ Our kitchen handles wheat, dairy, eggs, and tree nuts. We can't
64
+ guarantee freedom from cross-contamination. Customers with severe
65
+ allergies order at their own risk.
66
+ </p>
67
+
68
+ <h2 className="font-serif text-2xl font-semibold">7. Returns</h2>
69
+ <p>
70
+ Baked goods are non-returnable for food-safety reasons. If something
71
+ is wrong with your order, contact us within 24 hours of delivery and
72
+ we'll replace it, refund it, or credit your account — your choice.
73
+ </p>
74
+
75
+ <h2 className="font-serif text-2xl font-semibold">8. Liability</h2>
76
+ <p>
77
+ To the maximum extent permitted by Ghanaian law, our liability for any
78
+ claim arising from this website or your order is limited to the value
79
+ of the order. We're not liable for indirect or consequential losses.
80
+ </p>
81
+
82
+ <h2 className="font-serif text-2xl font-semibold">9. Governing law</h2>
83
+ <p>
84
+ These terms are governed by the laws of Ghana. Disputes will be
85
+ resolved in the courts of Greater Accra.
86
+ </p>
87
+
88
+ <h2 className="font-serif text-2xl font-semibold">10. Contact</h2>
89
+ <p>
90
+ Questions? Email{" "}
91
+ <a
92
+ href="mailto:hello@akuasbakery.test"
93
+ className="text-primary font-semibold hover:underline"
94
+ >
95
+ hello@akuasbakery.test
96
+ </a>
97
+ .
98
+ </p>
99
+ </section>
100
+ </article>
101
+ );
102
+ }
@@ -0,0 +1,32 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import { useCartCount } from "@/lib/cart";
5
+
6
+ /**
7
+ * Cart pill — dynamic island. Reads the live cart count via the SDK and
8
+ * renders a link to `/cart`. Wrap in `<Suspense fallback={<CartPillSkeleton/>}>`
9
+ * so the cached header chrome streams without blocking on the cart fetch.
10
+ */
11
+ export function CartPill() {
12
+ const { count } = useCartCount();
13
+ return (
14
+ <Link
15
+ href="/cart"
16
+ className="inline-flex items-center gap-1.5 px-3.5 py-2 rounded-full bg-foreground text-background text-xs font-semibold tracking-wide transition-transform hover:scale-105"
17
+ >
18
+ Cart · {count}
19
+ </Link>
20
+ );
21
+ }
22
+
23
+ export function CartPillSkeleton() {
24
+ return (
25
+ <span
26
+ aria-hidden
27
+ className="inline-flex items-center gap-1.5 px-3.5 py-2 rounded-full bg-foreground/80 text-background text-xs font-semibold tracking-wide"
28
+ >
29
+ Cart · …
30
+ </span>
31
+ );
32
+ }
@@ -1,19 +1,190 @@
1
- export function Footer() {
1
+ import Link from "next/link";
2
+
3
+ const SOCIALS: { label: string; href: string; svg: React.ReactNode }[] = [
4
+ {
5
+ label: "Instagram",
6
+ href: "https://instagram.com/akuasbakery",
7
+ svg: (
8
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" aria-hidden className="w-5 h-5">
9
+ <rect x="3" y="3" width="18" height="18" rx="5" />
10
+ <circle cx="12" cy="12" r="4" />
11
+ <circle cx="17.5" cy="6.5" r="0.75" fill="currentColor" />
12
+ </svg>
13
+ ),
14
+ },
15
+ {
16
+ label: "TikTok",
17
+ href: "https://tiktok.com/@akuasbakery",
18
+ svg: (
19
+ <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden className="w-5 h-5">
20
+ <path d="M16 3v3.5a4.5 4.5 0 0 0 4.5 4.5V14a7.5 7.5 0 0 1-4.5-1.5V16a5 5 0 1 1-5-5v3a2 2 0 1 0 2 2V3z" />
21
+ </svg>
22
+ ),
23
+ },
24
+ {
25
+ label: "X",
26
+ href: "https://x.com/akuasbakery",
27
+ svg: (
28
+ <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden className="w-5 h-5">
29
+ <path d="M18 2h3l-7.5 8.6L22 22h-6.6l-5-6.5L4 22H1l8-9.2L1.4 2H8l4.6 6 5.4-6z" />
30
+ </svg>
31
+ ),
32
+ },
33
+ {
34
+ label: "Facebook",
35
+ href: "https://facebook.com/akuasbakery",
36
+ svg: (
37
+ <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden className="w-5 h-5">
38
+ <path d="M14 9V7a1 1 0 0 1 1-1h2V3h-3a4 4 0 0 0-4 4v2H8v3h2v9h3v-9h2.5l.5-3H13z" />
39
+ </svg>
40
+ ),
41
+ },
42
+ {
43
+ label: "WhatsApp",
44
+ href: "https://wa.me/233244000000",
45
+ svg: (
46
+ <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden className="w-5 h-5">
47
+ <path d="M12 2a10 10 0 0 0-8.6 15l-1.4 5 5.2-1.4A10 10 0 1 0 12 2zm5 14.2c-.2.6-1.2 1.2-1.7 1.2-.5.1-1.1.1-1.7-.1-.4-.1-.9-.3-1.5-.6a8.4 8.4 0 0 1-3.7-3.4c-.7-1-1-1.8-1-2.5 0-.7.4-1.1.6-1.3.2-.2.4-.2.5-.2h.4c.1 0 .3 0 .4.3l.6 1.4c.1.2 0 .3 0 .4l-.3.4-.3.3c-.1.1-.2.2-.1.4.2.4.7 1.1 1.4 1.8.9.8 1.7 1.1 1.9 1.2.2.1.3.1.5-.1l.6-.7c.2-.2.3-.2.5-.1l1.4.7c.2.1.3.2.4.3.1.2.1.6 0 1z" />
48
+ </svg>
49
+ ),
50
+ },
51
+ ];
52
+
53
+ const SITEMAP: { title: string; links: { label: string; href: string }[] }[] = [
54
+ {
55
+ title: "Shop",
56
+ links: [
57
+ { label: "All products", href: "/shop" },
58
+ { label: "Breads", href: "/categories/breads" },
59
+ { label: "Pastries", href: "/categories/pastries" },
60
+ { label: "Cakes", href: "/categories/cakes" },
61
+ { label: "Drinks", href: "/categories/drinks" },
62
+ { label: "Merch & More", href: "/categories/merch" },
63
+ { label: "Classes & Stays", href: "/categories/classes" },
64
+ ],
65
+ },
66
+ {
67
+ title: "Bakery",
68
+ links: [
69
+ { label: "Our story", href: "/about" },
70
+ { label: "FAQ", href: "/faq" },
71
+ { label: "Visit us", href: "/about#visit" },
72
+ { label: "Wholesale", href: "/categories/merch" },
73
+ ],
74
+ },
75
+ {
76
+ title: "Help",
77
+ links: [
78
+ { label: "Contact", href: "mailto:hello@akuasbakery.test" },
79
+ { label: "Custom cakes", href: "/faq#custom-cakes--celebrations" },
80
+ { label: "Allergens", href: "/faq#allergens--ingredients" },
81
+ { label: "Delivery", href: "/faq#ordering--delivery" },
82
+ ],
83
+ },
84
+ {
85
+ title: "Legal",
86
+ links: [
87
+ { label: "Terms of Service", href: "/terms" },
88
+ { label: "Privacy Policy", href: "/privacy" },
89
+ ],
90
+ },
91
+ ];
92
+
93
+ export async function Footer() {
94
+ "use cache";
95
+ const year = new Date().getFullYear();
2
96
  return (
3
- <footer className="mt-12 px-8 py-10 text-center text-xs text-muted-foreground border-t border-border bg-card">
4
- <p className="m-0 font-serif text-base text-foreground">Akua's Bakery</p>
5
- <p className="mt-1 mb-3">12 Independence Ave, Accra · +233 244 000 000</p>
6
- <p className="m-0">
7
- Built with{" "}
8
- <a
9
- href="https://www.npmjs.com/package/@cimplify/sdk"
10
- target="_blank"
11
- rel="noopener noreferrer"
12
- className="font-semibold text-primary hover:underline"
13
- >
14
- @cimplify/sdk
15
- </a>
16
- </p>
97
+ <footer className="mt-16 border-t border-border bg-card text-sm">
98
+ <div className="max-w-7xl mx-auto px-8 pt-12 pb-8">
99
+ <div className="grid gap-10 md:grid-cols-[1.4fr_repeat(4,1fr)]">
100
+ <div>
101
+ <p className="font-serif text-2xl text-foreground m-0 mb-2">Akua&apos;s Bakery</p>
102
+ <p className="text-muted-foreground leading-relaxed mb-4 max-w-sm">
103
+ Family-run bakery in East Legon. Sourdough, croissants, layered
104
+ cakes — handcrafted since 2018, delivered across Accra.
105
+ </p>
106
+ <address className="not-italic text-muted-foreground space-y-1">
107
+ <p className="m-0">12 Independence Ave, Accra</p>
108
+ <p className="m-0">
109
+ <a href="tel:+233244000000" className="hover:text-foreground transition-colors">
110
+ +233 244 000 000
111
+ </a>
112
+ </p>
113
+ <p className="m-0">
114
+ <a
115
+ href="mailto:hello@akuasbakery.test"
116
+ className="hover:text-foreground transition-colors"
117
+ >
118
+ hello@akuasbakery.test
119
+ </a>
120
+ </p>
121
+ <p className="m-0 text-xs">Tue–Sun · 8am–8pm · closed Mondays</p>
122
+ </address>
123
+ <div className="flex items-center gap-3 mt-5">
124
+ {SOCIALS.map((s) => (
125
+ <a
126
+ key={s.label}
127
+ href={s.href}
128
+ aria-label={s.label}
129
+ target="_blank"
130
+ rel="noopener noreferrer"
131
+ className="inline-flex items-center justify-center w-9 h-9 rounded-full border border-border text-muted-foreground hover:text-foreground hover:border-foreground transition-colors"
132
+ >
133
+ {s.svg}
134
+ </a>
135
+ ))}
136
+ </div>
137
+ </div>
138
+ {SITEMAP.map((section) => (
139
+ <nav key={section.title} aria-labelledby={`footer-${section.title}`}>
140
+ <p
141
+ id={`footer-${section.title}`}
142
+ className="font-semibold text-foreground mb-3 text-[13px] uppercase tracking-[0.08em]"
143
+ >
144
+ {section.title}
145
+ </p>
146
+ <ul className="space-y-2 m-0 p-0 list-none">
147
+ {section.links.map((link) => (
148
+ <li key={link.label}>
149
+ <Link
150
+ href={link.href}
151
+ className="text-muted-foreground hover:text-foreground transition-colors"
152
+ >
153
+ {link.label}
154
+ </Link>
155
+ </li>
156
+ ))}
157
+ </ul>
158
+ </nav>
159
+ ))}
160
+ </div>
161
+
162
+ <div className="mt-12 pt-6 border-t border-border flex flex-col sm:flex-row items-center justify-between gap-3 text-xs text-muted-foreground">
163
+ <p className="m-0">© {year} Akua&apos;s Bakery. All rights reserved.</p>
164
+ <p className="m-0 inline-flex items-center gap-1.5">
165
+ <span className="text-muted-foreground/80">Powered by</span>
166
+ <a
167
+ href="https://app.cimplify.io"
168
+ target="_blank"
169
+ rel="noopener noreferrer"
170
+ aria-label="Cimplify"
171
+ className="inline-flex items-center gap-1 font-serif text-foreground hover:text-primary transition-colors"
172
+ >
173
+ <span className="font-semibold tracking-tight">Cimplify</span>
174
+ <svg
175
+ viewBox="0 0 12 12"
176
+ aria-hidden
177
+ className="w-3 h-3 opacity-70"
178
+ fill="none"
179
+ stroke="currentColor"
180
+ strokeWidth="1.5"
181
+ >
182
+ <path d="M3 9L9 3M9 3H4M9 3v5" strokeLinecap="round" strokeLinejoin="round" />
183
+ </svg>
184
+ </a>
185
+ </p>
186
+ </div>
187
+ </div>
17
188
  </footer>
18
189
  );
19
190
  }
@@ -1,41 +1,51 @@
1
- "use client";
2
-
3
1
  import Link from "next/link";
4
- import { usePathname } from "next/navigation";
5
- import { useCartCount } from "@/lib/cart";
2
+ import { Suspense } from "react";
3
+ import { NavLink } from "./nav-link";
4
+ import { CartPill, CartPillSkeleton } from "./cart-pill";
6
5
 
7
6
  const TAGLINE = "ACCRA · SINCE 2018";
8
7
 
9
- function navLinkClass(active: boolean) {
10
- return [
11
- "text-[13px] font-medium tracking-wide transition-colors",
12
- active ? "text-primary" : "text-muted-foreground hover:text-foreground",
13
- ].join(" ");
14
- }
15
-
8
+ /**
9
+ * Server-rendered header chrome. Brand mark + nav layout streams from the
10
+ * cache; the active-link styling and live cart count are dynamic islands
11
+ * mounted in their own Suspense boundaries so the chrome never blocks.
12
+ */
16
13
  export function Header() {
17
- const pathname = usePathname();
18
- const { count } = useCartCount();
19
14
  return (
20
15
  <header className="sticky top-0 z-30 flex items-center justify-between px-8 py-4 border-b border-border bg-background/90 backdrop-blur-md">
21
16
  <Link href="/" className="flex items-baseline gap-2">
22
17
  <span className="font-serif text-[22px] font-semibold -tracking-[0.02em]">
23
- Akua's Bakery
18
+ Akua&apos;s Bakery
24
19
  </span>
25
20
  <span className="text-[11px] font-medium uppercase tracking-[0.12em] text-muted-foreground">
26
21
  {TAGLINE}
27
22
  </span>
28
23
  </Link>
29
24
  <nav className="flex items-center gap-6">
30
- <Link href="/" className={navLinkClass(pathname === "/")}>Home</Link>
31
- <Link href="/shop" className={navLinkClass(pathname === "/shop")}>Shop</Link>
32
- <Link
33
- href="/cart"
34
- className="inline-flex items-center gap-1.5 px-3.5 py-2 rounded-full bg-foreground text-background text-xs font-semibold tracking-wide transition-transform hover:scale-105"
35
- >
36
- Cart · {count}
37
- </Link>
25
+ <Suspense fallback={<NavLinkFallback>Home</NavLinkFallback>}>
26
+ <NavLink href="/">Home</NavLink>
27
+ </Suspense>
28
+ <Suspense fallback={<NavLinkFallback>Shop</NavLinkFallback>}>
29
+ <NavLink href="/shop">Shop</NavLink>
30
+ </Suspense>
31
+ <Suspense fallback={<NavLinkFallback>About</NavLinkFallback>}>
32
+ <NavLink href="/about">About</NavLink>
33
+ </Suspense>
34
+ <Suspense fallback={<NavLinkFallback>FAQ</NavLinkFallback>}>
35
+ <NavLink href="/faq">FAQ</NavLink>
36
+ </Suspense>
37
+ <Suspense fallback={<CartPillSkeleton />}>
38
+ <CartPill />
39
+ </Suspense>
38
40
  </nav>
39
41
  </header>
40
42
  );
41
43
  }
44
+
45
+ function NavLinkFallback({ children }: { children: React.ReactNode }) {
46
+ return (
47
+ <span className="text-[13px] font-medium tracking-wide text-muted-foreground">
48
+ {children}
49
+ </span>
50
+ );
51
+ }
@@ -0,0 +1,20 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import { usePathname } from "next/navigation";
5
+
6
+ export function NavLink({ href, children }: { href: string; children: React.ReactNode }) {
7
+ const pathname = usePathname();
8
+ const active = pathname === href;
9
+ return (
10
+ <Link
11
+ href={href}
12
+ className={[
13
+ "text-[13px] font-medium tracking-wide transition-colors",
14
+ active ? "text-primary" : "text-muted-foreground hover:text-foreground",
15
+ ].join(" ")}
16
+ >
17
+ {children}
18
+ </Link>
19
+ );
20
+ }
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { useRouter, useSearchParams, usePathname } from "next/navigation";
3
+ import Link from "next/link";
4
4
  import {
5
5
  CardVariant,
6
6
  FoodProductCard,
@@ -60,39 +60,23 @@ interface Props {
60
60
 
61
61
  /**
62
62
  * Variant-aware product card that opens the URL-driven product modal on
63
- * click (`?product=<slug>`). Renders the underlying SDK variant card
64
- * (Food, Bundle, Composite, …) directly and supplies a `renderLink` that
65
- * intercepts navigation — so a single `<CardShell>`-rendered `<a>` tag
66
- * wraps the card (no nested anchors, no hydration error).
63
+ * click. Uses `next/link` with `?product=<slug>` so the link is statically
64
+ * pre-renderable — no `useSearchParams` dependency means cards don't
65
+ * become dynamic islands. The modal (which already reads `useSearchParams`
66
+ * inside a Suspense boundary in the root layout) handles the rest.
67
67
  */
68
68
  export function StoreProductCard({ product, variant }: Props) {
69
- const router = useRouter();
70
- const pathname = usePathname();
71
- const searchParams = useSearchParams();
72
-
73
69
  const slug = product.slug || product.id;
74
70
  const Card = VARIANT_CARDS[variant ?? resolveVariant(product)];
75
-
76
- const open = () => {
77
- const next = new URLSearchParams(searchParams?.toString() ?? "");
78
- next.set("product", slug);
79
- router.push(`${pathname}?${next.toString()}`, { scroll: false });
80
- };
71
+ const href = `?product=${encodeURIComponent(slug)}`;
81
72
 
82
73
  return (
83
74
  <Card
84
75
  product={product}
85
- renderLink={({ href, className, children }) => (
86
- <a
87
- href={href}
88
- className={className}
89
- onClick={(e) => {
90
- e.preventDefault();
91
- open();
92
- }}
93
- >
76
+ renderLink={({ className, children }) => (
77
+ <Link href={href} scroll={false} prefetch={false} className={className}>
94
78
  {children}
95
- </a>
79
+ </Link>
96
80
  )}
97
81
  />
98
82
  );
@@ -0,0 +1,27 @@
1
+ import { createCimplifyClient, type CimplifyClient } from "@cimplify/sdk";
2
+
3
+ /**
4
+ * Server-side Cimplify client. Used by Server Components to fetch catalogue
5
+ * data during SSR/RSC for SEO-friendly product/category/collection pages.
6
+ *
7
+ * Cached per-request via React's cache mechanism — calling this multiple
8
+ * times within the same request returns the same client instance.
9
+ *
10
+ * Base-URL resolution:
11
+ * 1) NEXT_PUBLIC_CIMPLIFY_API_URL (matches the client-side default)
12
+ * 2) http://127.0.0.1:8787 — the local mock during dev
13
+ */
14
+ let cached: CimplifyClient | undefined;
15
+
16
+ export function getServerClient(): CimplifyClient {
17
+ if (cached) return cached;
18
+ const baseUrl =
19
+ process.env.NEXT_PUBLIC_CIMPLIFY_API_URL?.trim() || "http://127.0.0.1:8787";
20
+ const publicKey = process.env.NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY ?? "mock-dev";
21
+ cached = createCimplifyClient({
22
+ baseUrl,
23
+ publicKey,
24
+ suppressPublicKeyWarning: true,
25
+ });
26
+ return cached;
27
+ }
@@ -14,6 +14,10 @@ const MOCK_URL = process.env.NEXT_PUBLIC_CIMPLIFY_API_URL?.trim() || "http://127
14
14
  * pass the absolute URL through `<CimplifyProvider/>`).
15
15
  */
16
16
  const nextConfig: NextConfig = {
17
+ // Enable Next 16's `cacheComponents` mode so we can use `'use cache'` +
18
+ // `cacheTag` / `cacheLife` for SSR caching. Cached chrome streams first,
19
+ // dynamic Suspense boundaries fill in when ready.
20
+ cacheComponents: true,
17
21
  async rewrites() {
18
22
  return [
19
23
  { source: "/api/v1/:path*", destination: `${MOCK_URL}/api/v1/:path*` },