The Adhara SDK

This repo is a consumer of the real Adhara SDK, not a second place to reimplement it — and never vendors it.

Two tiers, both optional

Adhara integration happens at two levels, and most features only need the first:

  1. Raw HTTP (src/lib/adhara.ts) — public endpoints need no auth; authenticated ones need ADHARA_API_KEY. Used for blog/event reads, form/newsletter submission, and scheduling/links reads. These are plain fetch() calls against confirmed Adhara REST endpoints — no SDK required.
  2. The real SDK (@eimglobalsolutions/adhara-sdk) — optional, and only for authenticated operations: multi-item commerce checkout, media gallery browsing, and form provisioning. The public storefront (catalog + single-item checkout) is raw HTTP too, so a site needs no SDK to sell.

Never vendored

@eimglobalsolutions/adhara-sdk is a private-registry package. It is never added to package.json — every call site imports it dynamically and degrades to the local JSON path when it isn’t installed:

export function getSdkClient(): Promise<AdharaSdkClient | null> {
  if (!sdkClientPromise) {
    sdkClientPromise = (async () => {
      try {
        // @ts-expect-error — optional external package, not a workspace dependency.
        const mod = await import('@eimglobalsolutions/adhara-sdk');
        const AdharaClient = mod.AdharaClient ?? mod.default;
        return new AdharaClient({ apiKey: process.env.ADHARA_API_KEY || '', baseUrl: baseUrl() });
      } catch {
        return null;
      }
    })();
  }
  return sdkClientPromise;
}

Install it yourself (from the private registry) when you’re ready to go live with an SDK-backed feature — the app runs and degrades correctly with or without it, on every deploy target, including edge runtimes like Cloudflare Workers.

“Layer on top of the SDK, don’t reimplement it”

When a feature needs the SDK and the SDK is missing a method, or has one with the wrong shape, the fix goes at the SDK’s own source (a sibling repo), not as a workaround here. This repo is a thin consumer layer, never a second implementation of Adhara’s API surface.

That discipline has found and fixed real, confirmed gaps in the SDK — not guessed at unconfirmed ones. Every one of these was found by reading the real backend route/schema files directly and cross-checking against what the SDK claimed, then verified with a real build + test run after the fix:

Area What was wrong Fix
Commerce getPublicService() was missing entirely, even though the backend route existed Added, mirroring getPublicProduct()’s pattern
Commerce Checkout request types claimed a multi-item items: CartItem[] shape that matches neither real checkout endpoint Replaced with the two real, distinct shapes — public single-item and authenticated multi-item
Forms SubmitFormRequest claimed a { data: ... } body Real backend requires response_data, keyed by each field’s id
Leads LeadsResource.capture() posted to /public/leads/{workspaceSlug} Real endpoint is a bare POST /public/leads, workspace resolved from workspace_id in the body — a genuine backend inconsistency vs. every other public/* route, not a bug to route around
Media Gallery No MediaResource existed at all — a fully missing resource, not a wrong-shaped method Added MediaResource (folder/file listing), matching the real backend and the real frontend’s own working consumer code

Real, confirmed extension points (found, not built)

A few real capabilities were discovered on the backend during this work that aren’t wired up yet — documented as genuine next steps, not guesses at maybe-existing features:

  • A full session-based public shopping cart API (POST/GET/DELETE /public/cart/{workspace_slug}, .../items, .../validate, .../checkout) that would remove the public checkout path’s current “exactly one distinct cart line” limit. The SDK doesn’t wrap it yet; adopting it means moving the cart from this repo’s client-side localStorage to an Adhara-hosted server session — a real architectural change, not a small patch.
  • A confirmed authenticated workspace-links REST API (create/update/delete/reorder) with no SDK resource and no in-app admin UI calling it yet — this port only wires the public read side of /links.

Extending it yourself

If you’re adding a new Adhara-backed feature:

  1. Check whether the SDK already has a resource for it (client.<resource>).
  2. If it’s missing or wrong, read the real backend’s route + schema files directly — don’t trust the SDK’s types as ground truth without cross-checking.
  3. Fix or add it at the SDK source, rebuild, and run its test suite.
  4. Write a thin wrapper in src/lib/adhara<Feature>.ts here that degrades to null/empty when the SDK isn’t installed or the call fails — follow adharaCommerce.ts or adharaMedia.ts as the pattern.
  5. Wire it into a src/services/*Store.ts that resolves local vs. Adhara via resolveFeatureBackend() — see Overview.