1.0.1 • Published 8 months ago

supabase-integration v1.0.1

Weekly downloads
-
License
MIT
Repository
-
Last release
8 months ago

Supabase Integration

A comprehensive npm package to integrate Supabase with JavaScript, TypeScript, and React. This package provides ready-to-use services for authentication and basic CRUD operations on your Supabase database.

Features

  • Authentication: Sign up, sign in, sign out, OAuth integration (e.g., Google, GitHub).
  • Database Operations: Create, Read, Update, Delete (CRUD) operations on your Supabase tables.
  • Call Postgres Functions: Execute stored procedures in your Supabase database.

Installation

npm install supabase-integration

Usage

Initialization

Before using the package, you need to initialize it with your Supabase project credentials. Replace 'https://your-supabase-url.supabase.co' and 'your-anon-key' with your actual Supabase URL and anonymous key.

// JavaScript or TypeScript
import SupabaseIntegration from "supabase-integration";

const supabase = new SupabaseIntegration({
  supabaseUrl: "https://your-supabase-url.supabase.co",
  supabaseKey: "your-anon-key",
});
// React (typically done in a separate file like supabaseClient.js or supabaseClient.ts)
import SupabaseIntegration from "supabase-integration";

const supabase = new SupabaseIntegration({
  supabaseUrl: "https://your-supabase-url.supabase.co",
  supabaseKey: "your-anon-key",
});

export default supabase;

JavaScript

Authentication

Sign Up

const { data, error } = await supabase.auth.signUp({
  email: "user@example.com",
  password: "securepassword",
});

if (error) {
  console.error("Sign Up Error:", error.message);
} else {
  console.log("Sign Up Success:", data);
}

Sign In

const { data, error } = await supabase.auth.signIn({
  email: "user@example.com",
  password: "securepassword",
});

if (error) {
  console.error("Sign In Error:", error.message);
} else {
  console.log("Sign In Success:", data);
}

Sign In with OAuth

const { data, error } = await supabase.auth.signInWithOAuth({
  provider: "google", // e.g., 'google', 'github'
  redirectTo: "https://your-app.com/welcome",
  scopes: "openid email profile",
  queryParams: { prompt: "consent" },
});

if (error) {
  console.error("OAuth Sign In Error:", error.message);
} else {
  console.log("OAuth Sign In Success:", data);
  // The user will be redirected to the OAuth provider's sign-in page.
}

Sign Out

const { error } = await supabase.auth.signOut();

if (error) {
  console.error("Sign Out Error:", error.message);
} else {
  console.log("Sign Out Success");
}

CRUD Operations

Create (Insert)

const { data: insertData, error: insertError } =
  await supabase.database.insertData(
    "users",
    {
      email: "newuser@example.com",
      name: "New User",
    },
    { returnData: true }
  );

if (insertError) {
  console.error("Insert Error:", insertError.message);
} else {
  console.log("Insert Success:", insertData);
}

Read (Fetch)

const { data: fetchData, error: fetchError } =
  await supabase.database.fetchData("users", {
    select: "id, email, name",
    order: "id:asc",
    limit: 10,
  });

if (fetchError) {
  console.error("Fetch Error:", fetchError.message);
} else {
  console.log("Fetch Success:", fetchData);
}

Update

const { data: updateData, error: updateError } =
  await supabase.database.updateData(
    "users",
    { name: "Updated User" },
    { id: 1 },
    { returnData: true }
  );

if (updateError) {
  console.error("Update Error:", updateError.message);
} else {
  console.log("Update Success:", updateData);
}

Delete

const { data: deleteData, error: deleteError } =
  await supabase.database.deleteData("users", { id: 1 }, { returnData: true });

if (deleteError) {
  console.error("Delete Error:", deleteError.message);
} else {
  console.log("Delete Success:", deleteData);
}

Call a Postgres Function

const { data, error } = await supabase.database.callFunction(
  "your_function_name",
  {
    arg1: "value1",
    arg2: "value2",
  }
);

if (error) {
  console.error("Function Call Error:", error.message);
} else {
  console.log("Function Call Success:", data);
}

TypeScript

Using the package with TypeScript provides enhanced type safety and IntelliSense support.

Initialization

import SupabaseIntegration from "supabase-integration";

interface SupabaseConfig {
  supabaseUrl: string;
  supabaseKey: string;
}

const config: SupabaseConfig = {
  supabaseUrl: "https://your-supabase-url.supabase.co",
  supabaseKey: "your-anon-key",
};

const supabase = new SupabaseIntegration(config);

Authentication

Sign Up

interface SignUpResponse {
  data: {
    user: {
      id: string;
      email: string;
      // other user fields
    };
    session: any; // Define more specific types as needed
  } | null;
  error: any; // Define more specific error types as needed
}

const { data, error }: SignUpResponse = await supabase.auth.signUp({
  email: "user@example.com",
  password: "securepassword",
});

if (error) {
  console.error("Sign Up Error:", error.message);
} else {
  console.log("Sign Up Success:", data);
}

Sign In

interface SignInResponse {
  data: {
    session: any; // Define more specific types as needed
    user: {
      id: string;
      email: string;
      // other user fields
    };
  } | null;
  error: any;
}

const { data, error }: SignInResponse = await supabase.auth.signIn({
  email: "user@example.com",
  password: "securepassword",
});

if (error) {
  console.error("Sign In Error:", error.message);
} else {
  console.log("Sign In Success:", data);
}

Sign In with OAuth

interface OAuthOptions {
  provider: "google" | "github" | string;
  redirectTo?: string;
  scopes?: string;
  queryParams?: Record<string, string>;
}

const oauthOptions: OAuthOptions = {
  provider: "github",
  redirectTo: "https://your-app.com/welcome",
};

const { data, error } = await supabase.auth.signInWithOAuth(oauthOptions);

if (error) {
  console.error("OAuth Sign In Error:", error.message);
} else {
  console.log("OAuth Sign In Success:", data);
}

Sign Out

const { error } = await supabase.auth.signOut();

if (error) {
  console.error("Sign Out Error:", error.message);
} else {
  console.log("Sign Out Success");
}

CRUD Operations

Create (Insert)

interface User {
  id: string;
  email: string;
  name: string;
}

interface InsertResponse {
  data: User[] | null;
  error: any;
}

const { data: insertData, error: insertError }: InsertResponse =
  await supabase.database.insertData(
    "users",
    {
      email: "newuser@example.com",
      name: "New User",
    },
    { returnData: true }
  );

if (insertError) {
  console.error("Insert Error:", insertError.message);
} else {
  console.log("Insert Success:", insertData);
}

Read (Fetch)

interface FetchResponse<T> {
  data: T[] | null;
  error: any;
}

interface User {
  id: string;
  email: string;
  name: string;
}

const { data: fetchData, error: fetchError }: FetchResponse<User> =
  await supabase.database.fetchData("users", {
    select: "id, email, name",
    order: "id:asc",
    limit: 10,
  });

if (fetchError) {
  console.error("Fetch Error:", fetchError.message);
} else {
  console.log("Fetch Success:", fetchData);
}

Update

interface UpdateResponse<T> {
  data: T[] | null;
  error: any;
}

interface User {
  id: string;
  email: string;
  name: string;
}

const { data: updateData, error: updateError }: UpdateResponse<User> =
  await supabase.database.updateData(
    "users",
    { name: "Updated User" },
    { id: "1" },
    { returnData: true }
  );

if (updateError) {
  console.error("Update Error:", updateError.message);
} else {
  console.log("Update Success:", updateData);
}

Delete

interface DeleteResponse<T> {
  data: T[] | null;
  error: any;
}

interface User {
  id: string;
  email: string;
  name: string;
}

const { data: deleteData, error: deleteError }: DeleteResponse<User> =
  await supabase.database.deleteData(
    "users",
    { id: "1" },
    { returnData: true }
  );

if (deleteError) {
  console.error("Delete Error:", deleteError.message);
} else {
  console.log("Delete Success:", deleteData);
}

Call a Postgres Function

interface FunctionResponse {
  data: any;
  error: any;
}

const { data, error }: FunctionResponse = await supabase.database.callFunction(
  "your_function_name",
  {
    arg1: "value1",
    arg2: "value2",
  }
);

if (error) {
  console.error("Function Call Error:", error.message);
} else {
  console.log("Function Call Success:", data);
}

React

Integrating supabase-integration with React allows you to manage authentication and CRUD operations seamlessly within your React components. Below are the steps and examples to help you get started.

1. Initialize Supabase in a Separate File

Create a file named supabaseClient.js or supabaseClient.ts in your project's src directory.

// src/supabaseClient.js

import SupabaseIntegration from "supabase-integration";

const supabase = new SupabaseIntegration({
  supabaseUrl: "https://your-supabase-url.supabase.co",
  supabaseKey: "your-anon-key",
});

export default supabase;

2. Set Up a React Context (Optional but Recommended)

Using React Context allows you to provide the supabase instance throughout your application without prop drilling.

// src/contexts/SupabaseContext.jsx

import React, { createContext, useContext, useState, useEffect } from "react";
import supabase from "../supabaseClient";

const SupabaseContext = createContext();

export const SupabaseProvider = ({ children }) => {
  const [user, setUser] = useState(null);

  useEffect(() => {
    // Listen to authentication state changes
    const unsubscribe = supabase.auth.onAuthStateChange((event, session) => {
      setUser(session?.user || null);
    });

    // Fetch the current session
    supabase.auth.fetchData().then(({ data }) => {
      setUser(data?.user || null);
    });

    return () => {
      unsubscribe();
    };
  }, []);

  return (
    <SupabaseContext.Provider value={{ supabase, user }}>
      {children}
    </SupabaseContext.Provider>
  );
};

export const useSupabase = () => {
  return useContext(SupabaseContext);
};

3. Wrap Your Application with the SupabaseProvider

// src/index.jsx

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { SupabaseProvider } from "./contexts/SupabaseContext";

ReactDOM.render(
  <React.StrictMode>
    <SupabaseProvider>
      <App />
    </SupabaseProvider>
  </React.StrictMode>,
  document.getElementById("root")
);

4. Use Supabase in Your Components

AuthButtons Component

// src/components/AuthButtons.jsx

import React from "react";
import { useSupabase } from "../contexts/SupabaseContext";

const AuthButtons = () => {
  const { supabase } = useSupabase();

  const handleGoogleSignIn = async () => {
    const { data, error } = await supabase.auth.signInWithOAuth({
      provider: "google",
      redirectTo: "https://your-app.com/welcome",
    });

    if (error) {
      console.error("OAuth Sign In Error:", error.message);
      alert(`Sign in failed: ${error.message}`);
    } else {
      console.log("OAuth Sign In Success:", data);
      // The user will be redirected to the OAuth provider's sign-in page.
    }
  };

  const handleSignOut = async () => {
    const { error } = await supabase.auth.signOut();

    if (error) {
      console.error("Sign Out Error:", error.message);
      alert(`Sign out failed: ${error.message}`);
    } else {
      console.log("Sign Out Success");
    }
  };

  return (
    <div>
      <button onClick={handleGoogleSignIn}>Sign In with Google</button>
      <button onClick={handleSignOut}>Sign Out</button>
    </div>
  );
};

export default AuthButtons;

App Component

// src/App.jsx

import React from "react";
import { useSupabase } from "./contexts/SupabaseContext";
import AuthButtons from "./components/AuthButtons";

const App = () => {
  const { user } = useSupabase();

  return (
    <div>
      <h1>Supabase Integration Example</h1>
      {user ? <p>Welcome, {user.email}</p> : <p>Please sign in</p>}
      <AuthButtons />
    </div>
  );
};

export default App;

CRUD Operations Example

// src/components/UserList.jsx

import React, { useEffect, useState } from "react";
import { useSupabase } from "../contexts/SupabaseContext";

const UserList = () => {
  const { supabase } = useSupabase();
  const [users, setUsers] = useState([]);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchUsers = async () => {
      const { data, error } = await supabase.database.fetchData("users", {
        select: "id, email, name",
        order: "id:asc",
        limit: 10,
      });

      if (error) {
        setError(error.message);
      } else {
        setUsers(data);
      }
    };

    fetchUsers();
  }, [supabase]);

  if (error) {
    return <p>Error fetching users: {error}</p>;
  }

  return (
    <div>
      <h2>User List</h2>
      {users.length === 0 ? (
        <p>No users found.</p>
      ) : (
        <ul>
          {users.map((user) => (
            <li key={user.id}>
              {user.email} - {user.name}
            </li>
          ))}
        </ul>
      )}
    </div>
  );
};

export default UserList;

Configuration

This package does not rely on environment files (.env). Instead, configuration values are passed directly through the SupabaseIntegration constructor as shown in the initialization examples above.


Contributing

Contributions are welcome! Please open an issue or submit a pull request for any improvements or bug fixes.


License

MIT


Example Project Structure

After integrating with React, your project structure might look like this:

your-react-app/
├── src/
│   ├── components/
│   │   ├── AuthButtons.jsx
│   │   └── UserList.jsx
│   ├── contexts/
│   │   └── SupabaseContext.jsx
│   ├── supabaseClient.js
│   ├── App.jsx
│   └── index.jsx
├── package.json
├── tsconfig.json
├── README.md
└── .gitignore
1.0.1

8 months ago

1.0.0

8 months ago