JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 5644208
  • Score
    100M100P100Q223916F
  • License MIT

JavaScript SDK for Base44 API

Package Exports

    This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@base44/sdk) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

    Readme

    Base44 JavaScript SDK

    A modern JavaScript SDK for interacting with the Base44 API. Designed to work with both JavaScript and TypeScript projects.

    Installation

    npm install @base44/sdk
    # or
    yarn add @base44/sdk

    Usage

    Basic Setup

    import { createClient } from '@base44/sdk';
    
    // Create a client instance
    const base44 = createClient({
      serverUrl: 'https://base44.app', // Optional, defaults to 'https://base44.app'
      appId: 'your-app-id',            // Required
      token: 'your-user-token',        // Optional, for user authentication
      serviceToken: 'your-service-token', // Optional, for service role authentication
      autoInitAuth: true,              // Optional, defaults to true - auto-detects tokens from URL or localStorage
    });

    Working with Entities

    // List all products
    const products = await base44.entities.Product.list();
    
    // Filter products by category
    const filteredProducts = await base44.entities.Product.filter({
      category: ['electronics', 'computers']
    });
    
    // Get a specific product
    const product = await base44.entities.Product.get('product-id');
    
    // Create a new product
    const newProduct = await base44.entities.Product.create({
      name: 'New Product',
      price: 99.99,
      category: 'electronics'
    });
    
    // Update a product
    const updatedProduct = await base44.entities.Product.update('product-id', {
      price: 89.99
    });
    
    // Delete a product
    await base44.entities.Product.delete('product-id');
    
    // Bulk create products
    const newProducts = await base44.entities.Product.bulkCreate([
      { name: 'Product 1', price: 19.99 },
      { name: 'Product 2', price: 29.99 }
    ]);

    Service Role Authentication

    Service role authentication allows server-side applications to perform operations with elevated privileges. This is useful for administrative tasks, background jobs, and server-to-server communication.

    import { createClient } from '@base44/sdk';
    
    // Create a client with service role token
    const base44 = createClient({
      appId: 'your-app-id',
      token: 'user-token',              // For user operations
      serviceToken: 'service-token'     // For service role operations
    });
    
    // User operations (uses user token)
    const userEntities = await base44.entities.User.list();
    
    // Service role operations (uses service token)
    const allEntities = await base44.asServiceRole.entities.User.list();
    
    // Service role has access to:
    // - base44.asServiceRole.entities
    // - base44.asServiceRole.integrations
    // - base44.asServiceRole.functions
    // Note: Service role does NOT have access to auth module for security
    
    // If no service token is provided, accessing asServiceRole throws an error
    const clientWithoutService = createClient({ appId: 'your-app-id' });
    try {
      await clientWithoutService.asServiceRole.entities.User.list();
    } catch (error) {
      // Error: Service token is required to use asServiceRole
    }

    Server-Side Usage

    For server-side applications, you can create a client from incoming HTTP requests:

    import { createClientFromRequest } from '@base44/sdk';
    
    // In your server handler (Express, Next.js, etc.)
    app.get('/api/data', async (req, res) => {
      try {
        // Extract client configuration from request headers
        const base44 = createClientFromRequest(req);
        
        // Headers used:
        // - Authorization: Bearer <user-token>
        // - Base44-Service-Authorization: Bearer <service-token>
        // - Base44-App-Id: <app-id>
        // - Base44-Api-Url: <custom-api-url> (optional)
        
        // Use appropriate authentication based on available tokens
        let data;
        if (base44.asServiceRole) {
          // Service token available - use elevated privileges
          data = await base44.asServiceRole.entities.SensitiveData.list();
        } else {
          // Only user token available - use user permissions
          data = await base44.entities.PublicData.list();
        }
        
        res.json(data);
      } catch (error) {
        res.status(500).json({ error: error.message });
      }
    });

    Working with Integrations

    // Send an email using the Core integration
    const emailResult = await base44.integrations.Core.SendEmail({
      to: 'user@example.com',
      subject: 'Hello from Base44',
      body: 'This is a test email sent via the Base44 SDK'
    });
    
    // Use a custom integration
    const result = await base44.integrations.CustomPackage.CustomEndpoint({
      param1: 'value1',
      param2: 'value2'
    });
    
    // Upload a file
    const fileInput = document.querySelector('input[type="file"]');
    const file = fileInput.files[0];
    const uploadResult = await base44.integrations.Core.UploadFile({
      file,
      metadata: { type: 'profile-picture' }
    });

    Authentication

    The SDK provides comprehensive authentication capabilities to help you build secure applications.

    Creating an Authenticated Client

    To create a client with authentication:

    import { createClient } from '@base44/sdk';
    import { getAccessToken } from '@base44/sdk/utils/auth-utils';
    
    // Create a client with authentication
    const base44 = createClient({
      appId: 'your-app-id',
      token: getAccessToken() // Automatically retrieves token from localStorage or URL
    });
    
    // Check authentication status
    const isAuthenticated = await base44.auth.isAuthenticated();
    console.log('Authenticated:', isAuthenticated);
    
    // Get current user information (requires authentication)
    if (isAuthenticated) {
      const user = await base44.auth.me();
      console.log('Current user:', user);
    }

    Login and Logout

    import { createClient } from '@base44/sdk';
    import { getAccessToken, saveAccessToken, removeAccessToken } from '@base44/sdk/utils/auth-utils';
    
    const base44 = createClient({ appId: 'your-app-id' });
    
    // Redirect to the login page
    // This will redirect to: base44.app/login?from_url=http://your-app.com/dashboard&app_id=your-app-id
    function handleLogin() {
      base44.auth.login('/dashboard');
    }
    
    // Handle successful login (on return from Base44 login)
    function handleLoginReturn() {
      const token = getAccessToken();
      if (token) {
        console.log('Successfully logged in with token:', token);
        // The token is automatically saved to localStorage and removed from URL
      }
    }
    
    // Logout
    function handleLogout() {
      removeAccessToken();
      window.location.href = '/login';
    }

    Real-World Authentication Example (React)

    Here's a complete example of implementing Base44 authentication in a React application:

    import React, { createContext, useContext, useEffect, useState } from 'react';
    import { Navigate, Outlet, Route, Routes, useLocation } from 'react-router-dom';
    import { createClient } from '@base44/sdk';
    import { getAccessToken, removeAccessToken } from '@base44/sdk/utils/auth-utils';
    
    // Create AuthContext
    const AuthContext = createContext(null);
    
    // Auth Provider Component
    function AuthProvider({ children }) {
      const [user, setUser] = useState(null);
      const [loading, setLoading] = useState(true);
      const [client] = useState(() => 
        createClient({ 
          appId: 'your-app-id', 
          token: getAccessToken()
        })
      );
    
      useEffect(() => {
        async function loadUser() {
          try {
            const isAuth = await client.auth.isAuthenticated();
            if (isAuth) {
              const userData = await client.auth.me();
              setUser(userData);
            }
          } catch (error) {
            console.error('Authentication error:', error);
          } finally {
            setLoading(false);
          }
        }
        
        loadUser();
      }, [client]);
    
      const login = () => {
        client.auth.login(window.location.pathname);
      };
    
      const logout = () => {
        removeAccessToken();
        setUser(null);
        window.location.href = '/login';
      };
    
      return (
        <AuthContext.Provider value={{ user, loading, client, login, logout }}>
          {children}
        </AuthContext.Provider>
      );
    }
    
    // Custom hook to use auth context
    function useAuth() {
      const context = useContext(AuthContext);
      if (!context) {
        throw new Error('useAuth must be used within an AuthProvider');
      }
      return context;
    }
    
    // Protected Route Component
    function ProtectedRoute() {
      const { user, loading, login } = useAuth();
      const location = useLocation();
    
      // Check if we're returning from login with a token in URL
      useEffect(() => {
        const token = getAccessToken(); // This will save token from URL if present
        if (token && !user && !loading) {
          window.location.reload(); // Reload to apply the new token
        }
      }, [location, user, loading]);
    
      if (loading) {
        return <div>Loading...</div>;
      }
    
      if (!user) {
        // If not authenticated, redirect to login
        login();
        return <div>Redirecting to login...</div>;
      }
    
      // If authenticated, render the child routes
      return <Outlet />;
    }
    
    // Dashboard Component (protected)
    function Dashboard() {
      const { user, client, logout } = useAuth();
      const [todos, setTodos] = useState([]);
      const [loading, setLoading] = useState(true);
    
      useEffect(() => {
        async function loadTodos() {
          try {
            // Load user-specific data using the SDK
            const items = await client.entities.Todo.filter({ 
              assignee: user.id 
            });
            setTodos(items);
          } catch (error) {
            console.error('Failed to load todos:', error);
          } finally {
            setLoading(false);
          }
        }
    
        loadTodos();
      }, [client, user]);
    
      return (
        <div>
          <h1>Welcome, {user.name}!</h1>
          <button onClick={logout}>Logout</button>
          
          <h2>Your Todos</h2>
          {loading ? (
            <div>Loading todos...</div>
          ) : (
            <ul>
              {todos.map(todo => (
                <li key={todo.id}>{todo.title}</li>
              ))}
            </ul>
          )}
        </div>
      );
    }
    
    // Login Page
    function LoginPage() {
      const { login, user } = useAuth();
      
      if (user) {
        return <Navigate to="/dashboard" />;
      }
      
      return (
        <div>
          <h1>Login Required</h1>
          <button onClick={login}>Login with Base44</button>
        </div>
      );
    }
    
    // App Component
    function App() {
      return (
        <AuthProvider>
          <Routes>
            <Route path="/login" element={<LoginPage />} />
            <Route element={<ProtectedRoute />}>
              <Route path="/dashboard" element={<Dashboard />} />
              <Route path="/profile" element={<ProfilePage />} />
              {/* Add more protected routes here */}
            </Route>
            <Route path="/" element={<Navigate to="/dashboard" />} />
          </Routes>
        </AuthProvider>
      );
    }

    TypeScript Support

    This SDK includes TypeScript definitions out of the box:

    import { createClient, Base44Error } from '@base44/sdk';
    import type { Entity, Base44Client, AuthModule } from '@base44/sdk';
    
    // Create a typed client
    const base44: Base44Client = createClient({
      appId: 'your-app-id'
    });
    
    // Using the entities module with type safety
    async function fetchProducts() {
      try {
        const products: Entity[] = await base44.entities.Product.list();
        console.log(products.map(p => p.name));
        
        const product: Entity = await base44.entities.Product.get('product-id');
        console.log(product.name);
      } catch (error) {
        if (error instanceof Base44Error) {
          console.error(`Error ${error.status}: ${error.message}`);
        }
      }
    }
    
    // Service role operations with TypeScript
    async function adminOperations() {
      const base44 = createClient({
        appId: 'your-app-id',
        serviceToken: 'service-token'
      });
    
      // TypeScript knows asServiceRole requires a service token
      try {
        const allUsers: Entity[] = await base44.asServiceRole.entities.User.list();
        console.log(`Total users: ${allUsers.length}`);
      } catch (error) {
        if (error instanceof Error) {
          console.error(error.message); // Service token is required to use asServiceRole
        }
      }
    }
    
    // Authentication with TypeScript
    async function handleAuth(auth: AuthModule) {
      // Check authentication
      const isAuthenticated: boolean = await auth.isAuthenticated();
      
      if (isAuthenticated) {
        // Get user info
        const user: Entity = await auth.me();
        console.log(`Logged in as: ${user.name}, Role: ${user.role}`);
        
        // Update user
        const updatedUser: Entity = await auth.updateMe({
          preferences: { theme: 'dark' }
        });
      } else {
        // Redirect to login
        auth.login('/dashboard');
      }
    }
    
    // Execute with proper typing
    handleAuth(base44.auth);

    Advanced TypeScript Usage

    You can define your own entity interfaces for better type safety:

    // Define custom entity interfaces
    interface User extends Entity {
      name: string;
      email: string;
      role: 'admin' | 'editor' | 'viewer';
      preferences?: {
        theme: 'light' | 'dark';
        notifications: boolean;
      };
    }
    
    interface Product extends Entity {
      name: string;
      price: number;
      category: string;
      inStock: boolean;
    }
    
    // Use your custom interfaces with the SDK
    async function getLoggedInUser(): Promise<User | null> {
      const base44 = createClient({ appId: 'your-app-id' });
      
      try {
        const user = await base44.auth.me() as User;
        return user;
      } catch (error) {
        console.error('Failed to get user:', error);
        return null;
      }
    }
    
    // Use with React hooks
    function useBase44User() {
      const [user, setUser] = useState<User | null>(null);
      const [loading, setLoading] = useState<boolean>(true);
      
      useEffect(() => {
        const base44 = createClient({ appId: 'your-app-id' });
        
        async function fetchUser() {
          try {
            const userData = await base44.auth.me() as User;
            setUser(userData);
          } catch (error) {
            console.error('Auth error:', error);
          } finally {
            setLoading(false);
          }
        }
        
        fetchUser();
      }, []);
      
      return { user, loading };
    }

    Error Handling

    The SDK provides a custom Base44Error class for error handling:

    import { createClient, Base44Error } from '@base44/sdk';
    
    const base44 = createClient({ appId: 'your-app-id' });
    
    try {
      const result = await base44.entities.NonExistentEntity.list();
    } catch (error) {
      if (error instanceof Base44Error) {
        console.error(`Status: ${error.status}`);
        console.error(`Message: ${error.message}`);
        console.error(`Code: ${error.code}`);
        console.error(`Data: ${JSON.stringify(error.data)}`);
      } else {
        console.error('Unexpected error:', error);
      }
    }

    Functions

    The SDK supports invoking custom functions:

    // Invoke a function without parameters
    const result = await base44.functions.myFunction();
    
    // Invoke a function with parameters
    const result = await base44.functions.calculateTotal({
      items: ['item1', 'item2'],
      discount: 0.1
    });
    
    // Functions are automatically authenticated with the user token
    // Service role can also invoke functions
    const serviceResult = await base44.asServiceRole.functions.adminFunction();

    Testing

    The SDK includes comprehensive tests to ensure reliability.

    Running Tests

    # Run all tests
    npm test
    
    # Run unit tests only (no API calls)
    npm run test:unit
    
    # Run end-to-end tests (requires API access)
    npm run test:e2e
    
    # Run tests with coverage report
    npm run test:coverage

    Setting Up E2E Tests

    E2E tests require access to a Base44 API. To run these tests:

    1. Copy tests/.env.example to tests/.env

    2. Fill in your Base44 API credentials in the .env file:

      BASE44_SERVER_URL=https://base44.app
      BASE44_APP_ID=your_app_id_here
      BASE44_AUTH_TOKEN=your_auth_token_here
    3. Optionally, set SKIP_E2E_TESTS=true to skip E2E tests.

    Writing Your Own Tests

    You can use the provided test utilities for writing your own tests:

    const { createClient } = require('@base44/sdk');
    const { getTestConfig } = require('@base44/sdk/tests/utils/test-config');
    
    describe('My Tests', () => {
      let base44;
      
      beforeAll(() => {
        const config = getTestConfig();
        base44 = createClient({
          serverUrl: config.serverUrl,
          appId: config.appId,
        });
        
        if (config.token) {
          base44.setToken(config.token);
        }
      });
      
      test('My test', async () => {
        const todos = await base44.entities.Todo.filter({}, 10);
        expect(Array.isArray(todos)).toBe(true);
        expect(todos.length).toBeGreaterThan(0);
      });
    });

    License

    MIT