Massive cleanup. We are starting afresh

This commit is contained in:
Paul Copplestone committed 2020-01-02 13:06:46 +08:00
1 parent 3ae731da30
commit 15d0ae5faf
125 files changed
+1772 -25013

No files matched your search

+1 -1
View File
@@ -1,4 +1,4 @@
DS_Store
.DS_Store
node_modules
.next
out
+1 -22
View File
@@ -1,24 +1,3 @@
# Supabase
Supercharge PostgreSQL. [https://supabase.io](https://supabase.io)
## About
Supabase provide opensource tools that make PostgreSQL even better.
## Docs
All of our documeentation is stored in this repo as a single source of truth. You can view it online at [https://supabase.io/docs/-/about](https://supabase.io/docs/-/about).
## Development
This is monorepo. As much as we love `npm`, we have decided to use `yarn` to manage the separate workspaces.
```bash
yarn # installs all dependencies for all workspaces.
yarn workspaces dev # runs "dev" command in all workspaces.
yarn workspace @supabase/web dev # runs "dev" command in the "web" workspace.
yarn workspace @supabase/web add package # installs "package" in the "web" workspace
yarn workspace @supabase/web remove package # removes "package" in the "web" workspace
```
[Supabase](https://supabase.io)
+3
View File
@@ -0,0 +1,3 @@
# App
@todo
+1
View File
@@ -0,0 +1 @@
@todo
+1
View File
@@ -0,0 +1 @@
@todo
@@ -1,8 +0,0 @@
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=db
POSTGRES_HOST=db
POSTGRES_PORT=5432
PGRST_DB_URI=postgres://postgres:postgres@db:5432/postgres
PGRST_DB_SCHEMA=public
PGRST_DB_ANON_ROLE=postgres
-17
View File
@@ -1,17 +0,0 @@
# Docker and React Realtime example
A How-To guide for using Realtime with React and Docker.
Online documentation: [https://supabase.io/docs/realtime/guide-docker-react](https://supabase.io/docs/realtime/guide-docker-nextjs)
## Usage
1. Clone this repo
2. Run `docker-compose up`
3. Open two browser tabs to [http://localhost:3000](http://localhost:3000)
4. Add a user in one tab, and it will add a user in another
## Contributing
If you make changes to this repo, please ensure you update the online documentation too.
@@ -1,23 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
@@ -1,68 +0,0 @@
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
## Available Scripts
In the project directory, you can run:
### `yarn start`
Runs the app in the development mode.<br />
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.<br />
You will also see any lint errors in the console.
### `yarn test`
Launches the test runner in the interactive watch mode.<br />
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `yarn build`
Builds the app for production to the `build` folder.<br />
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.<br />
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `yarn eject`
**Note: this is a one-way operation. Once you `eject`, you can’t go back!**
If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).
### Code Splitting
This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
### Analyzing the Bundle Size
This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
### Making a Progressive Web App
This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
### Advanced Configuration
This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
### Deployment
This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
### `yarn build` fails to minify
This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
File diff suppressed because it is too large. Load diff
@@ -1,32 +0,0 @@
{
"name": "app",
"version": "0.1.0",
"private": true,
"dependencies": {
"axios": "^0.19.0",
"react": "^16.11.0",
"react-dom": "^16.11.0",
"react-scripts": "3.2.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

@@ -1,43 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

@@ -1,25 +0,0 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
@@ -1,2 +0,0 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
@@ -1,22 +0,0 @@
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #09d3ac;
}
@@ -1,33 +0,0 @@
import React, { useState } from 'react'
import axios from 'axios'
import './App.css';
function App() {
const [firstName, setFirstName] = useState('')
const [userList, setUserList] = useState([{ first_name: 'Paul' }])
const onAddUserClicked = async () => {
try {
addUser(firstName)
setFirstName('')
} catch (error) {
console.log('error', error)
}
}
return (
<div className="App">
<div><input value={firstName} type="text" onChange={e => setFirstName(e.target.value)}/></div>
<div><button onClick={onAddUserClicked}>Add User</button></div>
<div>{userList.map(user => <p key={user.first_name}>{user.first_name}</p>)}</div>
</div>
)
}
export default App;
const addUser = async (first_name) => {
let url = `${window.location.host}:3000/users`
console.log('url', url)
return axios.post(url, { first_name })
}
@@ -1,9 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div);
});
@@ -1,13 +0,0 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}
@@ -1,12 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 170.96 159.93"><defs><style>.cls-1{fill:#09d3ac;}</style></defs><path class="cls-1" d="M141.35,73.27c0-6.89-8.11-13-20.58-16.73,3-12.67,1.69-22.75-4.28-26.16a9.55,9.55,0,0,0-4.79-1.2c-5.57,0-12.61,3.89-19.72,10.62-7.11-6.68-14.13-10.55-19.69-10.55a9.46,9.46,0,0,0-4.86,1.22c-5.94,3.42-7.17,13.44-4.21,26.05-12.41,3.71-20.48,9.77-20.5,16.63s8.12,13,20.59,16.72c-3,12.68-1.7,22.75,4.28,26.16a9.41,9.41,0,0,0,4.78,1.2c5.58,0,12.62-3.89,19.73-10.62,7.1,6.68,14.12,10.55,19.69,10.55a9.59,9.59,0,0,0,4.86-1.22c5.94-3.42,7.16-13.44,4.21-26C133.27,86.18,141.34,80.12,141.35,73.27ZM96.56,42.06c8.19-7.33,13.31-8.12,15.13-8.12h0a4.71,4.71,0,0,1,2.42.58c2.86,1.63,4,7.38,3.09,15a56.73,56.73,0,0,1-1,5.79,97.7,97.7,0,0,0-12.58-2.07,98.47,98.47,0,0,0-8.24-10.08C95.75,42.79,96.15,42.42,96.56,42.06ZM71.77,78.94c.78,1.5,1.61,3,2.47,4.51S76,86.49,77,88c-2.71-.39-5.34-.88-7.84-1.46C69.86,84,70.75,81.5,71.77,78.94ZM69,59.9c2.53-.59,5.18-1.08,7.93-1.46-1,1.48-1.86,3-2.76,4.59s-1.69,3-2.46,4.52Q70.18,63.65,69,59.9Zm5.21,13.34q1.86-3.93,4.09-7.86c1.5-2.62,3.11-5.17,4.77-7.61,2.91-.22,5.91-.34,9-.33s6,.12,8.89.35c1.66,2.42,3.25,5,4.75,7.55s2.88,5.22,4.12,7.83c-1.23,2.62-2.6,5.25-4.08,7.85s-3.11,5.18-4.77,7.62c-2.91.23-5.91.34-9,.34s-6-.13-8.89-.36c-1.66-2.42-3.26-4.94-4.76-7.55S75.5,75.85,74.25,73.24Zm32.86-14.77c2.72.38,5.35.87,7.84,1.45-.74,2.47-1.62,5-2.64,7.55-.79-1.5-1.61-3-2.48-4.51S108,59.93,107.11,58.47Zm2.76,24.92q1.29-2.27,2.46-4.53c1,2.6,2,5.16,2.7,7.66-2.52.59-5.17,1.07-7.92,1.45Q108.52,85.75,109.87,83.39ZM92,46.56c1.8,1.92,3.57,4,5.3,6.23-1.71-.07-3.46-.12-5.23-.12s-3.58,0-5.33.12C88.45,50.57,90.2,48.48,92,46.56Zm-22.18-12A4.82,4.82,0,0,1,72.29,34a13.11,13.11,0,0,1,5.19,1.31,39.07,39.07,0,0,1,10,6.78l1.17,1.07a98.49,98.49,0,0,0-8.16,10,98.88,98.88,0,0,0-12.65,2.06c-.44-1.94-.8-3.84-1-5.67C65.8,42,67,36.24,69.81,34.6ZM64.53,85.26a58.75,58.75,0,0,1-5.54-2c-7.1-3-11.5-6.85-11.5-10.14S51.91,66,59,63.05a57.63,57.63,0,0,1,5.44-1.94A97.93,97.93,0,0,0,69,73.25,98.72,98.72,0,0,0,64.53,85.26Zm23,19.1c-8.19,7.33-13.31,8.11-15.14,8.11a4.69,4.69,0,0,1-2.42-.58c-2.86-1.63-4-7.38-3.09-15a56.07,56.07,0,0,1,1-5.78,99.51,99.51,0,0,0,12.58,2.06,97.17,97.17,0,0,0,8.24,10.08Zm4.57-4.51c-1.8-1.92-3.57-4-5.31-6.23,1.72.08,3.47.12,5.24.12s3.58,0,5.33-.11C95.63,95.85,93.87,97.93,92.09,99.85Zm22.18,12a4.82,4.82,0,0,1-2.48.59c-1.82,0-7-.8-15.16-8.1l-1.17-1.07a98.44,98.44,0,0,0,8.15-10,97,97,0,0,0,12.66-2.06c.44,1.94.79,3.84,1,5.67C118.27,104.42,117.12,110.18,114.27,111.81Zm10.8-28.44c-1.71.7-3.52,1.35-5.44,1.93a98.54,98.54,0,0,0-4.57-12.14,98.1,98.1,0,0,0,4.49-12,58.75,58.75,0,0,1,5.54,2c7.09,3,11.5,6.85,11.49,10.14S132.17,80.42,125.07,83.37ZM92,82.39a9.18,9.18,0,1,0-9.17-9.19A9.17,9.17,0,0,0,92,82.39ZM31,17.88V128.53H153.07V17.88ZM148.3,123.77H35.78V22.65H148.3Zm-85-33.9c-3,12.68-1.7,22.75,4.28,26.16a9.41,9.41,0,0,0,4.78,1.2c5.58,0,12.62-3.89,19.73-10.62,7.1,6.68,14.12,10.55,19.69,10.55a9.59,9.59,0,0,0,4.86-1.22c5.94-3.42,7.16-13.44,4.21-26,12.41-3.72,20.48-9.78,20.49-16.63s-8.11-13-20.58-16.73c3-12.67,1.69-22.75-4.28-26.16a9.55,9.55,0,0,0-4.79-1.2c-5.57,0-12.61,3.89-19.72,10.62-7.11-6.68-14.13-10.55-19.69-10.55a9.46,9.46,0,0,0-4.86,1.22c-5.94,3.42-7.17,13.44-4.21,26.05-12.41,3.71-20.48,9.77-20.5,16.63S50.84,86.13,63.31,89.87Zm24.21,14.49c-8.19,7.33-13.31,8.11-15.14,8.11a4.69,4.69,0,0,1-2.42-.58c-2.86-1.63-4-7.38-3.09-15a56.07,56.07,0,0,1,1-5.78,99.51,99.51,0,0,0,12.58,2.06,97.17,97.17,0,0,0,8.24,10.08Zm24.79-36.89c-.79-1.5-1.61-3-2.48-4.51s-1.8-3-2.72-4.49c2.72.38,5.35.87,7.84,1.45C114.21,62.39,113.33,64.92,112.31,67.47Zm2.72,19c-2.52.59-5.17,1.07-7.92,1.45q1.41-2.22,2.76-4.58t2.46-4.53C113.37,81.46,114.28,84,115,86.52Zm-5.21-13.35c-1.23,2.62-2.6,5.25-4.08,7.85s-3.11,5.18-4.77,7.62c-2.91.23-5.91.34-9,.34s-6-.13-8.89-.36c-1.66-2.42-3.26-4.94-4.76-7.55s-2.87-5.22-4.12-7.83q1.86-3.93,4.09-7.86c1.5-2.62,3.11-5.17,4.77-7.61,2.91-.22,5.91-.34,9-.33s6,.12,8.89.35c1.66,2.42,3.25,5,4.75,7.55S108.58,70.56,109.82,73.17ZM77,88c-2.71-.39-5.34-.88-7.84-1.46.74-2.46,1.63-5,2.65-7.55.78,1.5,1.61,3,2.47,4.51S76,86.49,77,88ZM74.21,63c-.87,1.5-1.69,3-2.46,4.52Q70.18,63.65,69,59.9c2.53-.59,5.18-1.08,7.93-1.46C76,59.92,75.11,61.45,74.21,63ZM92.09,99.85c-1.8-1.92-3.57-4-5.31-6.23,1.72.08,3.47.12,5.24.12s3.58,0,5.33-.11C95.63,95.85,93.87,97.93,92.09,99.85Zm22.18,12a4.82,4.82,0,0,1-2.48.59c-1.82,0-7-.8-15.16-8.1l-1.17-1.07a98.44,98.44,0,0,0,8.15-10,97,97,0,0,0,12.66-2.06c.44,1.94.79,3.84,1,5.67C118.27,104.42,117.12,110.18,114.27,111.81Zm5.28-50.66a58.75,58.75,0,0,1,5.54,2c7.09,3,11.5,6.85,11.49,10.14s-4.41,7.16-11.51,10.11c-1.71.7-3.52,1.35-5.44,1.93a98.54,98.54,0,0,0-4.57-12.14A98.1,98.1,0,0,0,119.55,61.15Zm-23-19.09c8.19-7.33,13.31-8.12,15.13-8.12h0a4.71,4.71,0,0,1,2.42.58c2.86,1.63,4,7.38,3.09,15a56.73,56.73,0,0,1-1,5.79,97.7,97.7,0,0,0-12.58-2.07,98.47,98.47,0,0,0-8.24-10.08C95.75,42.79,96.15,42.42,96.56,42.06ZM92,46.56c1.8,1.92,3.57,4,5.3,6.23-1.71-.07-3.46-.12-5.23-.12s-3.58,0-5.33.12C88.45,50.57,90.2,48.48,92,46.56Line truncated

Before

Width:  |  Height:  |  Size: 8.0 KiB

@@ -1,135 +0,0 @@
// This optional code is used to register a service worker.
// register() is not called by default.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
// existing tabs open on the page have been closed, since previously cached
// resources are updated in the background.
// To learn more about the benefits of this model and instructions on how to
// opt-in, read https://bit.ly/CRA-PWA
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
export function register(config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://bit.ly/CRA-PWA'
);
});
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config);
}
});
}
}
function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl, config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
}
@@ -1,38 +0,0 @@
# docker-compose.yml
version: '3'
services:
app:
image: node:10.15.0
command: bash -c "npm install && npm start"
volumes:
- ./app:/usr/src/app
working_dir: /usr/src/app
depends_on:
- realtime
ports:
- "80:3000"
realtime:
image: supabase/realtime
ports:
- "4000:4000"
env_file: .env.sample
depends_on:
- db
rest:
image: postgrest/postgrest
restart: always
ports:
- "3000:3000"
env_file: .env.sample
depends_on:
- db
db:
image: supabase/packaged
command: postgres -c wal_level=logical # Start with streaming enabled
ports:
- "6543:5432" # Use 6543 to avoid host port collisions
env_file: .env.sample
volumes:
- ./schema:/docker-entrypoint-initdb.d
-3
View File
@@ -1,3 +0,0 @@
{
"lockfileVersion": 1
}
@@ -1,8 +0,0 @@
-- Create a table of users
create table "public"."quotes" (
"id" bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
"first_name" text null,
"last_name" text null,
"inserted_at" timestamp without time zone not null default(now() at time zone 'utc'),
"updated_at" timestamp without time zone not null default (now() at time zone 'utc')
);
+1
View File
@@ -0,0 +1 @@
@todo
-39
View File
@@ -1,39 +0,0 @@
{
"name": "supabase-monorepo",
"private": true,
"description": "Supabase Monorepo",
"repository": "https://github.com/supabase/monorepo",
"workspaces": {
"packages": [
"packages/*"
],
"nohoist": [
"**/bulma",
"**/bulma/**"
]
},
"engines": {
"node": ">=10.13.0",
"yarn": "1.x"
},
"scripts": {
"build": "yarn run build:web",
"build:web": "yarn workspace @supabase/web build",
"deploy:web": "yarn workspace @supabase/web deploy",
"deploy:realtime-js": "yarn workspace @supabase/realtime-js deploy",
"dev": "concurrently --kill-others-on-fail \"yarn dev:web\" ",
"dev:web": "yarn workspace @supabase/web dev",
"test:pg-admin-js": "yarn workspace @supabase/pg-admin-js test",
"test:realtime-js": "yarn workspace @supabase/realtime-js test"
},
"dependencies": {
"concurrently": "^5.0.0"
},
"devDependencies": {
"now": "^16.3.1",
"prettier": "^1.18.2",
"esm": "3.2.25",
"jsdoc-test": "0.0.10",
"mocha": "6.2.2"
}
}
-8
View File
@@ -1,8 +0,0 @@
# RealtimeJS
Realtime PostgreSQL.
## Docs
View online at [https://supabase.io/docs/-/about](https://supabase.io/docs/-/about).
-25
View File
@@ -1,25 +0,0 @@
{
"name": "@supabase/pg-admin-js",
"version": "0.1.0",
"description": "Manage your PG Database.",
"repository": "https://github.com/supabase/monorepo",
"main": "src/index.js",
"scripts": {
"deploy": "npm version patch; npm publish --access=public",
"test": "mocha --require esm \"test/**/*_spec.js\""
},
"keywords": [
"supabase",
"postgresql",
"postgres"
],
"author": "@kiwicopple",
"license": "Apache-2.0",
"publishConfig": {
"registry": "https://registry.npmjs.org/"
},
"dependencies": {
"knex": "^0.20.1",
"pg": "^7.4.3"
}
}
-50
View File
@@ -1,50 +0,0 @@
import * as constants from '../utils/constants.js'
import * as postgres from '../utils/postgres.js'
var fs = require('fs')
var path = require('path')
var getAllSql = fs.readFileSync(path.join(__dirname, '../sql/getAllConfig.sql')).toString()
/**
* Gets all the config for a
* @param {Object} config The database config
* @param {string} config.host
* @param {string} config.user
* @param {string} config.password
* @param {string} config.database
* @param {number} config.port
* @param {Object} options
* @param {string} options.schema
*
* @example
* await getAll()
* //=>
* [
* {
* name: 'autovacuum',
* setting: 'on',
* unit: null,
* category: 'Autovacuum',
* short_desc: 'Starts the autovacuum subprocess.',
* extra_desc: null,
* context: 'sighup',
* vartype: 'bool',
* source: 'default',
* min_val: null,
* max_val: null,
* enumvals: null,
* boot_val: 'on',
* reset_val: 'on',
* sourcefile: null,
* sourceline: null,
* pending_restart: false
* }
* ]
*/
export const getAll = async (config = {}) => {
const dbConfig = { ...constants.POSTGRES_CONFIG, ...config }
const conn = await postgres.connect(dbConfig)
const results = await postgres.runQuery(conn, getAllSql)
postgres.disconnect(conn)
return results.rows
}
-31
View File
@@ -1,31 +0,0 @@
import * as constants from '../utils/constants.js'
import * as postgres from '../utils/postgres.js'
var fs = require('fs')
var path = require('path')
var getAllSql = fs.readFileSync(path.join(__dirname, '../sql/getAllPLugins.sql')).toString()
/**
* Queries a given schema for all the tables
* @param {Object} config The database config
* @param {Object} config The database config
* @param {string} config.host
* @param {string} config.user
* @param {string} config.password
* @param {string} config.database
* @param {number} config.port
*
* @example
* await getAll()
* //=>
* [
* { name: 'plpgsql', version: '1.0', schema: 'pg_catalog', description: 'PL/pgSQL procedural language' }
* ]
*/
export const getAll = async (config = {}, options = {}) => {
const dbConfig = { ...constants.POSTGRES_CONFIG, ...config }
const conn = await postgres.connect(dbConfig)
const results = await postgres.runQuery(conn, getAllSql)
postgres.disconnect(conn)
return results.rows
}
-33
View File
@@ -1,33 +0,0 @@
import * as constants from '../utils/constants.js'
import * as postgres from '../utils/postgres.js'
var fs = require('fs')
var path = require('path')
var getAllSql = fs.readFileSync(path.join(__dirname, '../sql/getAllTables.sql')).toString()
/**
* Queries a given schema for all the tables
* @param {Object} config The database config
* @param {string} config.host
* @param {string} config.user
* @param {string} config.password
* @param {string} config.database
* @param {number} config.port
* @param {Object} options
* @param {string} options.schema The database schema containing the tables. Defaults to 'public'
*
* @example
* await getAll()
* //=>
* [
* { table_schema: 'public', table_name: 'users' }
* ]
*/
export const getAll = async (config = {}, options = {}) => {
const dbConfig = { ...constants.POSTGRES_CONFIG, ...config }
const schema = options.schema || constants.DEFAULT_SCHEMA
const conn = await postgres.connect(dbConfig)
const results = await postgres.runQuery(conn, getAllSql, [schema])
postgres.disconnect(conn)
return results.rows
}
-32
View File
@@ -1,32 +0,0 @@
import * as constants from '../utils/constants.js'
import * as postgres from '../utils/postgres.js'
var fs = require('fs')
var path = require('path')
var getAllSql = fs.readFileSync(path.join(__dirname, '../sql/getAllTypes.sql')).toString()
/**
* Queries a given schema for all the tables
* @param {Object} config The database config
* @param {Object} config The database config
* @param {string} config.host
* @param {string} config.user
* @param {string} config.password
* @param {string} config.database
* @param {number} config.port
*
* @example
* await getAll()
* //=>
* [
* { name: 'boolean', internal_name: 'bool', size: '1', enums: '{}', description: 'boolean, \'true\'/\'false\'' },
* { name: 'smallint', internal_name: 'int2', size: '2', enums: '{}', description: '-32 thousand to 32 thousand, 2-byte storage' }
* ]
*/
export const getAll = async (config = {}, options = {}) => {
const dbConfig = { ...constants.POSTGRES_CONFIG, ...config }
const conn = await postgres.connect(dbConfig)
const results = await postgres.runQuery(conn, getAllSql)
postgres.disconnect(conn)
return results.rows
}
-42
View File
@@ -1,42 +0,0 @@
import * as constants from '../utils/constants.js'
import * as postgres from '../utils/postgres.js'
var fs = require('fs')
var path = require('path')
var getAllSql = fs.readFileSync(path.join(__dirname, '../sql/getAllViews.sql')).toString()
/**
* Queries a given schema for all the tables
* @param {Object} config The database config
* @param {string} config.host
* @param {string} config.user
* @param {string} config.password
* @param {string} config.database
* @param {number} config.port
* @param {Object} options
* @param {string} options.schema The database schema containing the tables. Defaults to 'public'
*
* @example
* await getAll()
* //=>
* [
* {
* table_schema: 'information_schema',
* table_name: 'attributes',
* check_option: 'NONE',
* is_updatable: 'NO',
* is_insertable_into: 'NO',
* is_trigger_updatable: 'NO',
* is_trigger_deletable: 'NO',
* is_trigger_insertable_into: 'NO',
* }
* ]
*/
export const getAll = async (config = {}, options = {}) => {
const dbConfig = { ...constants.POSTGRES_CONFIG, ...config }
const schema = options.schema || constants.DEFAULT_SCHEMA
const conn = await postgres.connect(dbConfig)
const results = await postgres.runQuery(conn, getAllSql, [schema])
postgres.disconnect(conn)
return results.rows
}
-3
View File
@@ -1,3 +0,0 @@
import * as tables from './api/tables'
export { tables }
@@ -1,13 +0,0 @@
select
table_schema,
table_name,
column_name,
column_default,
is_nullable::boolean,
data_type,
udt_name as format,
col_description((table_schema || '."' || table_name || '"')::regclass, ordinal_position)
from information_schema.columns
where table_schema = ?
order by table_schema, table_name, ordinal_position
@@ -1,22 +0,0 @@
SELECT
name,
setting,
unit,
category,
short_desc,
extra_desc,
context,
vartype,
source,
min_val,
max_val,
enumvals,
boot_val,
reset_val,
sourcefile,
sourceline,
pending_restart
FROM pg_settings
ORDER BY name;
@@ -1,26 +0,0 @@
select
coalesce(table_schema, referenced_schema) as table_schema,
coalesce(table_name, referenced_table) as table_name,
coalesce(column_name, referenced_column) as column_name,
constraint_schema,
constraint_name,
constraint_type,
check_clause,
referenced_schema,
referenced_table,
referenced_column
from information_schema.table_constraints
natural full join information_schema.key_column_usage
natural full join information_schema.check_constraints
inner join (
select
table_schema as referenced_schema,
table_name as referenced_table,
column_name as referenced_column,
constraint_name
from information_schema.constraint_column_usage
) as referenced_columns using (constraint_name)
where constraint_schema = ?
order by table_schema, table_name, ordinal_position
@@ -1,12 +0,0 @@
SELECT
tc.table_schema,
tc.constraint_name,
tc.table_name,
kcu.column_name,
ccu.table_schema AS foreign_table_schema,
ccu.table_name AS foreign_table_name,
ccu.column_name AS foreign_column_name
FROM information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu USING (constraint_schema, constraint_name)
JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name)
where tc.table_schema = ? and tc.constraint_type = 'FOREIGN KEY';
@@ -1,11 +0,0 @@
SELECT
e.extname AS "name",
e.extversion AS "version",
n.nspname AS "schema",
c.description AS "description"
FROM
pg_catalog.pg_extension e
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace
LEFT JOIN pg_catalog.pg_description c ON c.objoid = e.oid AND c.classoid = 'pg_catalog.pg_extension'::pg_catalog.regclass
ORDER BY 1;
@@ -1,16 +0,0 @@
select
table_schema,
table_name,
column_name,
sequence_name,
start_value,
minimum_value,
increment
from information_schema.columns
inner join information_schema.sequences on (
table_schema = sequence_schema and
pg_get_serial_sequence(table_schema || '."' || table_name || '"', column_name) = sequence_schema || '.' || sequence_name
)
where sequence_schema = ?
order by table_schema, table_name, ordinal_position
@@ -1,7 +0,0 @@
select
table_schema,
table_name
from information_schema.tables
where table_schema = ? and table_type = 'BASE TABLE'
order by table_schema, table_name;
@@ -1,30 +0,0 @@
SELECT
pg_catalog.Format_type ( t.oid, NULL ) AS name,
t.typname AS internal_name,
CASE
WHEN t.typrelid != 0 THEN Cast ( 'tuple' AS pg_catalog.TEXT )
WHEN t.typlen < 0 THEN Cast ( 'var' AS pg_catalog.TEXT )
ELSE Cast ( t.typlen AS pg_catalog.TEXT )
END AS size,
array (
select e.enumlabel
FROM pg_catalog.pg_enum e
WHERE e.enumtypid = t.oid
ORDER BY e.oid
) AS enums,
pg_catalog.obj_description ( t.oid, 'pg_type' ) AS description
FROM pg_catalog.pg_type t LEFT JOIN pg_catalog.pg_namespace n
ON n.oid = t.typnamespace
WHERE (
t.typrelid = 0
OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid )
)
and NOT EXISTS (
SELECT 1
FROM pg_catalog.pg_type el
WHERE el.oid = t.typelem AND el.typarray = t.oid
)
-- AND n.nspname = ?
-- AND n.nspname not in ('information_schema', 'pg_catalog')
AND pg_catalog.pg_type_is_visible ( t.oid )
ORDER BY 1, 2;
@@ -1,13 +0,0 @@
select
table_schema,
table_name,
check_option,
is_updatable,
is_insertable_into,
is_trigger_updatable,
is_trigger_deletable,
is_trigger_insertable_into
from information_schema.views
where table_schema = ?
-- and table_schema not in ('information_schema', 'pg_catalog')
@@ -1,13 +0,0 @@
export const POSTGRES_HOST = 'localhost'
export const POSTGRES_USER = 'postgres'
export const POSTGRES_PASSWORD = 'postgres'
export const POSTGRES_DATABASE = 'postgres'
export const POSTGRES_PORT = 5432
export const DEFAULT_SCHEMA = 'public'
export const POSTGRES_CONFIG = {
host: POSTGRES_HOST,
user: POSTGRES_USER,
password: POSTGRES_PASSWORD,
database: POSTGRES_DATABASE,
port: POSTGRES_PORT,
}
@@ -1,20 +0,0 @@
import knex from 'knex'
export function connect(config) {
return knex({ client: 'pg', connection: config })
}
export async function disconnect(conn) {
let cb = () => { return true }
conn.destroy(cb)
}
/**
* Executes a SQL string against the database
* @param conn an open Knex connection
* @param {string} query The SQL query
* @param {sting[]} params An optional array of paramaters to feed into the query
*/
export function runQuery(conn, query, params = {}) {
return conn.raw(query, params)
}
-5
View File
@@ -1,5 +0,0 @@
import assert from 'assert'
export function compareKeys (first, second) {
Object.keys(first).map(key => assert(Object.keys(second).includes(key)))
}
-35
View File
@@ -1,35 +0,0 @@
import assert from 'assert'
import * as config from '../src/api/config.js'
import { compareKeys } from './_helpers'
describe('Config', function() {
it('getAll() should return all settings', async () => {
let res = await config.getAll()
// Check that we have a result
assert(Array.isArray(res))
// Compare one of the values
const valid = {
name: 'autovacuum',
setting: 'on',
unit: null,
category: 'Autovacuum',
short_desc: 'Starts the autovacuum subprocess.',
extra_desc: null,
context: 'sighup',
vartype: 'bool',
source: 'default',
min_val: null,
max_val: null,
enumvals: null,
boot_val: 'on',
reset_val: 'on',
sourcefile: null,
sourceline: null,
pending_restart: false,
}
const compare = res.find(setting => setting.name === valid.name)
compareKeys(valid, compare)
})
})
@@ -1,7 +0,0 @@
// See https://github.com/supabase/monorepo/issues/3
// import doctest from 'jsdoc-test'
// describe('Run doctests', () => {
// doctest('src/api/tables.js')
// })
-22
View File
@@ -1,22 +0,0 @@
import assert from 'assert'
import * as types from '../src/api/plugins'
import { compareKeys } from './_helpers'
describe('Plugins', function() {
it('getAll() should return an array of tables', async () => {
let res = await types.getAll('public')
// Check that we have a result
assert(Array.isArray(res))
// Compare one of the values
const valid = {
name: 'plpgsql',
version: '1.0',
schema: 'pg_catalog',
description: 'PL/pgSQL procedural language',
}
const compare = res.find(setting => setting.name === valid.name)
compareKeys(valid, compare)
})
})
-11
View File
@@ -1,11 +0,0 @@
import assert from 'assert'
import * as tables from '../src/api/tables.js'
describe('Tables', function() {
it('getAll() should return an array of tables', async () => {
let res = await tables.getAll()
// Check that we have a result
assert(Array.isArray(res))
})
})
-23
View File
@@ -1,23 +0,0 @@
import assert from 'assert'
import * as types from '../src/api/types.js'
import { compareKeys } from './_helpers'
describe('Types', function() {
it('getAll() should return an array of tables', async () => {
let res = await types.getAll('public')
// Check that we have a result
assert(Array.isArray(res))
// Compare one of the values
const valid = {
name: 'smallint',
internal_name: 'int2',
size: '2',
enums: '{}',
description: '-32 thousand to 32 thousand, 2-byte storage',
}
const compare = res.find(setting => setting.name === valid.name)
compareKeys(valid, compare)
})
})
-26
View File
@@ -1,26 +0,0 @@
import assert from 'assert'
import * as views from '../src/api/views.js'
import { compareKeys } from './_helpers'
describe('Views', function() {
it('getAll() should return an array of tables', async () => {
let res = await views.getAll({}, { schema: 'information_schema' })
// Check that we have a result
assert(Array.isArray(res))
// Compare one of the values
const valid = {
table_schema: 'information_schema',
table_name: 'attributes',
check_option: 'NONE',
is_updatable: 'NO',
is_insertable_into: 'NO',
is_trigger_updatable: 'NO',
is_trigger_deletable: 'NO',
is_trigger_insertable_into: 'NO',
}
const compare = res.find(setting => setting.name === valid.name)
compareKeys(valid, compare)
})
})
-8
View File
@@ -1,8 +0,0 @@
# RealtimeJS
Realtime PostgreSQL.
## Docs
View online at [https://supabase.io/docs/-/about](https://supabase.io/docs/-/about).
-68
View File
@@ -1,68 +0,0 @@
{
"name": "@supabase/realtime-js",
"version": "0.1.4",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@types/node": {
"version": "12.12.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.6.tgz",
"integrity": "sha512-FjsYUPzEJdGXjwKqSpE0/9QEh6kzhTAeObA54rn6j3rR4C/mzpI9L0KNfoeASSPMMdxIsoJuCLDWcM/rVjIsSA=="
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"nan": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
},
"phoenix-channels": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/phoenix-channels/-/phoenix-channels-1.0.0.tgz",
"integrity": "sha1-TeOno0J0g97/xJCNj+yscl2wbWo=",
"requires": {
"websocket": "^1.0.24"
}
},
"typedarray-to-buffer": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
"integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
"requires": {
"is-typedarray": "^1.0.0"
}
},
"websocket": {
"version": "1.0.30",
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.30.tgz",
"integrity": "sha512-aO6klgaTdSMkhfl5VVJzD5fm+Srhh5jLYbS15+OiI1sN6h/RU/XW6WN9J1uVIpUKNmsTvT3Hs35XAFjn9NMfOw==",
"requires": {
"debug": "^2.2.0",
"nan": "^2.14.0",
"typedarray-to-buffer": "^3.1.5",
"yaeti": "^0.0.6"
}
},
"yaeti": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
"integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc="
}
}
}
-24
View File
@@ -1,24 +0,0 @@
{
"name": "@supabase/realtime-js",
"version": "0.1.4",
"description": "Listen to realtime updates to your PostgreSQL database.",
"repository": "https://github.com/supabase/monorepo",
"main": "src/index.js",
"scripts": {
"deploy": "npm version patch; npm publish --access=public",
"test": "mocha --require esm \"test/**/*_spec.js\""
},
"keywords": [
"supabase",
"realtime"
],
"author": "@kiwicopple",
"license": "Apache-2.0",
"publishConfig": {
"registry": "https://registry.npmjs.org/"
},
"dependencies": {
"@types/node": "^12.6.8",
"phoenix-channels": "^1.0.0"
}
}
-86
View File
@@ -1,86 +0,0 @@
import { Socket } from 'phoenix-channels'
export default class Realtime {
constructor(apiSocket){
this.socket = new Socket(apiSocket)
this.channel = this.socket.channel('realtime')
this.listeners = []
this.socket.onOpen(() => {
console.log('Socket connected')
})
this.socket.onClose(() => {
console.log('Socket disconnected')
})
}
/**
* Starts socket and all of its channels/ listeners
*
* @param {Array} listeners
* @param {Object} listeners[n]
* @param {String} listener.channel The name of channel
* @param {Function} listener.callback The callback function to fire when the channel receives a change
*/
start(listeners) {
this.socket.connect()
if (this.channel.state !== 'joined'){
this.channel
.join()
.receive('ok', resp => console.log('Joined Realtime successfully', resp))
.receive('error', resp => console.log('Unable to join', resp))
.receive('timeout', () => console.log('Networking issue. Still waiting...'))
listeners.forEach( listener => {
this.addListener(listener)
})
}
}
/**
* Stops socket and all of its channels/ listeners
*/
stop(){
this.listeners.forEach(({ channel, callback }) => {
this.channel.off(channel, callback)
})
this.socket.disconnect()
}
/**
* Adds a listener to the socket and activates it
*
* @param {Object} listener
* @param {String} listener.channel The name of channel
* @param {Function} listener.callback The callback function to fire when the channel receives a change
*
* @example
* addListener({channel: 'shout', callback: () => {}})
*/
addListener(listener){
this.listeners.push(listener)
let { channel, callback } = listener
this.channel.on(channel, callback)
}
/**
* Takes in String channel to:
* 1. turn channel off
* 2. remove specific listener from this.listener
*
* @param {String} channel
*
* @example
* removeListener('shout')
*/
removeListener(channel){
this.channel.off(channel)
let updatedListeners = this.listeners.filter(listener => {
let channelName = listener.channel
return channelName !== channel
})
this.listeners = updatedListeners
}
}
-7
View File
@@ -1,7 +0,0 @@
import * as mapper from './mapper'
import Realtime from './Realtime'
export {
mapper,
Realtime
}
-214
View File
@@ -1,214 +0,0 @@
// # Lifted from epgsql (src/epgsql_binary.erl), this module licensed under
// # 3-clause BSD found here: https://raw.githubusercontent.com/epgsql/epgsql/devel/LICENSE
//
// {:bool, 16, 1000},
// {:bpchar, 1042, 1014},
// {:bytea, 17, 1001},
// {:char, 18, 1002},
// {:cidr, 650, 651},
// {:date, 1082, 1182},
// {:daterange, 3912, 3913},
// {:float4, 700, 1021},
// {:float8, 701, 1022},
// {:geometry, 17063, 17071},
// {:hstore, 16935, 16940},
// {:inet, 869, 1041},
// {:int2, 21, 1005},
// {:int4, 23, 1007},
// {:int4range, 3904, 3905},
// {:int8, 20, 1016},
// {:int8range, 3926, 3927},
// {:interval, 1186, 1187},
// {:json, 114, 199},
// {:jsonb, 3802, 3807},
// {:macaddr, 829, 1040},
// {:macaddr8, 774, 775},
// {:point, 600, 1017},
// {:text, 25, 1009},
// {:time, 1083, 1183},
// {:timestamp, 1114, 1115},
// {:timestamptz, 1184, 1185},
// {:timetz, 1266, 1270},
// {:tsrange, 3908, 3909},
// {:tstzrange, 3910, 3911},
// {:uuid, 2950, 2951},
// {:varchar, 1043, 1015}
/**
* Takes an array of columns and an object of string values then converts each string value
* to its mapped type
* @param {{name: String, type: String}[]} columns
* @param {Object} records
* @param {Object} options The map of various options that can be applied to the mapper
* @param {Array} options.skipTypes The array of types that should not be converted
*
* @example
* convertChangeData([{name: 'first_name', type: 'text'}, {name: 'age', type: 'int4'}], {'Paul', '33'}, {})
* //=>
* { first_name: 'Paul', age: 33 }
*/
export const convertChangeData = (columns, records, options = {}) => {
let result = {}
let skipTypes = typeof options.skipTypes !== 'undefined' ? options.skipTypes : []
Object.entries(records).map(([key, value]) => {
result[key] = convertColumn(key, columns, records, skipTypes)
})
return result
}
/**
* Converts the value of an individual column
* @param {String} columnName The column that you want to convert
* @param {{name: String, type: String}[]} columns All of the columns
* @param {Object} records The map of string values
* @param {Array} skipTypes An array of types that should not be converted
* @return {object} Useless information
*
* @example
* convertColumn('age', [{name: 'first_name', type: 'text'}, {name: 'age', type: 'int4'}], ['Paul', '33'], [])
* //=>
* 33
*
* @example
* convertColumn('age', [{name: 'first_name', type: 'text'}, {name: 'age', type: 'int4'}], ['Paul', '33'], ['int4'])
* //=>
* "33"
*/
export const convertColumn = (columnName, columns, records, skipTypes) => {
let column = columns.find(x => x.name == columnName)
if(skipTypes.includes(column.type)) return noop(records[columnName])
else return convertCell(column.type, records[columnName])
}
/**
* If the value of the cell is `null`, returns null.
* Otherwise converts the string value to the correct type.
* @param {String} type A postgres column type
* @param {String} stringValue The cell value
*
* @example
* convertCell('bool', 'true')
* //=>
* true
*
* @example
* convertCell('int8', '10')
* //=>
* 10
*/
export const convertCell = (type, stringValue) => {
try {
if (stringValue === null) return null
// If not null, convert to correct type.
switch (type) {
case 'bool':
return toBoolean(stringValue)
case 'bpchar':
return noop(stringValue)
case 'bytea':
return noop(stringValue)
case 'char':
return noop(stringValue)
case 'cidr':
return noop(stringValue)
case 'date':
return toDate(stringValue)
case 'daterange':
return toDateRange(stringValue)
case 'float4':
return toFloat(stringValue)
case 'float8':
return toFloat(stringValue)
case 'geometry':
return noop(stringValue)
case 'hstore':
return noop(stringValue)
case 'inet':
return noop(stringValue)
case 'int2':
return toInt(stringValue)
case 'int4':
return toInt(stringValue)
case 'int4range':
return toIntRange(stringValue)
case 'int8':
return toInt(stringValue)
case 'int8range':
return toIntRange(stringValue)
case 'interval':
return noop(stringValue)
case 'json':
return toJson(stringValue)
case 'jsonb':
return toJson(stringValue)
case 'macaddr':
return noop(stringValue)
case 'macaddr8':
return noop(stringValue)
case 'point':
return noop(stringValue)
case 'text':
return noop(stringValue)
case 'time':
return noop(stringValue)
case 'timestamp':
return toDate(stringValue)
case 'timestamptz':
return toDate(stringValue)
case 'timetz':
return noop(stringValue)
case 'tsrange':
return noop(stringValue)
case 'tstzrange':
return noop(stringValue)
case 'uuid':
return noop(stringValue)
case 'varchar':
return noop(stringValue)
default:
// Unhandled and custom types will always return as strings
return noop(stringValue)
}
} catch (error) {
console.log(`Could not convert cell of type ${type} and value ${stringValue}`)
return stringValue
}
}
/**
* Passes back the raw string value
*/
const noop = stringValue => {
return stringValue
}
const toBoolean = stringValue => {
switch (stringValue) {
case 't':
return true
case 'f':
return false
default:
return null
}
}
const toDate = stringValue => {
return new Date(stringValue)
}
const toDateRange = stringValue => {
let arr = JSON.parse(stringValue)
return [new Date(arr[0]), new Date(arr[1])]
}
const toFloat = stringValue => {
return parseFloat(stringValue)
}
const toInt = stringValue => {
return parseInt(stringValue)
}
const toIntRange = stringValue => {
let arr = JSON.parse(stringValue)
return [parseInt(arr[0]), parseInt(arr[1])]
}
const toJson = stringValue => {
return JSON.parse(stringValue)
}
@@ -1,5 +0,0 @@
import doctest from 'jsdoc-test'
describe('Run doctests', () => {
doctest('src/mapper.js')
})
-10
View File
@@ -1,10 +0,0 @@
# Supabase
Landing page for [supabase.io](supabase.io).
## Deployment
This site is deployed as a STATIC site on Netlify. This means that pages must be listed in `next.config.js`. To update the site on Netlify, just push to `master`.
See the [NextJS](https://nextjs.org/learn/excel/static-html-export/exporting-other-pages) docs for more details.
-18
View File
@@ -1,18 +0,0 @@
module.exports = function(api) {
api.cache(true)
return {
presets: ['next/babel'],
plugins: [
['@babel/plugin-proposal-decorators', { legacy: true }],
[
'module-resolver',
{
root: ['./'],
alias: {
'~': '.',
},
},
],
],
}
}
-53
View File
@@ -1,53 +0,0 @@
import React, { useState, useEffect } from 'react'
import Link from 'next/link'
import SignUpForm from '~/components/SignUpForm'
import WidthWrapper from '~/components/WidthWrapper'
import {version} from '~/package.json'
export default function Footer({ isFullwidth }) {
return (
<footer className="footer p-b-md">
<WidthWrapper isFullwidth={isFullwidth}>
<div className="columns">
<div className="column">
<h3 className="title is-3 ">
<img src="/supabase-logo.svg" alt="Supabase" width="180" />
</h3>
<SignUpForm />
</div>
<div className="column is-3"></div>
<div className="column is-2">
<p className="heading">Products</p>
<p>
<Link href="/docs">
<a className="">Docs</a>
</Link>
</p>
</div>
<div className="column is-2">
<p className="heading">Company</p>
<p>
<a href="https://github.com/supabase/monorepo" target="_blank">
Github
</a>
</p>
</div>
</div>
<hr />
<div className="level">
<div className="level-left ">
<div className="level-item ">
<small className="has-text-weight-bold">© Supabase. v{version}</small>
</div>
</div>
<div className="level-right">
<div className="level-item">
<a className="is-size-7 m-r-md">Terms of Use</a>·
<a className="is-size-7 m-l-md">Privacy Policy</a>
</div>
</div>
</div>
</WidthWrapper>
</footer>
)
}
-9
View File
@@ -1,9 +0,0 @@
import React, { useState, useEffect } from 'react'
export default () => {
return (
<div style={{ textAlign: 'center', width: 800, padding: 100, margin: 'auto' }}>
We haven't come up with a cool loading component yet. Consider this this shittiest easter egg you've ever found.
</div>
)
}
-47
View File
@@ -1,47 +0,0 @@
import React, { useState, useEffect } from 'react'
import Link from 'next/link'
import WidthWrapper from '~/components/WidthWrapper'
export default function Navbar({ isFullwidth }) {
const [mobileActive, setMobileActive] = useState(false)
return (
<nav className="navbar" role="navigation" aria-label="main navigation">
<WidthWrapper isFullwidth={isFullwidth}>
<div className="navbar-brand">
<Link href="/">
<a className="navbar-item has-text-weight-bold">
<img src="/supabase-logo.svg" alt="Supabase" />
</a>
</Link>
<a
role="button"
className="navbar-burger burger"
aria-label="menu"
aria-expanded="false"
data-target="navbarBasicExample"
onClick={() => setMobileActive(!mobileActive)}
>
<span aria-hidden="true" />
<span aria-hidden="true" />
<span aria-hidden="true" />
</a>
</div>
<div id="navbarBasicExample" className={`navbar-menu ${mobileActive ? 'is-active' : ''}`}>
<div className="navbar-start"></div>
<div className="navbar-end p-r-sm">
<div className="navbar-item">
<Link href={`/docs/[category]/[slug]`} as={`/docs/-/about`}>
<a className="">Docs</a>
</Link>
</div>
</div>
</div>
</WidthWrapper>
</nav>
)
}
-49
View File
@@ -1,49 +0,0 @@
import React, { useState, useEffect } from 'react'
import Link from 'next/link'
import { useRouter } from 'next/router'
export default function Navbar({ }) {
const router = useRouter()
let { category } = router.query
return (
<nav className="tabs m-none">
<ul>
<li className={category == '-' ? 'is-active' : ''}>
<Link href={`/docs/[category]/[slug]`} as={`/docs/-/about`}>
<a className="">Supabase</a>
</Link>
</li>
<li className={category == 'packaged' ? 'is-active' : ''}>
<Link href={`/docs/[category]/[slug]`} as={`/docs/packaged/introduction`}>
<a className="">Packaged</a>
</Link>
</li>
<li className={category == 'admin-api' ? 'is-active' : ''}>
<Link href={`/docs/[category]/[slug]`} as={`/docs/admin-api/introduction`}>
<a className="">Admin API</a>
</Link>
</li>
<li className={category == 'realtime' ? 'is-active' : ''}>
<Link href={`/docs/[category]/[slug]`} as={`/docs/realtime/introduction`}>
<a className="">Realtime</a>
</Link>
</li>
<li className={category == 'restful' ? 'is-active' : ''}>
<Link href={`/docs/[category]/[slug]`} as={`/docs/restful/introduction`}>
<a className="">Restful</a>
</Link>
</li>
<li className={category == 'graphql' ? 'is-active' : ''}>
<Link href={`/docs/[category]/[slug]`} as={`/docs/graphql/introduction`}>
<a className="">GraphQL</a>
</Link>
</li>
<li className={category == 'baseless' ? 'is-active' : ''}>
<Link href={`/docs/[category]/[slug]`} as={`/docs/baseless/introduction`}>
<a className="">Baseless</a>
</Link>
</li>
</ul>
</nav>
)
}
-41
View File
@@ -1,41 +0,0 @@
import React, { useState, useEffect } from 'react'
export default function SignUpForm() {
const [email, setEmail] = useState('')
return (
<form
action="https://gmail.us5.list-manage.com/subscribe/post?u=c6785f4e1c9c77f231e367f6e&amp;id=18cccc8b62"
method="post"
id="mc-embedded-subscribe-form"
name="mc-embedded-subscribe-form"
className="field is-grouped"
target="_blank"
noValidate
>
<p className="control is-expanded">
<input
type="email"
value={email}
name="EMAIL"
className="input email"
id="mce-EMAIL"
placeholder="your@email.com"
onChange={e => setEmail(e.target.value)}
required
/>
</p>
<div style={{ position: 'absolute', left: '-5000px' }} aria-hidden="true">
<input type="text" name="b_c6785f4e1c9c77f231e367f6e_18cccc8b62" tabIndex="-1" />
</div>
<div className="control">
<input
type="submit"
value="Early Sign Up"
name="subscribe"
id="mc-embedded-subscribe"
className="button is-primary"
/>
</div>
</form>
)
}
-4
View File
@@ -1,4 +0,0 @@
export default function WidthWrapper({ isFullwidth, children }) {
if (!isFullwidth) return <div className="section container p-b-none p-t-none">{children}</div>
else return <>{children}</>
}
@@ -1,94 +0,0 @@
import '~/styles/style.scss'
import Navbar from '../Navbar'
import NavbarDocs from '../NavbarDocs'
import Footer from '../Footer'
import Head from 'next/head'
import Link from 'next/link'
import { useRouter } from 'next/router'
import React, { useState, useEffect } from 'react'
export default function DocsLayout(props) {
const [sidebarVisible, toggleSidebar] = useState(false)
const { sidebar } = props
return (
<>
<Head>
<title>Supabase | Docs</title>
</Head>
<div className="">
<Navbar isFullwidth={true} />
<NavbarDocs />
<div className="columns m-none is-gapless">
<div
className="DocsMenuColumn docs-subnav column is-narrow is-hidden-mobile"
style={{ width: 250 }}
>
{Sidebar(sidebar, () => toggleSidebar(false))}
</div>
<div className="column">{props.children}</div>
</div>
<Footer isFullwidth={true} />
<nav
className="navbar is-fixed-bottom has-background-dark is-hidden-tablet"
role="navigation"
aria-label="sub navigation"
>
<a className="navbar-brand" onClick={() => toggleSidebar(!sidebarVisible)}>
<div className="navbar-item">
<h5 className="title is-5">Menu</h5>
</div>
<span
role="button"
className={sidebarVisible ? 'navbar-burger is-active' : 'navbar-burger'}
aria-label="menu"
aria-expanded="false"
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</span>
</a>
<div className={sidebarVisible ? 'navbar-menu is-active' : 'navbar-menu'}>
<div className="navbar-end docs-subnav">
{Sidebar(sidebar, () => toggleSidebar(false))}
<div className="p-md">
<a className="button is-fullwidth" onClick={() => toggleSidebar(!sidebarVisible)}>
Hide
</a>
</div>
</div>
</div>
</nav>
</div>
</>
)
}
const Sidebar = (sidebar, onMenuItemClicked) => {
const router = useRouter()
let { category, slug } = router.query
return Object.entries(sidebar || []).map(([heading, pages]) => {
return (
<div key={heading}>
<p className="menu-label">{heading}</p>
<ul className="menu-list">
{pages.map(page => (
<li key={page.slug}>
<Link href={`/docs/[category]/[slug]`} as={`/docs/${category}/${page.slug}`}>
<a
className={slug == page.slug ? 'is-active' : ''}
onClick={() => onMenuItemClicked(page)}
>
{page.title}
</a>
</Link>
</li>
))}
</ul>
</div>
)
})
}
@@ -1,19 +0,0 @@
import '~/styles/style.scss'
import Navbar from '../Navbar'
import Footer from '../Footer'
import Head from 'next/head'
export default function MainLayout(props) {
return (
<>
<Head>
<title>Supabase</title>
</Head>
<div className="">
<Navbar />
{props.children}
<Footer />
</div>
</>
)
}
-5
View File
@@ -1,5 +0,0 @@
# Hello World
This is a sample blog post, using markdown.
I also has a [link to the homepage](/)
-25
View File
@@ -1,25 +0,0 @@
import Link from 'next/link'
export const metadata = {
title: 'Supabase',
description: 'Supercharge PostgreSQL.',
sidebarLabel: 'About'
}
### Single source of truth
This is the single source of truth for Supabase documentation and information.
We are a lean open-source company. To make things easier you you (and us) all documentation is in this single repository.
### Contributions
Like what we're doing and want to help? We'll go out of our way to help you help us.
Whether you're a first time open source contributor or a veteran, we'd love your [contribution.](/docs/-/contributing)
### In Production
Here are some companies that use Supabase in production.
- [Nimbus for Work](https://nimbusforwork.com)
- Want to add your company? Submit a PR.
@@ -1,16 +0,0 @@
export const metadata = {
title: 'Contributing',
description: 'Supabase Contribution Guidelines.'
}
### Want to contribute?
So ... we're even looking for contributions on our contributions guidelines.
Supabase is thinking in public. Everything is online, no matter how raw the current state.
We'll make this awesome, we promise. But if you can't wait then why not jump into our github and:
- submit an issue
- create a pull request
- try one of our products and give feedback
@@ -1,34 +0,0 @@
export const metadata = {
title: 'Admin API',
description: 'SQL is awesome, but sometimes not so awesome for beginners.',
sidebarLabel: 'Getting Started'
}
### Coming soon
We're busy making Realtime awesome right now, and we'll get around to this as soon as we can.
### What it is
Superbase Admin API is a RESTful interface for interacting with your database schema (listing tables, views, settings, etc).
### How it works
We took all the common SQL commands that we think you'd need, and we put a RESTful interface in front of them.
### What it isn't
It's not for interacting with your data - it for querying the schema (tables, views) and database (settings).
### Features
- 100% open source
- Built with JS, can be used on the client (web, mobile)
### Benefits
- Familiar
- Quick
- and Dirty
@@ -1,29 +0,0 @@
export const metadata = {
title: 'Schemas',
description:
'A database contains one or more named schemas, which in turn contain tables. Schemas also contain other kinds of named objects, including data types, functions, and operators.',
}
### Introduction
A database contains one or more named schemas, which in turn contain tables. Schemas also contain other kinds of named objects, including data types, functions, and operators.
Read more about schemas [here](https://www.postgresql.org/docs/current/ddl-schemas.html).
### GET
Request a list of schemas
```
curl \
https://fakeurl.com
```
### POST
Create a new schema
```
curl \
https://fakeurl.com
```
@@ -1,17 +0,0 @@
export const metadata = {
title: 'Tables',
description:
'Something about tables.',
}
### Introduction
Something about tables
### Request a list of tables
```
curl \
https://fakeurl.com
```
@@ -1,14 +0,0 @@
export const metadata = {
title: 'Baseless',
description: 'We\'re building a serverless PostgreSQL so you can get started in seconds. Export your database to a fully native PostgreSQL instance at any time.'
}
### Motivation
Relational databases are great but the set up can be cumbersome for quick prototyping and small products.
Additionally, even a small Postgres database can cost you $5/month.
We want to provide developers with the fastest and cheapest route to market using PostgreSQL.
### Coming soon
We're busy making Realtime awesome right now, and we'll get around to this as soon as we can.
@@ -1,8 +0,0 @@
export const metadata = {
title: 'GraphQL',
description: 'Extend your database with a fully functional GraphQL API, without a line of code.'
}
### Coming soon
We're busy making Realtime awesome right now, and we'll get around to this as soon as we can.
@@ -1,40 +0,0 @@
export const metadata = {
title: 'Packaged PostgreSQL',
description: 'PostgreSQL is easy, we\'re just making it slightly easier.',
sidebarLabel: 'Getting Started'
}
### Coming soon
We're busy making Realtime awesome right now, and we'll get around to this as soon as we can.
### What it is
Supabase Packaged is simply PostgreSQL, with all the common plugins you may need as well as a few bells-and-whistles we think you may need.
We wrap it all up to make it easy to deploy to various platforms.
### How it works
It's pretty simple, we just PostgreSQL and various other tools into packages for usage with:
- Containers: Docker & Kubernetes
- More coming soon
### What it isn't
It's not a replacement for your full production instance.
### Features
- 100% open source
- Restful Admin interface for interacting with your database schema (listing tables, views, settings, etc)
- Master replication enabled by default
- Plugins: PostGIS, TimescaleDb, wal2json
### Benefits
- Get up and running quickly
- Try out PostgreSQL plugins without having to go through painful installations
- Best practices implemented out-of-the-box
@@ -1,6 +0,0 @@
export const metadata = {
title: 'With Docker and NextJs',
description: 'A How-To guide for using Realtime with NextJs.'
}
> Draft
@@ -1,38 +0,0 @@
export const metadata = {
title: 'Realtime',
description: 'Listen to your database updates, inserts, and deletes over websockets.',
sidebarLabel: 'Overview'
}
### What it is
Supabase Realtime is an elixir server that allows you to listen to PostgreSQL inserts/updates/deletes over websockets.
### Where it is
All code is hosted at [https://github.com/supabase/realtime](https://github.com/supabase/realtime).
### How it works
Realtime listens to PostgreSQL's replication functionality and converts the byte stream into JSON. It then broadcasts the JSON over websockets.
It is built with [Phoenix](https://phoenixframework.org/), an Elixir framework that's incredibly scalable.
### What it isn't
- Supabase Realtime is a passive listen/broadcast system. You don't use it to make updates to your database.
- We don't (yet) intend to build client-side databases that can do all the offline conflict resolution that other services like Firebase provide.
### Features
- 100% open source under the Apache 2.0 License
- Accessible by mobile and web
- Works without wal2json :)
### Benefits
- You own your data. Realtime can be pointed at any PostgreSQL database that has replication enabled.
- Build chat apps and other systems that require realtime functionality.
- Listening to data changes on client side solves stale data problems and update collisions.
- Many systems that give you realtime functionality require you to update via the same interface that the listener is on. Supabase is source agnostic. Update your database from anywhere and you'll still get the changes.
- Scale the realtime servers without putting any additional load on your DB. All you need is one connection to your database, and you can handle thousands (or [millions](https://phoenixframework.org/blog/the-road-to-2-million-websocket-connections)) or users
@@ -1,37 +0,0 @@
export const metadata = {
title: 'Quick start',
description: 'From zero to Realtime in 5 minutes.'
}
> Draft
### Introduction
You can find the code for this @todo
## Running the server
The easiest way to use this is to set up a docker compose:
```yml
# docker-compose.yml
version: '3'
services:
realtime:
image: supabase/realtime
ports:
- "4000:4000"
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=db
- POSTGRES_HOST=localhost
- POSTGRES_PORT=5432
db:
image: supabase/packaged
ports:
- "5432:5432"
```
Once you are set up you can run `docker-compose up`
@@ -1,37 +0,0 @@
export const metadata = {
title: 'Realtime JS',
description: 'How to use the JS client.'
}
## Install
```bash
npm install --save @supabase/realtime-js
```
## Usage
#### Connect to the server
```js
import { Socket } = '@supabase/realtime-js'
var API_SOCKET = process.env.SOCKET_URL
var socket = new Socket(API_SOCKET)
var realtimeChannel = this.socket.channel('realtime')
socket.connect()
if (realtimeChannel.state !== 'joined') {
realtimeChannel
.join()
.receive('ok', resp => console.log('Joined successfully', resp))
.receive('error', resp => console.log('Unable to join', resp))
.receive('timeout', () => console.log('Networking issue. Still waiting...'))
// Listen to all changes in the database
realtimeChannel.on('shout', payload => {
console.log('Update received!', payload)
})
}
```
@@ -1,61 +0,0 @@
export const metadata = {
title: 'Realtime Server',
description: 'Guide for using the realtime server.'
}
## Database preparation
We have tried to keep the requirements to use this as simple as possible. However there are still *some* things that you need to enable on your Postgres database (namely, replication).
**1. Enable replication**
Make sure your database has replication turned on:
```bash
SHOW wal_level; # This should be "logical"
SHOW max_replication_slots; # You need at least one free slot for Supabase
```
**2. Listen to all table changes**
Create a publication for Supabase to listen to on all of your tables.
```bash
CREATE PUBLICATION supabase_realtime FOR ALL TABLES;
```
**3. (Optional) Receive old data**
If you want to receive the data the previous data (i.e. what the fields were *before* updates), then you need to set each table to have a full replica identity:
```bash
ALTER TABLE YOUR_TABLE_NAME replica identity full; # Change YOUR_TABLE_NAME
```
## Running the server
The easiest way to use this is to set up a docker compose:
```yml
# docker-compose.yml
version: '3'
services:
realtime:
image: supabase/realtime
ports:
- "4000:4000"
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=postgres
- POSTGRES_HOST=localhost
- POSTGRES_PORT=5432
```
Once you are set up you can run `docker-compose up`
## Next steps
Now that your server is running you can connect to it via one of the client libraries
@@ -1,9 +0,0 @@
export const metadata = {
title: 'Restful',
description: 'Add a fully documented Restful API, simply by introspecting the schema.',
sidebarLabel: 'Getting Started'
}
### Coming soon
We're busy making Realtime awesome right now, and we'll get around to this as soon as we can.
-37
View File
@@ -1,37 +0,0 @@
const withPlugins = require('next-compose-plugins')
// Next Config
const nextConfig = {
experimental: { publicDirectory: true },
}
// CSS
const withCSS = require('@zeit/next-css')
const withCssConfig = {}
// SASS
const withSass = require('@zeit/next-sass')
const withSassConfig = {
sassLoaderOptions: {
includePaths: ['./', 'absolute/path/b'],
},
}
// Markdown
const rehypePrism = require('@mapbox/rehype-prism')
const withMDX = require('@zeit/next-mdx')({
extension: /\.(md|mdx)?$/,
options: {
rehypePlugins: [rehypePrism],
},
})
const withMdxConfig = {}
module.exports = withPlugins(
[
[withCSS, withCssConfig],
[withSass, withSassConfig],
[withMDX, withMdxConfig],
],
nextConfig
)
-5
View File
@@ -1,5 +0,0 @@
{
"name": "supabase",
"version": 2,
"scope": "supabase"
}
-31
View File
@@ -1,31 +0,0 @@
{
"name": "@supabase/web",
"version": "0.1.25",
"description": "Supabase Main Website",
"scripts": {
"build": "next build",
"deploy": "yarn version && now --prod",
"dev": "next",
"export": "next export",
"start": "next start",
"static": "next build && next export"
},
"dependencies": {
"@mapbox/rehype-prism": "^0.3.1",
"@mdx-js/loader": "^1.3.1",
"@zeit/next-css": "^1.0.1",
"@zeit/next-mdx": "^1.2.0",
"@zeit/next-sass": "^1.0.0",
"bulma": "^0.7.5",
"next": "^9.0.5-canary.2",
"next-compose-plugins": "^2.2.0",
"node-sass": "^4.7.2",
"prismjs": "^1.17.1",
"react": "^16.7.0",
"react-dom": "^16.7.0"
},
"devDependencies": {
"@babel/plugin-proposal-decorators": "^7.4.4",
"babel-plugin-module-resolver": "^3.2.0"
}
}
-21
View File
@@ -1,21 +0,0 @@
import Document, { Head, Main, NextScript } from 'next/document'
export default class MyDocument extends Document {
render() {
return (
<html>
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="shortcut icon" type="image/png" href="/favicon.png" />
<link rel="stylesheet" type="text/css" href="/css/prism-tomorrow.css" />
<title>Supabase</title>
</head>
<Head />
<body className="has-navbar-fixed-bottom ">
<Main />
<NextScript />
</body>
</html>
)
}
}
-15
View File
@@ -1,15 +0,0 @@
// index.js
import React from 'react'
import MainLayout from '~/components/layouts/MainLayout'
// import MDXDocument, { metadata } from '~/pages/posts/post.mdx'
export default () => (
<>
<MainLayout>
<div className="section container">
<div className="content">
{/* <MDXDocument /> */}
</div>
</div>
</MainLayout>
</>
)
-16
View File
@@ -1,16 +0,0 @@
// index.js
import React from 'react'
import Layout from '~/components/layouts/MainLayout'
import NavbarDocs from '~/components//NavbarDocs'
export default () => (
<Layout>
<div className="section container">
<NavbarDocs />
<div className="content">
<h1>Docs</h1>
</div>
</div>
</Layout>
)
@@ -1,126 +0,0 @@
import { useRouter } from 'next/router'
import Layout from '~/components/layouts/DocsLayout'
import Loading from '~/components/Loading'
import Link from 'next/link'
const importReducer = ctx => {
let keys = ctx.keys()
let values = keys.map(ctx)
return keys.reduce((o, k, i) => {
o[k] = values[i]
return o
}, {})
}
// Import all docs
var Docs = []
Docs['-'] = importReducer(require.context('../../../content/docs/-', true, /.mdx$/))
Docs['packaged'] = importReducer(require.context('../../../content/docs/packaged', true, /.mdx$/))
Docs['admin-api'] = importReducer(require.context('../../../content/docs/admin-api', true, /.mdx$/))
Docs['realtime'] = importReducer(require.context('../../../content/docs/realtime', true, /.mdx$/))
Docs['restful'] = importReducer(require.context('../../../content/docs/restful', true, /.mdx$/))
Docs['graphql'] = importReducer(require.context('../../../content/docs/graphql', true, /.mdx$/))
Docs['baseless'] = importReducer(require.context('../../../content/docs/baseless', true, /.mdx$/))
// Set up all sidebars
var Sidebars = []
Sidebars['-'] = {
Introduction: ['about', 'contributing'],
}
Sidebars['packaged'] = {
Introduction: ['introduction'],
}
Sidebars['admin-api'] = {
Introduction: ['introduction'],
API: ['schemas', 'tables'],
}
Sidebars['realtime'] = {
Introduction: ['introduction', 'quick-start'],
Reference: ['realtime-server', 'realtime-js'],
Guides: ['docker-nextjs'],
}
Sidebars['restful'] = {
Introduction: ['introduction'],
}
Sidebars['graphql'] = {
Introduction: ['introduction'],
}
Sidebars['baseless'] = {
Introduction: ['introduction'],
}
const CategoryDocs = props => {
const router = useRouter()
if (!router.query.category || !router.query.slug) return <Loading />
const { category, slug } = router.query
const categoryDocs = Docs[category]
const categorySidebar = enrichSidebar(Sidebars[category], categoryDocs)
const documentation = categoryDocs[`./${slug}.mdx`]
const Content = documentation.default
const { metadata } = documentation
const { title, description } = metadata
const pages = Object.values(Sidebars[category]) // array of arrays
const pageArray = pages.concat.apply([], pages) // flatten
const sidebarIndex = pageArray.indexOf(slug)
const nextDocSlug = pageArray[sidebarIndex + 1]
const nextDoc = nextDocSlug ? categoryDocs[`./${nextDocSlug}.mdx`] : null
const previousDocSlug = pageArray[sidebarIndex - 1]
const previousDoc = previousDocSlug ? categoryDocs[`./${previousDocSlug}.mdx`] : null
return (
<Layout sidebar={categorySidebar} activeCategory={category}>
<div className="has-background-dark">
<div className="content w-m-800 p-md p-t-xl p-b-xl m-b-lg">
<h1 className="title">{title}</h1>
<p className="subtitle">{description}</p>
</div>
</div>
<div className="content w-m-800 p-md">
<Content />
</div>
<div className="w-m-800 p-md p-b-lg">
<nav className="columns reverse-row-order">
<div className="column ">
{!!nextDoc && (
<Link href={`/docs/[category]/[slug]`} as={`/docs/${category}/${nextDocSlug}`}>
<a className="box p-md">
<p className="heading has-text-grey">Next</p>
<p>{nextDoc.metadata.sidebarLabel || nextDoc.metadata.title}</p>
</a>
</Link>
)}
</div>
<div className="column is-hidden-mobile "></div>
<div className="column">
{!!previousDoc && (
<Link href={`/docs/[category]/[slug]`} as={`/docs/${category}/${previousDocSlug}`}>
<a className="box p-md has-text-right">
<p className="heading has-text-grey">Previous</p>
<p>{previousDoc.metadata.sidebarLabel || previousDoc.metadata.title}</p>
</a>
</Link>
)}
</div>
</nav>
</div>
</Layout>
)
}
export default CategoryDocs
/**
* Fills the sidebar array with relevant metadata,
*/
const enrichSidebar = (sidebar, categoryDocs) => {
return Object.keys(sidebar).reduce((acc, heading) => {
acc[heading] = sidebar[heading].map(slug => {
const documentation = categoryDocs[`./${slug}.mdx`]
const { metadata } = documentation
const { title, sidebarLabel } = metadata
return { slug, title: sidebarLabel || title }
})
return acc
}, {})
}
-97
View File
@@ -1,97 +0,0 @@
import MainLayout from '~/components/layouts/MainLayout'
import Link from 'next/link'
import SignUpForm from '~/components/SignUpForm'
export default class Home extends React.Component {
render() {
return (
<MainLayout>
<div className="section container">
<div className="columns">
<div className="column" style={{ maxWidth: 450 }}>
<h1 className="title is-1">Supabase</h1>
<p className="subtitle">Supercharge PostgreSQL.</p>
<SignUpForm />
</div>
</div>
</div>
<div className="section container m-b-lg">
<a name="pricing" id="pricing" />
<h3 className="title is-3 has-underline ">Products</h3>
<p className="subtitle">
Extend your existing Postgres Database with opensource products.
</p>
<div className="columns is-multiline">
<div className="column is-4">
<Link href={`/docs/[category]/[slug]`} as={`/docs/realtime/introduction`}>
<a className="box deep-hover" style={{ height: '100%' }}>
<h4 className="title is-4">Realtime</h4>
<p>Listen to your database updates, inserts, and deletes over websockets.</p>
</a>
</Link>
</div>
<div className="column is-4">
<Link href={`/docs/[category]/[slug]`} as={`/docs/restful/introduction`}>
<a className="box deep-hover" style={{ height: '100%' }}>
<h4 className="title is-4">Restful</h4>
<p>Add a fully documented Restful API, simply by introspecting the schema.</p>
</a>
</Link>
</div>
<div className="column is-4">
<Link href={`/docs/[category]/[slug]`} as={`/docs/graphql/introduction`}>
<a className="box deep-hover" style={{ height: '100%' }}>
<h4 className="title is-4">GraphQL</h4>
<p>Extend your database with a fully functional GraphQL API, without a line of code.</p>
</a>
</Link>
</div>
</div>
</div>
<div className="section container m-b-lg">
<a name="pricing" id="pricing" />
<h3 className="title is-3 has-underline ">Launch</h3>
<p className="subtitle">
Whether you're a DB expert or just a beginner, Supabase makes it ridiculously easy to
get started with PostgreSQL.
</p>
<div className="columns is-multiline">
<div className="column is-4">
<Link href={`/docs/[category]/[slug]`} as={`/docs/packaged/introduction`}>
<a className="box deep-hover" style={{ height: '100%' }}>
<h4 className="title is-4">Packaged PostgreSQL</h4>
<p>
We've packaged PostgreSQL with a bunch of plugins and goodies that we think
you'll like.
</p>
</a>
</Link>
</div>
<div className="column is-4">
<Link href={`/docs/[category]/[slug]`} as={`/docs/admin-api/introduction`}>
<a className="box deep-hover" style={{ height: '100%' }}>
<h4 className="title is-4">Admin API</h4>
<p>Manage your PostgreSQL database with a well documented Restful API.</p>
</a>
</Link>
</div>
<div className="column is-4">
<Link href={`/docs/[category]/[slug]`} as={`/docs/baseless/introduction`}>
<a className="box deep-hover" style={{ height: '100%' }}>
<h4 className="title is-4">Baseless</h4>
<p>
We're building a serverless PostgreSQL so you can get started in seconds. Export
your database to a fully native PostgreSQL instance at any time.
</p>
</a>
</Link>
</div>
</div>
</div>
</MainLayout>
)
}
}
-26
View File
@@ -1,26 +0,0 @@
import MainLayout from '~/components/layouts/MainLayout'
import Link from 'next/link'
export default class Thanks extends React.Component {
render() {
return (
<MainLayout>
<div className="section container m-t-xxl m-b-xxl ">
<div className="columns is-centered">
<div className="column" style={{ maxWidth: 450 }}>
<h1 className="title is-1">Thanks!</h1>
<p className="subtitle">You're super early.</p>
<p className="">We've put you on the early-bird list.</p>
<p className="">
If you're feeling really brave, why don't you check out our{' '}
<Link href={`/docs/[category]/[slug]`} as={`/docs/-/about`}>
<a className="">docs</a>
</Link>{' '}
and start using our free &amp; opensource products?
</p>
</div>
</div>
</div>
</MainLayout>
)
}
}
-134
View File
@@ -1,134 +0,0 @@
/*
Note that including this file in DocsLayout.js (even with a CSS loader)
seems to break the documentation links, but only in production.
Steps to replicate:
- Uncomment the CSS loader from next.config.js
- Add `import '~/styles/prism-tomorrow.css'` to DocsLayout.js
- Run in dev: Go to homepage -> click on a links to the docs -> success
- Deploy to Prod
- Run in prod: Go to homepage -> click on a links to the docs -> location doesn't change
*/
/**
* prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML
* Based on https://github.com/chriskempson/tomorrow-theme
* @author Rose Pritchard
*/
code[class*="language-"],
pre[class*="language-"] {
color: #ccc;
background: none;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 1em;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #2d2d2d;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.block-comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #999;
}
.token.punctuation {
color: #ccc;
}
.token.tag,
.token.attr-name,
.token.namespace,
.token.deleted {
color: #e2777a;
}
.token.function-name {
color: #6196cc;
}
.token.boolean,
.token.number,
.token.function {
color: #f08d49;
}
.token.property,
.token.class-name,
.token.constant,
.token.symbol {
color: #f8c555;
}
.token.selector,
.token.important,
.token.atrule,
.token.keyword,
.token.builtin {
color: #cc99cd;
}
.token.string,
.token.char,
.token.attr-value,
.token.regex,
.token.variable {
color: #7ec699;
}
.token.operator,
.token.entity,
.token.url {
color: #67cdcc;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
.token.inserted {
color: green;
}
-360
View File
@@ -1,360 +0,0 @@
@charset "utf-8";
@import url(https://cdn.rawgit.com/kiwicopple/quick-font/master/css/circular.css);
@import url(https://use.fontawesome.com/releases/v5.6.3/css/all.css);
/// BULMA
// Set your brand colors
// $green: #45d092;
$green: #45d092;
$blue: #0069ff;
$yellow: #f8c945;
$orange: #ec6e2d;
$grey-900: #1f1f1f;
$grey-800: #2a2a2a;
$grey-700: #3b3b3b;
$grey-600: #4c4c4c;
$grey-500: #5e5e5e;
$grey-400: #6f6f6f;
$grey-300: #7f7f7f;
$grey-200: #8f8f8f;
$grey-100: #eeeeee;
$background: $grey-900;
$background: $grey-900;
$border-color: $grey-400;
$primary: $green;
$link: $green;
$shadow: 0 0 5px 5px rgba(0, 0, 0, 0.3);
$shadow-shallow: 0 0 3px 3px rgba(0, 0, 0, 0.2);
$text-shallow: 0 0 3px rgba(0, 0, 0, 0.3);
// Typography
$family-sans-serif: 'Circular', BlinkMacSystemFont, -apple-system, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 'Helvetica', 'Arial',
sans-serif;
$body-size: 0.9rem;
$text: $grey-100;
$text-light: $grey-100;
$text-strong: $grey-100;
$title-color: $text;
$subtitle-color: $text;
$text-invert: $grey-900;
$link: $primary;
$link-invert: $text;
$link-hover: $text;
$link-visited: $primary;
// $link-hover-border: $grey-100;
// $link-focus: $grey-100;
// $link-focus-border: $grey-100;
// $link-active: $grey-100;
// $link-active-border: $grey-100;
// Navbar
$navbar-background-color: $background;
$navbar-item-color: $text;
$navbar-item-hover-color: $primary;
$navbar-item-hover-background-color: $background;
$navbar-dropdown-background-color: $grey-800;
$navbar-dropdown-item-hover-color: $primary;
$navbar-dropdown-boxed-shadow: $shadow;
$navbar-dropdown-arrow: $text;
$navbar-divider-background-color: $border-color;
// Footer
$footer-background-color: $background;
// Forms
$input-background-color: $background;
$input-color: $text;
$input-border-color: $border-color;
$label-color: $text;
// Buttons
$button-color: $text;
$button-background-color: $background;
$button-border-color: $border-color;
$button-hover-color: $text;
// Box
$box-background-color: $grey-800;
$box-color: #fff;
$box-shadow: $shadow-shallow;
// Modal
$modal-card-body-background-color: $background;
$modal-card-title-color: $text;
.modal-card-head,
.modal-card-foot {
background: $background !important;
}
// Dropdown
$dropdown-content-background-color: $grey-600;
$dropdown-item-color: $text;
$dropdown-item-hover-color: $text;
$dropdown-item-active-color: $background;
// Menu
$menu-item-hover-color: $primary;
$menu-item-active-color: $text-invert;
// Menu
$tabs-border-bottom-color: $border-color;
$tabs-link-color: $grey-200;
// Import only what you need from Bulma
@import '../node_modules/bulma/bulma.sass';
// SPACING CSS - see usage: https://github.com/jgthms/bulma/issues/451#issuecomment-331758839
$sizeUnit: rem;
$marginKey: 'm';
$paddingKey: 'p';
$separator: '-';
$sizes: (
('none', 0),
('xxs', 0.125),
('xs', 0.25),
('sm', 0.5),
('md', 1),
('lg', 2),
('xl', 4),
('xxl', 8)
);
$positions: (('t', 'top'), ('r', 'right'), ('b', 'bottom'), ('l', 'left'));
@function sizeValue($key, $value) {
@return if($key == 'none', 0, $value + $sizeUnit);
}
@each $size in $sizes {
$sizeKey: nth($size, 1);
$sizeValue: nth($size, 2);
.#{$marginKey}#{$separator}#{$sizeKey} {
margin: sizeValue($sizeKey, $sizeValue) !important;
}
.#{$paddingKey}#{$separator}#{$sizeKey} {
padding: sizeValue($sizeKey, $sizeValue) !important;
}
@each $position in $positions {
$posKey: nth($position, 1);
$posValue: nth($position, 2);
.#{$marginKey}#{$separator}#{$posKey}#{$separator}#{$sizeKey} {
margin-#{$posValue}: sizeValue($sizeKey, $sizeValue) !important;
}
.#{$paddingKey}#{$separator}#{$posKey}#{$separator}#{$sizeKey} {
padding-#{$posValue}: sizeValue($sizeKey, $sizeValue) !important;
}
}
}
// end spacing
$widths: (
('100', 100),
('200', 200),
('300', 300),
('400', 400),
('500', 500),
('600', 600),
('700', 700),
('800', 800),
('900', 900),
('1000', 1000),
('1100', 1100),
('1200', 1200)
);
@each $width in $widths {
$widthKey: nth($width, 1);
$widthValue: nth($width, 2);
.w-#{$widthKey} {
width: #{$widthValue}px !important;
margin: 0 auto;
}
// Set max widths
.w-m-#{$widthKey} {
max-width: #{$widthValue}px !important;
margin: 0 auto;
}
}
//
// Custom CSS
//
html,
body {
background: $background;
color: $text;
}
::selection {
background: $primary;
color: $text-invert;
}
::-moz-selection {
background: $primary;
color: $text-invert;
}
hr {
border: 1px solid $border-color;
}
// Navbar
.navbar-item {
a {
color: $text;
&:hover {
color: $primary;
}
}
}
@media only screen and (max-width: 1023px) {
.navbar {
.section.container {
padding: 00px !important;
}
}
}
.footer {
box-shadow: inset 0px 5px 5px 0px rgba(0, 0, 0, 0.3);
.heading {
color: $grey-200;
}
a {
color: $text;
&:hover {
color: $primary;
}
}
}
.has-flex-start {
justify-content: flex-start;
}
.has-flex-end {
justify-content: flex-end;
}
.half-and-half {
overflow: auto;
div {
width: 50% !important;
float: left;
}
div:last-child {
text-align: right;
}
}
.content {
h1,
h2,
h3,
h4,
h5,
h6,
table tr th,
p,
strong {
color: $text;
}
a {
box-shadow: inset 0 -3px 0 -1px $primary;
transition: box-shadow 0.15s ease-in-out;
color: $text;
padding-bottom: 2px;
&:hover {
box-shadow: inset 0 -30px 0 -1px $primary;
}
}
}
hr.is-title-accent {
margin-top: 5px;
max-width: 100px;
}
h1.has-underline,
h2.has-underline,
h3.has-underline {
&::after {
content: '\2501';
display: block;
color: $primary;
}
}
.has-shadow {
box-shadow: $shadow;
}
.has-border-primary {
border: 1px solid $primary !important;
}
.DocsMenuColumn {
border-right: 1px solid $border-color !important;
}
.docs-subnav {
.menu-label {
padding: 1rem 1rem 0 1rem;
}
.menu-list {
li a {
border-radius: 0;
border-left: 3px solid $background;
color: $grey-200;
&.is-active {
background: none;
color: $text;
border-left: 3px solid $primary;
}
}
}
}
.button {
text-shadow: $text-shallow;
font-weight: bold;
&.is-primary {
// color: $background;
&.has-shadow {
box-shadow: 1px 1px 5px 5px rgba($primary, 0);
transition: box-shadow 0.2s ease-in-out;
&:hover {
color: $background;
box-shadow: 1px 1px 5px 5px rgba($primary, 0.1);
}
}
}
&.is-dark {
color: $grey-200 !important;
border: 1px solid transparent;
}
}
pre {
background: $grey-700;
border-radius: 5px;
margin-bottom: 30px;
padding: 0px;
padding-left: 20px;
padding-bottom: 20px;
}
code {
margin-left: 0px;
margin-right: 0px;
white-space: pre;
background: $grey-700;
color: $text;
border-radius: 3px;
}
.has-overflow-scroll {
overflow: auto;
}
.deep-hover {
transition: all 0.2s ease;
&:hover {
box-shadow: 0 30px 60px 0 rgba(0, 0, 0, 0.5), 0 0 0 1px $primary !important;
}
}
@media only screen and (min-width: 769px) {
.reverse-row-order {
display: flex;
flex-direction: row-reverse;
}
}
+3
View File
@@ -0,0 +1,3 @@
node_modules
build
.docusaurus
Executable
+3
View File
@@ -0,0 +1,3 @@
# Supabase
Supabase Web
Loaded 100 of 125 files, more files were not shown because too many files have changed in this diff. Show more