Skip to content

@eventista/sdk-api-client

REST and GraphQL client for Eventista APIs. Provides RestClient (apisauce-backed) with HMAC request signing, pluggable storage adapter, and platform-agnostic core.

Terminal window
bun add @eventista/sdk-api-client @eventista/sdk-core

RestClient works the same on every runtime — what changes is the StorageAdapter you wire in for token persistence.

Use the bundled createWebSessionStorageAdapter from the /adapters/web sub-path. It reads/writes window.sessionStorage and is safe to import in the browser bundle.

lib/apiClient.ts
"use client";
import { RestClient } from "@eventista/sdk-api-client";
import { createWebSessionStorageAdapter } from "@eventista/sdk-api-client/adapters/web";
export const apiClient = new RestClient({
baseURL: process.env.NEXT_PUBLIC_API_URL!,
storage: createWebSessionStorageAdapter(),
getLanguage: async () => "en",
getSigningSecret: () => process.env.NEXT_PUBLIC_API_SIGNING_SECRET,
onUnauthorized: () => {
window.location.href = "/login";
},
});
app/events/page.tsx
"use client";
import { useEffect, useState } from "react";
import { apiClient } from "@/lib/apiClient";
export default function EventsPage() {
const [events, setEvents] = useState<unknown[]>([]);
useEffect(() => {
apiClient.get<{ events: unknown[] }>("/v1/events").then((res) => {
if (res.data && !res.data.isErr) setEvents(res.data.data.events);
});
}, []);
return <pre>{JSON.stringify(events, null, 2)}</pre>;
}

For server-side rendering (route handlers, server components), use MemoryStorageAdapter — no persistence between requests is the correct SSR behavior.

@react-native-async-storage/async-storage already exposes a Promise-based API that satisfies StorageAdapter — no wrapper needed beyond the type assertion.

lib/apiClient.ts
import { RestClient, type StorageAdapter } from "@eventista/sdk-api-client";
import AsyncStorage from "@react-native-async-storage/async-storage";
const rnStorage: StorageAdapter = {
getItem: (key) => AsyncStorage.getItem(key),
setItem: (key, value) => AsyncStorage.setItem(key, value),
removeItem: (key) => AsyncStorage.removeItem(key),
};
export const apiClient = new RestClient({
baseURL: process.env.EXPO_PUBLIC_API_URL!,
storage: rnStorage,
getLanguage: async () => "en",
getSigningSecret: () => process.env.EXPO_PUBLIC_API_SIGNING_SECRET,
});
// app/(tabs)/events.tsx
import { useEffect, useState } from "react";
import { FlatList, Text } from "react-native";
import { apiClient } from "../../lib/apiClient";
export default function EventsScreen() {
const [events, setEvents] = useState<{ id: string; name: string }[]>([]);
useEffect(() => {
apiClient
.get<{ events: { id: string; name: string }[] }>("/v1/events")
.then((res) => {
if (res.data && !res.data.isErr) setEvents(res.data.data.events);
});
}, []);
return (
<FlatList
data={events}
keyExtractor={(item) => item.id}
renderItem={({ item }) => <Text>{item.name}</Text>}
/>
);
}

The interceptor signs whitelisted endpoints (currently add-to-cart and payment/order/create) with HMAC-SHA256 over the canonical {timestamp}\n{method}\n{path}\n{bodySha256Hex} string. Provide getSigningSecret to enable signing — the HMAC is computed via @noble/hashes (pure JS, audited) so signing works unchanged on web, Node, and React Native / Hermes without any platform adapter or polyfill.

WIP. Public API is unstable — do not depend on it for production yet.