Files
supabase/apps/studio/components/interfaces/Auth/Policies/PolicyTableRow/PolicyTableRow.utils.ts
Charis d4079083fc chore(studio): drop @supabase/postgres-meta in favor of @supabase/pg-meta (#45844)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Refactor / dependency cleanup.

## What is the current behavior?

`apps/studio` lists both `@supabase/pg-meta` (workspace package) as a
runtime dep and `@supabase/postgres-meta` (external npm package,
`^0.64.4`) as a devDependency. The external package is used only for
type imports across 44 files — there is no runtime usage and no codegen
pipeline that needs it.

## What is the new behavior?

Every `Postgres*` type import (`PostgresTable`, `PostgresColumn`,
`PostgresPolicy`, `PostgresTrigger`, `PostgresView`,
`PostgresMaterializedView`, `PostgresForeignTable`, `PostgresSchema`,
`PostgresPublication`, `PostgresRelationship`, `PostgresPrimaryKey`) is
replaced with its `PG*` counterpart from `@supabase/pg-meta`, and the
external dep is removed from \`apps/studio/package.json\`. Top-level
type re-exports were added to \`packages/pg-meta/src/index.ts\` so
consumers can import directly from the package root.

Two latent issues surfaced by the stricter pg-meta types are also fixed:
- \`data/foreign-tables/foreign-tables-query.ts\` was casting
foreign-table results as \`PostgresView[]\`; corrected to
\`PGForeignTable[]\`.
- \`pg-meta\`'s \`PGTrigger\` Zod schema declared
\`orientation\`/\`activation\` as \`z.string()\`, inconsistent with
pg-meta's own \`getDatabaseTriggerUpdateSQL\` helper that requires the
narrow literal unions; tightened to \`z.enum\`.

## Additional context

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Updated internal TypeScript type definitions across the codebase to
use the latest type system from `@supabase/pg-meta`.
  * Removed `@supabase/postgres-meta` dependency.
* Enhanced type validation for database triggers and schemas to enforce
stricter constraints.

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45844)

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-13 16:07:10 +00:00

89 lines
3.5 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { ident, joinSqlFragments, safeSql, type SafeSqlFragment } from '@supabase/pg-meta'
import type { PGPolicy } from '@supabase/pg-meta'
import type { TableApiAccessData } from '@/data/privileges/table-api-access-query'
export type Policy = Omit<PGPolicy, 'definition' | 'check'> & {
definition: SafeSqlFragment | null
check: SafeSqlFragment | null
}
/**
* Single classifier for the RLS page's per-table admonition state. Shares the
* "granted / custom / revoked" grant semantics used by the Data API settings
* page's ExposedTableSelector so the two views agree on what counts as exposed.
*/
export type TableDataApiStatus =
| 'schema-not-exposed' // schema isn't in the PostgREST exposed list
| 'no-grants' // schema exposed, no API roles have any privileges (revoked)
| 'custom-grants' // schema exposed, partial / non-standard grants
| 'publicly-readable' // fully granted + RLS disabled (dangerous)
| 'locked-by-rls' // fully granted + RLS enabled, no policies
| 'secured' // fully granted + RLS enabled, policies exist
| 'unknown' // privileges query is still loading or errored — caller should stay silent
export function getTableDataApiStatus({
isSchemaExposed,
apiAccessData,
isRLSEnabled,
policiesCount,
}: {
isSchemaExposed: boolean
apiAccessData: TableApiAccessData | undefined
isRLSEnabled: boolean
policiesCount: number
}): TableDataApiStatus {
if (!isSchemaExposed) return 'schema-not-exposed'
if (apiAccessData?.apiAccessType === 'exposed-schema-no-grants') return 'no-grants'
if (apiAccessData?.apiAccessType === 'access') {
if (apiAccessData.grantStatus === 'custom') return 'custom-grants'
if (!isRLSEnabled) return 'publicly-readable'
if (policiesCount === 0) return 'locked-by-rls'
return 'secured'
}
// Schema is exposed but the privileges query hasn't resolved (still loading
// or errored). We return 'unknown' rather than 'schema-not-exposed' so the
// caller doesn't falsely tell the user to reconfigure API settings.
return 'unknown'
}
/**
* Returns the copy for the in-row admonition, or null when the row needs no
* admonition (the "everything is fine" `secured` case and the orthogonal
* `schema-not-exposed` case which is rendered separately with a link).
*/
export function getTableAdmonitionMessage(status: TableDataApiStatus): string | null {
switch (status) {
case 'custom-grants':
return 'This table has custom Data API permissions — access may be restricted for some roles or operations.'
case 'no-grants':
return 'This table cannot be accessed via the Data API. Enable access in your projects Data API settings.'
case 'publicly-readable':
return 'This table can be accessed by anyone via the Data API as RLS is disabled.'
case 'locked-by-rls':
return 'No data will be returned via the Data API as no RLS policies exist on this table.'
default:
return null
}
}
export const generatePolicyUpdateSQL = (policy: Policy): SafeSqlFragment => {
const parts: Array<SafeSqlFragment> = []
if (policy.definition != null) {
const semicolon = policy.check == null ? safeSql`;` : safeSql``
parts.push(safeSql`using (${policy.definition})${semicolon}`)
}
if (policy.check != null) {
parts.push(safeSql`with check (${policy.check});`)
}
const expression = parts.length > 0 ? joinSqlFragments(parts, '\n') : safeSql``
return safeSql`
alter policy ${ident(policy.name)}
on ${ident(policy.schema)}.${ident(policy.table)}
to ${joinSqlFragments(policy.roles.map(ident), ', ')}
${expression}`
}