116 lines
4.3 KiB
TypeScript
116 lines
4.3 KiB
TypeScript
// ---------------------------------------------------------------------------
|
|
// TygaRun Client — ready-made SaaS APIs for generated sites
|
|
// ---------------------------------------------------------------------------
|
|
// Universal client for ALL sdk.tyga.run modules: auth, scheduling (bookings/
|
|
// eventtypes/availability), crm, ecommerce, billing, notifications, webhooks...
|
|
// Where Lovable gives you raw tables, tyga.run gives you ready-made APIs.
|
|
//
|
|
// This stub ships unconfigured. When the project connects tyga.run, the
|
|
// builder replaces TYGARUN_CONFIG with real values (like lib/anydb.ts).
|
|
// Until then isConfigured() is false and hooks fall back to seed data.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const TYGARUN_CONFIG = {
|
|
baseUrl: "__TYGARUN_SDK_URL__", // e.g. https://sdk.tyga.run
|
|
// Browser-safe `tc_pub_` publishable key (Supabase-anon model): origin-locked,
|
|
// sandbox-pinned, module-restricted server-side. Safe to ship in public code.
|
|
publishableKey: "__TYGARUN_ANON_KEY__",
|
|
sandbox: "__TYGARUN_SANDBOX__", // "true" | "false"
|
|
};
|
|
|
|
export function isConfigured(): boolean {
|
|
return !TYGARUN_CONFIG.publishableKey.startsWith("__");
|
|
}
|
|
|
|
const TOKEN_KEY = "tygarun_token";
|
|
|
|
export function getToken(): string | null {
|
|
try { return localStorage.getItem(TOKEN_KEY); } catch { return null; }
|
|
}
|
|
export function setToken(token: string | null) {
|
|
try {
|
|
if (token) localStorage.setItem(TOKEN_KEY, token);
|
|
else localStorage.removeItem(TOKEN_KEY);
|
|
} catch { /* SSR / private mode */ }
|
|
}
|
|
|
|
export interface TygaRunError extends Error {
|
|
statusCode?: number;
|
|
body?: any;
|
|
}
|
|
|
|
/**
|
|
* Universal call to any tyga.run module endpoint.
|
|
* tygarun("scheduling", "/bookings", { query: { page: 1 } })
|
|
* tygarun("auth", "/signin", { method: "POST", body: { email, password } })
|
|
* tygarun("crm", "/contacts", { method: "POST", body: contact })
|
|
*/
|
|
export async function tygarun<T = any>(
|
|
module: string,
|
|
endpoint = "/",
|
|
opts: {
|
|
method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
body?: any;
|
|
query?: Record<string, any>;
|
|
headers?: Record<string, string>;
|
|
} = {}
|
|
): Promise<T> {
|
|
if (!isConfigured()) {
|
|
const err = new Error("tyga.run not connected") as TygaRunError;
|
|
err.statusCode = 0;
|
|
throw err;
|
|
}
|
|
const { method = "GET", body, query = {}, headers = {} } = opts;
|
|
const path = endpoint.startsWith("/") ? endpoint : `/${endpoint}`;
|
|
const url = new URL(`${TYGARUN_CONFIG.baseUrl.replace(/\/+$/, "")}/${module}${path}`);
|
|
Object.entries(query).forEach(([k, v]) => {
|
|
if (v !== null && v !== undefined) url.searchParams.append(k, String(v));
|
|
});
|
|
|
|
const token = getToken();
|
|
const res = await fetch(url.toString(), {
|
|
method,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Accept: "application/json",
|
|
// Publishable key ALWAYS authenticates the app (never the user).
|
|
Authorization: `Bearer ${TYGARUN_CONFIG.publishableKey}`,
|
|
// End-user identity (their JWT from auth.signin) rides separately.
|
|
...(token ? { "X-User-Token": token } : {}),
|
|
"X-Sandbox-Mode": TYGARUN_CONFIG.sandbox,
|
|
...headers,
|
|
},
|
|
body: body && method !== "GET" && method !== "DELETE" ? JSON.stringify(body) : undefined,
|
|
});
|
|
|
|
const text = await res.text();
|
|
let json: any = {};
|
|
try { json = text ? JSON.parse(text) : {}; } catch { /* non-JSON error body */ }
|
|
|
|
if (!res.ok) {
|
|
const err = new Error(json.error || json.message || `tyga.run ${module} error ${res.status}`) as TygaRunError;
|
|
err.statusCode = res.status;
|
|
err.body = json;
|
|
throw err;
|
|
}
|
|
return json as T;
|
|
}
|
|
|
|
// ── Auth convenience (JWT stored for user-scoped calls) ─────────────────────
|
|
export const auth = {
|
|
async signup(data: { email: string; password: string; firstName?: string; lastName?: string; [k: string]: any }) {
|
|
const res = await tygarun<any>("auth", "/signup", { method: "POST", body: data });
|
|
if (res.token) setToken(res.token);
|
|
return res;
|
|
},
|
|
async signin(email: string, password: string, rememberMe = false) {
|
|
const res = await tygarun<any>("auth", "/signin", { method: "POST", body: { email, password, rememberMe } });
|
|
if (res.token) setToken(res.token);
|
|
return res;
|
|
},
|
|
signout() { setToken(null); },
|
|
isSignedIn(): boolean { return Boolean(getToken()); },
|
|
};
|
|
|
|
export default tygarun;
|