diff --git a/DEVELOPERS.md b/DEVELOPERS.md index 0e0ac5537af..a17daf244c4 100644 --- a/DEVELOPERS.md +++ b/DEVELOPERS.md @@ -4,11 +4,12 @@ * [Installing Dependencies](#Installing-Dependencies) * [Building Supabase](#Building-Supabase) * [Start a Development Server](#Start-a-Development-Server) -* [Build in Public](#Build-in-Public) +* [Finally](#Finally) +* [Community Channels](#Community-Channels) ## Development Setup -This document describes how to set up your development environment to build and test Supabase. +First off, thanks for your interest in Supabase and for wanting to contribute! before you begin, read the [code of conduct](https://github.com/supabase/.github/blob/main/CODE_OF_CONDUCT.md) and check out the [existing issues](https://github.com/supabase/supabase/issues). This document describes how to set up your development environment to build and test Supabase. ### Installing Dependencies @@ -150,8 +151,12 @@ To debug code, and to see changes in real time, it is often useful to have a loc For more information on Supabase Studio, see the [Supabase Studio readme](./studio/README.md). -## Build in Public +## Finally -Videos of building supabase made in public. +After making your changes to the file(s) you'd like to update, it's time to open a pull request. Once you submit your pull request, others from the Supabase team/community will review it with you. -- [Contributing to open source as a beginner - Supabase](https://youtu.be/OAqhsylUuWg) - [@imskr](https://github.com/imskr) +Did you have an issue, like a merge conflict, or don't know how to open a pull request? Check out [GitHub's pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests) tutorial on how to resolve merge conflicts and other issues. Once your PR has been merged, you will be proudly listed as a contributor in the [contributor chart](https://github.com/supabase/supabase/graphs/contributors) + +## Community Channels + +Stuck somewhere? Have any questions? please join the [Discord Community Server](https://discord.supabase.com/) or the [Github Discussions](https://github.com/supabase/supabase/discussions). We are here to help! diff --git a/README.md b/README.md index d214ff5bbe3..a8a07c99b33 100644 --- a/README.md +++ b/README.md @@ -194,7 +194,7 @@ Our approach for client libraries is modular. Each sub-library is a standalone i - [Hungarian / Magyar](/i18n/README.hu.md) - [Nepali / नेपाली](/i18n/README.ne.md) - [Indonesian / Bahasa Indonesia](/i18n/README.id.md) -- [Italiano / Italian](/i18n/README.it.md) +- [Italian / Italiano](/i18n/README.it.md) - [Japanese / 日本語](/i18n/README.jp.md) - [Korean / 한국어](/i18n/README.ko.md) - [Malay / Bahasa Malaysia](/i18n/README.ms.md) diff --git a/about/docs/careers.mdx b/about/docs/careers.mdx index ac17c8d6705..c2afe678804 100644 --- a/about/docs/careers.mdx +++ b/about/docs/careers.mdx @@ -4,28 +4,4 @@ title: Work at Supabase description: We're hiring. Start your career at Supabase. --- -import Roles from '@site/docs/careers/_snippets/roles.mdx' -import About from '@site/docs/careers/_snippets/about.mdx' -import Team from '@site/docs/careers/_snippets/team.mdx' -import Apply from '@site/docs/careers/_snippets/apply.mdx' -import Process from '@site/docs/careers/_snippets/process.mdx' - -## Roles - - - -## About Supabase - - - -## About the team - - - -## Apply - - - -## Process - - +[Browse open roles](https://boards.greenhouse.io/supabase). diff --git a/about/package-lock.json b/about/package-lock.json index 1e189d2be29..6a564d42335 100644 --- a/about/package-lock.json +++ b/about/package-lock.json @@ -3552,17 +3552,6 @@ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==" }, - "clipboard": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz", - "integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==", - "optional": true, - "requires": { - "good-listener": "^1.2.2", - "select": "^1.1.2", - "tiny-emitter": "^2.0.0" - } - }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -5248,12 +5237,6 @@ "robust-predicates": "^3.0.0" } }, - "delegate": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", - "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", - "optional": true - }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -6673,15 +6656,6 @@ "slash": "^3.0.0" } }, - "good-listener": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", - "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", - "optional": true, - "requires": { - "delegate": "^3.1.2" - } - }, "got": { "version": "9.6.0", "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", @@ -10542,12 +10516,9 @@ "integrity": "sha512-MgMhSdHuHymNRqD6KM3eGS0PNqgK9q4QF5P0yoQQvpB6jNjeSAi3jcSAz0Sua/t9fa4xDOMar9HJbLa08gl9ug==" }, "prismjs": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.22.0.tgz", - "integrity": "sha512-lLJ/Wt9yy0AiSYBf212kK3mM5L8ycwlyTlSxHBAneXLR0nzFMlZ5y7riFPF3E33zXOF2IH95xdY5jIyZbM9z/w==", - "requires": { - "clipboard": "^2.0.0" - } + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", + "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==" }, "process": { "version": "0.11.10", @@ -11939,12 +11910,6 @@ "integrity": "sha1-CbqfG9W0b7sTRxjrGaaDgsuxuck=", "dev": true }, - "select": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", - "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=", - "optional": true - }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -13111,12 +13076,6 @@ "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" }, - "tiny-emitter": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", - "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", - "optional": true - }, "tiny-invariant": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", diff --git a/docker/.env.example b/docker/.env.example index 31c390e7c61..37e4b9a21d0 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -10,8 +10,6 @@ SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZX ## General SITE_URL=http://localhost:3000 -KONG_URL=http://kong:8000 -META_URL=http://meta:8080 ADDITIONAL_REDIRECT_URLS= JWT_EXPIRY=3600 DISABLE_SIGNUP=false @@ -41,3 +39,8 @@ KONG_HTTPS_PORT=8443 ## DB port POSTGRES_PORT=5432 + +# Studio + +## Public REST endpoint - replace this if you intend to use Studio outside of localhost +PUBLIC_REST_URL=http://localhost:8000/rest/v1/ diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index e8879568c3c..4b9758c97f7 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -14,8 +14,11 @@ services: ports: - ${STUDIO_PORT}:3000/tcp environment: - SUPABASE_URL: ${KONG_URL} - STUDIO_PG_META_URL: ${META_URL} + STUDIO_PG_META_URL: http://meta:8080 + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + + SUPABASE_URL: http://kong:8000 + SUPABASE_REST_URL: ${PUBLIC_REST_URL} SUPABASE_ANON_KEY: ${ANON_KEY} SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY} @@ -52,9 +55,11 @@ services: GOTRUE_URI_ALLOW_LIST: ${ADDITIONAL_REDIRECT_URLS} GOTRUE_DISABLE_SIGNUP: ${DISABLE_SIGNUP} - GOTRUE_JWT_SECRET: ${JWT_SECRET} - GOTRUE_JWT_EXP: ${JWT_EXPIRY} + GOTRUE_JWT_ADMIN_ROLES: service_role + GOTRUE_JWT_AUD: authenticated GOTRUE_JWT_DEFAULT_GROUP_NAME: authenticated + GOTRUE_JWT_EXP: ${JWT_EXPIRY} + GOTRUE_JWT_SECRET: ${JWT_SECRET} GOTRUE_EXTERNAL_EMAIL_ENABLED: ${ENABLE_EMAIL_SIGNUP} GOTRUE_MAILER_AUTOCONFIRM: ${ENABLE_EMAIL_AUTOCONFIRM} diff --git a/examples/angular-todo-list/package-lock.json b/examples/angular-todo-list/package-lock.json index f152818b879..01e9c1f41f6 100644 --- a/examples/angular-todo-list/package-lock.json +++ b/examples/angular-todo-list/package-lock.json @@ -10312,9 +10312,9 @@ "optional": true }, "nanoid": { - "version": "3.1.23", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", - "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", "dev": true }, "nanomatch": { diff --git a/examples/expo-todo-list/package-lock.json b/examples/expo-todo-list/package-lock.json index 19dfc2e88ad..aa287c0209b 100644 --- a/examples/expo-todo-list/package-lock.json +++ b/examples/expo-todo-list/package-lock.json @@ -6035,13 +6035,12 @@ } }, "plist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.1.tgz", - "integrity": "sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.4.tgz", + "integrity": "sha512-ksrr8y9+nXOxQB2osVNqrgvX/XQPOXaU4BQMKjYq8PvaY1U18mo+fKgBSwzK+luSyinOuPae956lSVcBwxlAMg==", "requires": { - "base64-js": "^1.2.3", - "xmlbuilder": "^9.0.7", - "xmldom": "0.1.x" + "base64-js": "^1.5.1", + "xmlbuilder": "^9.0.7" } }, "plugin-error": { @@ -7538,9 +7537,9 @@ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" }, "url-parse": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "requires": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -7852,11 +7851,6 @@ "sax": "^1.2.1" } }, - "xmldom": { - "version": "0.1.31", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz", - "integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==" - }, "xpipe": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/xpipe/-/xpipe-1.0.5.tgz", diff --git a/examples/expo-user-management/.expo-shared/assets.json b/examples/expo-user-management/.expo-shared/assets.json new file mode 100644 index 00000000000..1e6decfbb52 --- /dev/null +++ b/examples/expo-user-management/.expo-shared/assets.json @@ -0,0 +1,4 @@ +{ + "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true, + "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true +} diff --git a/examples/expo-user-management/.gitignore b/examples/expo-user-management/.gitignore new file mode 100644 index 00000000000..b267f5a58e1 --- /dev/null +++ b/examples/expo-user-management/.gitignore @@ -0,0 +1,15 @@ +node_modules/ +.expo/ +dist/ +.env +npm-debug.* +*.jks +*.p8 +*.p12 +*.key +*.mobileprovision +*.orig.* +web-build/ + +# macOS +.DS_Store diff --git a/examples/expo-user-management/App.tsx b/examples/expo-user-management/App.tsx new file mode 100644 index 00000000000..d3774d1e980 --- /dev/null +++ b/examples/expo-user-management/App.tsx @@ -0,0 +1,25 @@ +import 'react-native-url-polyfill/auto' +import { useState, useEffect } from 'react' +import { supabase } from './lib/supabase' +import Auth from './components/Auth' +import Account from './components/Account' +import { View } from 'react-native' +import { Session } from '@supabase/supabase-js' + +export default function App() { + const [session, setSession] = useState(null) + + useEffect(() => { + setSession(supabase.auth.session()) + + supabase.auth.onAuthStateChange((_event, session) => { + setSession(session) + }) + }, []) + + return ( + + {session && session.user ? : } + + ) +} diff --git a/examples/expo-user-management/README.md b/examples/expo-user-management/README.md new file mode 100644 index 00000000000..cfdead7d2d2 --- /dev/null +++ b/examples/expo-user-management/README.md @@ -0,0 +1,47 @@ +# React Native User Management example with Expo + +## Requirements + +- Install the [Expo CLI](https://docs.expo.io/get-started/installation/) + +## Setup & run locally + +### 1. Create new project + +Sign up to Supabase - [https://app.supabase.io](https://app.supabase.io) and create a new project. Wait for your database to start. + +### 2. Run "User Management Starter" Quickstart + +Once your database has started, run the "User Management Starter" quickstart. Inside of your project, enter the `SQL editor` tab and scroll down until you see `User Management Starter`. + +### 3. Get the URL and Key + +Go to the Project Settings (the cog icon), open the API tab, and find your API URL and `anon` key, you'll need these in the next step. + +The `anon` key is your client-side API key. It allows "anonymous access" to your database, until the user has logged in. Once they have logged in, the keys will switch to the user's own login token. This enables row level security for your data. Read more about this [below](#postgres-row-level-security). + +![image](https://user-images.githubusercontent.com/10214025/88916245-528c2680-d298-11ea-8a71-708f93e1ce4f.png) + +**_NOTE_**: The `service_role` key has full access to your data, bypassing any security policies. These keys have to be kept secret and are meant to be used in server environments and never on a client or browser. + +Set the details in the `/lib/supabase.js` file. + +### 4. Install the dependencies & run the project: + +Install the dependencies: + +```bash +yarn +``` + +Run the project: + +```bash +yarn start +``` + +## Authors + +- [Supabase](https://supabase.com) + +Supabase is open source, we'd love for you to follow along and get involved at https://github.com/supabase/supabase diff --git a/examples/expo-user-management/app.json b/examples/expo-user-management/app.json new file mode 100644 index 00000000000..9cb1c90b92a --- /dev/null +++ b/examples/expo-user-management/app.json @@ -0,0 +1,30 @@ +{ + "expo": { + "name": "expo-user-management", + "slug": "expo-user-management", + "version": "1.0.0", + "orientation": "portrait", + "icon": "./assets/icon.png", + "splash": { + "image": "./assets/splash.png", + "resizeMode": "contain", + "backgroundColor": "#ffffff" + }, + "updates": { + "fallbackToCacheTimeout": 0 + }, + "assetBundlePatterns": ["**/*"], + "ios": { + "supportsTablet": true + }, + "android": { + "adaptiveIcon": { + "foregroundImage": "./assets/adaptive-icon.png", + "backgroundColor": "#FFFFFF" + } + }, + "web": { + "favicon": "./assets/favicon.png" + } + } +} diff --git a/examples/expo-user-management/assets/adaptive-icon.png b/examples/expo-user-management/assets/adaptive-icon.png new file mode 100644 index 00000000000..03d6f6b6c67 Binary files /dev/null and b/examples/expo-user-management/assets/adaptive-icon.png differ diff --git a/examples/expo-user-management/assets/favicon.png b/examples/expo-user-management/assets/favicon.png new file mode 100644 index 00000000000..e75f697b180 Binary files /dev/null and b/examples/expo-user-management/assets/favicon.png differ diff --git a/examples/expo-user-management/assets/icon.png b/examples/expo-user-management/assets/icon.png new file mode 100644 index 00000000000..a0b1526fc7b Binary files /dev/null and b/examples/expo-user-management/assets/icon.png differ diff --git a/examples/expo-user-management/assets/splash.png b/examples/expo-user-management/assets/splash.png new file mode 100644 index 00000000000..0e89705a943 Binary files /dev/null and b/examples/expo-user-management/assets/splash.png differ diff --git a/examples/expo-user-management/babel.config.js b/examples/expo-user-management/babel.config.js new file mode 100644 index 00000000000..2900afe9d85 --- /dev/null +++ b/examples/expo-user-management/babel.config.js @@ -0,0 +1,6 @@ +module.exports = function(api) { + api.cache(true); + return { + presets: ['babel-preset-expo'], + }; +}; diff --git a/examples/expo-user-management/components/Account.tsx b/examples/expo-user-management/components/Account.tsx new file mode 100644 index 00000000000..4ad981861b5 --- /dev/null +++ b/examples/expo-user-management/components/Account.tsx @@ -0,0 +1,118 @@ +import { useState, useEffect } from 'react' +import { supabase } from '../lib/supabase' +import { StyleSheet, View, Alert } from 'react-native' +import { Button, Input } from 'react-native-elements' +import { ApiError, Session } from '@supabase/supabase-js' + +export default function Account({ session }: { session: Session }) { + const [loading, setLoading] = useState(true) + const [username, setUsername] = useState('') + const [website, setWebsite] = useState('') + const [avatar_url, setAvatarUrl] = useState('') + + useEffect(() => { + if (session) getProfile() + }, [session]) + + async function getProfile() { + try { + setLoading(true) + const user = supabase.auth.user() + if (!user) throw new Error('No user on the session!') + + let { data, error, status } = await supabase + .from('profiles') + .select(`username, website, avatar_url`) + .eq('id', user.id) + .single() + if (error && status !== 406) { + throw error + } + + if (data) { + setUsername(data.username) + setWebsite(data.website) + setAvatarUrl(data.avatar_url) + } + } catch (error) { + Alert.alert((error as ApiError).message) + } finally { + setLoading(false) + } + } + + async function updateProfile({ + username, + website, + avatar_url, + }: { + username: string + website: string + avatar_url: string + }) { + try { + setLoading(true) + const user = supabase.auth.user() + if (!user) throw new Error('No user on the session!') + + const updates = { + id: user.id, + username, + website, + avatar_url, + updated_at: new Date(), + } + + let { error } = await supabase.from('profiles').upsert(updates, { returning: 'minimal' }) + + if (error) { + throw error + } + } catch (error) { + Alert.alert((error as ApiError).message) + } finally { + setLoading(false) + } + } + + return ( + + + + + + setUsername(text)} /> + + + setWebsite(text)} /> + + + +