From 11315e987a2f552704b0e4b41f7af7922faaffec Mon Sep 17 00:00:00 2001 From: Bo Lu Date: Fri, 28 Jun 2024 18:54:22 +1000 Subject: [PATCH 01/16] docs: add Wrappers API access security suggestion (#27514) * docs: add wrappers security suggestion and example --- .../database/extensions/wrappers/overview.mdx | 86 ++++++++++++++++++- 1 file changed, 83 insertions(+), 3 deletions(-) diff --git a/apps/docs/content/guides/database/extensions/wrappers/overview.mdx b/apps/docs/content/guides/database/extensions/wrappers/overview.mdx index cf78407db38..87e5bc4bd8f 100644 --- a/apps/docs/content/guides/database/extensions/wrappers/overview.mdx +++ b/apps/docs/content/guides/database/extensions/wrappers/overview.mdx @@ -35,7 +35,7 @@ Examples: - A `subscriptions` table which maps to your Stripe subscriptions. - A `collections` table which maps to a Firebase collection. -Although a Foreign Table behaves like any other table, the data is not stored inside your database. The data remains inside the Remote Server. +Although a foreign table behaves like any other table, the data is not stored inside your database. The data remains inside the Remote Server. ### ETL with Wrappers @@ -111,9 +111,89 @@ This process can be taxing on your database if you are moving large amounts of d ## Security -Foreign Data Wrappers do not provide Row Level Security. We do not advise exposing them via your API. Wrappers should _always_ be stored in a private schema. For example, if you are connecting to your Stripe account, you should create a `stripe` schema to store all of your Foreign Tables inside. This schema should _not_ be added to the “Additional Schemas” setting in the API section. +Foreign Data Wrappers do not provide Row Level Security, thus it is not advised to expose them via your API. Wrappers should _always_ be stored in a private schema. For example, if you are connecting to your Stripe account, you should create a `stripe` schema to store all of your foreign tables inside. This schema should _not_ be added to the “Additional Schemas” setting in the API section. -If you want to expose any of the columns to your public API, create a [View](https://supabase.com/docs/guides/database/tables#views) in the `public` schema. You can also interact with your Foreign Tables inside a [Database Function](https://supabase.com/docs/guides/database/functions). +If you want to expose any of the foreign table columns to your public API, you can create a [Database Function with security definer](https://supabase.com/docs/guides/database/functions#security-definer-vs-invoker) in the `public` schema, and then you can interact with your foreign table through API. For better access control, the function should have appropriate filters on the foreign table to apply security rules based on your business needs. + +As an example, go to [SQL Editor](https://supabase.com/dashboard/project/_/sql/new) and then follow below steps, + +1. Create a Stripe Products foreign table: + + ```sql + create foreign table stripe.stripe_products ( + id text, + name text, + active bool, + default_price text, + description text, + created timestamp, + updated timestamp, + attrs jsonb + ) + server stripe_fdw_server + options ( + object 'products', + rowid_column 'id' + ); + ``` + +2. Create a security definer function that queries the foreign table and filters on the name prefix parameter: + + ```sql + create function public.get_stripe_products(name_prefix text) + returns table ( + id text, + name text, + active boolean, + default_price text, + description text + ) + language plpgsql + security definer set search_path = '' + as $$ + begin + return query + select + t.id, + t.name, + t.active, + t.default_price, + t.description + from + stripe.stripe_products t + where + t.name like name_prefix || '%' + ; + end; + $$; + ``` + +3. Restrict the function execution to a specific role only, for example, the authenticated users: + + + By default, the function created can be executed by any roles like `anon`, that means the + foreign table is public accessible. Always limit the function execution permission to + appropriate roles. + + + ```sql + -- revoke public execute permission + revoke execute on function public.get_stripe_products from public; + revoke execute on function public.get_stripe_products from anon; + + -- grant execute permission to a specific role only + grant execute on function public.get_stripe_products to authenticated; + ``` + +Once the preceding steps are finished, the function can be invoked from Supabase client to query the foreign table: + +```js +const { data, error } = await supabase + .rpc('get_stripe_products', { name_prefix: 'Test' }) + .select('*') +if (error) console.error(error) +else console.log(data) +``` ## Resources From 491f9803e0fdd6f10f2ca2310f6dc95e4d62b71f Mon Sep 17 00:00:00 2001 From: Ivan Vasilov Date: Fri, 28 Jun 2024 12:26:57 +0200 Subject: [PATCH 02/16] chore: Bump typescript to version 5.5 (#27590) Bump typescript to 5.5 in all apps and packages. --- apps/database-new/package.json | 2 +- apps/design-system/package.json | 2 +- apps/docs/package.json | 2 +- apps/studio/package.json | 2 +- apps/www/package.json | 2 +- package-lock.json | 28 ++++++++++++++-------------- packages/ai-commands/package.json | 2 +- packages/common/package.json | 2 +- packages/icons/package.json | 2 +- packages/pg-meta/package.json | 2 +- packages/ui/package.json | 2 +- tests/package.json | 2 +- 12 files changed, 25 insertions(+), 25 deletions(-) diff --git a/apps/database-new/package.json b/apps/database-new/package.json index 26b1fbd3d6a..e1d6f6a9e29 100644 --- a/apps/database-new/package.json +++ b/apps/database-new/package.json @@ -40,6 +40,6 @@ "autoprefixer": "^10.4.14", "nextjs-node-loader": "^1.1.5", "postcss": "^8.4.31", - "typescript": "^5.4.3" + "typescript": "^5.5.0" } } diff --git a/apps/design-system/package.json b/apps/design-system/package.json index 3c1fddaaba7..eb74f256f5d 100644 --- a/apps/design-system/package.json +++ b/apps/design-system/package.json @@ -52,7 +52,7 @@ "shiki": "^1.1.7", "tailwindcss": "^3.3.0", "tsconfig": "*", - "typescript": "^5", + "typescript": "^5.5.0", "unist-builder": "3.0.0" } } diff --git a/apps/docs/package.json b/apps/docs/package.json index 2351445488a..87c4a3482bf 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -103,6 +103,6 @@ "simple-git": "^3.24.0", "tsconfig": "*", "tsx": "^4.6.2", - "typescript": "^5.4.3" + "typescript": "^5.5.0" } } diff --git a/apps/studio/package.json b/apps/studio/package.json index 100ed2e156d..760a09a845f 100644 --- a/apps/studio/package.json +++ b/apps/studio/package.json @@ -159,6 +159,6 @@ "prettier": "^4.0.0-alpha.8", "storybook-dark-mode": "^3.0.1", "tailwindcss": "^3.4.1", - "typescript": "^5.4.3" + "typescript": "^5.5.0" } } diff --git a/apps/www/package.json b/apps/www/package.json index 99adbb68d9b..7718b9ba117 100644 --- a/apps/www/package.json +++ b/apps/www/package.json @@ -68,7 +68,7 @@ "swiper": "^11.0.7", "three": "^0.136.0", "typed.js": "^2.0.16", - "typescript": "^5.4.3", + "typescript": "^5.5.0", "ui": "*", "ui-patterns": "*", "use-debounce": "^7.0.1", diff --git a/package-lock.json b/package-lock.json index 373ff1b938a..0e0c3ab5cee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,7 +62,7 @@ "autoprefixer": "^10.4.14", "nextjs-node-loader": "^1.1.5", "postcss": "^8.4.31", - "typescript": "^5.4.3" + "typescript": "^5.5.0" } }, "apps/database-new/node_modules/@tanstack/query-core": { @@ -149,7 +149,7 @@ "shiki": "^1.1.7", "tailwindcss": "^3.3.0", "tsconfig": "*", - "typescript": "^5", + "typescript": "^5.5.0", "unist-builder": "3.0.0" } }, @@ -1011,7 +1011,7 @@ "simple-git": "^3.24.0", "tsconfig": "*", "tsx": "^4.6.2", - "typescript": "^5.4.3" + "typescript": "^5.5.0" } }, "apps/docs/node_modules/@tanstack/query-core": { @@ -1358,7 +1358,7 @@ "prettier": "^4.0.0-alpha.8", "storybook-dark-mode": "^3.0.1", "tailwindcss": "^3.4.1", - "typescript": "^5.4.3" + "typescript": "^5.5.0" } }, "apps/studio/node_modules/@heroicons/react": { @@ -2420,7 +2420,7 @@ "swiper": "^11.0.7", "three": "^0.136.0", "typed.js": "^2.0.16", - "typescript": "^5.4.3", + "typescript": "^5.5.0", "ui": "*", "ui-patterns": "*", "use-debounce": "^7.0.1", @@ -40194,9 +40194,9 @@ "license": "MIT" }, "node_modules/typescript": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", - "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.2.tgz", + "integrity": "sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -42666,7 +42666,7 @@ "sql-formatter": "^15.0.2", "ts-jest": "^29.1.1", "tsconfig": "*", - "typescript": "^5.4.3" + "typescript": "^5.5.0" } }, "packages/ai-commands/node_modules/argparse": { @@ -42775,7 +42775,7 @@ "@types/react": "^18.2.24", "@types/react-dom": "^18.2.8", "tsconfig": "*", - "typescript": "^5.4.3" + "typescript": "^5.5.0" }, "peerDependencies": { "@supabase/auth-js": "^2.63.0", @@ -42814,7 +42814,7 @@ "packages/icons": { "dependencies": { "@supabase/build-icons": "*", - "typescript": "^5.4.3" + "typescript": "^5.5.0" } }, "packages/pg-meta": { @@ -42827,7 +42827,7 @@ }, "devDependencies": { "@types/pg-format": "^1.0.1", - "typescript": "^5.4.3" + "typescript": "^5.5.0" } }, "packages/shared-data": { @@ -42941,7 +42941,7 @@ "ts-jest": "^29.1.1", "tsconfig": "*", "tsconfig-paths-webpack-plugin": "^4.0.1", - "typescript": "^5.4.3" + "typescript": "^5.5.0" }, "peerDependencies": { "next": "*", @@ -43706,7 +43706,7 @@ "jest-environment-jsdom": "^29.7.0", "postgres": "^3.0.5", "ts-jest": "^29.1.1", - "typescript": "^5.4.3" + "typescript": "^5.5.0" } }, "tests/node_modules/@testdeck/core": { diff --git a/packages/ai-commands/package.json b/packages/ai-commands/package.json index c6fd2214ea2..67127512fc3 100644 --- a/packages/ai-commands/package.json +++ b/packages/ai-commands/package.json @@ -34,6 +34,6 @@ "sql-formatter": "^15.0.2", "ts-jest": "^29.1.1", "tsconfig": "*", - "typescript": "^5.4.3" + "typescript": "^5.5.0" } } diff --git a/packages/common/package.json b/packages/common/package.json index 3765018aff6..94c79aa9b0a 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -20,7 +20,7 @@ "@types/react": "^18.2.24", "@types/react-dom": "^18.2.8", "tsconfig": "*", - "typescript": "^5.4.3" + "typescript": "^5.5.0" }, "peerDependencies": { "@supabase/supabase-js": "*", diff --git a/packages/icons/package.json b/packages/icons/package.json index 1588a17be3d..5bbbe5cf4e5 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -5,7 +5,7 @@ "build:icons": "build-icons --templateSrc=./scripts/exportTemplate.mjs --renderUniqueKey --iconFileExtension=.ts --exportFileName=index.ts" }, "dependencies": { - "typescript": "^5.4.3", + "typescript": "^5.5.0", "@supabase/build-icons": "*" } } diff --git a/packages/pg-meta/package.json b/packages/pg-meta/package.json index a5ddc5e690b..1f40228e6a6 100644 --- a/packages/pg-meta/package.json +++ b/packages/pg-meta/package.json @@ -11,6 +11,6 @@ }, "devDependencies": { "@types/pg-format": "^1.0.1", - "typescript": "^5.4.3" + "typescript": "^5.5.0" } } diff --git a/packages/ui/package.json b/packages/ui/package.json index e933ac89047..c8d0f04bdd6 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -116,7 +116,7 @@ "ts-jest": "^29.1.1", "tsconfig": "*", "tsconfig-paths-webpack-plugin": "^4.0.1", - "typescript": "^5.4.3" + "typescript": "^5.5.0" }, "peerDependencies": { "next": "*", diff --git a/tests/package.json b/tests/package.json index 4e01114c9ff..15e50147555 100644 --- a/tests/package.json +++ b/tests/package.json @@ -31,6 +31,6 @@ "jest-allure2-adapter": "^0.3.12", "jest-environment-jsdom": "^29.7.0", "postgres": "^3.0.5", - "typescript": "^5.4.3" + "typescript": "^5.5.0" } } From d89097d5c71003d599c80fb8df01d3d75147b34d Mon Sep 17 00:00:00 2001 From: TheOtherBrian1 <91111415+TheOtherBrian1@users.noreply.github.com> Date: Fri, 28 Jun 2024 06:37:25 -0400 Subject: [PATCH 03/16] Renamed Sveltekit Variable from SUPABASE_KEY to SUPABASE_ANON_KEY (#27332) --- .../Home/Connect/content/sveltekit/supabasejs/content.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/studio/components/interfaces/Home/Connect/content/sveltekit/supabasejs/content.tsx b/apps/studio/components/interfaces/Home/Connect/content/sveltekit/supabasejs/content.tsx index 7a6c11670ce..7a399e2f1f0 100644 --- a/apps/studio/components/interfaces/Home/Connect/content/sveltekit/supabasejs/content.tsx +++ b/apps/studio/components/interfaces/Home/Connect/content/sveltekit/supabasejs/content.tsx @@ -33,7 +33,7 @@ SUPABASE_ANON_KEY=${projectKeys.anonKey ?? 'your-anon-key'} import { createClient } from "@supabase/supabase-js"; const supabaseUrl = process.env.SUPABASE_URL; -const supabaseKey = process.env.SUPABASE_KEY; +const supabaseKey = process.env.SUPABASE_ANON_KEY; export const supabase = createClient(supabaseUrl, supabaseKey); `} From 0677592b84f08b129a86a2e36c8f22e5bc096204 Mon Sep 17 00:00:00 2001 From: Jan Tennert Date: Fri, 28 Jun 2024 12:49:37 +0200 Subject: [PATCH 04/16] feat: connect Kotlin example (#27313) * Add Kotlin connect * fix key * Fix some mistakes * Update content.tsx --- .../Home/Connect/Connect.constants.ts | 14 ++++ .../androidkotlin/supabasekt/content.tsx | 83 +++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 apps/studio/components/interfaces/Home/Connect/content/androidkotlin/supabasekt/content.tsx diff --git a/apps/studio/components/interfaces/Home/Connect/Connect.constants.ts b/apps/studio/components/interfaces/Home/Connect/Connect.constants.ts index 355050b9a7c..24bb9cec4a9 100644 --- a/apps/studio/components/interfaces/Home/Connect/Connect.constants.ts +++ b/apps/studio/components/interfaces/Home/Connect/Connect.constants.ts @@ -206,6 +206,20 @@ export const MOBILES: ConnectionType[] = [ }, ], }, + { + key: 'androidkotlin', + label: 'Android Kotlin', + icon: 'kotlin', + guideLink: 'https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin', + children: [ + { + key: 'supabasekt', + label: 'supabase-kt', + children: [], + icon: 'supabase', + }, + ], + }, ] export const ORMS: ConnectionType[] = [ diff --git a/apps/studio/components/interfaces/Home/Connect/content/androidkotlin/supabasekt/content.tsx b/apps/studio/components/interfaces/Home/Connect/content/androidkotlin/supabasekt/content.tsx new file mode 100644 index 00000000000..7e866e184ea --- /dev/null +++ b/apps/studio/components/interfaces/Home/Connect/content/androidkotlin/supabasekt/content.tsx @@ -0,0 +1,83 @@ +import type { ContentFileProps } from 'components/interfaces/Home/Connect/Connect.types' + +import { + ConnectTabs, + ConnectTabTriggers, + ConnectTabTrigger, + ConnectTabContent, +} from 'components/interfaces/Home/Connect/ConnectTabs' +import SimpleCodeBlock from 'components/to-be-cleaned/SimpleCodeBlock' + +const ContentFile = ({ projectKeys }: ContentFileProps) => { + return ( + + + + + + + + + {` +@Serializable +data class TodoItem(val id: Int, val name: String) + `} + + + + + + {` +val supabase = createSupabaseClient( + supabaseUrl = "${projectKeys.apiUrl ?? 'your-project-url'}", + supabaseKey = "${projectKeys.anonKey ?? 'your-anon-key'}" + ) { + install(Postgrest) +} + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + MaterialTheme { + // A surface container using the 'background' color from the theme + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + TodoList() + } + } + } + } +} + +@Composable +fun TodoList() { + var items by remember { mutableStateOf>(listOf()) } + LaunchedEffect(Unit) { + withContext(Dispatchers.IO) { + items = supabase.from("todos") + .select().decodeList() + } + } + LazyColumn { + items( + items, + key = { item -> item.id }, + ) { item -> + Text( + item.name, + modifier = Modifier.padding(8.dp), + ) + } + } +} +`} + + + + ) +} + +export default ContentFile From 389feea6c86d223cf4a6273590097b49cef524c0 Mon Sep 17 00:00:00 2001 From: Girish Savlesha Date: Fri, 28 Jun 2024 18:17:35 +0530 Subject: [PATCH 05/16] :bug: fix: wrap column around quotes for creating index sql command (#27499) * :bug: fix: wrap column around quotes for creating index sql command * Fix the package.lock. --------- Co-authored-by: Girish Savlesha Co-authored-by: Ivan Vasilov --- .../Database/Indexes/CreateIndexSidePanel.tsx | 6 ++-- package-lock.json | 34 +++++++++++-------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/apps/studio/components/interfaces/Database/Indexes/CreateIndexSidePanel.tsx b/apps/studio/components/interfaces/Database/Indexes/CreateIndexSidePanel.tsx index 4ac909504bc..d6533a455ba 100644 --- a/apps/studio/components/interfaces/Database/Indexes/CreateIndexSidePanel.tsx +++ b/apps/studio/components/interfaces/Database/Indexes/CreateIndexSidePanel.tsx @@ -99,9 +99,9 @@ const CreateIndexSidePanel = ({ visible, onClose }: CreateIndexSidePanelProps) = }) const generatedSQL = ` -CREATE INDEX ON "${selectedSchema}"."${selectedEntity}" USING ${selectedIndexType} (${selectedColumns.join( - ', ' - )}); +CREATE INDEX ON "${selectedSchema}"."${selectedEntity}" USING ${selectedIndexType} (${selectedColumns + .map((column) => `"${column}"`) + .join(', ')}); `.trim() const onSaveIndex = () => { diff --git a/package-lock.json b/package-lock.json index 0e0c3ab5cee..df8c62dd365 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17988,6 +17988,11 @@ "source-map": "^0.6.1" } }, + "node_modules/confbox": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", + "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==" + }, "node_modules/config": { "resolved": "packages/config", "link": true @@ -26019,6 +26024,7 @@ }, "node_modules/jsonc-parser": { "version": "3.2.0", + "dev": true, "license": "MIT" }, "node_modules/jsonfile": { @@ -30987,14 +30993,14 @@ "peer": true }, "node_modules/mlly": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.6.1.tgz", - "integrity": "sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz", + "integrity": "sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==", "dependencies": { "acorn": "^8.11.3", "pathe": "^1.1.2", - "pkg-types": "^1.0.3", - "ufo": "^1.3.2" + "pkg-types": "^1.1.1", + "ufo": "^1.5.3" } }, "node_modules/mobx": { @@ -33246,13 +33252,13 @@ } }, "node_modules/pkg-types": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", - "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.1.tgz", + "integrity": "sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==", "dependencies": { - "jsonc-parser": "^3.2.0", - "mlly": "^1.2.0", - "pathe": "^1.1.0" + "confbox": "^0.1.7", + "mlly": "^1.7.0", + "pathe": "^1.1.2" } }, "node_modules/playwright": { @@ -40210,9 +40216,9 @@ "license": "MIT" }, "node_modules/ufo": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.4.0.tgz", - "integrity": "sha512-Hhy+BhRBleFjpJ2vchUNN40qgkh0366FWJGqVLYBHev0vpHTrXSA0ryT+74UiW6KWsldNurQMKGqCm1M2zBciQ==" + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz", + "integrity": "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==" }, "node_modules/uglify-js": { "version": "3.17.4", From a2dc897d053be4e8e3dd4894e77c1d6df9e347ea Mon Sep 17 00:00:00 2001 From: hallidayo <22655069+Hallidayo@users.noreply.github.com> Date: Fri, 28 Jun 2024 14:09:27 +0100 Subject: [PATCH 06/16] docs: swift guide for connect (#27541) * connect swift guide for studio * remove Model wording Co-authored-by: Guilherme Souza * Update apps/studio/components/interfaces/Home/Connect/content/swift/supabaseswift/content.tsx Co-authored-by: Guilherme Souza * changed to newer components Co-authored-by: Guilherme Souza * Fix a merge conflict. --------- Co-authored-by: Guilherme Souza Co-authored-by: Ivan Vasilov --- .../Home/Connect/Connect.constants.ts | 14 ++++ .../content/swift/supabaseswift/content.tsx | 84 +++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 apps/studio/components/interfaces/Home/Connect/content/swift/supabaseswift/content.tsx diff --git a/apps/studio/components/interfaces/Home/Connect/Connect.constants.ts b/apps/studio/components/interfaces/Home/Connect/Connect.constants.ts index 24bb9cec4a9..e7adce95098 100644 --- a/apps/studio/components/interfaces/Home/Connect/Connect.constants.ts +++ b/apps/studio/components/interfaces/Home/Connect/Connect.constants.ts @@ -206,6 +206,20 @@ export const MOBILES: ConnectionType[] = [ }, ], }, + { + key: 'swift', + label: 'Swift', + icon: 'swift', + guideLink: 'https://supabase.com/docs/guides/getting-started/tutorials/with-swift', + children: [ + { + key: 'supabaseswift', + label: 'supabase-swift', + children: [], + icon: 'supabase', + }, + ], + }, { key: 'androidkotlin', label: 'Android Kotlin', diff --git a/apps/studio/components/interfaces/Home/Connect/content/swift/supabaseswift/content.tsx b/apps/studio/components/interfaces/Home/Connect/content/swift/supabaseswift/content.tsx new file mode 100644 index 00000000000..a22a289bccc --- /dev/null +++ b/apps/studio/components/interfaces/Home/Connect/content/swift/supabaseswift/content.tsx @@ -0,0 +1,84 @@ +import type { ContentFileProps } from 'components/interfaces/Home/Connect/Connect.types' + +import { + ConnectTabs, + ConnectTabTriggers, + ConnectTabTrigger, + ConnectTabContent, +} from 'components/interfaces/Home/Connect/ConnectTabs' +import SimpleCodeBlock from 'components/to-be-cleaned/SimpleCodeBlock' + +const ContentFile = ({ projectKeys }: ContentFileProps) => { + return ( + + + + + + + + + + {` +import Foundation +import Supabase + +let supabase = SupabaseClient( + supabaseURL: URL(string: "${projectKeys.apiUrl ?? 'your-project-url'}")!, + supabaseKey: "${projectKeys.anonKey ?? 'your-anon-key'}" +) + `} + + + + + + {` +import Foundation + +struct Todo: Identifiable, Decodable { + var id: Int + var title: String +} +`} + + + + + + {` +import Supabase +import SwiftUI + +struct ContentView: View { + @State var todos: [Todo] = [] + + var body: some View { + NavigationStack { + List(todos) { todo in + Text(todo.title) + } + .navigationTitle("Todos") + .task { + do { + todos = try await supabase.from("todos").select().execute().value + } catch { + debugPrint(error) + } + } + } + } +} + +#Preview { + ContentView() +} + +`} + + + + ) +} + +export default ContentFile From b92072d8d4c38158b25ccfc697d8b47a5ab69353 Mon Sep 17 00:00:00 2001 From: hallidayo <22655069+Hallidayo@users.noreply.github.com> Date: Fri, 28 Jun 2024 14:27:13 +0100 Subject: [PATCH 07/16] feat: ionic react connect example (#27573) ionic react connect example Co-authored-by: Ivan Vasilov --- .../Home/Connect/Connect.constants.ts | 14 +++ .../content/ionicreact/supabasejs/content.tsx | 115 ++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 apps/studio/components/interfaces/Home/Connect/content/ionicreact/supabasejs/content.tsx diff --git a/apps/studio/components/interfaces/Home/Connect/Connect.constants.ts b/apps/studio/components/interfaces/Home/Connect/Connect.constants.ts index e7adce95098..50c4465350e 100644 --- a/apps/studio/components/interfaces/Home/Connect/Connect.constants.ts +++ b/apps/studio/components/interfaces/Home/Connect/Connect.constants.ts @@ -206,6 +206,20 @@ export const MOBILES: ConnectionType[] = [ }, ], }, + { + key: 'ionicreact', + label: 'Ionic React', + icon: 'react', + guideLink: 'https://supabase.com/docs/guides/getting-started/tutorials/with-ionic-react', + children: [ + { + key: 'supabasejs', + label: 'Supabase-js', + children: [], + icon: 'supabase', + }, + ], + }, { key: 'swift', label: 'Swift', diff --git a/apps/studio/components/interfaces/Home/Connect/content/ionicreact/supabasejs/content.tsx b/apps/studio/components/interfaces/Home/Connect/content/ionicreact/supabasejs/content.tsx new file mode 100644 index 00000000000..adaed38bbcc --- /dev/null +++ b/apps/studio/components/interfaces/Home/Connect/content/ionicreact/supabasejs/content.tsx @@ -0,0 +1,115 @@ +import type { ContentFileProps } from 'components/interfaces/Home/Connect/Connect.types' + +import { + ConnectTabs, + ConnectTabTriggers, + ConnectTabTrigger, + ConnectTabContent, +} from 'components/interfaces/Home/Connect/ConnectTabs' +import SimpleCodeBlock from 'components/to-be-cleaned/SimpleCodeBlock' + +const ContentFile = ({ projectKeys }: ContentFileProps) => { + return ( + + + + + + + + + + {` +REACT_APP_SUPABASE_URL=${projectKeys.apiUrl ?? 'your-project-url'} +REACT_APP_SUPABASE_ANON_KEY=${projectKeys.anonKey ?? 'your-anon-key'} + `} + + + + + + {` +import { createClient } from '@supabase/supabase-js' + +const supabaseUrl = process.env.REACT_APP_SUPABASE_URL +const supabaseAnonKey = process.env.REACT_APP_SUPABASE_ANON_KEY + +export const supabase = createClient(supabaseUrl, supabaseAnonKey) +`} + + + + + + {` +import React, { useEffect, useState } from 'react'; +import { setupIonicReact, IonApp } from '@ionic/react'; +import { + IonContent, + IonHeader, + IonTitle, + IonToolbar, + IonList, + IonItem, +} from '@ionic/react'; + +/* Core CSS required for Ionic components to work properly */ +import '@ionic/react/css/core.css'; + +/* Theme variables */ +import './theme/variables.css'; + +import { supabase } from './supabaseClient'; + +setupIonicReact(); + +export default function App() { + const [todos, setTodos] = useState([]); + useEffect(() => { + getTodos(); + }, []); + + const getTodos = async () => { + try { + const { data, error } = await supabase.from('todos').select(); + + if (error) { + console.error('Error fetching todos:', error.message); + return; + } + + if (data) { + setTodos(data); + } + } catch (error) { + console.error('Error fetching todos:', error.message); + } + }; + + return ( + + <> + + + Todos + + + + + {todos.map((todo) => ( + {todo.title} + ))} + + + + + ); +} +`} + + + + ) +} + +export default ContentFile From bc807b9f4eabd1764c23f800bf6f7c4e4ad140fa Mon Sep 17 00:00:00 2001 From: Craig Cannon Date: Fri, 28 Jun 2024 09:36:45 -0400 Subject: [PATCH 08/16] Update humans.txt (#27545) --- apps/docs/public/humans.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/docs/public/humans.txt b/apps/docs/public/humans.txt index f251af7c9c7..e303ee814d5 100644 --- a/apps/docs/public/humans.txt +++ b/apps/docs/public/humans.txt @@ -18,6 +18,7 @@ Chase Granberry Chris Caruso Chris Copplestone Chris Gwilliams +Craig Cannon Dave Wilson Deji I Div Arora From 2658d7e8a5045a211548d549f5f409b4da132b69 Mon Sep 17 00:00:00 2001 From: Nick McIntosh <2713055+heysailor@users.noreply.github.com> Date: Fri, 28 Jun 2024 21:38:05 +0800 Subject: [PATCH 09/16] Correct RLS description (#22530) The RLS description appeared to have been copy-pasted from elsewhere, and did not reflect the RLS rule. Co-authored-by: Charis <26616127+charislam@users.noreply.github.com> --- apps/docs/content/guides/storage/schema/helper-functions.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/content/guides/storage/schema/helper-functions.mdx b/apps/docs/content/guides/storage/schema/helper-functions.mdx index a29ab4bb17a..b8fef508159 100644 --- a/apps/docs/content/guides/storage/schema/helper-functions.mdx +++ b/apps/docs/content/guides/storage/schema/helper-functions.mdx @@ -17,7 +17,7 @@ Returns the name of a file. For example, if your file is stored in `public/subfo This example demonstrates how you would allow any user to download a file called `favicon.ico`: ```sql -create policy "Allow authenticated uploads" +create policy "Allow public downloads" on storage.objects for select to public From 122ad64a8f70ba3ad7edcf3545ae79811a115c96 Mon Sep 17 00:00:00 2001 From: Limane Gaya Date: Fri, 28 Jun 2024 15:48:00 +0200 Subject: [PATCH 10/16] fix some typos (#27566) --- .../_blog/2024-06-26-postgis-generate-vector-tiles.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/www/_blog/2024-06-26-postgis-generate-vector-tiles.mdx b/apps/www/_blog/2024-06-26-postgis-generate-vector-tiles.mdx index ae29e4ef30b..103fc2d23c0 100644 --- a/apps/www/_blog/2024-06-26-postgis-generate-vector-tiles.mdx +++ b/apps/www/_blog/2024-06-26-postgis-generate-vector-tiles.mdx @@ -32,7 +32,7 @@ Using PostGIS we can then programmatically generate vector tiles and serve them Vector tiles are packets of geographic data, packaged into pre-defined roughly-square shaped "tiles" for transfer over the web. Map data is requested by a client as a set of "tiles" corresponding to square areas of land of a pre-defined size and location. -Especially for large datasets, this has the benefit that the data transfer is greatly reduced because because only data within the current viewport, and at the current zoom level needs to be transferred. +Especially for large datasets, this has the benefit that the data transfer is greatly reduced because only data within the current viewport, and at the current zoom level needs to be transferred. @@ -71,7 +71,7 @@ PG_USE_COPY=true ogr2ogr -f pgdump places.sql places.geojson Enable the PostGIS extension on your Supabase Database on a dedicated separate `gis` schema. To do so you can navigate to the [SQL Editor](/dashboard/project/_/sql/new) and run the following SQL, or you can enable the extension from the [Database Extensions Settings](/dashboard/project/_/database/extensions). -As PostGIS can be quite compute heavy, we recommend enabling it on a decidacted separate schema, for example names `gis`! +As PostGIS can be quite compute heavy, we recommend enabling it on a dedicated separate schema, for example, named `gis`! ```sql CREATE SCHEMA IF NOT EXISTS "gis"; @@ -149,14 +149,14 @@ END; $$; ``` -To limit the amount of data send over the wire, we limit the amount of metadata to include in the vector tile. For example we add a condition for the zoom level, and only return the place name when the user has zoomed in beyond level 13. +To limit the amount of data sent over the wire, we limit the amount of metadata to include in the vector tile. For example we add a condition for the zoom level, and only return the place name when the user has zoomed in beyond level 13. ## Use supabase-js to fetch vector tiles from MapLibre GL client You can find the full `index.html` code on [GitHub](https://github.com/bdon/supabase-vector-tile/blob/main/index.html). Here we'll highlight how to add a new protocol to MapLibreGL to fetch the bas64 encoded binary vector tile data via supabase-js so that MapLibre GL can fetch and render the data as your users interact with the map: ```js index.html -const client = supabase.createClient('you-supabase-api-url', 'your-supabase-anon-key') +const client = supabase.createClient('your-supabase-api-url', 'your-supabase-anon-key') function base64ToArrayBuffer(base64) { var binaryString = atob(base64) @@ -213,7 +213,7 @@ const map = new maplibregl.Map({ ## On demand fetch additional JSON metadata -To limit the amount of data send over the wire, we don't encode all the metadata in the vector tile itself, but rather set up an onclick handler to fetch the additional metadata on demand within the MapLibre GL popup: +To limit the amount of data sent over the wire, we don't encode all the metadata in the vector tile itself, but rather set up an onclick handler to fetch the additional metadata on demand within the MapLibre GL popup: ```js index.html // .. From 395734371319b84030ca51d506a187dd0acf6b9e Mon Sep 17 00:00:00 2001 From: Monica Khoury <99693443+monicakh@users.noreply.github.com> Date: Fri, 28 Jun 2024 18:41:06 +0300 Subject: [PATCH 11/16] Fix: project dropdown url for security advisor route (#27598) --- apps/studio/components/layouts/AppLayout/ProjectDropdown.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/studio/components/layouts/AppLayout/ProjectDropdown.tsx b/apps/studio/components/layouts/AppLayout/ProjectDropdown.tsx index 35f7477dc9a..00666dfebc0 100644 --- a/apps/studio/components/layouts/AppLayout/ProjectDropdown.tsx +++ b/apps/studio/components/layouts/AppLayout/ProjectDropdown.tsx @@ -41,9 +41,11 @@ export const sanitizeRoute = (route: string, routerQueries: ParsedUrlQuery) => { // [Joshen] Ideally we shouldn't use hard coded numbers, but temp workaround // for storage bucket route since its longer const isStorageBucketRoute = 'bucketId' in routerQueries + const isSecurityAdvisorRoute = 'preset' in routerQueries + return route .split('/') - .slice(0, isStorageBucketRoute ? 5 : 4) + .slice(0, isStorageBucketRoute || isSecurityAdvisorRoute ? 5 : 4) .join('/') } else { return route From 83ecfa5e76cbf521142c747fa97ff2ff00e64cc9 Mon Sep 17 00:00:00 2001 From: Wen Bo Xie <5532241+w3b6x9@users.noreply.github.com> Date: Fri, 28 Jun 2024 18:04:02 -0400 Subject: [PATCH 12/16] fix: simplify rooms_users policies (#27629) --- .../nextjs-authorization-demo/README.md | 57 +++++++++---------- .../app/protected/page.tsx | 10 ++-- .../components/create-room-modal.tsx | 4 +- 3 files changed, 34 insertions(+), 37 deletions(-) diff --git a/examples/realtime/nextjs-authorization-demo/README.md b/examples/realtime/nextjs-authorization-demo/README.md index e8826a14405..735b8591549 100644 --- a/examples/realtime/nextjs-authorization-demo/README.md +++ b/examples/realtime/nextjs-authorization-demo/README.md @@ -41,25 +41,23 @@ We'll be using: ```sql CREATE TABLE public.rooms ( id bigint GENERATED BY default AS IDENTITY PRIMARY KEY, - topic text NOT NULL + topic text NOT NULL UNIQUE ); - -CREATE UNIQUE INDEX "unique_topic" on public.rooms (topic); +ALTER TABLE public.rooms ENABLE ROW LEVEL SECURITY; CREATE TABLE public.profiles ( - id bigint GENERATED BY default AS IDENTITY PRIMARY KEY, + id uuid NOT NULL REFERENCES auth.users ON DELETE CASCADE, email text NOT NULL, - user_id uuid REFERENCES auth.users (id) + + PRIMARY KEY (id) ); +ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY; CREATE TABLE public.rooms_users ( user_id uuid REFERENCES auth.users (id), - room_id bigint REFERENCES public.rooms (id), + room_topic text REFERENCES public.rooms (topic), created_at timestamptz DEFAULT CURRENT_TIMESTAMP ); - -ALTER TABLE public.rooms ENABLE ROW LEVEL SECURITY; -ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY; ALTER TABLE public.rooms_users ENABLE ROW LEVEL SECURITY; ``` @@ -82,7 +80,6 @@ AS PERMISSIVE FOR INSERT TO supabase_auth_admin WITH CHECK (true); - CREATE POLICY "authenticated users can read rooms" ON "public"."rooms" AS PERMISSIVE FOR SELECT @@ -95,7 +92,6 @@ AS PERMISSIVE FOR INSERT TO authenticated WITH CHECK (TRUE); - CREATE POLICY "authenticated users can read rooms_users" ON "public"."rooms_users" AS PERMISSIVE FOR SELECT @@ -108,30 +104,30 @@ AS PERMISSIVE FOR INSERT TO authenticated WITH CHECK (TRUE); -CREATE POLICY "authenticated user can enter room" +CREATE POLICY "authenticated user can read broadcast messages and presence state" ON "realtime"."messages" AS PERMISSIVE FOR SELECT TO authenticated USING ( EXISTS ( - SELECT ru.user_id - FROM public.rooms_users ru - JOIN public.rooms r ON r.id = ru.room_id AND r.topic = realtime.topic() - WHERE ru.user_id = auth.uid() + SELECT 1 + FROM public.rooms_users + WHERE user_id = auth.uid() + AND room_topic = realtime.topic() AND realtime.messages.extension in ('broadcast', 'presence') ) ); -CREATE POLICY "authenticated user can broadcast in room" +CREATE POLICY "authenticated user can send broadcast messages and track presence" ON "realtime"."messages" AS PERMISSIVE FOR INSERT TO authenticated WITH CHECK ( EXISTS ( - SELECT ru.user_id - FROM public.rooms_users ru - JOIN public.rooms r ON r.id = ru.room_id AND r.topic = realtime.topic() - WHERE ru.user_id = auth.uid() + SELECT 1 + FROM public.rooms_users + WHERE user_id = auth.uid() + AND room_topic = realtime.topic() AND realtime.messages.extension in ('broadcast', 'presence') ) ); @@ -145,7 +141,7 @@ We need to create a database function and trigger to add an entry to `public.pro CREATE OR REPLACE FUNCTION insert_user() RETURNS TRIGGER AS $$ BEGIN - INSERT INTO public.profiles (user_id, email) VALUES (NEW.id, NEW.email); RETURN NEW; + INSERT INTO public.profiles (id, email) VALUES (NEW.id, NEW.email); RETURN NEW; END; $$ LANGUAGE plpgsql; @@ -159,18 +155,19 @@ GRANT INSERT ON TABLE public.profiles TO supabase_auth_admin; ## Coding Concerns -* Check we're using the `2.10.0` version of `@supabase/realtime-js` +* Check that you're using `@supabase/realtime-js` v2.44.0 or later. * You need to define that the channel is private using the new configuration field during channel creation: - ```typescript - let channel = supabase.realtime.channel(selectedRoom, { - config: { broadcast: { self: true }, private: true }, - }) - ``` -You can check `app/protected/page.tsx` for more information regarding this +```typescript + const channel = supabase.channel('room-1', { + config: { private: true }, + }) +``` + +You can check `app/protected/page.tsx` to see how we've set it up in the demo. ## Adding user to channel Type `/invite ` of an existing user and they will be added to the channel. -![](invite.png) \ No newline at end of file +![invite user slash command](invite.png) diff --git a/examples/realtime/nextjs-authorization-demo/app/protected/page.tsx b/examples/realtime/nextjs-authorization-demo/app/protected/page.tsx index 44ffd952573..0c497343775 100644 --- a/examples/realtime/nextjs-authorization-demo/app/protected/page.tsx +++ b/examples/realtime/nextjs-authorization-demo/app/protected/page.tsx @@ -23,15 +23,15 @@ export default function Chat() { } const addUserToChannel = async (email: string) => { - const user = await supabase.from('profiles').select('user_id').eq('email', email) + const user = await supabase.from('profiles').select('id').eq('email', email) if (!user.data?.length) { addMessage(true, true, `User ${email} not found`) } else { - const room = await supabase.from('rooms').select('id').eq('topic', selectedRoom) + const room = await supabase.from('rooms').select('topic').eq('topic', selectedRoom) await supabase .from('rooms_users') - .upsert({ user_id: user.data?.[0].user_id, room_id: room.data?.[0].id }) + .upsert({ user_id: user.data?.[0].id, room_topic: room.data?.[0].topic }) addMessage(true, true, `Added ${email} to channel ${selectedRoom}`) } } @@ -65,7 +65,7 @@ export default function Chat() { await supabase.auth.getUser() const token = (await supabase.auth.getSession()).data.session?.access_token! supabase.realtime.setAuth(token) - let main = supabase.realtime + let main = supabase .channel('supaslack') .on('broadcast', { event: 'new_room' }, () => getChannels()) .subscribe() @@ -86,7 +86,7 @@ export default function Chat() { channel?.unsubscribe() setUsers(new Set()) - let newChannel = supabase.realtime.channel(selectedRoom, { + let newChannel = supabase.channel(selectedRoom, { config: { broadcast: { self: true }, private: true, // This line will tell the server that you want to use a private channel for this connection diff --git a/examples/realtime/nextjs-authorization-demo/components/create-room-modal.tsx b/examples/realtime/nextjs-authorization-demo/components/create-room-modal.tsx index e37b0f7651a..a59d898b4e4 100644 --- a/examples/realtime/nextjs-authorization-demo/components/create-room-modal.tsx +++ b/examples/realtime/nextjs-authorization-demo/components/create-room-modal.tsx @@ -14,12 +14,12 @@ export default function CreateRoomModal({ channel }: { channel: RealtimeChannel supabase.realtime.setAuth(token) - const rooms_response = await supabase.from('rooms').insert({ topic }).select('id') + const rooms_response = await supabase.from('rooms').insert({ topic }).select('topic') if (rooms_response.data) { await supabase .from('rooms_users') - .insert({ user_id: user.data.user!.id, room_id: rooms_response.data![0].id }) + .insert({ user_id: user.data.user!.id, room_topic: rooms_response.data![0].topic }) await channel?.send({ type: 'broadcast', From 9a18d013c29b11851e922b5b1d19780ca94184cb Mon Sep 17 00:00:00 2001 From: Erik Petersen Date: Fri, 28 Jun 2024 18:39:15 -0400 Subject: [PATCH 13/16] Fix nextjs example in ssr docs (#27622) * docs: fix NextJS middleware code in SSR docs * Fix redirect loop that example would create * Fix formatting --- apps/docs/content/guides/auth/server-side/nextjs.mdx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/docs/content/guides/auth/server-side/nextjs.mdx b/apps/docs/content/guides/auth/server-side/nextjs.mdx index 8663a5f0eab..2925dab980d 100644 --- a/apps/docs/content/guides/auth/server-side/nextjs.mdx +++ b/apps/docs/content/guides/auth/server-side/nextjs.mdx @@ -243,11 +243,15 @@ export async function updateSession(request: NextRequest) { // supabase.auth.getUser(). A simple mistake could make it very hard to debug // issues with users being randomly logged out. - const { data: user, error } = await supabase.auth.getUser() + const { + data: { user }, + } = await supabase.auth.getUser() - if (!user) { + if (!user && !request.nextUrl.pathname.startsWith('/login')) { // no user, potentially respond by redirecting the user to the login page - return NextResponse.redirect('/login') + const url = request.nextUrl.clone() + url.pathname = '/login' + return NextResponse.redirect(url) } // IMPORTANT: You *must* return the supabaseResponse object as it is. If you're From e2bc80ac8d40e36c6d8fcc720a867497d8014123 Mon Sep 17 00:00:00 2001 From: Giuseppe Davide Tanca Date: Sat, 29 Jun 2024 00:50:23 +0200 Subject: [PATCH 14/16] fix(docs): broken references links (#27630) Co-authored-by: davide.tanca --- apps/docs/app/page.tsx | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/docs/app/page.tsx b/apps/docs/app/page.tsx index cbfde7d0394..14a864e6049 100644 --- a/apps/docs/app/page.tsx +++ b/apps/docs/app/page.tsx @@ -122,22 +122,22 @@ const selfHostingOptions = [ { title: 'Auth', icon: 'auth', - href: 'reference/self-hosting-auth/introduction', + href: '/reference/self-hosting-auth/introduction', }, { title: 'Realtime', icon: 'realtime', - href: 'reference/self-hosting-realtime/introduction', + href: '/reference/self-hosting-realtime/introduction', }, { title: 'Storage', icon: 'storage', - href: 'reference/self-hosting-storage/introduction', + href: '/reference/self-hosting-storage/introduction', }, { title: 'Analytics', icon: 'analytics', - href: 'reference/self-hosting-analytics/introduction', + href: '/reference/self-hosting-analytics/introduction', }, ] @@ -145,32 +145,32 @@ const clientLibraries = [ { title: 'Javascript', icon: 'reference-javascript', - href: 'reference/javascript/introduction', + href: '/reference/javascript/introduction', }, { title: 'Flutter', icon: 'reference-dart', - href: 'reference/dart/introduction', + href: '/reference/dart/introduction', }, { title: 'Python', icon: 'reference-python', - href: 'reference/python/introduction', + href: '/reference/python/introduction', }, { title: 'C#', icon: 'reference-csharp', - href: 'reference/csharp/introduction', + href: '/reference/csharp/introduction', }, { title: 'Swift', icon: 'reference-swift', - href: 'reference/swift/introduction', + href: '/reference/swift/introduction', }, { title: 'Kotlin', icon: 'reference-kotlin', - href: 'reference/kotlin/introduction', + href: '/reference/kotlin/introduction', }, ] @@ -179,25 +179,25 @@ const additionalResources = [ title: 'Management API', description: 'Manage your Supabase projects and organizations.', icon: 'reference-api', - href: 'reference/api/introduction', + href: '/reference/api/introduction', }, { title: 'Supabase CLI', description: 'Use the CLI to develop, manage and deploy your projects.', icon: 'reference-cli', - href: 'reference/cli/introduction', + href: '/reference/cli/introduction', }, { title: 'Platform Guides', description: 'Learn more about the tools and services powering Supabase.', icon: 'platform', - href: 'guides/platform', + href: '/guides/platform', }, { title: 'Integrations', description: 'Explore a variety of integrations from Supabase partners.', icon: 'integrations', - href: 'guides/integrations', + href: '/guides/integrations', }, ] From c72fa5d373e59a720cf265e67c3aa57440726a82 Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Sat, 29 Jun 2024 06:11:32 -0300 Subject: [PATCH 15/16] chore(docs): add params for swift methods (#27008) --- apps/docs/spec/supabase_swift_v2.yml | 163 ++++++++++++++++++++++++++- 1 file changed, 157 insertions(+), 6 deletions(-) diff --git a/apps/docs/spec/supabase_swift_v2.yml b/apps/docs/spec/supabase_swift_v2.yml index 1d645bcaeb7..2898b170b65 100644 --- a/apps/docs/spec/supabase_swift_v2.yml +++ b/apps/docs/spec/supabase_swift_v2.yml @@ -138,6 +138,32 @@ functions: - When both **Confirm email** and **Confirm phone** (even when phone provider is disabled) are enabled in [your project](/dashboard/project/_/auth/providers), an obfuscated/fake user object is returned. - When either **Confirm email** or **Confirm phone** (even when phone provider is disabled) is disabled, the error message, `User already registered` is returned. - To fetch the currently logged-in user, refer to [`getUser()`](/docs/reference/swift/get-user). + overwriteParams: + - name: email + isOptional: true + type: String + description: One of `email` or `phone` must be provided. + - name: phone + isOptional: true + type: String + description: One of `email` or `phone` must be provided. + - name: password + type: String + - name: data + isOptional: true + type: JSONObject + description: > + A custom data object to store additional user metadata. + - name: redirectTo + isOptional: true + type: URL + description: > + Only for email signups. + The redirect URL embedded in the email link. + Must be a configured redirect URL for your Supabase instance. + - name: captchaToken + isOptional: true + type: String examples: - id: sign-up name: Sign up with email and password @@ -232,7 +258,6 @@ functions: - `PASSWORD_RECOVERY` - Emitted instead of the `SIGNED_IN` event when the user lands on a page that includes a password recovery link in the URL. - Use it to show a UI to the user where they can [reset their password](/docs/guides/auth/passwords#resetting-a-users-password-forgot-password). - examples: - id: listen-to-auth-changes name: Listen to auth changes @@ -292,6 +317,20 @@ functions: title: "signInWithPassword()" notes: | - Requires either an email and password or a phone number and password. + overwriteParams: + - name: email + isOptional: true + type: String + description: One of `email` or `phone` must be provided. + - name: phone + isOptional: true + type: String + description: One of `email` or `phone` must be provided. + - name: password + type: String + - name: captchaToken + isOptional: true + type: String examples: - id: sign-in-with-email-and-password name: Sign in with email and password @@ -322,6 +361,42 @@ functions: ``` - id: sign-in-with-otp title: "signInWithOTP()" + overwriteParams: + - name: email + isOptional: true + type: String + description: One of `email` or `phone` must be provided. + - name: phone + isOptional: true + type: String + description: One of `email` or `phone` must be provided. + - name: redirectTo + isOptional: true + type: String + description: > + Only for email signups. + The redirect URL embedded in the email link. + Must be a configured redirect URL for your Supabase instance. + - name: channel + isOptional: true + type: MessagingChannel + description: > + The channel to use for sending messages. + Only for phone signups. + - name: shouldCreateUser + isOptional: true + type: Bool + description: > + Whether to create the user if they don't already exist. + Defaults to true. + - name: data + isOptional: true + type: JSONObject + description: > + A custom data object to store additional user metadata. + - name: captchaToken + isOptional: true + type: String notes: | - Requires either an email or phone number. - This method is used for passwordless sign-ins where a OTP is sent to the user's email or phone number. @@ -365,6 +440,31 @@ functions: ``` - id: sign-in-with-oauth title: "signInWithOAuth()" + overwriteParams: + - name: provider + type: Provider + description: > + The third-party provider. + - name: redirectTo + type: URL + isOptional: true + description: > + A URL to send the user to after they are confirmed. + - name: scopes + type: String + isOptional: true + description: > + A space-separated list of scopes granted to the OAuth application. + - name: queryParams + type: "[(name: String, value: String?)]" + isOptional: true + description: > + Additional query params. + - name: configure + type: Callback + isOptional: true + description: > + A custom configuration callback for opening the OAuth flow externally. notes: | - This method is used for signing in using a third-party provider. - Supabase supports many different [third-party providers](https://supabase.com/docs/guides/auth#providers). @@ -454,7 +554,27 @@ functions: ) ``` - id: sign-in-with-sso - title: 'signInWithSSO()' + title: "signInWithSSO()" + overwriteParams: + - name: providerId + isOptional: true + type: String + description: > + UUID of the SSO provider. + One of `providerId` or `domain` is required. + - name: domain + isOptional: true + type: String + description: > + Domain name of the organization to use SSO with. + One of `providerId` or `domain` is required. + - name: redirectTo + type: String + description: > + The URL to redirect the user to after they have signed in. + Must be a configured redirect URL for your Supabase instance. + - name: captchaToken + type: String notes: | - Before you can call this method you need to [establish a connection](/docs/guides/auth/sso/auth-sso-saml#managing-saml-20-connections) to an identity provider. Use the [CLI commands](/docs/reference/cli/supabase-sso) to do this. - If you've associated an email domain to the identity provider, you can use the `domain` property to start a sign-in flow. @@ -506,6 +626,37 @@ functions: ``` - id: verify-otp title: "verifyOTP()" + overwriteParams: + - name: email + isOptional: true + type: String + description: One of `phone`, `email`, or `token_hash` must be provided. + - name: phone + isOptional: true + type: String + description: One of `phone`, `email`, or `token_hash` must be provided. + - name: token_hash + isOptional: true + type: String + description: > + The token hash from the user's email link. + One of `phone`, `email`, or `token_hash` must be provided. + - name: type + type: EmailOTPType | MobileOTPType + - name: token + isOptional: true + type: String + description: The OTP sent to the user. Required if using `phone` or `email`. + - name: redirectTo + isOptional: true + type: URL + description: > + A URL to redirect the user to after they are confirmed. + Must be in your configured redirect URLs. + - name: captchaToken + isOptional: true + type: String + description: Deprecated. notes: | - The `verifyOTP` method takes in different verification types. If a phone number is used, the type can either be `sms` or `phone_change`. If an email address is used, the type can be one of the following: `signup`, `magiclink`, `recovery`, `invite`, `email_change`, or `email`. - The verification type used should be determined based on the corresponding auth method called before `verifyOTP` to sign up / sign-in a user. @@ -629,7 +780,7 @@ functions: let identities = try await supabase.auth.userIdentities() ``` - id: link-identity - title: 'linkIdentity()' + title: "linkIdentity()" notes: | - The **Enable Manual Linking** option must be enabled from your [project's authentication settings](/dashboard/project/_/settings/auth). - The user needs to be signed in to call `linkIdentity()`. @@ -657,7 +808,7 @@ functions: } ``` - id: unlink-identity - title: 'unlinkIdentity()' + title: "unlinkIdentity()" notes: | - The **Enable Manual Linking** option must be enabled from your [project's authentication settings](/dashboard/project/_/settings/auth). - The user needs to be signed in to call `unlinkIdentity()`. @@ -928,7 +1079,7 @@ functions: let factors = try await supabase.auth.mfa.listFactors() ``` - id: admin-api - title: 'Overview' + title: "Overview" notes: | - Any method under the `supabase.auth.admin` namespace requires a `service_role` key. - These methods are considered admin methods and should be called on a trusted server. Never expose your `service_role` key in the browser. @@ -949,7 +1100,7 @@ functions: let adminAuthClient = supabase.auth.admin ``` - id: delete-user - title: 'deleteUser()' + title: "deleteUser()" notes: | - The `deleteUser()` method requires the user's ID, which maps to the `auth.users.id` column. examples: From 05dfbec84696a64851d0d037d88beec4b03ba858 Mon Sep 17 00:00:00 2001 From: Long Hoang <1732217+loong@users.noreply.github.com> Date: Sun, 30 Jun 2024 23:07:15 +0800 Subject: [PATCH 16/16] docs: add fair use to billing faq (#27580) * docs: service restrictions * fix: typo in fair use policy * fix: correct some vale errors * Update apps/docs/content/guides/platform/billing-faq.mdx Co-authored-by: Charis <26616127+charislam@users.noreply.github.com> * Update apps/docs/content/guides/platform/billing-faq.mdx Co-authored-by: Charis <26616127+charislam@users.noreply.github.com> * Update apps/docs/content/guides/platform/billing-faq.mdx Co-authored-by: Charis <26616127+charislam@users.noreply.github.com> * Update apps/docs/content/guides/platform/billing-faq.mdx Co-authored-by: Charis <26616127+charislam@users.noreply.github.com> * Update apps/docs/content/guides/platform/billing-faq.mdx Co-authored-by: Charis <26616127+charislam@users.noreply.github.com> * Update apps/docs/content/guides/platform/billing-faq.mdx Co-authored-by: Charis <26616127+charislam@users.noreply.github.com> * Update apps/docs/content/guides/platform/billing-faq.mdx Co-authored-by: Charis <26616127+charislam@users.noreply.github.com> --------- Co-authored-by: Charis <26616127+charislam@users.noreply.github.com> --- .../content/guides/platform/billing-faq.mdx | 38 +++++++++++++++++-- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/apps/docs/content/guides/platform/billing-faq.mdx b/apps/docs/content/guides/platform/billing-faq.mdx index 4c29c53557b..000372dbd3a 100644 --- a/apps/docs/content/guides/platform/billing-faq.mdx +++ b/apps/docs/content/guides/platform/billing-faq.mdx @@ -15,7 +15,7 @@ Read more on [how billing is organized](https://supabase.com/docs/guides/platfor #### How many free projects can I have? -You are entitled to two active free projects. Paused projects do not count towards your quota. Note that within an organization, we count the free project limits from all members that are either Owner or Admin. If you’ve got another organization member with the Admin or Owner role that has already exhausted their free project quota, you won’t be able to launch another free project in that organization. You can create simply create another free plan organization or change the role of the affected member in your [organization’s team settings](https://supabase.com/dashboard/org/_/team). +You are entitled to two active free projects. Paused projects do not count towards your quota. Note that within an organization, we count the free project limits from all members that are either Owner or Admin. If you’ve got another organization member with the Admin or Owner role that has already exhausted their free project quota, you won’t be able to launch another free project in that organization. You can create another free plan organization or change the role of the affected member in your [organization’s team settings](https://supabase.com/dashboard/org/_/team). #### Can I mix free and paid projects in a single organization? @@ -86,15 +86,45 @@ We can transfer the amount as credits to another organization of your choice. Yo #### What will happen when I exceed the free plan quota? -When you exceed the Free plan quota, we will monitor and notify you about the exceeding limits. It is important to take action at this point. If you continue to exceed the limits without reducing your usage, we will pause your projects. To avoid project pausing, you have two options: reduce your usage or upgrade to a paid plan. +You will be notified when you exceed the free plan quota. It is important to take action at this point. If you continue to exceed the limits without reducing your usage, service restrictions will apply. To avoid service restrictions, you have two options: reduce your usage or upgrade to a paid plan. Learn more about restrictions in the [Fair Use Policy](#fair-use-policy) section. #### What will happen when I exceed the Pro plan quota and have the spend cap on? -When you exceed the Pro plan quota, we will monitor and notify you about the exceeding limits. To unblock yourself, you can simply toggle off your spend cap in your [organization’s billing settings](https://supabase.com/dashboard/org/_/billing) to pay for over-usage beyond the Pro plans limits. If you continue to exceed the limits without reducing your usage or turning off the spend cap, we will pause your projects. +You will be notified when you exceed your Pro plan quota. To unblock yourself, you can toggle off your spend cap in your [organization’s billing settings](https://supabase.com/dashboard/org/_/billing) to pay for over-usage beyond the Pro plans limits. If you continue to exceed the limits without reducing your usage or turning off the spend cap, restrictions will apply. Learn more about restrictions in the [Fair Use Policy](#fair-use-policy) section. #### How do I scale beyond the limits of my Pro plan? -The Pro plan has a spend cap enabled by default to keep costs under control. If you want to scale beyond the plans included quota, ~~simply~~ switch off the spend cap to pay for additional usage beyond the plans included limits. You can toggle the spend cap in the [organization's billing settings](https://supabase.com/dashboard/org/_/billing). Read more about the [spend cap](https://supabase.com/docs/guides/platform/spend-cap). +The Pro plan has a spend cap enabled by default to keep costs under control. If you want to scale beyond the plans included quota, switch off the spend cap to pay for additional usage beyond the plans included limits. You can toggle the spend cap in the [organization's billing settings](https://supabase.com/dashboard/org/_/billing). Read more about the [spend cap](https://supabase.com/docs/guides/platform/spend-cap). + +## Fair Use Policy + +#### What is the Fair Use Policy? + +Our Fair Use Policy gives developers the freedom to build and experiment with Supabase, while protecting our infrastructure. Under the Fair Use policy, service restrictions may apply to your organization if: + +- You continually exceed the free plan quota +- You continually exceed Pro plan quota and have the spend cap enabled +- You have overdue invoices +- You have an expired credit card + +You will receive a notification before Fair Use Policy restrictions are applied. However, in some cases, like suspected abuse of our services, restrictions may be applied without prior notice. + +#### How is the Fair Use Policy applied? + +The Fair Use Policy is applied through service restrictions. This could mean: + +- Pausing projects +- Switching databases to read-only mode +- Disabling new project launches/transfers +- Responding with a 402 status code for all API requests + +The Fair Use Policy is generally applied to all projects of the restricted organization. + +#### How can I remove restrictions applied from the Fair Use Policy? + +To remove restrictions, you will need to address the issue that caused the restriction. This could be reducing your usage, paying overdue invoices, updating your payment method, or any other issue that caused the restriction. Once the issue is resolved, the restriction will be lifted. + +Restrictions due to usage limits are lifted with the next billing cycle as your quota refills at the beginning of each cycle. You can see when your current billing cycle ends on the [billing page](https://supabase.com/dashboard/org/_/usage) under "Billing Breakdown". If your organization is on the free plan, you can also lift restrictions immediately by [upgrading](https://supabase.com/dashboard/org/_/billing?panel=subscriptionPlan) to Pro. ## Reports and invoices