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:
- Raw HTTP (
src/lib/adhara.ts) — public endpoints need no auth; authenticated ones needADHARA_API_KEY. Used for blog/event reads, form/newsletter submission, and scheduling/links reads. These are plainfetch()calls against confirmed Adhara REST endpoints — no SDK required. - 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-sidelocalStorageto 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:
- Check whether the SDK already has a resource for it (
client.<resource>). - 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.
- Fix or add it at the SDK source, rebuild, and run its test suite.
- Write a thin wrapper in
src/lib/adhara<Feature>.tshere that degrades tonull/empty when the SDK isn’t installed or the call fails — followadharaCommerce.tsoradharaMedia.tsas the pattern. - Wire it into a
src/services/*Store.tsthat resolves local vs. Adhara viaresolveFeatureBackend()— see Overview.