UNPKG

solobase-js

Version:

A 100% drop-in replacement for the Supabase JavaScript client. Self-hosted Supabase alternative with complete API compatibility.

194 lines 6.32 kB
import { SolobaseFetch } from './lib/fetch.js'; import { SolobaseAuthClient } from './SolobaseAuthClient.js'; import { SolobaseQueryBuilder } from './SolobaseQueryBuilder.js'; import { SolobaseStorageClient } from './SolobaseStorageClient.js'; import { SolobaseRealtimeClient } from './SolobaseRealtimeClient.js'; import { SolobaseSubscriptionClient } from './SolobaseSubscriptionClient.js'; import { CookieManager } from './lib/CookieManager.js'; /** * Main Solobase client - 100% compatible with Supabase client API */ export class SolobaseClient { constructor(baseUrl, apikey, options = {}) { /** * Create a custom function (for compatibility) */ this.functions = { invoke: async (functionName, options) => { const response = await this.fetch.post(`/functions/v1/${functionName}`, { body: options?.body, headers: options?.headers, }); return { data: response.data, error: response.error ? { message: response.error.message, context: {}, } : null, }; } }; this.baseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl; this.apikey = apikey; this.options = options; // Initialize cookie manager if cookies are provided (SSR mode) if (options.cookies) { const initialCookies = {}; if (options.cookies.getAll) { const cookies = options.cookies.getAll(); cookies.forEach(({ name, value }) => { initialCookies[name] = value; }); } this.cookieManager = new CookieManager(initialCookies, options.cookies); } // Initialize fetch client this.fetch = new SolobaseFetch(this.baseUrl, this.apikey, options.global?.headers); // Initialize auth client with cookie manager this.auth = new SolobaseAuthClient(this.fetch, options.auth, this.cookieManager); // Initialize storage client this.storage = new SolobaseStorageClient(this.fetch); // Initialize subscription client this.subscription = new SolobaseSubscriptionClient(this.fetch); // Initialize realtime client this.realtime = new SolobaseRealtimeClient(this.baseUrl, options.realtime); // Set up auth state change listener to update tokens this.auth.onAuthStateChange((event, session) => { const token = session?.access_token || null; this.fetch.setAuth(token); this.realtime.setAuth(token); }); } /** * Create a query builder for a table * * @example * ```js * const { data, error } = await solobase * .from('users') * .select('*') * .eq('id', 1) * .single() * ``` */ from(table) { return new SolobaseQueryBuilder(this.fetch, table, this.options.db?.schema || 'public'); } /** * Execute a raw SQL query with parameters * * @example * ```js * const { data, error } = await solobase.rpc('get_user_profile', { user_id: 1 }) * ``` */ async rpc(fn, args = {}, options = {}) { const headers = {}; if (options.head) { headers['Prefer'] = 'head'; } if (options.count) { headers['Prefer'] = (headers['Prefer'] || '') + (headers['Prefer'] ? ',' : '') + `count=${options.count}`; } const response = await this.fetch.post(`/rest/v1/rpc/${fn}`, { body: args, headers, }); return { data: response.data, error: response.error ? { message: response.error.message, details: '', hint: '', code: '', } : null, count: Array.isArray(response.data) ? response.data.length : (response.data ? 1 : 0), status: response.status, statusText: response.statusText, }; } /** * Create a channel for real-time communication * * @example * ```js * const channel = solobase.channel('realtime:public:users') * channel * .on('postgres_changes', { event: '*', schema: 'public', table: 'users' }, (payload) => { * console.log('Change received!', payload) * }) * .subscribe() * ``` */ channel(topic, chanParams) { return this.realtime.channel(topic, chanParams); } /** * Get all active channels */ getChannels() { return this.realtime.getChannels(); } /** * Remove a channel */ removeChannel(channel) { return this.realtime.removeChannel(channel); } /** * Remove all channels */ removeAllChannels() { return this.realtime.removeAllChannels(); } /** * Listen for postgres changes on a table, schema, or database * * @example * ```js * solobase * .channel('db-changes') * .on('postgres_changes', { * event: '*', * schema: 'public', * table: 'users' * }, (payload) => console.log(payload)) * .subscribe() * ``` */ on(event, filter, callback) { const topic = `realtime:${filter.schema}${filter.table ? `:${filter.table}` : ''}`; const channel = this.channel(topic); return channel.on(event, (payload) => { // Filter based on the event type and other criteria if (filter.event === '*' || payload.eventType === filter.event) { callback(payload); } }); } /** * Close all connections and clean up */ removeAllSubscriptions() { return this.removeAllChannels(); } /** * Get the current base URL */ get supabaseUrl() { return this.baseUrl; } /** * Get the current API key */ get supabaseKey() { return this.apikey; } /** * Access the raw REST endpoint (for advanced use cases) */ get rest() { return this.fetch; } } //# sourceMappingURL=SolobaseClient.js.map