Skip to main content

React SDK (@nself/client)

Framework-agnostic TypeScript client for ɳSelf. Auth, GraphQL, Storage, and Realtime in one package.

@nself/client

The React SDK provides a typed client for every nself service surface. It works in any JavaScript environment: React, Vue, Svelte, Node.js, or plain TypeScript.

Install

pnpm add @nself/client

Create a client

import { createClient } from '@nself/client'

export const nself = createClient({
  url: process.env.NEXT_PUBLIC_NSELF_URL!,
  anonKey: process.env.NEXT_PUBLIC_NSELF_ANON_KEY!,
})

Set these environment variables in .env.local:

NEXT_PUBLIC_NSELF_URL=https://api.nself.org
NEXT_PUBLIC_NSELF_ANON_KEY=your_anon_key

Auth

// Sign in
const { session, error } = await nself.auth.signIn({ email, password })

// Sign up
await nself.auth.signUp({ email, password })

// Sign out
await nself.auth.signOut()

// Get current user
const { user } = await nself.auth.getUser()

// Listen to auth changes
const unsub = nself.auth.onAuthStateChange((session) => {
  console.log('session changed:', session)
})
unsub() // call to unsubscribe

GraphQL

Run nself generate --lang typescript to emit typed documents. Then:

import { GetMessagesDocument } from '@/graphql/graphql'

const { data, errors } = await nself.graphql.query(GetMessagesDocument, {
  variables: { limit: 20 },
})

// Mutation
await nself.graphql.mutate(CreateMessageDocument, {
  variables: { body: 'Hello' },
})

// Subscription (realtime via WebSocket)
const handle = nself.graphql.subscribe(OnMessageInsertDocument, {
  onData: ({ data }) => console.log(data),
  onError: (err) => console.error(err),
})
handle.unsubscribe()

Storage

// Upload
const { url, error } = await nself.storage.from('avatars').upload('user/photo.jpg', file)

// Download
const { blob } = await nself.storage.from('avatars').download('user/photo.jpg')

// Public URL
const publicUrl = nself.storage.from('avatars').getPublicUrl('user/photo.jpg')

// Signed URL (time-limited)
const { url } = await nself.storage.from('docs').createSignedUrl('private/report.pdf', 3600)

// List
const { items } = await nself.storage.from('uploads').list('user-1/')

// Delete
await nself.storage.from('uploads').remove(['user-1/old-photo.jpg'])

Realtime

// Subscribe to INSERT events on the messages table
const channel = nself.realtime
  .channel('inbox')
  .on('INSERT', (payload) => {
    console.log('new message:', payload.new)
  })
  .subscribe((status) => {
    console.log('status:', status) // SUBSCRIBING → SUBSCRIBED
  })

// Subscribe to all events (INSERT, UPDATE, DELETE)
nself.realtime.channel('all-events').on('*', handleAny).subscribe()

// Cleanup (e.g. in React useEffect return)
channel.unsubscribe()
nself.realtime.removeAllChannels()