cimplify
TypeScript SDK

Assets

Build CDN URLs for storefront brand assets, render them through `next/image`, and pass external image hosts (Cloudinary, Unsplash, merchant S3) through untouched. The SDK ships `assetUrl`, `isCimplifyAsset`, and `useImage`: pure functions; no network calls; SSR-safe.

The asset surface on the SDK is read-side only: building URLs for images you've already uploaded via cimplify assets upload. Customer-runtime uploads still go through client.uploads.upload(file).

assetUrl(path, opts?)

Pure URL builder. Prepends the CDN base for relative paths, passes absolute URLs through with the transform query contract appended.

import { assetUrl } from "@cimplify/sdk";

assetUrl("hero/main.jpg")
// "https://storefrontassetscdn.cimplify.io/hero/main.jpg"

assetUrl("hero/main.jpg", { w: 1200, format: "webp", quality: 80 })
// "https://storefrontassetscdn.cimplify.io/hero/main.jpg?w=1200&format=webp&quality=80"

assetUrl("hero/main.jpg", { base: "http://localhost:8787/storage" })
// "http://localhost:8787/storage/hero/main.jpg"

assetUrl("https://res.cloudinary.com/foo/bar.jpg")
// "https://res.cloudinary.com/foo/bar.jpg"   (absolute → passthrough)

Options

FieldTypeNotes
basestringOverride the CDN base. Defaults to DEFAULT_CDN_BASE_URL.
w / hnumberWidth / height in pixels (on-the-fly resizing)
qualitynumber0–100
format"auto" | "webp" | "avif" | "jpeg""auto" lets the CDN pick by Accept header

The transform query is only meaningful when the URL terminates on the Cimplify storefront CDN (which supports on-the-fly resizing). For external hosts, unknown params are typically ignored; the image still loads at its original size.

isCimplifyAsset(src, base?)

Decides whether src is hosted on a Cimplify CDN. Used by the storefront's next/image loader to skip transforms for external URLs.

import { isCimplifyAsset } from "@cimplify/sdk";

isCimplifyAsset("hero/main.jpg")                                      // true (relative → ours)
isCimplifyAsset("/img/seed/bakery/x.jpg")                             // true (dev mock passthrough)
isCimplifyAsset("https://storefrontassetscdn.cimplify.io/x.jpg")     // true
isCimplifyAsset("https://cdn.cimplify.io/x.jpg")                     // true
isCimplifyAsset("https://static-tmp.cimplify.io/seed/x.jpg")         // true
isCimplifyAsset("https://res.cloudinary.com/demo/upload/x.jpg")      // false
isCimplifyAsset("https://images.unsplash.com/photo-xyz")             // false

Built-in next/image loader

Every storefront template scaffolded by cimplify init ships lib/cimplify-loader.ts and points images.loaderFile at it. The loader:

import type { ImageLoader } from "next/image";
import { assetUrl, isCimplifyAsset } from "@cimplify/sdk";

const cdnBase = process.env.NEXT_PUBLIC_CIMPLIFY_CDN_URL?.trim() || undefined;

const cimplifyImageLoader: ImageLoader = ({ src, width, quality }) => {
  if (isCimplifyAsset(src, cdnBase)) {
    return assetUrl(src, { base: cdnBase, w: width, quality, format: "auto" });
  }
  return src;
};

export default cimplifyImageLoader;

Cloudinary URLs from client.catalogue.getProducts() flow through untouched. Cimplify-hosted URLs get the transform query. The result: every <Image> works regardless of where its asset lives, and Cimplify-hosted ones get edge-optimized.

To point the loader at a different CDN (for testing, multi-CDN setups, etc.) set NEXT_PUBLIC_CIMPLIFY_CDN_URL in your .env.local:

NEXT_PUBLIC_CIMPLIFY_CDN_URL=http://localhost:8787/storage

useImage(path, opts?) (React)

Thin hook that returns { src, loader } for <Image>:

import Image from "next/image";
import { useImage } from "@cimplify/sdk/react";

export function Hero() {
  const { src, loader } = useImage("hero/main.jpg", { format: "webp", quality: 85 });
  return <Image src={src} loader={loader} alt="..." width={1200} height={800} />;
}

If images.loaderFile is already set globally in your next.config.ts, you typically don't need useImage; just <Image src={assetUrl("hero/main.jpg")} /> works. useImage is useful when you want per-component transform overrides on a project that doesn't use a global loader.

Options

FieldNotes
basePer-call CDN base override
w, hDefault transform values; per-image width from <Image> still wins
format, qualityDefault transform values

useImage is useMemo-stable across renders when the path + opts don't change.

Constants

import { DEFAULT_CDN_BASE_URL, CIMPLIFY_CDN_HOSTS } from "@cimplify/sdk";

DEFAULT_CDN_BASE_URL // "https://storefrontassetscdn.cimplify.io"
CIMPLIFY_CDN_HOSTS   // readonly ["storefrontassetscdn.cimplify.io", "cdn.cimplify.io", "static-tmp.cimplify.io"]

What's not in v1

  • useUpload hook: runtime customer-facing uploads with progress + cancel. Deferred to v1.1. Customer uploads today go through client.uploads.upload(file) (no progress, no cancel; just await).
  • SEED_IDS typed const tree: demo-only convenience for referencing seed-image slugs in code. Generate-from-seed-source step deferred to v1.1; today demos use seedImage(industry, slug) from the SDK's mock module.
  • Cloudinary / S3 path-transform support: the loader passes external hosts through unchanged; Cloudinary's c_fill,w_500/ path transforms aren't synthesized.
  • assets rm server-side delete: CLI removes manifest entries; the remote blob stays until v1.1's media-manager DELETE wiring.

Where it lives in the platform

  • Wire format: POST /v1/businesses/{id}/assets/{init,confirm}; see the management API reference
  • Backend service: crate::uploads::service::UploadService::init_storefront_asset
  • Served from the Cimplify asset CDN at storefrontassetscdn.cimplify.io
  • Storage key: assets/{business_id}/{folder}/{filename}: deterministic, idempotent, agent-predictable

On this page