npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@dypai-ai/client-sdk

v1.12.0

Published

Official JavaScript/TypeScript SDK for DYPAI — backend-as-a-service with visual workflows, AI agents, and MCP.

Readme

@dypai-ai/client-sdk

The official JavaScript/TypeScript SDK for DYPAI — backend-as-a-service with visual workflows, AI agents, and MCP.

npm install @dypai-ai/client-sdk

Quick Start

import { createClient } from '@dypai-ai/client-sdk';

const dypai = createClient('https://your-project.dypai.ai');

// Sign in
const { data, error } = await dypai.auth.signInWithPassword({
  email: '[email protected]',
  password: 'securepassword',
});

// Call an endpoint
const { data: products } = await dypai.api.get('list_products');

Table of Contents


Installation

npm install @dypai-ai/client-sdk

React hooks (optional):

# React hooks are included — no extra package needed
# Import from '@dypai-ai/client-sdk/react'

Creating the Client

import { createClient } from '@dypai-ai/client-sdk';

// Basic — JWT-authenticated apps
const dypai = createClient('https://your-project.dypai.ai');

// With API key — for public endpoints that don't require auth
const dypai = createClient(
  'https://your-project.dypai.ai',
  'your-public-api-key'
);

// With options
const dypai = createClient('https://your-project.dypai.ai', {
  auth: {
    autoRefreshToken: true,   // default: true
    persistSession: true,     // default: true
  },
  redirects: {
    passwordRecovery: '/reset-password',
    signIn: '/dashboard',
  },
});

Authentication

Sign Up

const { data, error } = await dypai.auth.signUp({
  email: '[email protected]',
  password: 'securepassword',
  name: 'John Doe',
});

if (error) {
  console.error(error.message);
} else if (data.confirmationRequired) {
  console.log('Check your email to confirm your account');
}

Sign In with Password

const { data, error } = await dypai.auth.signInWithPassword({
  email: '[email protected]',
  password: 'securepassword',
});

if (data) {
  console.log('Welcome!', data.user.email);
}

Sign In with OAuth

await dypai.auth.signInWithOAuth('google');
// Redirects to Google login page

Sign In with Magic Link (OTP)

// Send magic link
const { error } = await dypai.auth.signInWithOtp({ email: '[email protected]' });

// Verify OTP code
const { data, error } = await dypai.auth.verifyOtp({
  email: '[email protected]',
  token: '123456',
  type: 'email',
});

Get Current User

const { data: user, error } = await dypai.auth.getUser();
console.log(user.email, user.role);

Get Session

const { data: session, error } = await dypai.auth.getSession();
if (session) {
  console.log('Token:', session.token);
  console.log('User:', session.user.email);
}

Password Recovery

// Request reset email
const { error } = await dypai.auth.resetPasswordForEmail('[email protected]');

// Set new password on the passwordRecovery route.
// The SDK stores the reset token and cleans the URL automatically.
const { error } = await dypai.auth.setPassword('new-secure-password');

Resend Confirmation Email

const { error } = await dypai.auth.resendConfirmationEmail('[email protected]');

Update User Profile

const { data, error } = await dypai.auth.updateUser({
  data: { name: 'Jane Doe', avatar_url: 'https://...' },
});

Sign Out

await dypai.auth.signOut();

Listen to Auth Changes

const { data: { subscription } } = dypai.auth.onAuthStateChange((event, session) => {
  console.log(event); // 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED' | ...

  if (event === 'SIGNED_IN') {
    console.log('User:', session.user.email);
  }

  if (event === 'SIGNED_OUT') {
    window.location.href = '/login';
  }
});

// Stop listening
subscription.unsubscribe();

Database (CRUD)

Interact with your project's database tables using a fluent API:

Select (Read)

// Get all rows
const { data, error } = await dypai.db.from('products').select();

// With filters
const { data, error } = await dypai.db.from('products').select({
  category: 'electronics',
  active: true,
});

Insert (Create)

const { data, error } = await dypai.db.from('products').insert({
  name: 'Wireless Headphones',
  price: 59.99,
  category: 'electronics',
});

Update

const { data, error } = await dypai.db.from('products').update('prod_123', {
  price: 49.99,
  on_sale: true,
});

Delete

const { data, error } = await dypai.db.from('products').delete('prod_123');

Endpoints (Custom API)

Call your custom DYPAI endpoints (workflows exposed as APIs):

GET

const { data, error } = await dypai.api.get('list_products');

// With query parameters
const { data, error } = await dypai.api.get('search', {
  params: { q: 'headphones', limit: 20 },
});

POST

const { data, error } = await dypai.api.post('create_order', {
  product_id: 'prod_123',
  quantity: 2,
});

PUT / PATCH

const { data, error } = await dypai.api.put('update_profile', {
  name: 'Jane Doe',
  bio: 'Developer',
});

const { data, error } = await dypai.api.patch('update_settings', {
  theme: 'dark',
});

DELETE

const { data, error } = await dypai.api.delete('cancel_subscription', {
  params: { subscription_id: 'sub_123' },
});

File Upload

Upload files using Smart Upload (signed URLs, direct upload to cloud storage):

const file = document.querySelector('input[type="file"]').files[0];

const { data, error } = await dypai.api.upload('storage_files', file, {
  params: {
    operation: 'upload',
    file_path: `avatars/${userId}.jpg`,
    // Domain params are fine here, e.g. task_id/file_name/content_type.
    // Do not pass confirm or client_upload; the SDK controls Smart Upload.
  },
  onProgress: (percent) => {
    console.log(`Upload: ${percent}%`);
  },
});

confirm and client_upload are internal Smart Upload flags. They may exist in the endpoint input schema, but browser code should not include them in params.

Download

await dypai.api.download('storage_files', {
  operation: 'download',
  file_path: 'reports/monthly.pdf',
});

Direct Database Access (Admin)

Server-side only. This is for scripts, migrations, seeds, and backend code. Never expose the serviceRoleKey in browser/client-side code. For end-user data access, use Endpoints or Database CRUD.

Direct database access bypasses endpoints and workflows. It requires a serviceRoleKey:

import { createClient } from '@dypai-ai/client-sdk';

// Server-side only (Node.js, Bun, Deno)
const dypai = createClient('https://your-project.dypai.ai', {
  serviceRoleKey: process.env.DYPAI_SERVICE_ROLE_KEY,
});

Select with Filters

const { data } = await dypai.db.direct
  .from('products')
  .eq('category', 'electronics')
  .gt('price', 50)
  .orderBy('price', 'DESC')
  .limit(20)
  .select();

Bulk Insert

// Auto-chunked at 1,000 rows per request
const { data, error } = await dypai.db.direct
  .from('products')
  .insert(tenThousandRows);

Update with Filters

await dypai.db.direct
  .from('products')
  .eq('category', 'deprecated')
  .update({ active: false });

Delete with Filters

await dypai.db.direct
  .from('products')
  .eq('id', 'abc123')
  .delete();

Upsert

await dypai.db.direct
  .from('products')
  .upsert({ id: 'prod_1', name: 'Widget', price: 12.99 }, 'id');

Raw SQL

// Migrations
await dypai.db.direct.sql('ALTER TABLE products ADD COLUMN sku TEXT');

// Queries with bind parameters ($1, $2, ...)
const { data } = await dypai.db.direct.sql(
  'SELECT category, COUNT(*) as count FROM products WHERE price > $1 GROUP BY category',
  [25]
);

Available Filters

| Method | SQL | |--------|-----| | .eq(col, val) | col = val | | .neq(col, val) | col != val | | .gt(col, val) | col > val | | .gte(col, val) | col >= val | | .lt(col, val) | col < val | | .lte(col, val) | col <= val | | .like(col, val) | col ILIKE %val% | | .in(col, [a,b]) | col IN (a, b) | | .isNull(col) | col IS NULL | | .notNull(col) | col IS NOT NULL |


User Management (Admin)

Manage application users (requires manage_users permission):

List Users

const { data, error } = await dypai.users.list({ page: 1, per_page: 50 });
console.log(data.users); // [{ id, email, role, ... }, ...]

Create User

const { data, error } = await dypai.users.create({
  email: '[email protected]',
  password: 'securepassword',
  role: 'editor',
  user_metadata: { name: 'New User' },
});

Update User Role

const { data, error } = await dypai.users.update('user_id', {
  role: 'admin',
});

Delete User

const { data, error } = await dypai.users.delete('user_id');

React Integration

Setup

// src/lib/dypai.ts
import { createClient } from '@dypai-ai/client-sdk';

export const dypai = createClient(import.meta.env.VITE_DYPAI_URL);
// src/App.tsx
import { DypaiProvider } from '@dypai-ai/client-sdk/react';
import { dypai } from './lib/dypai';

function App() {
  return (
    <DypaiProvider client={dypai}>
      <Router />
    </DypaiProvider>
  );
}

useAuth

import { useAuth } from '@dypai-ai/client-sdk/react';

function LoginPage() {
  const { signIn, isLoading, isAuthenticated } = useAuth();

  if (isAuthenticated) return <Navigate to="/dashboard" />;

  const handleSubmit = async (e: FormEvent) => {
    e.preventDefault();
    const { error } = await signIn(email, password);
    if (error) alert(error.message);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="email" value={email} onChange={...} />
      <input type="password" value={password} onChange={...} />
      <button disabled={isLoading}>Sign In</button>
    </form>
  );
}
function Navbar() {
  const { user, isAuthenticated, signOut } = useAuth();

  if (!isAuthenticated) return <Link to="/login">Sign In</Link>;

  return (
    <div>
      <span>{user.email}</span>
      <button onClick={signOut}>Sign Out</button>
    </div>
  );
}

useEndpoint

import { useEndpoint } from '@dypai-ai/client-sdk/react';

function ProductList() {
  const { data: products, isLoading, error, refetch } = useEndpoint('list_products');

  if (isLoading) return <Spinner />;
  if (error) return <Error message={error.message} />;

  return (
    <div>
      {products.map(p => <ProductCard key={p.id} product={p} />)}
      <button onClick={refetch}>Refresh</button>
    </div>
  );
}
// With params and auto-refetch
function Notifications() {
  const { data } = useEndpoint('get_notifications', {
    params: { unread: true },
    refetchInterval: 30000, // every 30s
  });

  return <Badge count={data?.length ?? 0} />;
}
// Conditional fetching
function UserProfile({ userId }: { userId?: string }) {
  const { data: profile } = useEndpoint('get_user_profile', {
    params: { id: userId },
    enabled: !!userId, // only fetch when userId exists
  });

  return profile ? <Profile data={profile} /> : null;
}

useAction

import { useAction } from '@dypai-ai/client-sdk/react';

function CreateProduct() {
  const { mutate, isLoading } = useAction('create_product', {
    onSuccess: (data) => toast.success(`Created: ${data.name}`),
    onError: (err) => toast.error(err.message),
  });

  const handleSubmit = async (formData: ProductForm) => {
    const { data, error } = await mutate(formData);
  };

  return (
    <form onSubmit={handleSubmit}>
      {/* form fields */}
      <button disabled={isLoading}>Create</button>
    </form>
  );
}
// PUT, PATCH, DELETE
const { mutate: updateTask } = useAction('update_task', { method: 'PUT' });
const { mutate: patchSettings } = useAction('settings', { method: 'PATCH' });
const { mutate: deleteItem } = useAction('delete_item', { method: 'DELETE' });

await updateTask({ id: '123', done: true });
await patchSettings({ theme: 'dark' });
await deleteItem({ id: '123' });

useChat

import { useChat } from '@dypai-ai/client-sdk/react';

function SupportChat() {
  const { messages, input, setInput, sendMessage, isLoading, stop } = useChat('support_agent');

  return (
    <section>
      {messages.map(message => (
        <article key={message.id}>
          <strong>{message.role}</strong>
          <p>{message.content}</p>
          {message.parts?.map((part, index) => {
            if (part.type === 'tool-call') {
              return <small key={index}>Calling {part.toolName}...</small>;
            }
            if (part.type === 'tool-result') {
              return <small key={index}>{part.toolName} finished</small>;
            }
            return null;
          })}
        </article>
      ))}

      <input value={input} onChange={event => setInput(event.target.value)} />
      <button onClick={() => sendMessage()} disabled={isLoading}>Send</button>
      {isLoading && <button onClick={stop}>Stop</button>}
    </section>
  );
}

useChat supports DYPAI agent streams that use the Vercel AI SDK UI Message Stream protocol, plus legacy DYPAI text streams for older engines. Assistant text is accumulated in message.content; streamed tool calls and tool results are exposed in message.parts.

useUpload

import { useUpload } from '@dypai-ai/client-sdk/react';

function AvatarUpload() {
  const { upload, progress, isUploading } = useUpload('storage_files', {
    onSuccess: () => toast.success('Uploaded!'),
  });

  const handleFile = async (e: ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;

    await upload(file, {
      operation: 'upload',
      file_path: `avatars/${userId}.jpg`,
    });
  };

  return (
    <div>
      <input type="file" accept="image/*" onChange={handleFile} disabled={isUploading} />
      {isUploading && <ProgressBar value={progress} />}
    </div>
  );
}

ProtectedRoute

import { ProtectedRoute } from '@dypai-ai/client-sdk/react';

// Basic protection
<ProtectedRoute>
  <Dashboard />
</ProtectedRoute>

// With redirect
<ProtectedRoute redirectTo="/login">
  <Dashboard />
</ProtectedRoute>

// Role-based access
<ProtectedRoute
  roles={['admin', 'editor']}
  loadingComponent={<Spinner />}
  unauthorizedComponent={<AccessDenied />}
  unauthenticatedComponent={<LoginPrompt />}
>
  <AdminPanel />
</ProtectedRoute>

TypeScript Support

The SDK is fully typed. You can pass your database schema and endpoint map for complete type safety:

// Define your database schema
interface Database {
  products: {
    id: string;
    name: string;
    price: number;
    active: boolean;
  };
  orders: {
    id: string;
    product_id: string;
    quantity: number;
    status: 'pending' | 'shipped' | 'delivered';
  };
}

// Define your endpoint map
interface Api {
  list_products: {
    response: Database['products'][];
  };
  create_order: {
    body: { product_id: string; quantity: number };
    response: Database['orders'];
  };
}

// Create a fully typed client
const dypai = createClient<Database, Api>(
  'https://your-project.dypai.ai'
);

// Now everything has autocomplete and type checking
const { data } = await dypai.db.from('products').select(); // data: Product[]
const { data } = await dypai.api.post('create_order', {    // body is typed
  product_id: 'prod_123',
  quantity: 2,
});

API Reference

Full auto-generated API docs: dypai-solutions.github.io/client-sdk


Response Format

All SDK methods return a consistent { data, error } object:

const { data, error } = await dypai.auth.signInWithPassword({ ... });

if (error) {
  console.error(error.message);  // Human-readable message
  console.error(error.status);   // HTTP status code
  console.error(error.code);     // Error code (if available)
  return;
}

// data is guaranteed to be non-null here
console.log(data);

License

MIT