Chore/postgrest v9 (#3988)
* using slack clone to test * updates auth functions to handle new GUC commands * move postgREST to new version * testing with todo list * makeing our mount setup far more robust * Adds some usage commands * cleans up the auth functions * test with todos app * fix env var for GUC * new auth functions - changed for performance improvement * Adds some integration tests for RLS * anon volume on postgres * remove unused helpers * fix broken docusaurus build * Fix complaining vercel * test instructions * Use named imports * Fixes imports * all relative * chore: add in tsconfig.json to /web * finding these all over the place * Update docker/docker-compose.yml Co-authored-by: Steve Chavez <stevechavezast@gmail.com> Co-authored-by: Jonathan Summers-Muir <MildTomato@users.noreply.github.com> Co-authored-by: Steve Chavez <stevechavezast@gmail.com>
This commit is contained in:
3
babel.config.js
Normal file
3
babel.config.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
presets: [['@babel/preset-env', { targets: { node: 'current' } }], '@babel/preset-typescript'],
|
||||
}
|
||||
@@ -13,7 +13,7 @@ DISABLE_SIGNUP=false
|
||||
|
||||
## Email auth
|
||||
ENABLE_EMAIL_SIGNUP=true
|
||||
ENABLE_EMAIL_AUTOCONFIRM=false
|
||||
ENABLE_EMAIL_AUTOCONFIRM=true
|
||||
SMTP_ADMIN_EMAIL=admin@example.com
|
||||
SMTP_HOST=mail
|
||||
SMTP_PORT=2500
|
||||
|
||||
48
docker/dev/data.sql
Normal file
48
docker/dev/data.sql
Normal file
@@ -0,0 +1,48 @@
|
||||
create table profiles (
|
||||
id uuid references auth.users not null,
|
||||
updated_at timestamp with time zone,
|
||||
username text unique,
|
||||
avatar_url text,
|
||||
website text,
|
||||
|
||||
primary key (id),
|
||||
unique(username),
|
||||
constraint username_length check (char_length(username) >= 3)
|
||||
);
|
||||
|
||||
alter table profiles enable row level security;
|
||||
|
||||
create policy "Public profiles are viewable by the owner."
|
||||
on profiles for select
|
||||
using ( auth.uid() = id );
|
||||
|
||||
create policy "Users can insert their own profile."
|
||||
on profiles for insert
|
||||
with check ( auth.uid() = id );
|
||||
|
||||
create policy "Users can update own profile."
|
||||
on profiles for update
|
||||
using ( auth.uid() = id );
|
||||
|
||||
-- Set up Realtime
|
||||
begin;
|
||||
drop publication if exists supabase_realtime;
|
||||
create publication supabase_realtime;
|
||||
commit;
|
||||
alter publication supabase_realtime add table profiles;
|
||||
|
||||
-- Set up Storage
|
||||
insert into storage.buckets (id, name)
|
||||
values ('avatars', 'avatars');
|
||||
|
||||
create policy "Avatar images are publicly accessible."
|
||||
on storage.objects for select
|
||||
using ( bucket_id = 'avatars' );
|
||||
|
||||
create policy "Anyone can upload an avatar."
|
||||
on storage.objects for insert
|
||||
with check ( bucket_id = 'avatars' );
|
||||
|
||||
create policy "Anyone can update an avatar."
|
||||
on storage.objects for update
|
||||
with check ( bucket_id = 'avatars' );
|
||||
@@ -7,4 +7,9 @@ services:
|
||||
ports:
|
||||
- '2500:2500' # SMTP
|
||||
- '9000:9000' # web interface
|
||||
- '1100:1100' # POP3
|
||||
- '1100:1100' # POP3
|
||||
db:
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ./dev/data.sql
|
||||
target: /docker-entrypoint-initdb.d/data.sql
|
||||
@@ -65,7 +65,7 @@ services:
|
||||
|
||||
rest:
|
||||
container_name: supabase-rest
|
||||
image: postgrest/postgrest:v8.0.0
|
||||
image: postgrest/postgrest:v8.0.0.20211102
|
||||
depends_on:
|
||||
- db
|
||||
restart: unless-stopped
|
||||
@@ -74,7 +74,7 @@ services:
|
||||
PGRST_DB_SCHEMA: public, storage
|
||||
PGRST_DB_ANON_ROLE: anon
|
||||
PGRST_JWT_SECRET: ${JWT_SECRET}
|
||||
|
||||
PGRST_DB_USE_LEGACY_GUCS: "false"
|
||||
realtime:
|
||||
container_name: supabase-realtime
|
||||
image: supabase/realtime:v0.15.0
|
||||
@@ -141,20 +141,12 @@ services:
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
PGDATA: /var/lib/postgresql/data/pgdata
|
||||
volumes:
|
||||
- type: volume
|
||||
source: volume_database
|
||||
target: /var/lib/postgresql/data
|
||||
- /var/lib/postgresql/data/pgdata
|
||||
- type: bind
|
||||
source: ./volumes/db/init
|
||||
target: /docker-entrypoint-initdb.d
|
||||
|
||||
volumes:
|
||||
volume_database:
|
||||
driver: local
|
||||
driver_opts:
|
||||
type: none
|
||||
device: ./volumes/db/data
|
||||
o: bind
|
||||
volume_storage:
|
||||
driver: local
|
||||
driver_opts:
|
||||
|
||||
@@ -129,11 +129,11 @@ services:
|
||||
- name: cors
|
||||
|
||||
## Secure Database routes
|
||||
- name: pg-meta
|
||||
- name: meta
|
||||
_comment: "pg-meta: /pg/* -> http://pg-meta:8080/*"
|
||||
url: http://pg-meta:8080/
|
||||
url: http://meta:8080/
|
||||
routes:
|
||||
- name: pg-meta-all
|
||||
- name: meta-all
|
||||
strip_path: true
|
||||
paths:
|
||||
- /pg/
|
||||
|
||||
@@ -88,21 +88,39 @@ VALUES ('20171026211738'),
|
||||
('20180108183307'),
|
||||
('20180119214651'),
|
||||
('20180125194653');
|
||||
|
||||
-- Gets the User ID from the request cookie
|
||||
create or replace function auth.uid() returns uuid as $$
|
||||
select nullif(current_setting('request.jwt.claim.sub', true), '')::uuid;
|
||||
$$ language sql stable;
|
||||
|
||||
-- Gets the User ID from the request cookie
|
||||
create or replace function auth.role() returns text as $$
|
||||
select nullif(current_setting('request.jwt.claim.role', true), '')::text;
|
||||
$$ language sql stable;
|
||||
create or replace function auth.uid()
|
||||
returns uuid
|
||||
language sql stable
|
||||
as $$
|
||||
select
|
||||
coalesce(
|
||||
current_setting('request.jwt.claim.sub', true),
|
||||
(current_setting('request.jwt.claims', true)::jsonb ->> 'sub')
|
||||
)::uuid
|
||||
$$;
|
||||
|
||||
-- Gets the User email
|
||||
create or replace function auth.email() returns text as $$
|
||||
select nullif(current_setting('request.jwt.claim.email', true), '')::text;
|
||||
$$ language sql stable;
|
||||
create or replace function auth.role()
|
||||
returns text
|
||||
language sql stable
|
||||
as $$
|
||||
select
|
||||
coalesce(
|
||||
current_setting('request.jwt.claim.role', true),
|
||||
(current_setting('request.jwt.claims', true)::jsonb ->> 'role')
|
||||
)::text
|
||||
$$;
|
||||
|
||||
create or replace function auth.email()
|
||||
returns text
|
||||
language sql stable
|
||||
as $$
|
||||
select
|
||||
coalesce(
|
||||
current_setting('request.jwt.claim.email', true),
|
||||
(current_setting('request.jwt.claims', true)::jsonb ->> 'email')
|
||||
)::text
|
||||
$$;
|
||||
|
||||
-- usage on auth functions to API roles
|
||||
GRANT USAGE ON SCHEMA auth TO anon, authenticated, service_role;
|
||||
|
||||
0
docker/volumes/db/init/data.sql
Executable file
0
docker/volumes/db/init/data.sql
Executable file
951
examples/nextjs-slack-clone/package-lock.json
generated
951
examples/nextjs-slack-clone/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
1437
examples/nextjs-todo-list/package-lock.json
generated
1437
examples/nextjs-todo-list/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -8,8 +8,8 @@
|
||||
"clean": "rm package-lock.json & rm -rf node_modules/ dist/ .next/"
|
||||
},
|
||||
"dependencies": {
|
||||
"@supabase/supabase-js": "^1.3.2",
|
||||
"@supabase/ui": "^0.6.1",
|
||||
"@supabase/supabase-js": "^1.28.0",
|
||||
"@supabase/ui": "^0.36.0",
|
||||
"next": "^11.1.1",
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1"
|
||||
|
||||
194
jest.config.ts
Normal file
194
jest.config.ts
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* For a detailed explanation regarding each configuration property and type check, visit:
|
||||
* https://jestjs.io/docs/configuration
|
||||
*/
|
||||
|
||||
export default {
|
||||
// All imported modules in your tests should be mocked automatically
|
||||
// automock: false,
|
||||
|
||||
// Stop running tests after `n` failures
|
||||
// bail: 0,
|
||||
|
||||
// The directory where Jest should store its cached dependency information
|
||||
// cacheDirectory: "/private/var/folders/62/vmlm9g556_n1v120hqkjrp8r0000gn/T/jest_dx",
|
||||
|
||||
// Automatically clear mock calls and instances between every test
|
||||
clearMocks: true,
|
||||
|
||||
// Indicates whether the coverage information should be collected while executing the test
|
||||
collectCoverage: false,
|
||||
|
||||
// An array of glob patterns indicating a set of files for which coverage information should be collected
|
||||
// collectCoverageFrom: undefined,
|
||||
|
||||
// The directory where Jest should output its coverage files
|
||||
coverageDirectory: 'tests/coverage',
|
||||
|
||||
// An array of regexp pattern strings used to skip coverage collection
|
||||
// coveragePathIgnorePatterns: [
|
||||
// "/node_modules/"
|
||||
// ],
|
||||
|
||||
// Indicates which provider should be used to instrument code for coverage
|
||||
coverageProvider: 'v8',
|
||||
|
||||
// A list of reporter names that Jest uses when writing coverage reports
|
||||
coverageReporters: [
|
||||
'json',
|
||||
'text',
|
||||
'lcov',
|
||||
// "clover"
|
||||
],
|
||||
|
||||
// An object that configures minimum threshold enforcement for coverage results
|
||||
// coverageThreshold: undefined,
|
||||
|
||||
// A path to a custom dependency extractor
|
||||
// dependencyExtractor: undefined,
|
||||
|
||||
// Make calling deprecated APIs throw helpful error messages
|
||||
// errorOnDeprecated: false,
|
||||
|
||||
// Force coverage collection from ignored files using an array of glob patterns
|
||||
// forceCoverageMatch: [],
|
||||
|
||||
// A path to a module which exports an async function that is triggered once before all test suites
|
||||
// globalSetup: undefined,
|
||||
|
||||
// A path to a module which exports an async function that is triggered once after all test suites
|
||||
// globalTeardown: undefined,
|
||||
|
||||
// A set of global variables that need to be available in all test environments
|
||||
// globals: {},
|
||||
|
||||
// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
|
||||
// maxWorkers: "50%",
|
||||
|
||||
// An array of directory names to be searched recursively up from the requiring module's location
|
||||
// moduleDirectories: [
|
||||
// "node_modules"
|
||||
// ],
|
||||
|
||||
// An array of file extensions your modules use
|
||||
// moduleFileExtensions: [
|
||||
// "js",
|
||||
// "jsx",
|
||||
// "ts",
|
||||
// "tsx",
|
||||
// "json",
|
||||
// "node"
|
||||
// ],
|
||||
|
||||
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
|
||||
// moduleNameMapper: {},
|
||||
|
||||
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
|
||||
// modulePathIgnorePatterns: [],
|
||||
|
||||
// Activates notifications for test results
|
||||
// notify: false,
|
||||
|
||||
// An enum that specifies notification mode. Requires { notify: true }
|
||||
// notifyMode: "failure-change",
|
||||
|
||||
// A preset that is used as a base for Jest's configuration
|
||||
// preset: undefined,
|
||||
|
||||
// Run tests from one or more projects
|
||||
// projects: undefined,
|
||||
|
||||
// Use this configuration option to add custom reporters to Jest
|
||||
// reporters: undefined,
|
||||
|
||||
// Automatically reset mock state between every test
|
||||
// resetMocks: false,
|
||||
|
||||
// Reset the module registry before running each individual test
|
||||
// resetModules: false,
|
||||
|
||||
// A path to a custom resolver
|
||||
// resolver: undefined,
|
||||
|
||||
// Automatically restore mock state between every test
|
||||
// restoreMocks: false,
|
||||
|
||||
// The root directory that Jest should scan for tests and modules within
|
||||
// rootDir: undefined,
|
||||
|
||||
// A list of paths to directories that Jest should use to search for files in
|
||||
// roots: [
|
||||
// "<rootDir>"
|
||||
// ],
|
||||
|
||||
// Allows you to use a custom runner instead of Jest's default test runner
|
||||
// runner: "jest-runner",
|
||||
|
||||
// The paths to modules that run some code to configure or set up the testing environment before each test
|
||||
setupFiles: ['<rootDir>/tests/jest-env'],
|
||||
|
||||
// A list of paths to modules that run some code to configure or set up the testing framework before each test
|
||||
// setupFilesAfterEnv: [],
|
||||
|
||||
// The number of seconds after which a test is considered as slow and reported as such in the results.
|
||||
// slowTestThreshold: 5,
|
||||
|
||||
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
|
||||
// snapshotSerializers: [],
|
||||
|
||||
// The test environment that will be used for testing
|
||||
// testEnvironment: "jest-environment-node",
|
||||
|
||||
// Options that will be passed to the testEnvironment
|
||||
// testEnvironmentOptions: {},
|
||||
|
||||
// Adds a location field to test results
|
||||
// testLocationInResults: false,
|
||||
|
||||
// // The glob patterns Jest uses to detect test files
|
||||
testMatch: [
|
||||
'<rootDir>/tests/**/*.test.ts',
|
||||
// "**/?(*.)+(spec|test).[tj]s?(x)"
|
||||
],
|
||||
|
||||
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
|
||||
testPathIgnorePatterns: ['/node_modules/', 'docker'],
|
||||
|
||||
// The regexp pattern or array of patterns that Jest uses to detect test files
|
||||
// testRegex: [],
|
||||
|
||||
// This option allows the use of a custom results processor
|
||||
// testResultsProcessor: undefined,
|
||||
|
||||
// This option allows use of a custom test runner
|
||||
// testRunner: "jest-circus/runner",
|
||||
|
||||
// This option sets the URL for the jsdom environment. It is reflected in properties such as location.href
|
||||
// testURL: "http://localhost",
|
||||
|
||||
// Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout"
|
||||
// timers: "real",
|
||||
|
||||
// A map from regular expressions to paths to transformers
|
||||
transform: {
|
||||
'^.+\\.tsx?$': 'ts-jest',
|
||||
},
|
||||
|
||||
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
|
||||
// transformIgnorePatterns: [
|
||||
// "/node_modules/",
|
||||
// "\\.pnp\\.[^\\/]+$"
|
||||
// ],
|
||||
|
||||
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
|
||||
// unmockedModulePathPatterns: undefined,
|
||||
|
||||
// Indicates whether each individual test should be reported during the run
|
||||
// verbose: undefined,
|
||||
|
||||
// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
|
||||
// watchPathIgnorePatterns: [],
|
||||
|
||||
// Whether to use watchman for file crawling
|
||||
// watchman: true,
|
||||
}
|
||||
4496
package-lock.json
generated
Normal file
4496
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
47
package.json
Normal file
47
package.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "Supabase",
|
||||
"description": "The open source Firebase alternative.",
|
||||
"version": "0.0.0",
|
||||
"author": "Supabase, Inc.",
|
||||
"license": "Apache-2.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docker:dev": "cd docker && docker-compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml up --renew-anon-volumes",
|
||||
"docker:up": "cd docker && docker-compose up",
|
||||
"docker:down": "cd docker && docker-compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml down --remove-orphans",
|
||||
"docker:remove": "cd docker && docker-compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml rm -vfs",
|
||||
"test": "jest"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.16.0",
|
||||
"@babel/preset-env": "^7.16.4",
|
||||
"@babel/preset-typescript": "^7.16.0",
|
||||
"@supabase/supabase-js": "^1.28.1",
|
||||
"@types/jest": "^27.0.3",
|
||||
"@types/node": "^14.14.14",
|
||||
"axios": "^0.24.0",
|
||||
"babel-jest": "^27.3.1",
|
||||
"dotenv": "^10.0.0",
|
||||
"faker": "^5.5.3",
|
||||
"jest": "^27.3.1",
|
||||
"ts-jest": "^27.0.7",
|
||||
"ts-node": "^9.1.1",
|
||||
"typescript": "^4.5.2"
|
||||
},
|
||||
"directories": {
|
||||
"doc": "docs"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/supabase/supabase.git"
|
||||
},
|
||||
"keywords": [
|
||||
"postgres",
|
||||
"firebase",
|
||||
"storage",
|
||||
"functions",
|
||||
"database",
|
||||
"auth"
|
||||
]
|
||||
}
|
||||
14
tests/README.md
Normal file
14
tests/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
## Tests
|
||||
|
||||
These tests can be run with Docker.
|
||||
|
||||
### Steps
|
||||
|
||||
In the parent folder:
|
||||
|
||||
- `npm run docker:dev`
|
||||
- `npm run test`
|
||||
|
||||
### Clean up
|
||||
|
||||
- `npm run docker:remove`
|
||||
64
tests/integration/index.test.ts
Normal file
64
tests/integration/index.test.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import * as faker from 'faker'
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const unauthorized = createClient(process.env.SUPABASE_URL, 'FAKE_KEY')
|
||||
const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY_ANON)
|
||||
const admin = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY_ADMIN)
|
||||
|
||||
test('Unauthorized', async () => {
|
||||
const { error } = await unauthorized.from('profiles').select()
|
||||
expect(error.message).toBe('Invalid authentication credentials')
|
||||
})
|
||||
|
||||
test('Simple test', async () => {
|
||||
const fakeOne = {
|
||||
email: faker.internet.email().toLowerCase(),
|
||||
password: faker.internet.password(),
|
||||
username: faker.internet.userName(),
|
||||
}
|
||||
const fakeTwo = {
|
||||
email: faker.internet.email().toLowerCase(),
|
||||
password: faker.internet.password(),
|
||||
username: faker.internet.userName(),
|
||||
}
|
||||
const first = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY_ANON)
|
||||
const second = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY_ANON)
|
||||
|
||||
const { user: firstUser } = await first.auth.signUp({
|
||||
email: fakeOne.email,
|
||||
password: fakeOne.password,
|
||||
})
|
||||
const { user: secondUser } = await second.auth.signUp({
|
||||
email: fakeTwo.email,
|
||||
password: fakeTwo.password,
|
||||
})
|
||||
expect(firstUser.email).toEqual(fakeOne.email)
|
||||
expect(secondUser.email).toEqual(fakeTwo.email)
|
||||
|
||||
const { data: firstProfile } = await first
|
||||
.from('profiles')
|
||||
.insert({
|
||||
id: firstUser.id,
|
||||
username: fakeOne.username,
|
||||
})
|
||||
.single()
|
||||
expect(firstProfile.username).toMatch(fakeOne.username)
|
||||
|
||||
// Cannot insert the second user on the first client
|
||||
const { error: secondProfile } = await first
|
||||
.from('profiles')
|
||||
.insert({
|
||||
id: secondUser.id,
|
||||
username: fakeTwo.username,
|
||||
})
|
||||
.single()
|
||||
expect(secondProfile.message).toMatch(/new row violates row-level security policy for table/)
|
||||
|
||||
const { data: firstProfileList } = await first.from('profiles').select()
|
||||
const { data: secondProfileList } = await second.from('profiles').select()
|
||||
const { data: adminProfileList } = await admin.from('profiles').select()
|
||||
|
||||
expect(firstProfileList.length).toBe(1)
|
||||
expect(secondProfileList.length).toBe(0)
|
||||
expect(adminProfileList.length).toBeGreaterThanOrEqual(1)
|
||||
})
|
||||
5
tests/jest-env.js
Normal file
5
tests/jest-env.js
Normal file
@@ -0,0 +1,5 @@
|
||||
process.env.SUPABASE_URL = 'http://localhost:8000'
|
||||
process.env.SUPABASE_KEY_ANON =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYyNzIwODU0MCwiZXhwIjoxOTc0MzYzNzQwfQ.zcaQfHd3VA7XgJmdGfmV86OLVJT9s2MTmSy-e69BpUY'
|
||||
process.env.SUPABASE_KEY_ADMIN =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIiwiaWF0IjoxNjI3MjA4NTQwLCJleHAiOjE5NzQzNjM3NDB9.pkT3PNpO4DtO45Ac5HK_TKCx8sGLgNtV__pr_ZrRSAU'
|
||||
5
tsconfig.json
Normal file
5
tsconfig.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"skipLibCheck": true
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ title: Phone Auth with MessageBird
|
||||
description: How to set up and use Mobile OTP with MessageBird and Supabase.
|
||||
---
|
||||
|
||||
import ExtensionsComponent from '../../../../web/src/components/Extensions'
|
||||
import Tabs from '@theme/Tabs'
|
||||
import TabItem from '@theme/TabItem'
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ title: Phone Auth with Twilio
|
||||
description: How to set up and use Mobile OTP with Twilio and Supabase.
|
||||
---
|
||||
|
||||
import ExtensionsComponent from '../../../../web/src/components/Extensions'
|
||||
import Tabs from '@theme/Tabs'
|
||||
import TabItem from '@theme/TabItem'
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ title: Database
|
||||
description: Use Supabase to manage your data.
|
||||
---
|
||||
|
||||
import ExtensionsComponent from '../../src/components/Extensions'
|
||||
import ExtensionsComponent from '@site/src/components/Extensions'
|
||||
|
||||
Supabase is built on top of [Postgres](/docs/postgres/server/about), an extremely scalable Relational Database.
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ Your first array data!
|
||||
To query an array, PostgreSQL uses 1-based arrays, so be careful, since you're probably used to 0-based arrays in Javascript.
|
||||
|
||||
<Tabs
|
||||
defaultValue="UI"
|
||||
defaultValue="SQL"
|
||||
values={[
|
||||
{label: 'SQL', value: 'SQL'},
|
||||
{label: 'JS', value: 'JavaScript'},
|
||||
|
||||
@@ -4,7 +4,7 @@ title: Overview
|
||||
description: Using Postgres extensions.
|
||||
---
|
||||
|
||||
import ExtensionsComponent from '../../../src/components/Extensions'
|
||||
import ExtensionsComponent from '@site/src/components/Extensions'
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ title: "http: RESTful Client"
|
||||
description: An HTTP Client for PostgreSQL Functions.
|
||||
---
|
||||
|
||||
import ExtensionsComponent from '../../../../src/components/Extensions'
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ title: "pgTAP: Unit Testing"
|
||||
description: Unit testing in PostgreSQL.
|
||||
---
|
||||
|
||||
import ExtensionsComponent from '../../../../src/components/Extensions'
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ title: "plv8: Javascript Language"
|
||||
description: Javascript language for PostgreSQL.
|
||||
---
|
||||
|
||||
import ExtensionsComponent from '../../../../src/components/Extensions'
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ title: "uuid-ossp: Unique Identifiers"
|
||||
description: A UUID generator for PostgreSQL.
|
||||
---
|
||||
|
||||
import ExtensionsComponent from '../../../../src/components/Extensions'
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ title: "Full Text Search"
|
||||
description: How to use full text search in PostgreSQL.
|
||||
---
|
||||
|
||||
import ExtensionsComponent from '../../../../web/src/components/Extensions'
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ sidebar_label: Overview
|
||||
description: Getting started with Self Hosting.
|
||||
---
|
||||
|
||||
import ExtensionsComponent from '../../../src/components/Extensions'
|
||||
import JwtGenerator from '@site/src/components/JwtGenerator'
|
||||
|
||||
There are several ways to use Supabase:
|
||||
|
||||
@@ -4,7 +4,7 @@ title: Contributing
|
||||
description: Want to help?
|
||||
---
|
||||
|
||||
import Sponsors from '../../src/components/Sponsors'
|
||||
import Sponsors from '@site/src/components/Sponsors'
|
||||
|
||||
## How to contribute
|
||||
|
||||
|
||||
23287
web/package-lock.json
generated
23287
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -36,7 +36,7 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^14.14.14",
|
||||
"@types/node": "^14.17.34",
|
||||
"axios": "^0.21.1",
|
||||
"babel-plugin-css-modules-transform": "^1.6.2",
|
||||
"clsx": "^1.1.1",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState } from 'react'
|
||||
import extensions from '../data/extensions.json'
|
||||
import extensions from '@site/src/data/extensions.json'
|
||||
|
||||
export default function Extensions() {
|
||||
const [filter, setFilter] = useState('')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import sponsors from '../data/sponsors.json'
|
||||
import sponsors from '@site/src/data/sponsors.json'
|
||||
|
||||
|
||||
export default function Sponsors() {
|
||||
|
||||
5
web/tsconfig.json
Normal file
5
web/tsconfig.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "CommonJS"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user