cimplify
TypeScript SDK

Server Components

`@cimplify/sdk/server` is a Node-only entry for the Next.js App Router. It ships three things: a request-memoized client factory, a typed cache-tag scheme, and Server Action revalidation helpers.

Caching is Next's job. Wrap composed reads in a function with "use cache" + cacheTag(tags.X()) + cacheLife(...), and revalidate from Server Actions via revalidateProducts() and friends. The SDK doesn't try to be a caching layer of its own.

getServerClient

Returns a standard CimplifyClient wrapped in React's cache(), so every Server Component in the same request shares a single instance. Reads server env vars (CIMPLIFY_SECRET_KEY, CIMPLIFY_API_URL) with friendly defaults for the local mock.

app/page.tsx
import { unstable_cacheTag as cacheTag, unstable_cacheLife as cacheLife } from "next/cache";
import { getServerClient, tags } from "@cimplify/sdk/server";

async function getCatalogue() {
  "use cache";
  cacheTag(tags.products());
  cacheLife("hours");

  const r = await getServerClient().catalogue.getProducts({ limit: 24 });
  if (!r.ok) throw new Error(r.error.message);
  return r.value.items;
}

export default async function Home() {
  const products = await getCatalogue();
  return <ul>{products.map((p) => <li key={p.id}>{p.name}</li>)}</ul>;
}

Options

OptionTypeDescription
secretKeystringDefaults to CIMPLIFY_SECRET_KEY.
baseUrlstringDefaults to CIMPLIFY_API_URL.
fetchtypeof fetchInject a custom fetch (e.g. for tests).

tags: cache-tag builders

Pass these to cacheTag() on cached functions, or to next.tags on raw fetches. Tag strings are namespaced under cimplify: so they can't collide with consumer tags.

BuilderTag
tags.products()cimplify:products
tags.product(id)cimplify:product:<id>
tags.categories()cimplify:categories
tags.category(id)cimplify:category:<id>
tags.categoryProducts(id)cimplify:category:<id>:products
tags.collections()cimplify:collections
tags.collection(id)cimplify:collection:<id>
tags.collectionProducts(id)cimplify:collection:<id>:products
tags.business()cimplify:business
tags.locations()cimplify:locations
tags.orders(customerId)cimplify:orders:<customerId>
tags.order(id)cimplify:order:<id>
app/products/[slug]/page.tsx
import { unstable_cacheTag as cacheTag, unstable_cacheLife as cacheLife } from "next/cache";
import { notFound } from "next/navigation";
import { getServerClient, tags } from "@cimplify/sdk/server";

async function getProduct(slug: string) {
  "use cache";
  cacheTag(tags.product(slug));
  cacheLife("hours");

  const r = await getServerClient().catalogue.getProductBySlug(slug);
  if (!r.ok) return null;
  return r.value;
}

export default async function Page({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const product = await getProduct(slug);
  if (!product) notFound();
  return <pre>{JSON.stringify(product, null, 2)}</pre>;
}

Server Actions: revalidate*

After a write, call the matching revalidate* helper to invalidate every cached read tagged with that resource. The helpers wrap Next's revalidateTag so consumers don't have to learn the tag scheme.

app/actions.ts
"use server";
import { getServerClient, revalidateProducts, revalidateProduct } from "@cimplify/sdk/server";

export async function archiveProduct(productId: string) {
  const client = getServerClient();
  const r = await client.catalogue.archiveProduct(productId);
  if (!r.ok) throw new Error(r.error.message);

  await revalidateProduct(productId);
  await revalidateProducts();
}

Helpers

HelperInvalidates
revalidateProducts()Products list.
revalidateProduct(id)Single product + the products list (denormalized fields are usually embedded).
revalidateCategories()Categories list.
revalidateCategory(id)Category + its products + the list.
revalidateCollections()Collections list.
revalidateCollection(id)Collection + its products + the list.
revalidateBusiness()Business profile (name, currency, branding).
revalidateByTag(tag)Escape hatch; invalidate by raw tag.

Pre-fetching for client components

SSR-prefetch on the server, hand off as props to a client component. The client component skips its initial fetch and renders instantly.

app/shop/page.tsx
import { unstable_cacheTag as cacheTag, unstable_cacheLife as cacheLife } from "next/cache";
import { getServerClient, tags } from "@cimplify/sdk/server";
import ShopClient from "./shop-client";

async function getShopData() {
  "use cache";
  cacheTag(tags.products(), tags.categories());
  cacheLife("hours");

  const client = getServerClient();
  const [products, categories] = await Promise.all([
    client.catalogue.getProducts({ limit: 24 }),
    client.catalogue.getCategories(),
  ]);
  return {
    products: products.ok ? products.value.items : [],
    categories: categories.ok ? categories.value : [],
  };
}

export default async function Shop() {
  const { products, categories } = await getShopData();
  return <ShopClient products={products} categories={categories} />;
}
app/shop/shop-client.tsx
"use client";
import { CataloguePage } from "@cimplify/sdk/react";
import type { Product, Category } from "@cimplify/sdk/server";

export default function ShopClient({
  products,
  categories,
}: {
  products: Product[];
  categories: Category[];
}) {
  return <CataloguePage products={products} categories={categories} pageSize={24} />;
}

Env vars

VariablePurpose
CIMPLIFY_SECRET_KEYServer key for getServerClient. Never expose to the browser.
CIMPLIFY_API_URLAPI base URL (defaults to production; set to http://127.0.0.1:8787 for the local mock).
NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEYBrowser-safe public key for client-side usage.

Where next

On this page