@dypai-ai/client-sdk - v1.12.0
    Preparing search index...

    @dypai-ai/client-sdk - v1.12.0

    @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
    
    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: 'user@example.com',
    password: 'securepassword',
    });

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

    npm install @dypai-ai/client-sdk
    

    React hooks (optional):

    # React hooks are included — no extra package needed
    # Import from '@dypai-ai/client-sdk/react'
    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',
    },
    });

    const { data, error } = await dypai.auth.signUp({
    email: 'user@example.com',
    password: 'securepassword',
    name: 'John Doe',
    });

    if (error) {
    console.error(error.message);
    } else if (data.confirmationRequired) {
    console.log('Check your email to confirm your account');
    }
    const { data, error } = await dypai.auth.signInWithPassword({
    email: 'user@example.com',
    password: 'securepassword',
    });

    if (data) {
    console.log('Welcome!', data.user.email);
    }
    await dypai.auth.signInWithOAuth('google');
    // Redirects to Google login page
    // Send magic link
    const { error } = await dypai.auth.signInWithOtp({ email: 'user@example.com' });

    // Verify OTP code
    const { data, error } = await dypai.auth.verifyOtp({
    email: 'user@example.com',
    token: '123456',
    type: 'email',
    });
    const { data: user, error } = await dypai.auth.getUser();
    console.log(user.email, user.role);
    const { data: session, error } = await dypai.auth.getSession();
    if (session) {
    console.log('Token:', session.token);
    console.log('User:', session.user.email);
    }
    // Request reset email
    const { error } = await dypai.auth.resetPasswordForEmail('user@example.com');

    // 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');
    const { error } = await dypai.auth.resendConfirmationEmail('user@example.com');
    
    const { data, error } = await dypai.auth.updateUser({
    data: { name: 'Jane Doe', avatar_url: 'https://...' },
    });
    await dypai.auth.signOut();
    
    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();

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

    // 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,
    });
    const { data, error } = await dypai.db.from('products').insert({
    name: 'Wireless Headphones',
    price: 59.99,
    category: 'electronics',
    });
    const { data, error } = await dypai.db.from('products').update('prod_123', {
    price: 49.99,
    on_sale: true,
    });
    const { data, error } = await dypai.db.from('products').delete('prod_123');
    

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

    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,
    });
    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',
    });
    const { data, error } = await dypai.api.delete('cancel_subscription', {
    params: { subscription_id: 'sub_123' },
    });

    Upload files using Smart Upload (signed URLs, direct upload to cloud storage). Since SDK 1.12.0, params.operation defaults to "upload" on dedicated upload endpoints:

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

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

    Backend (Flow): prefer storage.upload({ bucket, path }) from @dypai-ai/flow — see platform docs file storage / flow ts.

    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.

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

    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,
    });
    const { data } = await dypai.db.direct
    .from('products')
    .eq('category', 'electronics')
    .gt('price', 50)
    .orderBy('price', 'DESC')
    .limit(20)
    .select();
    // Auto-chunked at 1,000 rows per request
    const { data, error } = await dypai.db.direct
    .from('products')
    .insert(tenThousandRows);
    await dypai.db.direct
    .from('products')
    .eq('category', 'deprecated')
    .update({ active: false });
    await dypai.db.direct
    .from('products')
    .eq('id', 'abc123')
    .delete();
    await dypai.db.direct
    .from('products')
    .upsert({ id: 'prod_1', name: 'Widget', price: 12.99 }, 'id');
    // 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]
    );
    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

    Manage application users (requires manage_users permission):

    const { data, error } = await dypai.users.list({ page: 1, per_page: 50 });
    console.log(data.users); // [{ id, email, role, ... }, ...]
    const { data, error } = await dypai.users.create({
    email: 'new@example.com',
    password: 'securepassword',
    role: 'editor',
    user_metadata: { name: 'New User' },
    });
    const { data, error } = await dypai.users.update('user_id', {
    role: 'admin',
    });
    const { data, error } = await dypai.users.delete('user_id');
    

    // 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>
    );
    }
    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>
    );
    }
    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;
    }
    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' });
    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.

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

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

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

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

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

    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.
    // This map is normally auto-generated into dypai/types/endpoints.gen.ts — prefer
    // importing it. The canonical shape is { method, input, output }
    // (the older { response, params, body } form is deprecated and loses method-aware typing).
    interface Api {
    list_products: {
    method: 'GET';
    input: Record<string, never>;
    output: Database['products'][];
    };
    create_order: {
    method: 'POST';
    input: { product_id: string; quantity: number };
    output: 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', { // input is typed
    product_id: 'prod_123',
    quantity: 2,
    });

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


    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);

    MIT