supabase / supabase-js

An isomorphic Javascript client for Supabase. Query your Supabase database, subscribe to realtime events, upload and download files, browse typescript examples, invoke postgres functions via rpc, invoke supabase edge functions, query pgvector.
https://supabase.com
MIT License
3.27k stars 271 forks source link

`SupabaseClient` Request/Response Events? 📬 #400

Open prescience-data opened 2 years ago

prescience-data commented 2 years ago

Feature request

It would be handy for the SupabaseClient class to include an event emitter which emits before and after each query or rpc call.

Below is a quick sketch of some initial thoughts, but actual implementation would require more planning if interested.

Given Supabase already has emitters for auth events, it seems logical that queries might get the same treatment.

Describe the solution you'd like

  1. Add an events property to SupabaseClient:

    public readonly events: EventEmitter = new EventEmitter()
  2. Create type signatures and export events names:

    
    export const [QUERY_REQUEST, QUERY_RESPONSE, RPC_REQUEST, RPC_RESPONSE] = [
    "QUERY_REQUEST",
    "QUERY_RESPONSE",
    "RPC_REQUEST",
    "RPC_RESPONSE"
    ]
    export const clientEvents = [
    QUERY_REQUEST,
    QUERY_RESPONSE,
    RPC_REQUEST,
    RPC_RESPONSE
    ]
    export type ClientEvent = typeof clientEvents[number]

export interface SupabaseClient { on( eventName: typeof RPC_REQUEST, listener: (fn: string, params?: object) => void ): this }


3. Emit table (or rpc) name and query params for each event.
https://github.com/supabase/supabase-js/blob/v1.31.1/src/SupabaseClient.ts#L104

```typescript

  rpc<T = any>(
    fn: string,
    params?: object,
    {
      head = false,
      count = null,
    }: { head?: boolean; count?: null | 'exact' | 'planned' | 'estimated' } = {}
  ) {
    const rest = this._initPostgRESTClient()
    this.events.emit(RPC_REQUEST, { fn, params })
    const response = await rest.rpc<T>(fn, params, { head, count })
    this.events.emit(RPC_RESPONSE, {fn, params, response })
    return response
  }

Describe alternatives you've considered

Making my own emitter and hooks pre and post request. This is becoming unwieldy across several projects trying to keep changes in sync.

soedirgo commented 2 years ago

Super late reply here, sorry about that. I wonder if custom fetch would do the job:

const supabase = createClient('...', '...', {
  global: {
    fetch: (...args) => {
      emitPreRequest()
      return fetch(...args).then((res) => {
        emitPostRequest()
        return res
      }
    }
  }
})