UNPKG

@fluxbase/sdk

Version:

Official TypeScript SDK for Fluxbase - Backend as a Service

1,769 lines (1,760 loc) 87.2 kB
'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,