Update Supabase clients and refactor codebase

Refactored several Supabase client functions and updated them to use generics. Also, the '@kit/supabase-config' package was removed from the project and all references were replaced accordingly. The project's dependencies were updated as well, including the Supabase package which was upgraded to the latest version.
This commit is contained in:
giancarlo
2024-04-11 12:31:08 +08:00
parent 1c344d0d7f
commit 48f1ee90c4
29 changed files with 1337 additions and 96 deletions

4
apps/web/supabase/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
# Supabase
.branches
.temp
.env

View File

@@ -0,0 +1,72 @@
# A string used to distinguish different Supabase projects on the same host. Defaults to the working
# directory name when running `supabase init`.
project_id = "next-supabase-saas-kit-turbo"
[api]
# Port to use for the API URL.
port = 54321
# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API
# endpoints. public and storage are always included.
schemas = ["public", "storage", "graphql_public"]
# Extra schemas to add to the search_path of every request. public is always included.
extra_search_path = ["public", "extensions"]
# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size
# for accidental or malicious requests.
max_rows = 1000
[db]
# Port to use for the local database URL.
port = 54322
# The database major version to use. This has to be the same as your remote database's. Run `SHOW
# server_version;` on the remote database to check.
major_version = 15
[studio]
# Port to use for Supabase Studio.
port = 54323
# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they
# are monitored, and you can view the emails that would have been sent from the web interface.
[inbucket]
# Port to use for the email testing server web interface.
port = 54324
smtp_port = 54325
pop3_port = 54326
[storage]
# The maximum file size allowed (e.g. "5MB", "500KB").
file_size_limit = "50MiB"
[auth]
# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used
# in emails.
site_url = "http://localhost:3000"
# A list of *exact* URLs that auth providers are permitted to redirect to post authentication.
additional_redirect_urls = ["https://localhost:3000"]
# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 seconds (one
# week).
jwt_expiry = 3600
# Allow/disallow new user signups to your project.
enable_signup = true
[auth.email]
# Allow/disallow new user signups via email to your project.
enable_signup = true
# If enabled, a user will be required to confirm any email change on both the old, and new email
# addresses. If disabled, only the new email is required to confirm.
double_confirm_changes = true
# If enabled, users need to confirm their email address before signing in.
enable_confirmations = true
# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`,
# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin`, `notion`, `twitch`,
# `twitter`, `slack`, `spotify`, `workos`, `zoom`.
[auth.external.apple]
enabled = false
client_id = ""
secret = ""
# Overrides the default auth redirectUrl.
redirect_uri = ""
# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure,
# or any other third-party OIDC providers.
url = ""

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,25 @@
-- We seed the role_permissions table with the default roles and permissions
insert into public.role_permissions(
role,
permission)
values (
'owner',
'roles.manage'),
(
'owner',
'billing.manage'),
(
'owner',
'settings.manage'),
(
'owner',
'members.manage'),
(
'owner',
'invites.manage'),
(
'member',
'settings.manage'),
(
'member',
'invites.manage');

View File

@@ -0,0 +1,60 @@
-- These webhooks are only for development purposes.
-- In production, you should manually create webhooks in the Supabase dashboard (or create a migration to do so).
-- We don't do it because you'll need to manually add your webhook URL and secret key.
-- this webhook will be triggered after deleting an account
create trigger "accounts_teardown" after delete
on "public"."accounts" for each row
execute function "supabase_functions"."http_request"(
'http://host.docker.internal:3000/api/db/webhook',
'POST',
'{"Content-Type":"application/json", "X-Supabase-Event-Signature":"WEBHOOKSECRET"}',
'{}',
'1000'
);
-- this webhook will be triggered after every insert on the accounts_memberships table
create trigger "accounts_memberships_insert" after insert
on "public"."accounts_memberships" for each row
execute function "supabase_functions"."http_request"(
'http://host.docker.internal:3000/api/db/webhook',
'POST',
'{"Content-Type":"application/json", "X-Supabase-Event-Signature":"WEBHOOKSECRET"}',
'{}',
'1000'
);
-- this webhook will be triggered after every delete on the accounts_memberships table
create trigger "account_membership_delete" after delete
on "public"."accounts_memberships" for each row
execute function "supabase_functions"."http_request"(
'http://host.docker.internal:3000/api/db/webhook',
'POST',
'{"Content-Type":"application/json", "X-Supabase-Event-Signature":"WEBHOOKSECRET"}',
'{}',
'1000'
);
-- this webhook will be triggered after a delete on the subscriptions table
-- which should happen when a user deletes their account (and all their subscriptions)
create trigger "account_delete" after delete
on "public"."subscriptions" for each row
execute function "supabase_functions"."http_request"(
'http://host.docker.internal:3000/api/db/webhook',
'POST',
'{"Content-Type":"application/json", "X-Supabase-Event-Signature":"WEBHOOKSECRET"}',
'{}',
'1000'
);
-- this webhook will be triggered after every insert on the invitations table
-- which should happen when a user invites someone to their account
create trigger "invitations_insert" after insert
on "public"."invitations" for each row
execute function "supabase_functions"."http_request"(
'http://host.docker.internal:3000/api/db/webhook',
'POST',
'{"Content-Type":"application/json", "X-Supabase-Event-Signature":"WEBHOOKSECRET"}',
'{}',
'1000'
);

View File

@@ -0,0 +1,74 @@
create extension if not exists http with schema extensions;
create extension if not exists pg_tle;
select
no_plan ();
create or replace function install_extensions()
returns void
as $$
declare
installed boolean;
begin
select exists (
select
1
from
pg_catalog.pg_extension
where
extname = 'supabase-dbdev'
) into installed;
if installed then
return;
end if;
perform
pgtle.install_extension(
'supabase-dbdev',
resp.contents ->> 'version',
'PostgreSQL package manager',
resp.contents ->> 'sql'
)
from http(
(
'GET',
'https://api.database.dev/rest/v1/'
|| 'package_versions?select=sql,version'
|| '&package_name=eq.supabase-dbdev'
|| '&order=version.desc'
|| '&limit=1',
array[
('apiKey', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InhtdXB0cHBsZnZpaWZyYndtbXR2Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2ODAxMDczNzIsImV4cCI6MTk5NTY4MzM3Mn0.z2CN0mvO2No8wSi46Gw59DFGCTJrzM0AQKsu_5k134s')::http_header
],
null,
null
)
) x,
lateral (
select
((row_to_json(x) -> 'content') #>> '{}')::json -> 0
) resp(contents);
create extension if not exists "supabase-dbdev";
perform dbdev.install('supabase-dbdev');
perform dbdev.install('basejump-supabase_test_helpers');
end
$$ language plpgsql;
select install_extensions();
select has_column(
'auth',
'users',
'id',
'id should exist'
);
select
*
from
finish ();
rollback;

View File

@@ -0,0 +1,37 @@
create schema if not exists makerkit;
-- anon, authenticated, and service_role should have access to tests schema
grant USAGE on schema makerkit to anon, authenticated, service_role;
-- Don't allow public to execute any functions in the tests schema
alter default PRIVILEGES in schema makerkit revoke execute on FUNCTIONS from public;
-- Grant execute to anon, authenticated, and service_role for testing purposes
alter default PRIVILEGES in schema makerkit grant execute on FUNCTIONS to anon,
authenticated, service_role;
create or replace function makerkit.get_account_by_slug(
account_slug text
)
returns setof accounts
as $$
begin
return query
select
*
from
accounts
where
slug = account_slug;
end;
$$ language PLPGSQL;
select
*
from
finish();
rollback;

View File

@@ -0,0 +1,21 @@
BEGIN;
create extension "basejump-supabase_test_helpers" version '0.0.6';
select no_plan();
--- we insert a user into auth.users and return the id into user_id to use
select tests.create_supabase_user('test1', 'test1@test.com');
select tests.create_supabase_user('test2');
-- Create an organization account
select tests.authenticate_as('test1');
select public.create_account('Test');
select * from finish();
ROLLBACK;

View File

@@ -0,0 +1,56 @@
BEGIN;
create extension "basejump-supabase_test_helpers" version '0.0.6';
select no_plan();
--- we insert a user into auth.users and return the id into user_id to use
select tests.create_supabase_user('test1', 'test1@test.com');
select tests.create_supabase_user('test2');
-- Create an organization account
select tests.authenticate_as('test1');
select public.create_account('Test');
select public.create_account('Test');
select public.create_account('Test');
-- should automatically create slugs for the accounts
select row_eq(
$$ select slug from public.accounts where name = 'Test' and slug = 'test' $$,
row('test'::text),
'The first organization account should automatically create a slug named "test"'
);
select row_eq(
$$ select slug from public.accounts where name = 'Test' and slug = 'test-1' $$,
row('test-1'::text),
'The second organization account should automatically create a slug named "test-1"'
);
select row_eq(
$$ select slug from public.accounts where name = 'Test' and slug = 'test-2' $$,
row('test-2'::text),
'The third organization account should automatically create a slug named "test-2"'
);
-- Should automatically update the slug if the name is updated
update public.accounts set name = 'Test 4' where slug = 'test-2';
select row_eq(
$$ select slug from public.accounts where name = 'Test 4' $$,
row('test-4'::text),
'Updating the name of an organization account should update the slug'
);
-- Should fail if the slug is updated to an existing slug
select throws_ok(
$$ update public.accounts set slug = 'test-1' where slug = 'test-4' $$,
'duplicate key value violates unique constraint "accounts_slug_key"'
);
select * from finish();
ROLLBACK;

View File

@@ -0,0 +1,78 @@
begin;
create extension "basejump-supabase_test_helpers" version '0.0.6';
select
no_plan();
--- we insert a user into auth.users and return the id into user_id to use
select
tests.create_supabase_user('test1', 'test1@test.com');
select
tests.create_supabase_user('test2');
-- Create an organization account
select
tests.authenticate_as('test1');
select
public.create_account('Test');
select
row_eq($$
select
primary_owner_user_id, is_personal_account, slug, name from
makerkit.get_account_by_slug('test') $$, row
(tests.get_supabase_uid('test1'), false, 'test'::text,
'Test'::varchar), 'Users can create an organization account');
-- Should be the primary owner of the organization account by default
select
row_eq($$
select
account_role from public.accounts_memberships
where
account_id =(
select
id
from public.accounts
where
slug = 'test')
and user_id = tests.get_supabase_uid('test1') $$, row
('owner'::public.account_role), 'The primary owner should have the owner role for the organization account');
-- Should be able to see the organization account
select
isnt_empty($$
select
* from public.accounts
where
primary_owner_user_id = tests.get_supabase_uid('test1') $$, 'The primary owner should be able to see the organization account');
-- Others should not be able to see the organization account
select
tests.authenticate_as('test2');
select
is_empty($$
select
* from public.accounts
where
primary_owner_user_id = tests.get_supabase_uid('test1') $$, 'Other users should not be able to see the organization account');
-- should not have any role for the organization account
select
is (public.has_role_on_account((
select
id
from makerkit.get_account_by_slug('test'))),
false,
'Foreign users should not have any role for the organization account');
select
*
from
finish();
rollback;

View File

@@ -0,0 +1,57 @@
BEGIN;
create extension "basejump-supabase_test_helpers" version '0.0.6';
select no_plan();
--- we insert a user into auth.users and return the id into user_id to use
select tests.create_supabase_user('test1', 'test1@test.com');
select tests.create_supabase_user('test2');
------------
--- Primary Owner
------------
select tests.authenticate_as('test1');
-- should create the personal account automatically with the same ID as the user
SELECT row_eq(
$$ select primary_owner_user_id, is_personal_account, name from public.accounts order by created_at desc limit 1 $$,
ROW (tests.get_supabase_uid('test1'), true, 'test1'::varchar),
'Inserting a user should create a personal account when personal accounts are enabled'
);
-- anon users should not be able to see the personal account
set local role anon;
SELECT throws_ok(
$$ select * from public.accounts order by created_at desc limit 1 $$,
'permission denied for schema public'
);
-- the primary owner should be able to see the personal account
select tests.authenticate_as('test1');
SELECT isnt_empty(
$$ select * from public.accounts where primary_owner_user_id = tests.get_supabase_uid('test1') $$,
'The primary owner should be able to see the personal account'
);
------------
--- Other Users
-- other users should not be able to see the personal account
select tests.authenticate_as('test2');
SELECT is_empty(
$$ select * from public.accounts where primary_owner_user_id = tests.get_supabase_uid('test1') $$,
'Other users should not be able to see the personal account'
);
SELECT *
FROM finish();
ROLLBACK;

View File

@@ -0,0 +1,36 @@
BEGIN;
create extension "basejump-supabase_test_helpers" version '0.0.6';
select no_plan();
select has_table('public', 'config', 'Makerkit config table should exist');
select has_table('public', 'accounts', 'Makerkit accounts table should exist');
select has_table('public', 'accounts_memberships', 'Makerkit account_users table should exist');
select has_table('public', 'invitations', 'Makerkit invitations table should exist');
select has_table('public', 'billing_customers', 'Makerkit billing_customers table should exist');
select has_table('public', 'subscriptions', 'Makerkit billing_subscriptions table should exist');
select has_table('public', 'role_permissions', 'Makerkit roles_permissions table should exist');
SELECT schema_privs_are('public', 'anon', Array [NULL], 'Anon should not have access to public schema');
-- set the role to anonymous for verifying access tests
set role anon;
select throws_ok('select public.get_config()');
select throws_ok('select public.is_set(''enable_organization_accounts'')');
-- set the role to the service_role for testing access
set role service_role;
select ok(public.get_config() is not null),
'Makerkit get_config should be accessible to the service role';
-- set the role to authenticated for tests
set role authenticated;
select ok(public.get_config() is not null), 'Makerkit get_config should be accessible to authenticated users';
select ok(public.is_set('enable_organization_accounts')),
'Makerkit is_set should be accessible to authenticated users';
select isnt_empty('select * from public.config', 'authenticated users should have access to Makerkit config');
SELECT *
FROM finish();
ROLLBACK;