@assemblyline-agents/supabase 2.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +1 -1
- package/dist/events.d.ts +3 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +49 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -4
- package/skills/supabase/SKILL.md +0 -8
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Official Assembly Line Supabase connection plugin.
|
|
4
4
|
|
|
5
|
-
It connects agents to Supabase, exposing project, database, and platform tools through Supabase's MCP server. The package exports `defineSupabaseConnection(options)` to declare the connection in an agent definition and an `assemblyLinePlugin` module so the Assembly Line CLI and compiler can discover the plugin's connection metadata.
|
|
5
|
+
It connects agents to Supabase, exposing project, database, and platform tools through Supabase's MCP server. The package exports `defineSupabaseConnection(options)` to declare the connection in an agent definition and an `assemblyLinePlugin` module so the Assembly Line CLI and compiler can discover the plugin's connection metadata.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
package/dist/events.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AACA,OAAO,EAOL,KAAK,4BAA4B,EAElC,MAAM,2BAA2B,CAAC;AAInC,eAAO,MAAM,cAAc,EAAE,4BAqB5B,CAAC"}
|
package/dist/events.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createHash, timingSafeEqual } from "node:crypto";
|
|
2
|
+
import { ConnectionEventError, headerValue, parseConnectionEventJson, providerJson, requireEnvironmentValue, stringField } from "@assemblyline-agents/core";
|
|
3
|
+
export const supabaseEvents = {
|
|
4
|
+
async reconcile(context) {
|
|
5
|
+
const resources = context.resources.map(tableResource);
|
|
6
|
+
if (!resources.length)
|
|
7
|
+
return { status: "needs_setup", instructions: "Add Supabase event resources with projectRef, schema, and table." };
|
|
8
|
+
const token = (await context.getToken()).token;
|
|
9
|
+
const secret = requireEnvironmentValue(context.env, "SUPABASE_WEBHOOK_SECRET");
|
|
10
|
+
for (const resource of resources)
|
|
11
|
+
await query(context.fetch, token, resource.projectRef, installSql(resource, context.callbackUrl, secret, context.selectedEvents));
|
|
12
|
+
return { status: "active", state: { resources }, detail: `${resources.length} Supabase database webhook${resources.length === 1 ? " is" : "s are"} active.` };
|
|
13
|
+
},
|
|
14
|
+
async remove(context) { const token = (await context.getToken()).token; for (const resource of context.resources.map(tableResource))
|
|
15
|
+
await query(context.fetch, token, resource.projectRef, removeSql(resource)); },
|
|
16
|
+
check(context) { const count = Array.isArray(context.state?.resources) ? context.state.resources.length : 0; return count ? { status: "active", detail: `${count} Supabase database webhook${count === 1 ? " is" : "s are"} configured.` } : { status: "needs_setup", detail: "No Supabase database webhooks are configured." }; },
|
|
17
|
+
ingress(request, context) {
|
|
18
|
+
const expected = `Bearer ${requireEnvironmentValue(context.env, "SUPABASE_WEBHOOK_SECRET")}`;
|
|
19
|
+
if (!safeEqual(expected, headerValue(request.headers, "authorization") ?? ""))
|
|
20
|
+
throw new ConnectionEventError("Supabase webhook bearer token is invalid.", 401);
|
|
21
|
+
const payload = parseConnectionEventJson(request.body);
|
|
22
|
+
const operation = stringField(payload, "type")?.toLowerCase();
|
|
23
|
+
const event = operation === "insert" ? "row.inserted" : operation === "update" ? "row.updated" : operation === "delete" ? "row.deleted" : undefined;
|
|
24
|
+
if (!event)
|
|
25
|
+
throw new ConnectionEventError("Supabase webhook operation is unsupported.");
|
|
26
|
+
const eventId = createHash("sha256").update(request.body).digest("hex");
|
|
27
|
+
return { events: [{ event, eventId, payload: payload }], response: { status: 200, body: { ok: true } }, audit: { event, schema: stringField(payload, "schema") ?? "unknown", table: stringField(payload, "table") ?? "unknown" } };
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
async function query(fetchImpl, token, projectRef, query) { await providerJson(fetchImpl, `https://api.supabase.com/v1/projects/${encodeURIComponent(projectRef)}/database/query`, { method: "POST", headers: { authorization: `Bearer ${token}`, "content-type": "application/json" }, body: JSON.stringify({ query }) }); }
|
|
31
|
+
function tableResource(resource) { const projectRef = stringField(resource, "projectRef"); const schema = identifier(stringField(resource, "schema") ?? "public"); const table = identifier(stringField(resource, "table")); if (!projectRef || !table)
|
|
32
|
+
throw new Error("Supabase event resources require projectRef and table."); const name = `assembly_line_${createHash("sha256").update(`${projectRef}:${schema}:${table}`).digest("hex").slice(0, 16)}`; return { projectRef, schema, table, name }; }
|
|
33
|
+
function identifier(value) { if (!value || !/^[A-Za-z_][A-Za-z0-9_]*$/u.test(value))
|
|
34
|
+
throw new Error(`Invalid Supabase SQL identifier: ${value ?? "(missing)"}.`); return value; }
|
|
35
|
+
function literal(value) { return `'${value.replaceAll("'", "''")}'`; }
|
|
36
|
+
function installSql(resource, callbackUrl, secret, events) {
|
|
37
|
+
const operations = events.map((event) => event === "row.inserted" ? "INSERT" : event === "row.updated" ? "UPDATE" : "DELETE").join(" OR ");
|
|
38
|
+
return `create extension if not exists pg_net with schema extensions;
|
|
39
|
+
create or replace function public.${resource.name}_fn() returns trigger language plpgsql security definer as $$
|
|
40
|
+
begin
|
|
41
|
+
perform net.http_post(url := ${literal(callbackUrl)}, headers := jsonb_build_object('Content-Type','application/json','Authorization',${literal(`Bearer ${secret}`)}), body := jsonb_build_object('type', TG_OP, 'table', TG_TABLE_NAME, 'schema', TG_TABLE_SCHEMA, 'record', case when TG_OP = 'DELETE' then null else to_jsonb(NEW) end, 'old_record', case when TG_OP = 'INSERT' then null else to_jsonb(OLD) end));
|
|
42
|
+
return coalesce(NEW, OLD);
|
|
43
|
+
end $$;
|
|
44
|
+
drop trigger if exists ${resource.name}_trigger on "${resource.schema}"."${resource.table}";
|
|
45
|
+
create trigger ${resource.name}_trigger after ${operations} on "${resource.schema}"."${resource.table}" for each row execute function public.${resource.name}_fn();`;
|
|
46
|
+
}
|
|
47
|
+
function removeSql(resource) { return `drop trigger if exists ${resource.name}_trigger on "${resource.schema}"."${resource.table}"; drop function if exists public.${resource.name}_fn();`; }
|
|
48
|
+
function safeEqual(left, right) { const a = Buffer.from(left); const b = Buffer.from(right); return a.length === b.length && timingSafeEqual(a, b); }
|
|
49
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,wBAAwB,EACxB,YAAY,EACZ,uBAAuB,EACvB,WAAW,EAGZ,MAAM,2BAA2B,CAAC;AAInC,MAAM,CAAC,MAAM,cAAc,GAAiC;IAC1D,KAAK,CAAC,SAAS,CAAC,OAAO;QACrB,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACvD,IAAI,CAAC,SAAS,CAAC,MAAM;YAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,kEAAkE,EAAE,CAAC;QAC1I,MAAM,KAAK,GAAG,CAAC,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC;QAC/C,MAAM,MAAM,GAAG,uBAAuB,CAAC,OAAO,CAAC,GAAG,EAAE,yBAAyB,CAAC,CAAC;QAC/E,KAAK,MAAM,QAAQ,IAAI,SAAS;YAAE,MAAM,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC;QACpK,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,6BAA6B,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,UAAU,EAAE,CAAC;IAChK,CAAC;IACD,KAAK,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,KAAK,GAAG,CAAC,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,MAAM,QAAQ,IAAI,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC;QAAE,MAAM,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACnN,KAAK,CAAC,OAAO,IAAI,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,KAAK,6BAA6B,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,+CAA+C,EAAE,CAAC,CAAC,CAAC;IAClU,OAAO,CAAC,OAAO,EAAE,OAAO;QACtB,MAAM,QAAQ,GAAG,UAAU,uBAAuB,CAAC,OAAO,CAAC,GAAG,EAAE,yBAAyB,CAAC,EAAE,CAAC;QAC7F,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,eAAe,CAAC,IAAI,EAAE,CAAC;YAAE,MAAM,IAAI,oBAAoB,CAAC,2CAA2C,EAAE,GAAG,CAAC,CAAC;QAChK,MAAM,OAAO,GAAG,wBAAwB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvD,MAAM,SAAS,GAAG,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;QAC9D,MAAM,KAAK,GAAG,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC;QACpJ,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,oBAAoB,CAAC,4CAA4C,CAAC,CAAC;QACzF,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACxE,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAqB,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,SAAS,EAAE,KAAK,EAAE,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,SAAS,EAAE,EAAE,CAAC;IACnP,CAAC;CACF,CAAC;AAEF,KAAK,UAAU,KAAK,CAAC,SAAuB,EAAE,KAAa,EAAE,UAAkB,EAAE,KAAa,IAAmB,MAAM,YAAY,CAAC,SAAS,EAAE,wCAAwC,kBAAkB,CAAC,UAAU,CAAC,iBAAiB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAClX,SAAS,aAAa,CAAC,QAAoB,IAAmB,MAAM,UAAU,GAAG,WAAW,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,MAAM,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,MAAM,KAAK,GAAG,UAAU,CAAC,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,KAAK;IAAE,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC,CAAC,MAAM,IAAI,GAAG,iBAAiB,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,UAAU,IAAI,MAAM,IAAI,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACvgB,SAAS,UAAU,CAAC,KAAyB,IAAY,IAAI,CAAC,KAAK,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,KAAK,CAAC;IAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,KAAK,IAAI,WAAW,GAAG,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC;AAC9M,SAAS,OAAO,CAAC,KAAa,IAAY,OAAO,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACtF,SAAS,UAAU,CAAC,QAAuB,EAAE,WAAmB,EAAE,MAAc,EAAE,MAAgB;IAChG,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,KAAK,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3I,OAAO;oCAC2B,QAAQ,CAAC,IAAI;;iCAEhB,OAAO,CAAC,WAAW,CAAC,qFAAqF,OAAO,CAAC,UAAU,MAAM,EAAE,CAAC;;;yBAG5I,QAAQ,CAAC,IAAI,gBAAgB,QAAQ,CAAC,MAAM,MAAM,QAAQ,CAAC,KAAK;iBACxE,QAAQ,CAAC,IAAI,kBAAkB,UAAU,QAAQ,QAAQ,CAAC,MAAM,MAAM,QAAQ,CAAC,KAAK,0CAA0C,QAAQ,CAAC,IAAI,QAAQ,CAAC;AACrK,CAAC;AACD,SAAS,SAAS,CAAC,QAAuB,IAAY,OAAO,0BAA0B,QAAQ,CAAC,IAAI,gBAAgB,QAAQ,CAAC,MAAM,MAAM,QAAQ,CAAC,KAAK,qCAAqC,QAAQ,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC;AACpN,SAAS,SAAS,CAAC,IAAY,EAAE,KAAa,IAAa,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmG,KAAK,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAG7K,MAAM,MAAM,yBAAyB,GAAG,0BAA0B,CAAC;AACnE,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,yEAAoN;AAC/R,eAAO,MAAM,kBAAkB,kDAA0C,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { connectionPluginMetadata, defineMcpPluginConnection, definePlugin } from "@assemblyline-agents/core";
|
|
1
|
+
import { connectionPluginMetadata, defineConnectionPluginEvents, defineMcpPluginConnection, definePlugin } from "@assemblyline-agents/core";
|
|
2
|
+
import { supabaseEvents } from "./events.js";
|
|
2
3
|
const PLUGIN = connectionPluginMetadata("supabase");
|
|
3
|
-
export function defineSupabaseConnection(options) {
|
|
4
|
+
export function defineSupabaseConnection(options) { const definition = defineMcpPluginConnection(PLUGIN, options); const events = defineConnectionPluginEvents(PLUGIN, options.events, supabaseEvents); if (events)
|
|
5
|
+
definition.events = events; return definition; }
|
|
4
6
|
export const assemblyLinePlugin = definePlugin({ connections: [PLUGIN] });
|
|
5
7
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,YAAY,EAAmC,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,4BAA4B,EAAE,yBAAyB,EAAE,YAAY,EAAmC,MAAM,2BAA2B,CAAC;AAC7K,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,MAAM,MAAM,GAAG,wBAAwB,CAAC,UAAU,CAAE,CAAC;AAErD,MAAM,UAAU,wBAAwB,CAAC,OAAkC,IAAI,MAAM,UAAU,GAAG,yBAAyB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,MAAM,GAAG,4BAA4B,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,IAAI,MAAM;IAAE,UAAU,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC;AAC/R,MAAM,CAAC,MAAM,kBAAkB,GAAG,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assemblyline-agents/supabase",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -9,12 +9,11 @@
|
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@assemblyline-agents/core": "
|
|
12
|
+
"@assemblyline-agents/core": "3.1.0"
|
|
13
13
|
},
|
|
14
14
|
"description": "Official Assembly Line Supabase connection plugin.",
|
|
15
15
|
"files": [
|
|
16
|
-
"dist"
|
|
17
|
-
"skills"
|
|
16
|
+
"dist"
|
|
18
17
|
],
|
|
19
18
|
"engines": {
|
|
20
19
|
"node": ">=22.19.0"
|
package/skills/supabase/SKILL.md
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: supabase
|
|
3
|
-
description: Use configured Supabase tools for projects, databases, docs, logs, storage, and Edge Functions.
|
|
4
|
-
---
|
|
5
|
-
# Supabase
|
|
6
|
-
Resolve the organization and project first. Prefer read-only schema, docs, and log tools; bound database queries tightly.
|
|
7
|
-
|
|
8
|
-
The deployment owner configures Supabase OAuth or project-scoped access. The scaffold is read-only; SQL execution, migrations, deployments, storage writes, and project changes require writes to be enabled with the configured approval gate.
|