Skip to content

docs: add SDK documentation and SKILL.md#20

Merged
tomaspozo merged 23 commits intomainfrom
tomas/func-538-add-initial-documentation-and-skillsmd-at-the-package-level
Mar 31, 2026
Merged

docs: add SDK documentation and SKILL.md#20
tomaspozo merged 23 commits intomainfrom
tomas/func-538-add-initial-documentation-and-skillsmd-at-the-package-level

Conversation

@tomaspozo
Copy link
Copy Markdown
Member

@tomaspozo tomaspozo commented Mar 28, 2026

Summary

  • Add SKILL.md as a lightweight entry point that routes agents to the right doc file
  • Add docs/ folder with 11 focused, self-contained documentation files covering the full SDK surface
  • Ship docs/ and SKILL.md with the npm package (files in package.json) so agents can find them in node_modules/@supabase/server/
  • Frame documentation as runtime-agnostic — Edge Functions tied to Deno/platform, not the default

Documentation files

File Content
getting-started.md Installation, first endpoint, SupabaseContext, CORS, runtimes
auth-modes.md 4 auth modes, array syntax, named keys, credential flow
hono-adapter.md Middleware setup, per-route auth, CORS, error handling
core-primitives.md 6 composable primitives, composition pipeline, custom handlers
ssr-frameworks.md Next.js/Nuxt/SvelteKit/Remix integration via core primitives
environment-variables.md All env vars, auto-injection (Platform vs CLI), runtime setup
error-handling.md Error classes, 8 codes, error surface per layer
security.md Timing-safe comparison, auth model, named key isolation, CORS, JWT verification
typescript-generics.md Database generic across all entry points, type generation
api-reference.md Every function signature, type, and error constant

…docs with npm

SKILL.md now instructs agents to find documentation in the installed
@supabase/server package (node_modules or repo root) instead of using
relative paths. Added docs/ and SKILL.md to package.json files array
so they ship with npm installs.
Copilot AI review requested due to automatic review settings March 28, 2026 05:19
@linear
Copy link
Copy Markdown

linear Bot commented Mar 28, 2026

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a packaged documentation set for @supabase/server (plus a SKILL.md entry point) so agents/users can discover and navigate SDK usage directly from the installed npm package.

Changes:

  • Add SKILL.md as a doc router for common questions and entry points.
  • Add docs/ with focused guides covering auth, adapters, primitives, env, errors, webhooks, generics, and a full API reference.
  • Ensure docs/ and SKILL.md ship in the npm tarball via package.json#files.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 14 comments.

Show a summary per file
File Description
package.json Include docs/ and SKILL.md in published npm package files.
SKILL.md Provide a lightweight doc entry point mapping questions to specific docs.
docs/getting-started.md Quickstart and createSupabaseContext usage examples.
docs/auth-modes.md Explain allow modes, syntax, and request requirements.
docs/hono-adapter.md Document Hono middleware adapter and patterns (CORS, error handling, overrides).
docs/core-primitives.md Document low-level primitives pipeline and examples.
docs/environment-variables.md Document env var formats, runtime behavior, and overrides.
docs/error-handling.md Document error classes, surfacing patterns, and handling examples.
docs/typescript-generics.md Document Database generics across entrypoints and adapters.
docs/webhooks.md Document verifyWebhookSignature usage and security notes.
docs/api-reference.md Provide a consolidated export-by-entrypoint reference.
CHANGELOG.md Reformat existing changelog bullet formatting.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/error-handling.md
Comment thread docs/auth-modes.md Outdated
Comment on lines +24 to +30
console.log(ctx.userClaims.id) // "d0f1a2b3-..."
console.log(ctx.userClaims.email) // "user@example.com"
console.log(ctx.userClaims.role) // "authenticated"

// ctx.claims has the raw JWT payload
console.log(ctx.claims.sub) // same as userClaims.id
console.log(ctx.claims.exp) // token expiration (epoch seconds)
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this 'user' mode example, SupabaseContext.userClaims and claims are typed as nullable (UserClaims | null, JWTClaims | null) even though they’re guaranteed at runtime for allow: 'user'. As written, ctx.userClaims.id / ctx.claims.sub won’t type-check under strictNullChecks; use non-null assertions (ctx.userClaims!.id, ctx.claims!.sub) or add an explicit guard before accessing these fields.

Suggested change
console.log(ctx.userClaims.id) // "d0f1a2b3-..."
console.log(ctx.userClaims.email) // "user@example.com"
console.log(ctx.userClaims.role) // "authenticated"
// ctx.claims has the raw JWT payload
console.log(ctx.claims.sub) // same as userClaims.id
console.log(ctx.claims.exp) // token expiration (epoch seconds)
console.log(ctx.userClaims!.id) // "d0f1a2b3-..."
console.log(ctx.userClaims!.email) // "user@example.com"
console.log(ctx.userClaims!.role) // "authenticated"
// ctx.claims has the raw JWT payload
console.log(ctx.claims!.sub) // same as userClaims.id
console.log(ctx.claims!.exp) // token expiration (epoch seconds)

Copilot uses AI. Check for mistakes.
Comment thread docs/error-handling.md Outdated
import { EnvError } from '@supabase/server'

try {
const supabase = createContextClient({ auth: { token: auth.token } })
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the “Client factories throw” example, auth.token is referenced but auth isn’t defined in this code block (it’s in a different snippet above). To keep this block self-contained, either include the verifyAuth(...) call in the same snippet or replace auth.token with a placeholder variable (e.g., token) that’s defined locally.

Suggested change
const supabase = createContextClient({ auth: { token: auth.token } })
const token = 'user-jwt-token'
const supabase = createContextClient({ auth: { token } })

Copilot uses AI. Check for mistakes.
Comment thread docs/typescript-generics.md Outdated
Comment on lines +58 to +59
const supabase = createContextClient<Database>({
auth: { token: auth.token },
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This core-primitives example references auth.token, but auth isn’t defined in the snippet. To make it copy/paste-able, either show where auth comes from (e.g., const { data: auth } = await verifyAuth(...)) or replace it with a locally-defined token placeholder.

Suggested change
const supabase = createContextClient<Database>({
auth: { token: auth.token },
const token = 'YOUR_ACCESS_TOKEN'
const supabase = createContextClient<Database>({
auth: { token },

Copilot uses AI. Check for mistakes.
Comment thread docs/core-primitives.md Outdated
Comment on lines +131 to +133
import { createContextClient } from '@supabase/server/core'

// With a user's token (from verifyAuth)
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This createContextClient snippet references auth.token / auth.keyName, but auth isn’t defined within the code block (it appears only in a separate snippet above). Consider making this snippet self-contained (include the verifyAuth(...) call in the same block) or replace auth.* with locally-defined placeholders like token/keyName.

Suggested change
import { createContextClient } from '@supabase/server/core'
// With a user's token (from verifyAuth)
import { createContextClient, verifyAuth } from '@supabase/server/core'
// With a user's token (from verifyAuth)
const { auth } = await verifyAuth(request)

Copilot uses AI. Check for mistakes.
Comment thread docs/error-handling.md
Comment on lines +64 to +78
const { data: ctx, error } = await createSupabaseContext(req, {
allow: 'user',
})

if (error) {
// Custom error format
return Response.json(
{
success: false,
error: { message: error.message, code: error.code },
},
{ status: error.status },
)
}

Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this snippet, destructuring { data: ctx, error } from the createSupabaseContext union result breaks TypeScript narrowing, so ctx remains typed as SupabaseContext | null even after if (error) return .... Prefer keeping the result object intact (e.g., const result = await createSupabaseContext(...)) or add an explicit non-null assertion/check before using ctx.supabase so the example type-checks under strictNullChecks.

Suggested change
const { data: ctx, error } = await createSupabaseContext(req, {
allow: 'user',
})
if (error) {
// Custom error format
return Response.json(
{
success: false,
error: { message: error.message, code: error.code },
},
{ status: error.status },
)
}
const result = await createSupabaseContext(req, {
allow: 'user',
})
if (result.error) {
// Custom error format
return Response.json(
{
success: false,
error: { message: result.error.message, code: result.error.code },
},
{ status: result.error.status },
)
}
const ctx = result.data!

Copilot uses AI. Check for mistakes.
Comment thread docs/getting-started.md
Comment on lines +89 to +99
const { data: ctx, error } = await createSupabaseContext(req, {
allow: 'user',
})

if (error) {
return Response.json(
{ message: error.message, code: error.code },
{ status: error.status },
)
}

Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This createSupabaseContext example destructures { data: ctx, error } from a union return type; with strictNullChecks, ctx remains SupabaseContext | null even after the if (error) { return ... } guard. To keep the snippet copy/paste-able, either avoid destructuring (check result.error then use result.data) or assert ctx non-null before ctx.supabase....

Suggested change
const { data: ctx, error } = await createSupabaseContext(req, {
allow: 'user',
})
if (error) {
return Response.json(
{ message: error.message, code: error.code },
{ status: error.status },
)
}
const result = await createSupabaseContext(req, {
allow: 'user',
})
if (result.error) {
return Response.json(
{ message: result.error.message, code: result.error.code },
{ status: result.error.status },
)
}
const ctx = result.data

Copilot uses AI. Check for mistakes.
Comment thread docs/core-primitives.md Outdated
}

// With partial overrides
const { data: env } = resolveEnv({
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this code block, env is declared twice (const { data: env, error } = ... and later const { data: env } = ...) which will fail if someone copies the snippet verbatim. Consider renaming the second variable (e.g., envWithOverrides) or splitting into two separate code blocks.

Suggested change
const { data: env } = resolveEnv({
const { data: envWithOverrides } = resolveEnv({

Copilot uses AI. Check for mistakes.
Comment thread docs/core-primitives.md
Comment on lines +76 to +83
const { data: auth, error } = await verifyCredentials(credentials, {
allow: 'user',
})

if (error) {
return Response.json({ message: error.message }, { status: error.status })
}

Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example destructures { data: auth, error } from verifyCredentials(...); under strictNullChecks, auth stays typed as AuthResult | null even after if (error) return ..., so auth.authType / auth.userClaims won’t type-check. Using const result = await verifyCredentials(...); if (result.error) ...; const auth = result.data; (or asserting non-null) makes the snippet copy/paste-able.

Suggested change
const { data: auth, error } = await verifyCredentials(credentials, {
allow: 'user',
})
if (error) {
return Response.json({ message: error.message }, { status: error.status })
}
const result = await verifyCredentials(credentials, {
allow: 'user',
})
if (result.error) {
return Response.json(
{ message: result.error.message },
{ status: result.error.status }
)
}
const auth = result.data

Copilot uses AI. Check for mistakes.
Comment thread docs/environment-variables.md Outdated
}

// With overrides
const { data: env } = resolveEnv({
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This snippet redeclares env in the same scope (const { data: env, error } = ... then later const { data: env } = ...), which will break if copy/pasted as-is. Rename the second variable or split into separate code blocks so it runs without edits.

Suggested change
const { data: env } = resolveEnv({
const { data: envWithOverrides } = resolveEnv({

Copilot uses AI. Check for mistakes.
…ontext in examples

- Add non-null assertions (!) after error guards where TS can't narrow
  destructured result tuples
- Split duplicate variable declarations into separate code blocks
- Add missing imports and show where variables like `auth` come from
- Keep { data, error } destructuring pattern consistent with SDK convention
- getting-started: replace Edge Function framing with runtime-neutral
  language, explain module worker pattern works across Deno/Bun/Workers,
  add Runtimes section covering all supported environments
- webhooks: replace Deno.env with process.env for portable examples
- environment-variables: add "Auto-injected in" column distinguishing
  Platform vs Local CLI, reframe section headers
- auth-modes: clean up example key values
- core-primitives: clarify "Integration with frameworks" wording
- types: simplify TSDoc for publishable/secret key descriptions
Add docs/ssr-frameworks.md covering the pattern for using core
primitives in Next.js, SvelteKit, Nuxt, and Remix — cookie extraction,
env bridging, JWKS caching, and a complete Next.js adapter example.

Replace the basic SSR example in core-primitives.md with a pointer
to the new dedicated doc. Add SSR row to SKILL.md routing table.
@tomaspozo tomaspozo requested a review from kallebysantos March 30, 2026 19:27
@tomaspozo tomaspozo enabled auto-merge (squash) March 30, 2026 19:28
Split the single generic example into per-platform sections
(Edge Functions, Cloudflare Workers, Hono, SSR Frameworks) so
AI agents pick the correct import specifier for each runtime.
Adds npm: prefix to all Deno examples and a Deno column to the
entry points table. Also adds createSupabaseContext examples.
Add secret key auth and webhook signature verification quick starts
to SKILL.md. Add explicit decision tree for allow:'always' so AI
agents confirm with the user before leaving endpoints unprotected.
- Add legacy keys warning to SKILL.md (avoid anon/service_role keys)
- Add AI coding skills install section to README
- Add server-to-server quick start with caller code to README
- Add runtimes, documentation table, and named secret keys to README
- Remove verifyWebhookSignature references from all docs
- Delete docs/webhooks.md (code removal in separate PR)
Edge Functions require verify_jwt = false in config.toml when
using allow: public, secret, or always — otherwise the platform
rejects requests before the handler runs.
@tomaspozo tomaspozo disabled auto-merge March 31, 2026 15:00
tomaspozo and others added 4 commits March 31, 2026 10:37
Add recipes for function-to-function calls, pg_net from database,
Stripe webhooks, and generic webhook signature verification.
Document the @supabase/server/wrappers entry point.
Refactor environment-variables.md into Supabase vs non-Supabase sections.
This envs will be injected from cli too
Comment thread docs/environment-variables.md Outdated
1. `Deno.env.get(name)` — Deno (including Supabase Edge Functions)
2. `process.env[name]` — Node.js, Bun, Cloudflare Workers (with node-compat)

### Deno / Supabase Edge Functions
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really sure if mentioning as "Deno / Supabase ...." will create confusion about "Vanilla Deno" exposing theses vars.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notice its mentioned at the end of "getting-started" docs

@kallebysantos kallebysantos force-pushed the tomas/func-538-add-initial-documentation-and-skillsmd-at-the-package-level branch from c433271 to 9972478 Compare March 31, 2026 20:41
@kallebysantos kallebysantos force-pushed the tomas/func-538-add-initial-documentation-and-skillsmd-at-the-package-level branch from 9972478 to c1ba488 Compare March 31, 2026 20:43
@tomaspozo tomaspozo merged commit 661329b into main Mar 31, 2026
2 of 3 checks passed
@tomaspozo tomaspozo deleted the tomas/func-538-add-initial-documentation-and-skillsmd-at-the-package-level branch March 31, 2026 21:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants