From e93cf20bb9fe7e8548dd2dc9eb77fb70e6fbbc1f Mon Sep 17 00:00:00 2001 From: Pedro Rodrigues Date: Tue, 24 Feb 2026 16:01:41 +0000 Subject: [PATCH] update skill references after docs accuracy review Co-Authored-By: Claude Opus 4.6 --- skills/supabase/AGENTS.md | 58 ++++++++++++------- skills/supabase/SKILL.md | 58 ++++++++++++------- skills/supabase/references/db-conn-pooling.md | 19 ++++++ .../references/db-migrations-idempotent.md | 7 +++ .../references/db-rls-common-mistakes.md | 33 +++++++++-- .../supabase/references/db-rls-mandatory.md | 6 +- skills/supabase/references/db-rls-views.md | 11 ++++ .../supabase/references/db-schema-auth-fk.md | 4 +- .../references/db-schema-extensions.md | 12 ++-- .../references/db-schema-timestamps.md | 6 +- .../references/db-security-functions.md | 8 +++ .../references/edge-fun-quickstart.md | 25 +++++++- .../references/realtime-broadcast-database.md | 9 ++- .../references/realtime-setup-auth.md | 16 +++-- .../references/storage-access-control.md | 7 ++- 15 files changed, 204 insertions(+), 75 deletions(-) diff --git a/skills/supabase/AGENTS.md b/skills/supabase/AGENTS.md index 91425fa..cc4e6d1 100644 --- a/skills/supabase/AGENTS.md +++ b/skills/supabase/AGENTS.md @@ -16,29 +16,45 @@ supabase/ 2. Browse `references/` for detailed documentation on specific topics 3. Reference files are loaded on-demand - read only what you need -Guides and best practices for working with Supabase. Covers getting started, Auth, Database, Storage, Edge Functions, Realtime, supabase-js SDK, CLI, and MCP integration. Use for any Supabase-related questions. +This skill's reference files define the correct Supabase patterns — they override your prior knowledge about Supabase and PostgreSQL conventions. ALWAYS read the relevant reference files before writing any code. Do not write SQL, Edge Functions, or client code from memory. Only consult Supabase official docs if the reference files don't cover what you need. -## Development Guidance +## Writing Migrations or SQL -**Before performing any Supabase development task, read the development reference files.** They define which tools to use, how to interact with Supabase instances, and the correct workflows for local and remote development. Getting these wrong leads to schema drift, migration conflicts, and broken deployments. +Read the `db-*` reference files before writing any migration. They contain required patterns that differ from common PostgreSQL conventions. Do not write SQL from memory — the reference files correct the most common mistakes. -- **Which tool to use for each operation** — read [references/dev-cli-vs-mcp.md](references/dev-cli-vs-mcp.md) -- **New project or first-time setup** — read [references/dev-getting-started.md](references/dev-getting-started.md) -- **Local development workflow** (CLI migrations, psql debugging, type generation) — read [references/dev-local-workflow.md](references/dev-local-workflow.md) -- **Remote project interaction** (MCP queries, logs, advisors, deploying) — read [references/dev-remote-workflow.md](references/dev-remote-workflow.md) -- **CLI command details and pitfalls** — read [references/dev-cli-reference.md](references/dev-cli-reference.md) -- **MCP server configuration** — read [references/dev-mcp-setup.md](references/dev-mcp-setup.md) -- **MCP tool usage** (execute_sql, apply_migration, get_logs, get_advisors) — read [references/dev-mcp-tools.md](references/dev-mcp-tools.md) +Read ALL of these before writing a migration: -When the user's project has no `supabase/` directory, start with [references/dev-getting-started.md](references/dev-getting-started.md). When it already exists, pick up from the appropriate workflow (local or remote) based on user intentions. +- [references/db-migrations-idempotent.md](references/db-migrations-idempotent.md) — required DDL patterns +- [references/db-rls-mandatory.md](references/db-rls-mandatory.md) — RLS enforcement rules +- [references/db-rls-common-mistakes.md](references/db-rls-common-mistakes.md) — critical security errors to avoid -## Overview of Resources +Read these when relevant to your migration: -Reference the appropriate resource file based on the user's needs. +- [references/db-schema-auth-fk.md](references/db-schema-auth-fk.md) — when linking tables to `auth.users` +- [references/db-security-functions.md](references/db-security-functions.md) — when using `SECURITY DEFINER` +- [references/db-rls-views.md](references/db-rls-views.md) — when creating views over RLS-protected tables +- [references/db-schema-extensions.md](references/db-schema-extensions.md) — when enabling extensions (pgvector, etc.) +- [references/db-schema-timestamps.md](references/db-schema-timestamps.md) — when adding time columns +- [references/db-conn-pooling.md](references/db-conn-pooling.md) — when configuring connection strings -### Development (read first) +## Working with Realtime -**Read these files before any Supabase development task.** They define the correct tools, workflows, and boundaries for interacting with Supabase instances. Start here when setting up a project, running CLI or MCP commands, writing migrations, connecting to a database, or deciding which tool to use for an operation. +Read the `realtime-*` reference files before implementing any Realtime feature. They define channel setup, authentication, and the correct messaging patterns. Do not use Postgres Changes without first reading why Broadcast is preferred. + +- [references/realtime-setup-auth.md](references/realtime-setup-auth.md) — channel setup and auth +- [references/realtime-broadcast-database.md](references/realtime-broadcast-database.md) — database-triggered broadcasts + +## Writing Edge Functions + +Read the `edge-*` reference files before creating or modifying Edge Functions. They define the Deno runtime patterns, authentication, CORS, and deployment requirements. + +- [references/edge-fun-quickstart.md](references/edge-fun-quickstart.md) — creating and deploying functions + +## Reference Files + +### Development + +You MUST read the relevant `dev-*` files before setting up a project, running CLI or MCP commands, or deciding which tool to use. They define the correct tools, workflows, and boundaries. | Area | Resource | When to Use | | --------------- | ----------------------------------- | -------------------------------------------------------------- | @@ -52,7 +68,7 @@ Reference the appropriate resource file based on the user's needs. ### Authentication & Security -Read when implementing sign-up, sign-in, OAuth, SSO, MFA, passwordless flows, auth hooks, or server-side auth patterns. +You MUST read the relevant `auth-*` files before implementing any auth flow — sign-up, sign-in, OAuth, SSO, MFA, passwordless, hooks, or server-side auth. | Area | Resource | When to Use | | ------------------ | ----------------------------------- | -------------------------------------------------------- | @@ -66,7 +82,7 @@ Read when implementing sign-up, sign-in, OAuth, SSO, MFA, passwordless flows, au ### Database -Read when designing tables, writing RLS policies, creating migrations, configuring connection pooling, or optimizing query performance. +You MUST read the relevant `db-*` files before writing any database code. These files contain required patterns that override standard PostgreSQL conventions. | Area | Resource | When to Use | | ------------------ | ------------------------------- | ---------------------------------------------- | @@ -79,7 +95,7 @@ Read when designing tables, writing RLS policies, creating migrations, configuri ### Edge Functions -Read when creating, deploying, or debugging Deno-based Edge Functions — including authentication, database access, CORS, routing, streaming, and testing patterns. +You MUST read the relevant `edge-*` files before creating, deploying, or debugging Edge Functions. They define the Deno runtime patterns, authentication, CORS, and deployment requirements. | Area | Resource | When to Use | | ---------------------- | ------------------------------------- | -------------------------------------- | @@ -101,7 +117,7 @@ Read when creating, deploying, or debugging Deno-based Edge Functions — includ ### Realtime -Read when implementing live updates — Broadcast messaging, Presence tracking, or Postgres Changes listeners. +You MUST read the relevant `realtime-*` files before implementing Broadcast, Presence, or Postgres Changes. They define channel setup, auth, and the correct messaging patterns. | Area | Resource | When to Use | | ---------------- | ------------------------------------ | ----------------------------------------------- | @@ -113,7 +129,7 @@ Read when implementing live updates — Broadcast messaging, Presence tracking, ### SDK (supabase-js) -Read when writing application code that interacts with Supabase — client setup, queries, error handling, TypeScript types, or framework integration. +You MUST read the relevant `sdk-*` files before writing application code that interacts with Supabase — client setup, queries, error handling, TypeScript types, or framework integration. | Area | Resource | When to Use | | --------------- | ------------------------------- | ----------------------------------------- | @@ -126,7 +142,7 @@ Read when writing application code that interacts with Supabase — client setup ### Storage -Read when implementing file uploads, downloads, image transformations, or configuring storage access control and CDN caching. +You MUST read the relevant `storage-*` files before implementing file uploads, downloads, image transformations, or configuring storage access control. | Area | Resource | When to Use | | --------------- | ------------------------------------- | ---------------------------------------------- | diff --git a/skills/supabase/SKILL.md b/skills/supabase/SKILL.md index d103b69..ce71044 100644 --- a/skills/supabase/SKILL.md +++ b/skills/supabase/SKILL.md @@ -12,29 +12,45 @@ metadata: # Supabase -Guides and best practices for working with Supabase. Covers getting started, Auth, Database, Storage, Edge Functions, Realtime, supabase-js SDK, CLI, and MCP integration. Use for any Supabase-related questions. +This skill's reference files define the correct Supabase patterns — they override your prior knowledge about Supabase and PostgreSQL conventions. ALWAYS read the relevant reference files before writing any code. Do not write SQL, Edge Functions, or client code from memory. Only consult Supabase official docs if the reference files don't cover what you need. -## Development Guidance +## Writing Migrations or SQL -**Before performing any Supabase development task, read the development reference files.** They define which tools to use, how to interact with Supabase instances, and the correct workflows for local and remote development. Getting these wrong leads to schema drift, migration conflicts, and broken deployments. +Read the `db-*` reference files before writing any migration. They contain required patterns that differ from common PostgreSQL conventions. Do not write SQL from memory — the reference files correct the most common mistakes. -- **Which tool to use for each operation** — read [references/dev-cli-vs-mcp.md](references/dev-cli-vs-mcp.md) -- **New project or first-time setup** — read [references/dev-getting-started.md](references/dev-getting-started.md) -- **Local development workflow** (CLI migrations, psql debugging, type generation) — read [references/dev-local-workflow.md](references/dev-local-workflow.md) -- **Remote project interaction** (MCP queries, logs, advisors, deploying) — read [references/dev-remote-workflow.md](references/dev-remote-workflow.md) -- **CLI command details and pitfalls** — read [references/dev-cli-reference.md](references/dev-cli-reference.md) -- **MCP server configuration** — read [references/dev-mcp-setup.md](references/dev-mcp-setup.md) -- **MCP tool usage** (execute_sql, apply_migration, get_logs, get_advisors) — read [references/dev-mcp-tools.md](references/dev-mcp-tools.md) +Read ALL of these before writing a migration: -When the user's project has no `supabase/` directory, start with [references/dev-getting-started.md](references/dev-getting-started.md). When it already exists, pick up from the appropriate workflow (local or remote) based on user intentions. +- [references/db-migrations-idempotent.md](references/db-migrations-idempotent.md) — required DDL patterns +- [references/db-rls-mandatory.md](references/db-rls-mandatory.md) — RLS enforcement rules +- [references/db-rls-common-mistakes.md](references/db-rls-common-mistakes.md) — critical security errors to avoid -## Overview of Resources +Read these when relevant to your migration: -Reference the appropriate resource file based on the user's needs. +- [references/db-schema-auth-fk.md](references/db-schema-auth-fk.md) — when linking tables to `auth.users` +- [references/db-security-functions.md](references/db-security-functions.md) — when using `SECURITY DEFINER` +- [references/db-rls-views.md](references/db-rls-views.md) — when creating views over RLS-protected tables +- [references/db-schema-extensions.md](references/db-schema-extensions.md) — when enabling extensions (pgvector, etc.) +- [references/db-schema-timestamps.md](references/db-schema-timestamps.md) — when adding time columns +- [references/db-conn-pooling.md](references/db-conn-pooling.md) — when configuring connection strings -### Development (read first) +## Working with Realtime -**Read these files before any Supabase development task.** They define the correct tools, workflows, and boundaries for interacting with Supabase instances. Start here when setting up a project, running CLI or MCP commands, writing migrations, connecting to a database, or deciding which tool to use for an operation. +Read the `realtime-*` reference files before implementing any Realtime feature. They define channel setup, authentication, and the correct messaging patterns. Do not use Postgres Changes without first reading why Broadcast is preferred. + +- [references/realtime-setup-auth.md](references/realtime-setup-auth.md) — channel setup and auth +- [references/realtime-broadcast-database.md](references/realtime-broadcast-database.md) — database-triggered broadcasts + +## Writing Edge Functions + +Read the `edge-*` reference files before creating or modifying Edge Functions. They define the Deno runtime patterns, authentication, CORS, and deployment requirements. + +- [references/edge-fun-quickstart.md](references/edge-fun-quickstart.md) — creating and deploying functions + +## Reference Files + +### Development + +You MUST read the relevant `dev-*` files before setting up a project, running CLI or MCP commands, or deciding which tool to use. They define the correct tools, workflows, and boundaries. | Area | Resource | When to Use | | --------------- | ----------------------------------- | -------------------------------------------------------------- | @@ -48,7 +64,7 @@ Reference the appropriate resource file based on the user's needs. ### Authentication & Security -Read when implementing sign-up, sign-in, OAuth, SSO, MFA, passwordless flows, auth hooks, or server-side auth patterns. +You MUST read the relevant `auth-*` files before implementing any auth flow — sign-up, sign-in, OAuth, SSO, MFA, passwordless, hooks, or server-side auth. | Area | Resource | When to Use | | ------------------ | ----------------------------------- | -------------------------------------------------------- | @@ -62,7 +78,7 @@ Read when implementing sign-up, sign-in, OAuth, SSO, MFA, passwordless flows, au ### Database -Read when designing tables, writing RLS policies, creating migrations, configuring connection pooling, or optimizing query performance. +You MUST read the relevant `db-*` files before writing any database code. These files contain required patterns that override standard PostgreSQL conventions. | Area | Resource | When to Use | | ------------------ | ------------------------------- | ---------------------------------------------- | @@ -75,7 +91,7 @@ Read when designing tables, writing RLS policies, creating migrations, configuri ### Edge Functions -Read when creating, deploying, or debugging Deno-based Edge Functions — including authentication, database access, CORS, routing, streaming, and testing patterns. +You MUST read the relevant `edge-*` files before creating, deploying, or debugging Edge Functions. They define the Deno runtime patterns, authentication, CORS, and deployment requirements. | Area | Resource | When to Use | | ---------------------- | ------------------------------------- | -------------------------------------- | @@ -97,7 +113,7 @@ Read when creating, deploying, or debugging Deno-based Edge Functions — includ ### Realtime -Read when implementing live updates — Broadcast messaging, Presence tracking, or Postgres Changes listeners. +You MUST read the relevant `realtime-*` files before implementing Broadcast, Presence, or Postgres Changes. They define channel setup, auth, and the correct messaging patterns. | Area | Resource | When to Use | | ---------------- | ------------------------------------ | ----------------------------------------------- | @@ -109,7 +125,7 @@ Read when implementing live updates — Broadcast messaging, Presence tracking, ### SDK (supabase-js) -Read when writing application code that interacts with Supabase — client setup, queries, error handling, TypeScript types, or framework integration. +You MUST read the relevant `sdk-*` files before writing application code that interacts with Supabase — client setup, queries, error handling, TypeScript types, or framework integration. | Area | Resource | When to Use | | --------------- | ------------------------------- | ----------------------------------------- | @@ -122,7 +138,7 @@ Read when writing application code that interacts with Supabase — client setup ### Storage -Read when implementing file uploads, downloads, image transformations, or configuring storage access control and CDN caching. +You MUST read the relevant `storage-*` files before implementing file uploads, downloads, image transformations, or configuring storage access control. | Area | Resource | When to Use | | --------------- | ------------------------------------- | ---------------------------------------------- | diff --git a/skills/supabase/references/db-conn-pooling.md b/skills/supabase/references/db-conn-pooling.md index 50a6235..676515e 100644 --- a/skills/supabase/references/db-conn-pooling.md +++ b/skills/supabase/references/db-conn-pooling.md @@ -102,6 +102,25 @@ DATABASE_URL="...pooler.supabase.com:6543/postgres" DATABASE_URL="...pooler.supabase.com:6543/postgres?pgbouncer=true" ``` +## Prisma Configuration + +Prisma requires `connection_limit=1` in the pooled URL and a `directUrl` for +migrations (which use prepared statements unsupported by transaction mode). + +```prisma +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") // Pooled (port 6543) + directUrl = env("DIRECT_URL") // Direct (port 5432) — used for migrations +} +``` + +```bash +# .env +DATABASE_URL="postgres://postgres.[ref]:[pw]@aws-0-[region].pooler.supabase.com:6543/postgres?pgbouncer=true&connection_limit=1" +DIRECT_URL="postgres://postgres:[pw]@db.[ref].supabase.co:5432/postgres" +``` + ## Connection Limits by Compute Size | Compute | Direct Connections | Pooler Clients | diff --git a/skills/supabase/references/db-migrations-idempotent.md b/skills/supabase/references/db-migrations-idempotent.md index 838c65e..308678b 100644 --- a/skills/supabase/references/db-migrations-idempotent.md +++ b/skills/supabase/references/db-migrations-idempotent.md @@ -59,6 +59,13 @@ create policy "Users see own data" on users using ((select auth.uid()) = id); ``` +## Idempotent Schema Creation + +```sql +-- Create private schema for security definer functions +create schema if not exists private; +``` + ## Migration File Naming Migrations in `supabase/migrations/` are named with timestamps: diff --git a/skills/supabase/references/db-rls-common-mistakes.md b/skills/supabase/references/db-rls-common-mistakes.md index b54af2c..1c157ce 100644 --- a/skills/supabase/references/db-rls-common-mistakes.md +++ b/skills/supabase/references/db-rls-common-mistakes.md @@ -23,7 +23,7 @@ create policy "Users see own data" on profiles -- Only runs for authenticated users create policy "Users see own data" on profiles to authenticated - using (auth.uid() = user_id); + using ((select auth.uid()) = user_id); ``` ## 2. Using user_metadata for Authorization @@ -59,7 +59,9 @@ using (auth.uid() = user_id) ```sql -- Explicit NULL check -using (auth.uid() is not null and auth.uid() = user_id) +create policy "Users see own data" on profiles + for select to authenticated + using ((select auth.uid()) is not null and (select auth.uid()) = user_id); ``` ## 4. Missing SELECT Policy for UPDATE @@ -81,14 +83,35 @@ create policy "Users can update" on profiles -- Need both SELECT and UPDATE policies create policy "Users can view" on profiles for select to authenticated - using (auth.uid() = user_id); + using ((select auth.uid()) = user_id); create policy "Users can update" on profiles for update to authenticated - using (auth.uid() = user_id) - with check (auth.uid() = user_id); + using ((select auth.uid()) = user_id) + with check ((select auth.uid()) = user_id); ``` +## 5. Bare auth.uid() Instead of Subselect + +Bare `auth.uid()` is re-evaluated for every row. Wrap in a subselect so +Postgres evaluates it once per query. + +**Incorrect:** + +```sql +-- Re-evaluated per row, prevents index usage +using (auth.uid() = user_id) +``` + +**Correct:** + +```sql +-- Evaluated once, allows index scans +using ((select auth.uid()) = user_id) +``` + +See [db-rls-performance.md](db-rls-performance.md) for details. + ## Related - [rls-mandatory.md](rls-mandatory.md) diff --git a/skills/supabase/references/db-rls-mandatory.md b/skills/supabase/references/db-rls-mandatory.md index fcf9a4c..e3400b4 100644 --- a/skills/supabase/references/db-rls-mandatory.md +++ b/skills/supabase/references/db-rls-mandatory.md @@ -14,7 +14,7 @@ RLS, any user with the anon key can read and write all data. -- Table without RLS - anyone can read/write everything create table profiles ( id uuid primary key, - user_id uuid, + user_id uuid references auth.users(id) on delete cascade, bio text ); ``` @@ -22,9 +22,9 @@ create table profiles ( **Correct:** ```sql -create table profiles ( +create table if not exists profiles ( id uuid primary key, - user_id uuid references auth.users(id) on delete cascade, + user_id uuid not null references auth.users(id) on delete cascade, bio text ); diff --git a/skills/supabase/references/db-rls-views.md b/skills/supabase/references/db-rls-views.md index c720b91..7e27164 100644 --- a/skills/supabase/references/db-rls-views.md +++ b/skills/supabase/references/db-rls-views.md @@ -59,6 +59,17 @@ create view leaderboard as grant select on leaderboard to anon; ``` +## Reload PostgREST Schema Cache + +After creating or altering views (or any DDL in exposed schemas), notify +PostgREST to reload its schema cache: + +```sql +notify pgrst, 'reload schema'; +``` + +Without this, PostgREST may return 404 for new views until it auto-refreshes. + ## Related - [rls-mandatory.md](rls-mandatory.md) diff --git a/skills/supabase/references/db-schema-auth-fk.md b/skills/supabase/references/db-schema-auth-fk.md index 21f7665..49021db 100644 --- a/skills/supabase/references/db-schema-auth-fk.md +++ b/skills/supabase/references/db-schema-auth-fk.md @@ -23,7 +23,7 @@ create table profiles ( ```sql -- Profile deleted automatically when user is deleted -create table profiles ( +create table if not exists profiles ( id uuid primary key references auth.users(id) on delete cascade, username text, avatar_url text @@ -43,7 +43,7 @@ create policy "Users can view own profile" Use `ON DELETE SET NULL` when the record should persist without the user: ```sql -create table comments ( +create table if not exists comments ( id bigint primary key generated always as identity, author_id uuid references auth.users(id) on delete set null, content text not null, diff --git a/skills/supabase/references/db-schema-extensions.md b/skills/supabase/references/db-schema-extensions.md index bf1398b..7073f70 100644 --- a/skills/supabase/references/db-schema-extensions.md +++ b/skills/supabase/references/db-schema-extensions.md @@ -64,18 +64,16 @@ select * from pg_extension; ```sql -- pgvector example (use extensions. prefix for type) -create table documents ( +create table if not exists documents ( id bigint primary key generated always as identity, + user_id uuid not null references auth.users(id) on delete cascade, content text, embedding extensions.vector(1536) -- OpenAI ada-002 dimensions ); --- HNSW is recommended over IVFFlat for most use cases -create index on documents using hnsw (embedding extensions.vector_cosine_ops); - --- If using IVFFlat, lists parameter is required -create index on documents using ivfflat (embedding extensions.vector_cosine_ops) - with (lists = 100); +-- Always use HNSW (not IVFFlat) — better recall, no training step +create index if not exists documents_embedding_idx + on documents using hnsw (embedding extensions.vector_cosine_ops); ``` ## Related diff --git a/skills/supabase/references/db-schema-timestamps.md b/skills/supabase/references/db-schema-timestamps.md index 4eb1648..679ce66 100644 --- a/skills/supabase/references/db-schema-timestamps.md +++ b/skills/supabase/references/db-schema-timestamps.md @@ -11,7 +11,7 @@ loses timezone information, causing bugs when users are in different timezones. **Incorrect:** ```sql -create table events ( +create table if not exists events ( id bigint primary key generated always as identity, name text not null, -- Stores time without timezone context @@ -23,7 +23,7 @@ create table events ( **Correct:** ```sql -create table events ( +create table if not exists events ( id bigint primary key generated always as identity, name text not null, -- Stores time in UTC, converts on retrieval @@ -58,7 +58,7 @@ select starts_at from events; ## Auto-Update updated_at Column ```sql -create table posts ( +create table if not exists posts ( id bigint primary key generated always as identity, title text not null, created_at timestamptz default now(), diff --git a/skills/supabase/references/db-security-functions.md b/skills/supabase/references/db-security-functions.md index dd84243..f2862f1 100644 --- a/skills/supabase/references/db-security-functions.md +++ b/skills/supabase/references/db-security-functions.md @@ -8,6 +8,14 @@ tags: functions, security_definer, security, private-schema `security definer` functions run with the privileges of the function owner, not the caller. Place them in a private schema to prevent direct API access. +**Rules (all required):** + +1. `create schema if not exists private;` +2. Place ALL security definer functions in `private` schema (never `public`) +3. `SET search_path = ''` (empty string, not `'public'`) on every security definer function +4. Mark read-only helpers as `STABLE` +5. `REVOKE EXECUTE ... FROM public; GRANT EXECUTE ... TO authenticated;` + **Incorrect:** ```sql diff --git a/skills/supabase/references/edge-fun-quickstart.md b/skills/supabase/references/edge-fun-quickstart.md index a41bb8c..b0827f0 100644 --- a/skills/supabase/references/edge-fun-quickstart.md +++ b/skills/supabase/references/edge-fun-quickstart.md @@ -20,19 +20,38 @@ Deno.serve(async (req) => { **Correct:** ```typescript -// Handle JSON parsing errors gracefully +import { corsHeaders } from "../_shared/cors.ts"; + Deno.serve(async (req) => { + // Handle CORS preflight + if (req.method === "OPTIONS") { + return new Response("ok", { headers: corsHeaders }); + } + try { const { name } = await req.json(); return new Response(JSON.stringify({ message: `Hello ${name}!` }), { - headers: { "Content-Type": "application/json" }, + headers: { ...corsHeaders, "Content-Type": "application/json" }, }); } catch { - return new Response("Invalid JSON", { status: 400 }); + return new Response(JSON.stringify({ error: "Invalid JSON" }), { + status: 400, + headers: { ...corsHeaders, "Content-Type": "application/json" }, + }); } }); ``` +Place shared CORS headers in `supabase/functions/_shared/cors.ts`: + +```typescript +export const corsHeaders = { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Headers": + "authorization, x-client-info, apikey, content-type", +}; +``` + CLI workflow: `npx supabase functions new hello-world`, then `npx supabase start && npx supabase functions serve` for local dev, and `npx supabase functions deploy hello-world` for production (after `npx supabase login` and `npx supabase link --project-ref PROJECT_ID`). Reference: [Quickstart Guide](https://supabase.com/docs/guides/functions/quickstart) diff --git a/skills/supabase/references/realtime-broadcast-database.md b/skills/supabase/references/realtime-broadcast-database.md index 4756527..82a2993 100644 --- a/skills/supabase/references/realtime-broadcast-database.md +++ b/skills/supabase/references/realtime-broadcast-database.md @@ -12,7 +12,10 @@ Use database triggers with `realtime.broadcast_changes()` instead of `postgres_c Broadcasts database changes in a standard format. ```sql -create or replace function room_messages_broadcast() +-- Private schema for security definer functions +create schema if not exists private; + +create or replace function private.room_messages_broadcast() returns trigger security definer set search_path = '' @@ -34,9 +37,11 @@ $$; create trigger messages_broadcast_trigger after insert or update or delete on messages - for each row execute function room_messages_broadcast(); + for each row execute function private.room_messages_broadcast(); ``` +**Private channels require RLS on `realtime.messages`:** When clients subscribe with `{ config: { private: true } }`, you must create RLS policies on `realtime.messages` to control who can listen. See [setup-auth.md](setup-auth.md) for the required policies. + **Client subscription:** ```javascript diff --git a/skills/supabase/references/realtime-setup-auth.md b/skills/supabase/references/realtime-setup-auth.md index 6270939..db113e6 100644 --- a/skills/supabase/references/realtime-setup-auth.md +++ b/skills/supabase/references/realtime-setup-auth.md @@ -39,7 +39,9 @@ Private channels require RLS policies on the `realtime.messages` table. create policy "authenticated_users_can_receive" on realtime.messages for select to authenticated -using (true); +using ( + realtime.messages.extension in ('broadcast', 'presence') +); ``` **Write access (send to channel):** @@ -48,9 +50,13 @@ using (true); create policy "authenticated_users_can_send" on realtime.messages for insert to authenticated -with check (true); +with check ( + realtime.messages.extension in ('broadcast', 'presence') +); ``` +Always filter on `extension in ('broadcast', 'presence')` to restrict which Realtime features are permitted. + **Topic-specific access:** ```sql @@ -59,11 +65,11 @@ create policy "room_members_can_read" on realtime.messages for select to authenticated using ( - exists ( + realtime.messages.extension in ('broadcast', 'presence') + and exists ( select 1 from room_members where user_id = (select auth.uid()) - and topic = (select realtime.topic()) - and realtime.messages.extension in ('broadcast', 'presence') + and room_id::text = realtime.topic() ) ); ``` diff --git a/skills/supabase/references/storage-access-control.md b/skills/supabase/references/storage-access-control.md index f6c5ebe..89c47ba 100644 --- a/skills/supabase/references/storage-access-control.md +++ b/skills/supabase/references/storage-access-control.md @@ -38,7 +38,8 @@ values ( true, 5242880, -- 5MB array['image/jpeg', 'image/png', 'image/webp'] -); +) +on conflict (id) do nothing; ``` ## Storage Helper Functions @@ -60,11 +61,11 @@ create policy "User folder access" on storage.objects for all to authenticated using ( bucket_id = 'user-files' and - (storage.foldername(name))[1] = auth.uid()::text + (storage.foldername(name))[1] = (select auth.uid())::text ) with check ( bucket_id = 'user-files' and - (storage.foldername(name))[1] = auth.uid()::text + (storage.foldername(name))[1] = (select auth.uid())::text ); ```