improvement(supabase): allow non-public schemas (#2511)

This commit is contained in:
Vikhyath Mondreti
2025-12-21 21:20:36 -08:00
committed by GitHub
parent f21eaf1f10
commit e4d211c2f0
10 changed files with 157 additions and 36 deletions

View File

@@ -69,6 +69,16 @@ export const SupabaseBlock: BlockConfig<SupabaseResponse> = {
value: ['query', 'get_row', 'insert', 'update', 'delete', 'upsert', 'count', 'text_search'],
},
},
{
id: 'schema',
title: 'Schema',
type: 'short-input',
placeholder: 'public (default)',
condition: {
field: 'operation',
value: ['query', 'get_row', 'insert', 'update', 'delete', 'upsert', 'count', 'text_search'],
},
},
{
id: 'apiKey',
title: 'Service Role Secret',
@@ -1026,6 +1036,7 @@ Return ONLY the PostgREST filter expression - no explanations, no markdown, no e
operation: { type: 'string', description: 'Operation to perform' },
projectId: { type: 'string', description: 'Supabase project identifier' },
table: { type: 'string', description: 'Database table name' },
schema: { type: 'string', description: 'Database schema (default: public)' },
apiKey: { type: 'string', description: 'Service role secret key' },
// Data for insert/update operations
data: { type: 'json', description: 'Row data' },

View File

@@ -20,6 +20,13 @@ export const countTool: ToolConfig<SupabaseCountParams, SupabaseCountResponse> =
visibility: 'user-or-llm',
description: 'The name of the Supabase table to count rows from',
},
schema: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Database schema to count from (default: public). Use this to access tables in other schemas.',
},
filter: {
type: 'string',
required: false,
@@ -54,11 +61,15 @@ export const countTool: ToolConfig<SupabaseCountParams, SupabaseCountResponse> =
method: 'HEAD',
headers: (params) => {
const countType = params.countType || 'exact'
return {
const headers: Record<string, string> = {
apikey: params.apiKey,
Authorization: `Bearer ${params.apiKey}`,
Prefer: `count=${countType}`,
}
if (params.schema) {
headers['Accept-Profile'] = params.schema
}
return headers
},
},

View File

@@ -20,6 +20,13 @@ export const deleteTool: ToolConfig<SupabaseDeleteParams, SupabaseDeleteResponse
visibility: 'user-or-llm',
description: 'The name of the Supabase table to delete from',
},
schema: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Database schema to delete from (default: public). Use this to access tables in other schemas.',
},
filter: {
type: 'string',
required: true,
@@ -51,11 +58,17 @@ export const deleteTool: ToolConfig<SupabaseDeleteParams, SupabaseDeleteResponse
return url
},
method: 'DELETE',
headers: (params) => ({
apikey: params.apiKey,
Authorization: `Bearer ${params.apiKey}`,
Prefer: 'return=representation',
}),
headers: (params) => {
const headers: Record<string, string> = {
apikey: params.apiKey,
Authorization: `Bearer ${params.apiKey}`,
Prefer: 'return=representation',
}
if (params.schema) {
headers['Content-Profile'] = params.schema
}
return headers
},
},
transformResponse: async (response: Response) => {

View File

@@ -20,6 +20,13 @@ export const getRowTool: ToolConfig<SupabaseGetRowParams, SupabaseGetRowResponse
visibility: 'user-or-llm',
description: 'The name of the Supabase table to query',
},
schema: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Database schema to query from (default: public). Use this to access tables in other schemas.',
},
filter: {
type: 'string',
required: true,
@@ -50,10 +57,16 @@ export const getRowTool: ToolConfig<SupabaseGetRowParams, SupabaseGetRowResponse
return url
},
method: 'GET',
headers: (params) => ({
apikey: params.apiKey,
Authorization: `Bearer ${params.apiKey}`,
}),
headers: (params) => {
const headers: Record<string, string> = {
apikey: params.apiKey,
Authorization: `Bearer ${params.apiKey}`,
}
if (params.schema) {
headers['Accept-Profile'] = params.schema
}
return headers
},
},
transformResponse: async (response: Response) => {

View File

@@ -20,6 +20,13 @@ export const insertTool: ToolConfig<SupabaseInsertParams, SupabaseInsertResponse
visibility: 'user-or-llm',
description: 'The name of the Supabase table to insert data into',
},
schema: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Database schema to insert into (default: public). Use this to access tables in other schemas.',
},
data: {
type: 'array',
required: true,
@@ -37,12 +44,18 @@ export const insertTool: ToolConfig<SupabaseInsertParams, SupabaseInsertResponse
request: {
url: (params) => `https://${params.projectId}.supabase.co/rest/v1/${params.table}?select=*`,
method: 'POST',
headers: (params) => ({
apikey: params.apiKey,
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
Prefer: 'return=representation',
}),
headers: (params) => {
const headers: Record<string, string> = {
apikey: params.apiKey,
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
Prefer: 'return=representation',
}
if (params.schema) {
headers['Content-Profile'] = params.schema
}
return headers
},
body: (params) => {
// Prepare the data - if it's an object but not an array, wrap it in an array
const dataToSend =

View File

@@ -20,6 +20,13 @@ export const queryTool: ToolConfig<SupabaseQueryParams, SupabaseQueryResponse> =
visibility: 'user-or-llm',
description: 'The name of the Supabase table to query',
},
schema: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Database schema to query from (default: public). Use this to access tables in other schemas.',
},
filter: {
type: 'string',
required: false,
@@ -84,10 +91,16 @@ export const queryTool: ToolConfig<SupabaseQueryParams, SupabaseQueryResponse> =
return url
},
method: 'GET',
headers: (params) => ({
apikey: params.apiKey,
Authorization: `Bearer ${params.apiKey}`,
}),
headers: (params) => {
const headers: Record<string, string> = {
apikey: params.apiKey,
Authorization: `Bearer ${params.apiKey}`,
}
if (params.schema) {
headers['Accept-Profile'] = params.schema
}
return headers
},
},
transformResponse: async (response: Response) => {

View File

@@ -20,6 +20,13 @@ export const textSearchTool: ToolConfig<SupabaseTextSearchParams, SupabaseTextSe
visibility: 'user-or-llm',
description: 'The name of the Supabase table to search',
},
schema: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Database schema to search in (default: public). Use this to access tables in other schemas.',
},
column: {
type: 'string',
required: true,
@@ -86,10 +93,16 @@ export const textSearchTool: ToolConfig<SupabaseTextSearchParams, SupabaseTextSe
return url
},
method: 'GET',
headers: (params) => ({
apikey: params.apiKey,
Authorization: `Bearer ${params.apiKey}`,
}),
headers: (params) => {
const headers: Record<string, string> = {
apikey: params.apiKey,
Authorization: `Bearer ${params.apiKey}`,
}
if (params.schema) {
headers['Accept-Profile'] = params.schema
}
return headers
},
},
transformResponse: async (response: Response) => {

View File

@@ -4,6 +4,7 @@ export interface SupabaseQueryParams {
apiKey: string
projectId: string
table: string
schema?: string
filter?: string
orderBy?: string
limit?: number
@@ -13,6 +14,7 @@ export interface SupabaseInsertParams {
apiKey: string
projectId: string
table: string
schema?: string
data: any
}
@@ -20,6 +22,7 @@ export interface SupabaseGetRowParams {
apiKey: string
projectId: string
table: string
schema?: string
filter: string
}
@@ -27,6 +30,7 @@ export interface SupabaseUpdateParams {
apiKey: string
projectId: string
table: string
schema?: string
filter: string
data: any
}
@@ -35,6 +39,7 @@ export interface SupabaseDeleteParams {
apiKey: string
projectId: string
table: string
schema?: string
filter: string
}
@@ -42,6 +47,7 @@ export interface SupabaseUpsertParams {
apiKey: string
projectId: string
table: string
schema?: string
data: any
}
@@ -93,6 +99,7 @@ export interface SupabaseTextSearchParams {
apiKey: string
projectId: string
table: string
schema?: string
column: string
query: string
searchType?: string
@@ -107,6 +114,7 @@ export interface SupabaseCountParams {
apiKey: string
projectId: string
table: string
schema?: string
filter?: string
countType?: string
}

View File

@@ -20,6 +20,13 @@ export const updateTool: ToolConfig<SupabaseUpdateParams, SupabaseUpdateResponse
visibility: 'user-or-llm',
description: 'The name of the Supabase table to update',
},
schema: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Database schema to update in (default: public). Use this to access tables in other schemas.',
},
filter: {
type: 'string',
required: true,
@@ -53,12 +60,18 @@ export const updateTool: ToolConfig<SupabaseUpdateParams, SupabaseUpdateResponse
return url
},
method: 'PATCH',
headers: (params) => ({
apikey: params.apiKey,
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
Prefer: 'return=representation',
}),
headers: (params) => {
const headers: Record<string, string> = {
apikey: params.apiKey,
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
Prefer: 'return=representation',
}
if (params.schema) {
headers['Content-Profile'] = params.schema
}
return headers
},
body: (params) => params.data,
},

View File

@@ -20,6 +20,13 @@ export const upsertTool: ToolConfig<SupabaseUpsertParams, SupabaseUpsertResponse
visibility: 'user-or-llm',
description: 'The name of the Supabase table to upsert data into',
},
schema: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Database schema to upsert into (default: public). Use this to access tables in other schemas.',
},
data: {
type: 'array',
required: true,
@@ -37,12 +44,18 @@ export const upsertTool: ToolConfig<SupabaseUpsertParams, SupabaseUpsertResponse
request: {
url: (params) => `https://${params.projectId}.supabase.co/rest/v1/${params.table}?select=*`,
method: 'POST',
headers: (params) => ({
apikey: params.apiKey,
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
Prefer: 'return=representation,resolution=merge-duplicates',
}),
headers: (params) => {
const headers: Record<string, string> = {
apikey: params.apiKey,
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
Prefer: 'return=representation,resolution=merge-duplicates',
}
if (params.schema) {
headers['Content-Profile'] = params.schema
}
return headers
},
body: (params) => {
// Prepare the data - if it's an object but not an array, wrap it in an array
const dataToSend =