@fluxbase/sdk
Version:
Official TypeScript SDK for Fluxbase - Backend as a Service
1,769 lines (1,760 loc) • 87.2 kB
JavaScript
'use strict';
// src/fetch.ts
var FluxbaseFetch = class {
constructor(baseUrl, options = {}) {
this.baseUrl = baseUrl.replace(/\/$/, "");
this.defaultHeaders = {
"Content-Type": "application/json",
...options.headers
};
this.timeout = options.timeout ?? 3e4;
this.debug = options.debug ?? false;
}
/**
* Update the authorization header
*/
setAuthToken(token) {
if (token) {
this.defaultHeaders["Authorization"] = `Bearer ${token}`;
} else {
delete this.defaultHeaders["Authorization"];
}
}
/**
* Make an HTTP request
*/
async request(path, options) {
const url = `${this.baseUrl}${path}`;
const headers = { ...this.defaultHeaders, ...options.headers };
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), options.timeout ?? this.timeout);
if (this.debug) {
console.log(`[Fluxbase SDK] ${options.method} ${url}`, options.body);
}
try {
const response = await fetch(url, {
method: options.method,
headers,
body: options.body ? JSON.stringify(options.body) : void 0,
signal: controller.signal
});
clearTimeout(timeoutId);
const contentType = response.headers.get("content-type");
let data;
if (contentType?.includes("application/json")) {
data = await response.json();
} else {
data = await response.text();
}
if (this.debug) {
console.log(`[Fluxbase SDK] Response:`, response.status, data);
}
if (!response.ok) {
const error = new Error(
typeof data === "object" && data && "error" in data ? String(data.error) : response.statusText
);
error.status = response.status;
error.details = data;
throw error;
}
return data;
} catch (err) {
clearTimeout(timeoutId);
if (err instanceof Error) {
if (err.name === "AbortError") {
const timeoutError = new Error("Request timeout");
timeoutError.status = 408;
throw timeoutError;
}
throw err;
}
throw new Error("Unknown error occurred");
}
}
/**
* GET request
*/
async get(path, options = {}) {
return this.request(path, { ...options, method: "GET" });
}
/**
* POST request
*/
async post(path, body, options = {}) {
return this.request(path, { ...options, method: "POST", body });
}
/**
* PUT request
*/
async put(path, body, options = {}) {
return this.request(path, { ...options, method: "PUT", body });
}
/**
* PATCH request
*/
async patch(path, body, options = {}) {
return this.request(path, { ...options, method: "PATCH", body });
}
/**
* DELETE request
*/
async delete(path, options = {}) {
return this.request(path, { ...options, method: "DELETE" });
}
/**
* HEAD request
*/
async head(path, options = {}) {
const url = `${this.baseUrl}${path}`;
const headers = { ...this.defaultHeaders, ...options.headers };
const response = await fetch(url, {
method: "HEAD",
headers
});
return response.headers;
}
};
// src/auth.ts
var AUTH_STORAGE_KEY = "fluxbase.auth.session";
var FluxbaseAuth = class {
constructor(fetch2, autoRefresh = true, persist = true) {
this.session = null;
this.refreshTimer = null;
this.fetch = fetch2;
this.persist = persist;
this.autoRefresh = autoRefresh;
if (this.persist && typeof localStorage !== "undefined") {
const stored = localStorage.getItem(AUTH_STORAGE_KEY);
if (stored) {
try {
this.session = JSON.parse(stored);
if (this.session) {
this.fetch.setAuthToken(this.session.access_token);
this.scheduleTokenRefresh();
}
} catch {
localStorage.removeItem(AUTH_STORAGE_KEY);
}
}
}
}
/**
* Get the current session
*/
getSession() {
return this.session;
}
/**
* Get the current user
*/
getUser() {
return this.session?.user ?? null;
}
/**
* Get the current access token
*/
getAccessToken() {
return this.session?.access_token ?? null;
}
/**
* Sign in with email and password
* Returns AuthSession if successful, or SignInWith2FAResponse if 2FA is required
*/
async signIn(credentials) {
const response = await this.fetch.post(
"/api/v1/auth/signin",
credentials
);
if ("requires_2fa" in response && response.requires_2fa) {
return response;
}
const authResponse = response;
const session = {
...authResponse,
expires_at: Date.now() + authResponse.expires_in * 1e3
};
this.setSession(session);
return session;
}
/**
* Sign up with email and password
*/
async signUp(credentials) {
const response = await this.fetch.post("/api/v1/auth/signup", credentials);
const session = {
...response,
expires_at: Date.now() + response.expires_in * 1e3
};
this.setSession(session);
return session;
}
/**
* Sign out the current user
*/
async signOut() {
try {
await this.fetch.post("/api/v1/auth/signout");
} finally {
this.clearSession();
}
}
/**
* Refresh the access token
*/
async refreshToken() {
if (!this.session?.refresh_token) {
throw new Error("No refresh token available");
}
const response = await this.fetch.post("/api/v1/auth/refresh", {
refresh_token: this.session.refresh_token
});
const session = {
...response,
expires_at: Date.now() + response.expires_in * 1e3
};
this.setSession(session);
return session;
}
/**
* Get the current user from the server
*/
async getCurrentUser() {
if (!this.session) {
throw new Error("Not authenticated");
}
return await this.fetch.get("/api/v1/auth/user");
}
/**
* Update the current user
*/
async updateUser(data) {
if (!this.session) {
throw new Error("Not authenticated");
}
const user = await this.fetch.patch("/api/v1/auth/user", data);
if (this.session) {
this.session.user = user;
this.saveSession();
}
return user;
}
/**
* Set the auth token manually
*/
setToken(token) {
this.fetch.setAuthToken(token);
}
/**
* Setup 2FA for the current user
* Returns TOTP secret and QR code URL
*/
async setup2FA() {
if (!this.session) {
throw new Error("Not authenticated");
}
return await this.fetch.post("/api/v1/auth/2fa/setup");
}
/**
* Enable 2FA after verifying the TOTP code
* Returns backup codes that should be saved by the user
*/
async enable2FA(code) {
if (!this.session) {
throw new Error("Not authenticated");
}
return await this.fetch.post("/api/v1/auth/2fa/enable", { code });
}
/**
* Disable 2FA for the current user
* Requires password confirmation
*/
async disable2FA(password) {
if (!this.session) {
throw new Error("Not authenticated");
}
return await this.fetch.post(
"/api/v1/auth/2fa/disable",
{ password }
);
}
/**
* Check 2FA status for the current user
*/
async get2FAStatus() {
if (!this.session) {
throw new Error("Not authenticated");
}
return await this.fetch.get("/api/v1/auth/2fa/status");
}
/**
* Verify 2FA code during login
* Call this after signIn returns requires_2fa: true
*/
async verify2FA(request) {
const response = await this.fetch.post("/api/v1/auth/2fa/verify", request);
const session = {
...response,
expires_at: Date.now() + response.expires_in * 1e3
};
this.setSession(session);
return session;
}
/**
* Send password reset email
* Sends a password reset link to the provided email address
* @param email - Email address to send reset link to
*/
async sendPasswordReset(email) {
return await this.fetch.post("/api/v1/auth/password/reset", { email });
}
/**
* Verify password reset token
* Check if a password reset token is valid before allowing password reset
* @param token - Password reset token to verify
*/
async verifyResetToken(token) {
return await this.fetch.post("/api/v1/auth/password/reset/verify", {
token
});
}
/**
* Reset password with token
* Complete the password reset process with a valid token
* @param token - Password reset token
* @param newPassword - New password to set
*/
async resetPassword(token, newPassword) {
return await this.fetch.post("/api/v1/auth/password/reset/confirm", {
token,
new_password: newPassword
});
}
/**
* Send magic link for passwordless authentication
* @param email - Email address to send magic link to
* @param options - Optional configuration for magic link
*/
async sendMagicLink(email, options) {
return await this.fetch.post("/api/v1/auth/magiclink", {
email,
redirect_to: options?.redirect_to
});
}
/**
* Verify magic link token and sign in
* @param token - Magic link token from email
*/
async verifyMagicLink(token) {
const response = await this.fetch.post("/api/v1/auth/magiclink/verify", {
token
});
const session = {
...response,
expires_at: Date.now() + response.expires_in * 1e3
};
this.setSession(session);
return session;
}
/**
* Sign in anonymously
* Creates a temporary anonymous user session
*/
async signInAnonymously() {
const response = await this.fetch.post("/api/v1/auth/signin/anonymous");
const session = {
...response,
expires_at: Date.now() + response.expires_in * 1e3
};
this.setSession(session);
return session;
}
/**
* Get list of enabled OAuth providers
*/
async getOAuthProviders() {
return await this.fetch.get("/api/v1/auth/oauth/providers");
}
/**
* Get OAuth authorization URL for a provider
* @param provider - OAuth provider name (e.g., 'google', 'github')
* @param options - Optional OAuth configuration
*/
async getOAuthUrl(provider, options) {
const params = new URLSearchParams();
if (options?.redirect_to) {
params.append("redirect_to", options.redirect_to);
}
if (options?.scopes && options.scopes.length > 0) {
params.append("scopes", options.scopes.join(","));
}
const queryString = params.toString();
const url = queryString ? `/api/v1/auth/oauth/${provider}/authorize?${queryString}` : `/api/v1/auth/oauth/${provider}/authorize`;
const response = await this.fetch.get(url);
return response;
}
/**
* Exchange OAuth authorization code for session
* This is typically called in your OAuth callback handler
* @param code - Authorization code from OAuth callback
*/
async exchangeCodeForSession(code) {
const response = await this.fetch.post("/api/v1/auth/oauth/callback", { code });
const session = {
...response,
expires_at: Date.now() + response.expires_in * 1e3
};
this.setSession(session);
return session;
}
/**
* Convenience method to initiate OAuth sign-in
* Redirects the user to the OAuth provider's authorization page
* @param provider - OAuth provider name (e.g., 'google', 'github')
* @param options - Optional OAuth configuration
*/
async signInWithOAuth(provider, options) {
const { url } = await this.getOAuthUrl(provider, options);
if (typeof window !== "undefined") {
window.location.href = url;
} else {
throw new Error("signInWithOAuth can only be called in a browser environment");
}
}
/**
* Internal: Set the session and persist it
*/
setSession(session) {
this.session = session;
this.fetch.setAuthToken(session.access_token);
this.saveSession();
this.scheduleTokenRefresh();
}
/**
* Internal: Clear the session
*/
clearSession() {
this.session = null;
this.fetch.setAuthToken(null);
if (this.persist && typeof localStorage !== "undefined") {
localStorage.removeItem(AUTH_STORAGE_KEY);
}
if (this.refreshTimer) {
clearTimeout(this.refreshTimer);
this.refreshTimer = null;
}
}
/**
* Internal: Save session to storage
*/
saveSession() {
if (this.persist && typeof localStorage !== "undefined" && this.session) {
localStorage.setItem(AUTH_STORAGE_KEY, JSON.stringify(this.session));
}
}
/**
* Internal: Schedule automatic token refresh
*/
scheduleTokenRefresh() {
if (!this.autoRefresh || !this.session?.expires_at) {
return;
}
if (this.refreshTimer) {
clearTimeout(this.refreshTimer);
}
const refreshAt = this.session.expires_at - 60 * 1e3;
const delay = refreshAt - Date.now();
if (delay > 0) {
this.refreshTimer = setTimeout(() => {
this.refreshToken().catch((err) => {
console.error("Failed to refresh token:", err);
this.clearSession();
});
}, delay);
}
}
};
// src/realtime.ts
var RealtimeChannel = class {
constructor(url, channelName, token = null) {
this.ws = null;
this.callbacks = /* @__PURE__ */ new Map();
this.reconnectAttempts = 0;
this.maxReconnectAttempts = 10;
this.reconnectDelay = 1e3;
this.heartbeatInterval = null;
this.url = url;
this.channelName = channelName;
this.token = token;
}
/**
* Listen to a specific event type
* @param event - The event type (INSERT, UPDATE, DELETE, or '*' for all)
* @param callback - The callback function
*/
on(event, callback) {
if (!this.callbacks.has(event)) {
this.callbacks.set(event, /* @__PURE__ */ new Set());
}
this.callbacks.get(event).add(callback);
return this;
}
/**
* Remove a callback
*/
off(event, callback) {
const callbacks = this.callbacks.get(event);
if (callbacks) {
callbacks.delete(callback);
}
return this;
}
/**
* Subscribe to the channel
*/
subscribe() {
this.connect();
return this;
}
/**
* Unsubscribe from the channel
*/
unsubscribe() {
if (this.ws) {
this.send({
type: "unsubscribe",
channel: this.channelName
});
this.disconnect();
}
}
/**
* Internal: Connect to WebSocket
*/
connect() {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
return;
}
const wsUrl = new URL(this.url);
wsUrl.protocol = wsUrl.protocol === "https:" ? "wss:" : "ws:";
wsUrl.pathname = "/realtime";
if (this.token) {
wsUrl.searchParams.set("token", this.token);
}
this.ws = new WebSocket(wsUrl.toString());
this.ws.onopen = () => {
console.log("[Fluxbase Realtime] Connected");
this.reconnectAttempts = 0;
this.send({
type: "subscribe",
channel: this.channelName
});
this.startHeartbeat();
};
this.ws.onmessage = (event) => {
try {
const message = JSON.parse(event.data);
this.handleMessage(message);
} catch (err) {
console.error("[Fluxbase Realtime] Failed to parse message:", err);
}
};
this.ws.onerror = (error) => {
console.error("[Fluxbase Realtime] WebSocket error:", error);
};
this.ws.onclose = () => {
console.log("[Fluxbase Realtime] Disconnected");
this.stopHeartbeat();
this.attemptReconnect();
};
}
/**
* Internal: Disconnect WebSocket
*/
disconnect() {
this.stopHeartbeat();
if (this.ws) {
this.ws.close();
this.ws = null;
}
}
/**
* Internal: Send a message
*/
send(message) {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(message));
}
}
/**
* Internal: Handle incoming message
*/
handleMessage(message) {
switch (message.type) {
case "heartbeat":
this.send({ type: "heartbeat" });
break;
case "broadcast":
if (message.payload) {
this.handleBroadcast(message.payload);
}
break;
case "ack":
console.log("[Fluxbase Realtime] Subscription acknowledged");
break;
case "error":
console.error("[Fluxbase Realtime] Error:", message.error);
break;
}
}
/**
* Internal: Handle broadcast message
*/
handleBroadcast(payload) {
const callbacks = this.callbacks.get(payload.type);
if (callbacks) {
callbacks.forEach((callback) => callback(payload));
}
const wildcardCallbacks = this.callbacks.get("*");
if (wildcardCallbacks) {
wildcardCallbacks.forEach((callback) => callback(payload));
}
}
/**
* Internal: Start heartbeat interval
*/
startHeartbeat() {
this.heartbeatInterval = setInterval(() => {
this.send({ type: "heartbeat" });
}, 3e4);
}
/**
* Internal: Stop heartbeat interval
*/
stopHeartbeat() {
if (this.heartbeatInterval) {
clearInterval(this.heartbeatInterval);
this.heartbeatInterval = null;
}
}
/**
* Internal: Attempt to reconnect
*/
attemptReconnect() {
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
console.error("[Fluxbase Realtime] Max reconnect attempts reached");
return;
}
this.reconnectAttempts++;
const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1);
console.log(`[Fluxbase Realtime] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
setTimeout(() => {
this.connect();
}, delay);
}
};
var FluxbaseRealtime = class {
constructor(url, token = null) {
this.channels = /* @__PURE__ */ new Map();
this.url = url;
this.token = token;
}
/**
* Create or get a channel
* @param channelName - Channel name (e.g., 'table:public.products')
*/
channel(channelName) {
if (this.channels.has(channelName)) {
return this.channels.get(channelName);
}
const channel = new RealtimeChannel(this.url, channelName, this.token);
this.channels.set(channelName, channel);
return channel;
}
/**
* Remove all channels
*/
removeAllChannels() {
this.channels.forEach((channel) => channel.unsubscribe());
this.channels.clear();
}
/**
* Update auth token for all channels
*/
setToken(token) {
this.token = token;
}
};
// src/storage.ts
var StorageBucket = class {
constructor(fetch2, bucketName) {
this.fetch = fetch2;
this.bucketName = bucketName;
}
/**
* Upload a file to the bucket
* @param path - The path/key for the file
* @param file - The file to upload (File, Blob, or ArrayBuffer)
* @param options - Upload options
*/
async upload(path, file, options) {
try {
const formData = new FormData();
const blob = file instanceof ArrayBuffer ? new Blob([file]) : file;
formData.append("file", blob);
if (options?.contentType) {
formData.append("content_type", options.contentType);
}
if (options?.metadata) {
formData.append("metadata", JSON.stringify(options.metadata));
}
if (options?.cacheControl) {
formData.append("cache_control", options.cacheControl);
}
if (options?.upsert !== void 0) {
formData.append("upsert", String(options.upsert));
}
const data = await this.fetch.request(
`/api/v1/storage/${this.bucketName}/${path}`,
{
method: "POST",
body: formData,
headers: {}
// Let browser set Content-Type for FormData
}
);
return { data, error: null };
} catch (error) {
return { data: null, error };
}
}
/**
* Download a file from the bucket
* @param path - The path/key of the file
*/
async download(path) {
try {
const response = await fetch(
`${this.fetch["baseUrl"]}/api/v1/storage/${this.bucketName}/${path}`,
{
headers: this.fetch["defaultHeaders"]
}
);
if (!response.ok) {
throw new Error(`Failed to download file: ${response.statusText}`);
}
const blob = await response.blob();
return { data: blob, error: null };
} catch (error) {
return { data: null, error };
}
}
/**
* List files in the bucket
* @param options - List options (prefix, limit, offset)
*/
async list(options) {
try {
const params = new URLSearchParams();
if (options?.prefix) {
params.set("prefix", options.prefix);
}
if (options?.limit) {
params.set("limit", String(options.limit));
}
if (options?.offset) {
params.set("offset", String(options.offset));
}
const queryString = params.toString();
const path = `/api/v1/storage/${this.bucketName}${queryString ? `?${queryString}` : ""}`;
const data = await this.fetch.get(path);
return { data: data.objects || [], error: null };
} catch (error) {
return { data: null, error };
}
}
/**
* Remove files from the bucket
* @param paths - Array of file paths to remove
*/
async remove(paths) {
try {
for (const path of paths) {
await this.fetch.delete(`/api/v1/storage/${this.bucketName}/${path}`);
}
return { data: null, error: null };
} catch (error) {
return { data: null, error };
}
}
/**
* Get a public URL for a file
* @param path - The file path
*/
getPublicUrl(path) {
const publicUrl = `${this.fetch["baseUrl"]}/api/v1/storage/${this.bucketName}/${path}`;
return { data: { publicUrl } };
}
/**
* Create a signed URL for temporary access to a file
* @param path - The file path
* @param options - Signed URL options
*/
async createSignedUrl(path, options) {
try {
const expiresIn = options?.expiresIn || 3600;
const data = await this.fetch.post(
`/api/v1/storage/${this.bucketName}/sign/${path}`,
{ expires_in: expiresIn }
);
return { data: { signedUrl: data.signed_url }, error: null };
} catch (error) {
return { data: null, error };
}
}
/**
* Move a file to a new location
* @param fromPath - Current file path
* @param toPath - New file path
*/
async move(fromPath, toPath) {
try {
const data = await this.fetch.post(
`/api/v1/storage/${this.bucketName}/move`,
{
from_path: fromPath,
to_path: toPath
}
);
return { data, error: null };
} catch (error) {
return { data: null, error };
}
}
/**
* Copy a file to a new location
* @param fromPath - Source file path
* @param toPath - Destination file path
*/
async copy(fromPath, toPath) {
try {
const data = await this.fetch.post(
`/api/v1/storage/${this.bucketName}/copy`,
{
from_path: fromPath,
to_path: toPath
}
);
return { data, error: null };
} catch (error) {
return { data: null, error };
}
}
};
var FluxbaseStorage = class {
constructor(fetch2) {
this.fetch = fetch2;
}
/**
* Get a reference to a storage bucket
* @param bucketName - The name of the bucket
*/
from(bucketName) {
return new StorageBucket(this.fetch, bucketName);
}
/**
* List all buckets
*/
async listBuckets() {
try {
const data = await this.fetch.get(
"/api/v1/storage/buckets"
);
return { data: data.buckets || [], error: null };
} catch (error) {
return { data: null, error };
}
}
/**
* Create a new bucket
* @param bucketName - The name of the bucket to create
*/
async createBucket(bucketName) {
try {
await this.fetch.post(`/api/v1/storage/buckets/${bucketName}`);
return { data: null, error: null };
} catch (error) {
return { data: null, error };
}
}
/**
* Delete a bucket
* @param bucketName - The name of the bucket to delete
*/
async deleteBucket(bucketName) {
try {
await this.fetch.delete(`/api/v1/storage/buckets/${bucketName}`);
return { data: null, error: null };
} catch (error) {
return { data: null, error };
}
}
/**
* Empty a bucket (delete all files)
* @param bucketName - The name of the bucket to empty
*/
async emptyBucket(bucketName) {
try {
const bucket = this.from(bucketName);
const { data: objects, error: listError } = await bucket.list();
if (listError) {
return { data: null, error: listError };
}
if (objects && objects.length > 0) {
const paths = objects.map((obj) => obj.key);
const { error: removeError } = await bucket.remove(paths);
if (removeError) {
return { data: null, error: removeError };
}
}
return { data: null, error: null };
} catch (error) {
return { data: null, error };
}
}
};
// src/settings.ts
var SystemSettingsManager = class {
constructor(fetch2) {
this.fetch = fetch2;
}
/**
* List all system settings
*
* @returns Promise resolving to ListSystemSettingsResponse
*
* @example
* ```typescript
* const response = await client.admin.settings.system.list()
* console.log(response.settings)
* ```
*/
async list() {
const settings = await this.fetch.get("/api/v1/admin/system/settings");
return { settings: Array.isArray(settings) ? settings : [] };
}
/**
* Get a specific system setting by key
*
* @param key - Setting key (e.g., 'app.auth.enable_signup')
* @returns Promise resolving to SystemSetting
*
* @example
* ```typescript
* const setting = await client.admin.settings.system.get('app.auth.enable_signup')
* console.log(setting.value)
* ```
*/
async get(key) {
return await this.fetch.get(`/api/v1/admin/system/settings/${key}`);
}
/**
* Update or create a system setting
*
* @param key - Setting key
* @param request - Update request with value and optional description
* @returns Promise resolving to SystemSetting
*
* @example
* ```typescript
* const updated = await client.admin.settings.system.update('app.auth.enable_signup', {
* value: { value: true },
* description: 'Enable user signup'
* })
* ```
*/
async update(key, request) {
return await this.fetch.put(`/api/v1/admin/system/settings/${key}`, request);
}
/**
* Delete a system setting
*
* @param key - Setting key to delete
* @returns Promise<void>
*
* @example
* ```typescript
* await client.admin.settings.system.delete('app.auth.enable_signup')
* ```
*/
async delete(key) {
await this.fetch.delete(`/api/v1/admin/system/settings/${key}`);
}
};
var AppSettingsManager = class {
constructor(fetch2) {
this.fetch = fetch2;
}
/**
* Get all application settings
*
* Returns structured settings for authentication, features, email, and security.
*
* @returns Promise resolving to AppSettings
*
* @example
* ```typescript
* const settings = await client.admin.settings.app.get()
*
* console.log('Signup enabled:', settings.authentication.enable_signup)
* console.log('Realtime enabled:', settings.features.enable_realtime)
* console.log('Email provider:', settings.email.provider)
* ```
*/
async get() {
return await this.fetch.get("/api/v1/admin/app/settings");
}
/**
* Update application settings
*
* Supports partial updates - only provide the fields you want to change.
*
* @param request - Settings to update (partial update supported)
* @returns Promise resolving to AppSettings - Updated settings
*
* @example
* ```typescript
* // Update authentication settings
* const updated = await client.admin.settings.app.update({
* authentication: {
* enable_signup: true,
* password_min_length: 12
* }
* })
*
* // Update multiple categories
* await client.admin.settings.app.update({
* authentication: { enable_signup: false },
* features: { enable_realtime: true },
* security: { enable_global_rate_limit: true }
* })
* ```
*/
async update(request) {
return await this.fetch.put("/api/v1/admin/app/settings", request);
}
/**
* Reset all application settings to defaults
*
* This will delete all custom settings and return to default values.
*
* @returns Promise resolving to AppSettings - Default settings
*
* @example
* ```typescript
* const defaults = await client.admin.settings.app.reset()
* console.log('Settings reset to defaults:', defaults)
* ```
*/
async reset() {
return await this.fetch.post("/api/v1/admin/app/settings/reset", {});
}
/**
* Enable user signup
*
* Convenience method to enable user registration.
*
* @returns Promise resolving to AppSettings
*
* @example
* ```typescript
* await client.admin.settings.app.enableSignup()
* ```
*/
async enableSignup() {
return await this.update({
authentication: { enable_signup: true }
});
}
/**
* Disable user signup
*
* Convenience method to disable user registration.
*
* @returns Promise resolving to AppSettings
*
* @example
* ```typescript
* await client.admin.settings.app.disableSignup()
* ```
*/
async disableSignup() {
return await this.update({
authentication: { enable_signup: false }
});
}
/**
* Update password minimum length
*
* Convenience method to set password requirements.
*
* @param length - Minimum password length (8-128 characters)
* @returns Promise resolving to AppSettings
*
* @example
* ```typescript
* await client.admin.settings.app.setPasswordMinLength(12)
* ```
*/
async setPasswordMinLength(length) {
if (length < 8 || length > 128) {
throw new Error("Password minimum length must be between 8 and 128 characters");
}
return await this.update({
authentication: { password_min_length: length }
});
}
/**
* Enable or disable a feature
*
* Convenience method to toggle feature flags.
*
* @param feature - Feature name ('realtime' | 'storage' | 'functions')
* @param enabled - Whether to enable or disable the feature
* @returns Promise resolving to AppSettings
*
* @example
* ```typescript
* // Enable realtime
* await client.admin.settings.app.setFeature('realtime', true)
*
* // Disable storage
* await client.admin.settings.app.setFeature('storage', false)
* ```
*/
async setFeature(feature, enabled) {
const featureKey = feature === "realtime" ? "enable_realtime" : feature === "storage" ? "enable_storage" : "enable_functions";
return await this.update({
features: { [featureKey]: enabled }
});
}
/**
* Enable or disable global rate limiting
*
* Convenience method to toggle global rate limiting.
*
* @param enabled - Whether to enable rate limiting
* @returns Promise resolving to AppSettings
*
* @example
* ```typescript
* await client.admin.settings.app.setRateLimiting(true)
* ```
*/
async setRateLimiting(enabled) {
return await this.update({
security: { enable_global_rate_limit: enabled }
});
}
};
var FluxbaseSettings = class {
constructor(fetch2) {
this.system = new SystemSettingsManager(fetch2);
this.app = new AppSettingsManager(fetch2);
}
};
// src/ddl.ts
var DDLManager = class {
constructor(fetch2) {
this.fetch = fetch2;
}
/**
* Create a new database schema
*
* Creates a new schema in the database. Schemas are used to organize tables
* into logical groups and provide namespace isolation.
*
* @param name - Schema name (must be valid PostgreSQL identifier)
* @returns Promise resolving to CreateSchemaResponse
*
* @example
* ```typescript
* // Create a schema for analytics data
* const result = await client.admin.ddl.createSchema('analytics')
* console.log(result.message) // "Schema created successfully"
* console.log(result.schema) // "analytics"
* ```
*/
async createSchema(name) {
const request = { name };
return await this.fetch.post("/api/v1/admin/ddl/schemas", request);
}
/**
* List all database schemas
*
* Retrieves a list of all schemas in the database. This includes both
* system schemas (like 'public', 'pg_catalog') and user-created schemas.
*
* @returns Promise resolving to ListSchemasResponse
*
* @example
* ```typescript
* const { schemas } = await client.admin.ddl.listSchemas()
*
* schemas.forEach(schema => {
* console.log(`Schema: ${schema.name}, Owner: ${schema.owner}`)
* })
* ```
*/
async listSchemas() {
return await this.fetch.get("/api/v1/admin/ddl/schemas");
}
/**
* Create a new table in a schema
*
* Creates a new table with the specified columns. Supports various column
* options including primary keys, nullability, data types, and default values.
*
* @param schema - Schema name where the table will be created
* @param name - Table name (must be valid PostgreSQL identifier)
* @param columns - Array of column definitions
* @returns Promise resolving to CreateTableResponse
*
* @example
* ```typescript
* // Create a users table
* await client.admin.ddl.createTable('public', 'users', [
* {
* name: 'id',
* type: 'UUID',
* primaryKey: true,
* defaultValue: 'gen_random_uuid()'
* },
* {
* name: 'email',
* type: 'TEXT',
* nullable: false
* },
* {
* name: 'name',
* type: 'TEXT'
* },
* {
* name: 'created_at',
* type: 'TIMESTAMPTZ',
* nullable: false,
* defaultValue: 'NOW()'
* }
* ])
* ```
*
* @example
* ```typescript
* // Create a products table with JSONB metadata
* await client.admin.ddl.createTable('public', 'products', [
* { name: 'id', type: 'SERIAL', primaryKey: true },
* { name: 'name', type: 'TEXT', nullable: false },
* { name: 'price', type: 'DECIMAL(10,2)', nullable: false },
* { name: 'metadata', type: 'JSONB' },
* { name: 'in_stock', type: 'BOOLEAN', defaultValue: 'true' }
* ])
* ```
*/
async createTable(schema, name, columns) {
const request = { schema, name, columns };
return await this.fetch.post("/api/v1/admin/ddl/tables", request);
}
/**
* List all tables in the database or a specific schema
*
* Retrieves a list of all tables. If a schema is specified, only tables
* from that schema are returned. Otherwise, all tables from all schemas
* are returned.
*
* @param schema - Optional schema name to filter tables
* @returns Promise resolving to ListTablesResponse
*
* @example
* ```typescript
* // List all tables in the public schema
* const { tables } = await client.admin.ddl.listTables('public')
*
* tables.forEach(table => {
* console.log(`Table: ${table.schema}.${table.name}`)
* table.columns?.forEach(col => {
* console.log(` - ${col.name}: ${col.type}`)
* })
* })
* ```
*
* @example
* ```typescript
* // List all tables across all schemas
* const { tables } = await client.admin.ddl.listTables()
*
* const tablesBySchema = tables.reduce((acc, table) => {
* if (!acc[table.schema]) acc[table.schema] = []
* acc[table.schema].push(table.name)
* return acc
* }, {} as Record<string, string[]>)
*
* console.log(tablesBySchema)
* ```
*/
async listTables(schema) {
const params = schema ? `?schema=${encodeURIComponent(schema)}` : "";
return await this.fetch.get(`/api/v1/admin/ddl/tables${params}`);
}
/**
* Delete a table from a schema
*
* Permanently deletes a table and all its data. This operation cannot be undone.
*
* @param schema - Schema name containing the table
* @param name - Table name to delete
* @returns Promise resolving to DeleteTableResponse
*
* @example
* ```typescript
* // Delete a table
* const result = await client.admin.ddl.deleteTable('public', 'old_data')
* console.log(result.message) // "Table deleted successfully"
* ```
*
* @example
* ```typescript
* // Safe deletion with confirmation
* const confirm = await askUser('Are you sure you want to delete this table?')
* if (confirm) {
* await client.admin.ddl.deleteTable('analytics', 'events')
* console.log('Table deleted')
* }
* ```
*/
async deleteTable(schema, name) {
return await this.fetch.delete(
`/api/v1/admin/ddl/tables/${encodeURIComponent(schema)}/${encodeURIComponent(name)}`
);
}
};
// src/oauth.ts
var OAuthProviderManager = class {
constructor(fetch2) {
this.fetch = fetch2;
}
/**
* List all OAuth providers
*
* Retrieves all configured OAuth providers including both enabled and disabled providers.
* Note: Client secrets are not included in the response for security reasons.
*
* @returns Promise resolving to ListOAuthProvidersResponse
*
* @example
* ```typescript
* const { providers } = await client.admin.oauth.listProviders()
*
* providers.forEach(provider => {
* console.log(`${provider.display_name}: ${provider.enabled ? 'enabled' : 'disabled'}`)
* })
* ```
*/
async listProviders() {
const providers = await this.fetch.get("/api/v1/admin/oauth/providers");
return Array.isArray(providers) ? providers : [];
}
/**
* Get a specific OAuth provider by ID
*
* Retrieves detailed configuration for a single OAuth provider.
* Note: Client secret is not included in the response.
*
* @param providerId - Provider ID (UUID)
* @returns Promise resolving to OAuthProvider
*
* @example
* ```typescript
* const provider = await client.admin.oauth.getProvider('provider-uuid')
*
* console.log('Provider:', provider.display_name)
* console.log('Scopes:', provider.scopes.join(', '))
* console.log('Redirect URL:', provider.redirect_url)
* ```
*/
async getProvider(providerId) {
return await this.fetch.get(`/api/v1/admin/oauth/providers/${providerId}`);
}
/**
* Create a new OAuth provider
*
* Creates a new OAuth provider configuration. For built-in providers (Google, GitHub, etc.),
* set `is_custom` to false. For custom OAuth2 providers, set `is_custom` to true and provide
* the authorization, token, and user info URLs.
*
* @param request - OAuth provider configuration
* @returns Promise resolving to CreateOAuthProviderResponse
*
* @example
* ```typescript
* // Create GitHub provider
* const result = await client.admin.oauth.createProvider({
* provider_name: 'github',
* display_name: 'GitHub',
* enabled: true,
* client_id: process.env.GITHUB_CLIENT_ID,
* client_secret: process.env.GITHUB_CLIENT_SECRET,
* redirect_url: 'https://yourapp.com/auth/callback',
* scopes: ['user:email', 'read:user'],
* is_custom: false
* })
*
* console.log('Provider created:', result.id)
* ```
*
* @example
* ```typescript
* // Create custom OAuth2 provider
* await client.admin.oauth.createProvider({
* provider_name: 'custom_sso',
* display_name: 'Custom SSO',
* enabled: true,
* client_id: 'client-id',
* client_secret: 'client-secret',
* redirect_url: 'https://yourapp.com/auth/callback',
* scopes: ['openid', 'profile', 'email'],
* is_custom: true,
* authorization_url: 'https://sso.example.com/oauth/authorize',
* token_url: 'https://sso.example.com/oauth/token',
* user_info_url: 'https://sso.example.com/oauth/userinfo'
* })
* ```
*/
async createProvider(request) {
return await this.fetch.post("/api/v1/admin/oauth/providers", request);
}
/**
* Update an existing OAuth provider
*
* Updates an OAuth provider configuration. All fields are optional - only provided fields
* will be updated. To update the client secret, provide a non-empty value.
*
* @param providerId - Provider ID (UUID)
* @param request - Fields to update
* @returns Promise resolving to UpdateOAuthProviderResponse
*
* @example
* ```typescript
* // Disable a provider
* await client.admin.oauth.updateProvider('provider-id', {
* enabled: false
* })
* ```
*
* @example
* ```typescript
* // Update scopes and redirect URL
* await client.admin.oauth.updateProvider('provider-id', {
* scopes: ['user:email', 'read:user', 'read:org'],
* redirect_url: 'https://newdomain.com/auth/callback'
* })
* ```
*
* @example
* ```typescript
* // Rotate client secret
* await client.admin.oauth.updateProvider('provider-id', {
* client_id: 'new-client-id',
* client_secret: 'new-client-secret'
* })
* ```
*/
async updateProvider(providerId, request) {
return await this.fetch.put(
`/api/v1/admin/oauth/providers/${providerId}`,
request
);
}
/**
* Delete an OAuth provider
*
* Permanently deletes an OAuth provider configuration. This will prevent users from
* authenticating with this provider.
*
* @param providerId - Provider ID (UUID) to delete
* @returns Promise resolving to DeleteOAuthProviderResponse
*
* @example
* ```typescript
* await client.admin.oauth.deleteProvider('provider-id')
* console.log('Provider deleted')
* ```
*
* @example
* ```typescript
* // Safe deletion with confirmation
* const provider = await client.admin.oauth.getProvider('provider-id')
* const confirmed = await confirm(`Delete ${provider.display_name}?`)
*
* if (confirmed) {
* await client.admin.oauth.deleteProvider('provider-id')
* }
* ```
*/
async deleteProvider(providerId) {
return await this.fetch.delete(
`/api/v1/admin/oauth/providers/${providerId}`
);
}
/**
* Enable an OAuth provider
*
* Convenience method to enable a provider.
*
* @param providerId - Provider ID (UUID)
* @returns Promise resolving to UpdateOAuthProviderResponse
*
* @example
* ```typescript
* await client.admin.oauth.enableProvider('provider-id')
* ```
*/
async enableProvider(providerId) {
return await this.updateProvider(providerId, { enabled: true });
}
/**
* Disable an OAuth provider
*
* Convenience method to disable a provider.
*
* @param providerId - Provider ID (UUID)
* @returns Promise resolving to UpdateOAuthProviderResponse
*
* @example
* ```typescript
* await client.admin.oauth.disableProvider('provider-id')
* ```
*/
async disableProvider(providerId) {
return await this.updateProvider(providerId, { enabled: false });
}
};
var AuthSettingsManager = class {
constructor(fetch2) {
this.fetch = fetch2;
}
/**
* Get current authentication settings
*
* Retrieves all authentication configuration settings.
*
* @returns Promise resolving to AuthSettings
*
* @example
* ```typescript
* const settings = await client.admin.authSettings.get()
*
* console.log('Password min length:', settings.password_min_length)
* console.log('Signup enabled:', settings.enable_signup)
* console.log('Session timeout:', settings.session_timeout_minutes, 'minutes')
* ```
*/
async get() {
return await this.fetch.get("/api/v1/admin/auth/settings");
}
/**
* Update authentication settings
*
* Updates one or more authentication settings. All fields are optional - only provided
* fields will be updated.
*
* @param request - Settings to update
* @returns Promise resolving to UpdateAuthSettingsResponse
*
* @example
* ```typescript
* // Strengthen password requirements
* await client.admin.authSettings.update({
* password_min_length: 16,
* password_require_uppercase: true,
* password_require_lowercase: true,
* password_require_number: true,
* password_require_special: true
* })
* ```
*
* @example
* ```typescript
* // Extend session timeout
* await client.admin.authSettings.update({
* session_timeout_minutes: 240,
* max_sessions_per_user: 10
* })
* ```
*
* @example
* ```typescript
* // Disable email verification during development
* await client.admin.authSettings.update({
* require_email_verification: false
* })
* ```
*/
async update(request) {
return await this.fetch.put("/api/v1/admin/auth/settings", request);
}
};
var FluxbaseOAuth = class {
constructor(fetch2) {
this.providers = new OAuthProviderManager(fetch2);
this.authSettings = new AuthSettingsManager(fetch2);
}
};
// src/impersonation.ts
var ImpersonationManager = class {
constructor(fetch2) {
this.fetch = fetch2;
}
/**
* Impersonate a specific user
*
* Start an impersonation session as a specific user. This allows you to see data
* exactly as that user would see it, respecting all RLS policies and permissions.
*
* @param request - Impersonation request with target user ID and reason
* @returns Promise resolving to impersonation session with access token
*
* @example
* ```typescript
* const result = await client.admin.impersonation.impersonateUser({
* target_user_id: 'user-123',
* reason: 'Support ticket #5678 - user reports missing data'
* })
*
* console.log('Impersonating:', result.target_user.email)
* console.log('Session ID:', result.session.id)
*
* // Use the access token for subsequent requests
* // (typically handled automatically by the SDK)
* ```
*/
async impersonateUser(request) {
return await this.fetch.post("/api/v1/auth/impersonate", request);
}
/**
* Impersonate anonymous user
*
* Start an impersonation session as an unauthenticated user. This allows you to see
* what data is publicly accessible and test RLS policies for anonymous access.
*
* @param request - Impersonation request with reason
* @returns Promise resolving to impersonation session with access token
*
* @example
* ```typescript
* await client.admin.impersonation.impersonateAnon({
* reason: 'Testing public data access for blog posts'
* })
*
* // Now all queries will use anonymous permissions
* const publicPosts = await client.from('posts').select('*')
* console.log('Public posts:', publicPosts.length)
* ```
*/
async impersonateAnon(request) {
return await this.fetch.post("/api/v1/auth/impersonate/anon", request);
}
/**
* Impersonate with service role
*
* Start an impersonation session with service-level permissions. This provides elevated
* access that may bypass RLS policies, useful for administrative operations.
*
* @param request - Impersonation request with reason
* @returns Promise resolving to impersonation session with access token
*
* @example
* ```typescript
* await client.admin.impersonation.impersonateService({
* reason: 'Administrative data cleanup'
* })
*
* // Now all queries will use service role permissions
* const allRecords = await client.from('sensitive_data').select('*')
* console.log('All records:', allRecords.length)
* ```
*/
async impersonateService(request) {
return await this.fetch.post("/api/v1/auth/impersonate/service", request);
}
/**
* Stop impersonation
*
* Ends the current impersonation session and returns to admin context.
* The session is marked as ended in the audit trail.
*
* @returns Promise resolving to stop confirmation
*
* @example
* ```typescript
* await client.admin.impersonation.stop()
* console.log('Impersonation ended')
*
* // Subsequent queries will use admin permissions
* ```
*/
async stop() {
return await this.fetch.delete("/api/v1/auth/impersonate");
}
/**
* Get current impersonation session
*
* Retrieves information about the active impersonation session, if any.
*
* @returns Promise resolving to current impersonation session or null
*
* @example
* ```typescript
* const current = await client.admin.impersonation.getCurrent()
*
* if (current.session) {
* console.log('Currently impersonating:', current.target_user?.email)
* console.log('Reason:', current.session.reason)
* console.log('Started:', current.session.started_at)
* } else {
* console.log('No active impersonation')
* }
* ```
*/
async getCurrent() {
return await this.fetch.get("/api/v1/auth/impersonate");
}
/**
* List impersonation sessions (audit trail)
*
* Retrieves a list of impersonation sessions for audit and compliance purposes.
* Can be filtered by admin user, target user, type, and active status.
*
* @param options - Filter and pagination options
* @returns Promise resolving to list of impersonation sessions
*
* @example
* ```typescript
* // List all sessions
* const { sessions, total } = await client.admin.impersonation.listSessions()
* console.log(`Total sessions: ${total}`)
*
* // List active sessions only
* const active = await client.admin.impersonation.listSessions({
* is_active: true
* })
* console.log('Active sessions:', active.sessions.length)
*
* // List sessions for a specific admin
* const adminSessions = await client.admin.impersonation.listSessions({
* admin_user_id: 'admin-uuid',
* limit: 50
* })
*
* // List user impersonation sessions only
* const userSessions = await client.admin.impersonation.listSessions({
* impersonation_type: 'user',
* offset: 0,