diff --git a/.github/workflows/api-package-sync.yml b/.github/workflows/api-package-sync.yml index cdba3fd3c7..d0bae534da 100644 --- a/.github/workflows/api-package-sync.yml +++ b/.github/workflows/api-package-sync.yml @@ -25,6 +25,8 @@ jobs: - name: Regenerate API package run: pnpm generate working-directory: packages/api + env: + SUPABASE_API_URL: https://api.supabase.com - name: Format API package run: pnpm exec nx run @supabase/api:fmt:fix @@ -32,7 +34,7 @@ jobs: - name: Check for generated changes id: check run: | - if git diff --ignore-space-at-eol --exit-code --quiet packages/api/src/generated; then + if git diff --ignore-space-at-eol --exit-code --quiet packages/api/src/generated packages/api/scripts/openapi-source.json; then echo "No generated changes detected." echo "has_changes=false" >> "$GITHUB_OUTPUT" else @@ -61,7 +63,7 @@ jobs: body: | This PR was automatically created to sync the generated `@supabase/api` package with the latest Management API OpenAPI document. - Changes were detected in the upstream OpenAPI document exposed by `https://api.supabase.com/api/v1-json`. + Changes were detected in the upstream OpenAPI documents exposed by `https://api.supabase.com/api/v1-json` and `https://api.supabase.com/api/v2-json`. branch: sync/api-package base: develop diff --git a/apps/cli/tests/helpers/legacy-mocks.ts b/apps/cli/tests/helpers/legacy-mocks.ts index 3e47545d79..f2ef553644 100644 --- a/apps/cli/tests/helpers/legacy-mocks.ts +++ b/apps/cli/tests/helpers/legacy-mocks.ts @@ -642,8 +642,17 @@ export function mockLegacyPlatformApiService( }, }); + // The legacy shell is a Go-parity port and only calls v1 operations, so v2 + // has no stub support — any v2 call from legacy code is a wiring bug. + const v2Proxy = new Proxy({} as ApiClient["v2"], { + get(_target, prop: string) { + return () => Effect.die(`Unmocked LegacyPlatformApi.v2.${prop}`); + }, + }); + const layer = Layer.succeed(LegacyPlatformApi, { v1: v1Proxy, + v2: v2Proxy, // Direct-service consumers don't exercise the raw-execute escape hatch. executeRaw: () => Effect.die("Unmocked LegacyPlatformApi.executeRaw"), } as ApiClient); diff --git a/packages/api/README.md b/packages/api/README.md index d82750704a..cfb0e9e27e 100644 --- a/packages/api/README.md +++ b/packages/api/README.md @@ -17,8 +17,14 @@ import { createApiClient } from "@supabase/api"; const client = await createApiClient({ accessToken: "" }); const projects = await client.v1.listAllProjects(); +const projectConfig = await client.v2.getProjectConfig({ ref: "" }); ``` +Operations are namespaced by version, derived from the leading path segment (`/v1/...` or +`/v2/...`). Same-named operations can coexist under separate namespaces: `client.v1.listOrganizationMembers` +and `client.v2.listOrganizationMembers` are distinct operations hitting `/v1/...` and `/v2/...` +respectively. + `baseUrl` defaults to `https://api.supabase.com` and `accessToken` can also come from `SUPABASE_ACCESS_TOKEN`. @@ -31,7 +37,10 @@ import { makeApiClient } from "@supabase/api/effect"; const program = Effect.gen(function* () { const client = yield* makeApiClient({ accessToken: "" }); - return yield* client.v1.listAllProjects(); + const projects = yield* client.v1.listAllProjects(); + const projectConfig = yield* client.v2.getProjectConfig({ ref: "" }); + + return { projects, projectConfig }; }); ``` @@ -51,6 +60,7 @@ The only callable client surface is the versioned namespace: ```ts const projects = await client.v1.listAllProjects(); +const projectConfig = await client.v2.getProjectConfig({ ref: "" }); ``` For tools that need the raw generated spec: @@ -74,14 +84,75 @@ The public binary input contract is: ## Development ```sh -pnpm check:all # Run all quality checks in parallel -pnpm fix:all # Auto-fix lint, format, and unused exports in parallel -pnpm test # Run tests -pnpm generate # Refresh the OpenAPI spec and regenerate the SDK +pnpm check:all # Run all quality checks in parallel +pnpm fix:all # Auto-fix lint, format, and unused exports in parallel +pnpm test # Run tests +pnpm generate # Refresh the OpenAPI spec and regenerate the SDK +pnpm generate:check # Regenerate in place and fail on any resulting diff ``` +## Spec pipeline + +The spec is built from two upstream OpenAPI documents, `{baseUrl}/api/v1-json` and +`{baseUrl}/api/v2-json`. They are fetched and merged into a single document (paths and +`components.schemas` are unioned, and `info.title` is normalized to `Supabase API`), then +overrides from `scripts/openapi-overrides.json` are applied to the merged document. The result is +validated — operation ids must be unique, and version-prefixed operation ids must match the +path's leading segment — before being written to `src/generated/openapi.json`. The merged +document keeps only the keys the generator consumes (`openapi`, `info`, `paths`, +`components.schemas`); upstream extras such as `servers`, `tags`, and `components.securitySchemes` +are dropped so the snapshot never contains keys a regeneration would remove. + +The committed snapshot and the generated modules are also checked against each other offline in +ordinary test runs: `scripts/generated-output-sync.unit.test.ts` re-renders every generated file +from the committed snapshot and requires byte equality, and `src/generated-contract-sync.unit.test.ts` +asserts the operation-level bijection. Hand edits to `src/generated` fail both. + +The base URL is resolved in this order: + +1. `SUPABASE_API_URL` environment variable +2. `scripts/openapi-source.json`, a committed sidecar file (`{ "baseUrl": ... }`) that is + rewritten after every successful `pnpm generate` run +3. `https://api.supabase.com` + To refresh from staging instead of production: ```sh SUPABASE_API_URL=https://api.supabase.green pnpm generate ``` + +`pnpm generate` is the single command to regenerate the spec and SDK. `pnpm generate:check` +regenerates in place, formats, and fails if that produces any diff in `src/generated` or +`scripts/openapi-source.json` — useful for verifying the committed snapshot is still current. If a +failed check leaves an unwanted diff, discard it with: + +```sh +git restore -- src/generated scripts/openapi-source.json +``` + +The hourly [`api-package-sync.yml`](../../.github/workflows/api-package-sync.yml) workflow runs +`generate` against production and opens a PR against `develop` whenever it detects drift, acting +as the automated drift detector for the committed snapshot. + +### Overrides + +`scripts/openapi-overrides.json` is a JSON-Patch-_like_ array applied to the merged document. It +supports: + +- `test` — assert a value at `path` before proceeding (as in RFC 6902) +- `add` — add a value at `path`; throws if the key already exists +- `replace` — replace the value at `path` +- `remove` — remove the value at `path` **if present** + +`remove` is deliberately remove-if-present rather than RFC 6902's strict "must exist" semantics, +because the upstream documents differ between environments — staging's `v2-json` is currently +served by two backend variants that disagree about some paths. Entries may carry a `$comment` +field to document why an override exists. + +### Known limitation: `deepObject` query parameters + +Three v2 operations declare object-valued query parameters with `style: deepObject`: +`v2-list-organization-members`, `v2-list-organization-projects`, and +`v2-list-organization-github-connections`. The client currently serializes these as JSON strings +rather than the expected `page[size]=...` form. Do not rely on those parameters until this is +fixed. diff --git a/packages/api/package.json b/packages/api/package.json index 871ca55188..19d31fe6b4 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -14,6 +14,7 @@ "scripts": { "generate:spec": "bun run scripts/download-openapi.ts", "generate": "bun run generate:spec && bun run scripts/generate.ts", + "generate:check": "pnpm generate && pnpm exec nx run @supabase/api:fmt:fix && git diff --exit-code -- src/generated scripts/openapi-source.json", "test": "nx run-many -t test:core test:e2e --projects=$npm_package_name", "test:core": "nx run-many -t test:unit test:integration --projects=$npm_package_name", "check:all": "nx run-many -t types:check lint:check fmt:check knip:check --projects=$npm_package_name", @@ -45,7 +46,8 @@ "scripts/download-openapi.ts", "scripts/download-openapi.unit.test.ts", "scripts/generate.ts", - "scripts/generate.unit.test.ts" + "scripts/generate.unit.test.ts", + "scripts/generated-output-sync.unit.test.ts" ], "ignoreDependencies": [ "undici", diff --git a/packages/api/scripts/download-openapi.ts b/packages/api/scripts/download-openapi.ts index a6e189b2b2..521dc83929 100644 --- a/packages/api/scripts/download-openapi.ts +++ b/packages/api/scripts/download-openapi.ts @@ -7,18 +7,36 @@ const DEFAULT_SUPABASE_API_URL = "https://api.supabase.com"; const scriptDir = path.dirname(fileURLToPath(import.meta.url)); const OPENAPI_SPEC_PATH = path.join(scriptDir, "../src/generated/openapi.json"); const OPENAPI_OVERRIDES_PATH = path.join(scriptDir, "openapi-overrides.json"); +const OPENAPI_SOURCE_PATH = path.join(scriptDir, "openapi-source.json"); + +const OPENAPI_DOCUMENT_VERSIONS = ["v1", "v2"] as const; +type OpenApiDocumentVersion = (typeof OPENAPI_DOCUMENT_VERSIONS)[number]; + +const HTTP_METHOD_KEYS = ["get", "post", "put", "patch", "delete", "head"] as const; type OpenApiDocument = { readonly [key: string]: unknown; readonly paths: Record; + readonly components?: { + readonly schemas?: Record; + }; }; -type JsonPatchOperation = { - readonly op: "add" | "test" | "replace"; - readonly path: string; - readonly value: unknown; +type OpenApiSource = { + readonly baseUrl: string; }; +type JsonPatchOperation = + | { + readonly op: "add" | "test" | "replace"; + readonly path: string; + readonly value: unknown; + } + | { + readonly op: "remove"; + readonly path: string; + }; + function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null; } @@ -109,16 +127,67 @@ function addJsonPointerValue(document: unknown, pointer: string, value: unknown) parent[key] = value; } +function removeJsonPointerValue(document: unknown, pointer: string): boolean { + const segments = jsonPointerSegments(pointer); + if (segments.length === 0) { + return false; + } + + let parent: unknown = document; + for (const segment of segments.slice(0, -1)) { + if (Array.isArray(parent)) { + const index = Number(segment); + if (!Number.isInteger(index) || index < 0 || index >= parent.length) { + return false; + } + parent = parent[index]; + continue; + } + if (isRecord(parent) && segment in parent) { + parent = parent[segment]; + continue; + } + return false; + } + + const key = segments[segments.length - 1]!; + if (Array.isArray(parent)) { + const index = Number(key); + if (!Number.isInteger(index) || index < 0 || index >= parent.length) { + return false; + } + parent.splice(index, 1); + return true; + } + + if (!isRecord(parent) || !(key in parent)) { + return false; + } + delete parent[key]; + return true; +} + function assertJsonPatchOperation(value: unknown): asserts value is JsonPatchOperation { if (!isRecord(value)) { throw new Error("OpenAPI override entry must be an object."); } - if (value.op !== "add" && value.op !== "test" && value.op !== "replace") { - throw new Error("OpenAPI overrides only support add, test and replace operations."); + if ( + value.op !== "add" && + value.op !== "test" && + value.op !== "replace" && + value.op !== "remove" + ) { + throw new Error("OpenAPI overrides only support add, test, replace and remove operations."); } if (typeof value.path !== "string") { throw new Error("OpenAPI override path must be a string."); } + if (value.op === "remove") { + if ("value" in value) { + throw new Error("OpenAPI remove overrides must not include a value."); + } + return; + } if (!("value" in value)) { throw new Error("OpenAPI override value is required."); } @@ -147,6 +216,17 @@ export function applyOpenApiOverrides( addJsonPointerValue(document, override.path, override.value); continue; } + if (override.op === "remove") { + // Deliberate deviation from RFC 6902 (mirroring the existing "add" + // deviation below, which throws when the target key already exists): + // silently ignore removal of a pointer that doesn't exist. This file + // applies to documents that differ between environments — staging's + // /api/v2-json is currently served by two backend variants that + // disagree about whether the webhook paths exist — so a strict + // remove would fail on most staging runs. + removeJsonPointerValue(document, override.path); + continue; + } replaceJsonPointerValue(document, override.path, override.value); } return document; @@ -160,9 +240,60 @@ async function loadOpenApiOverrides(): Promise> { return parsed; } -export function resolveOpenApiSpecUrl(baseUrl = process.env.SUPABASE_API_URL): string { - const normalizedBaseUrl = (baseUrl ?? DEFAULT_SUPABASE_API_URL).replace(/\/+$/, ""); - return `${normalizedBaseUrl}/api/v1-json`; +function assertOpenApiSource(value: unknown): asserts value is OpenApiSource { + if (!isRecord(value) || typeof value.baseUrl !== "string") { + throw new Error('OpenAPI source file must be an object with a string "baseUrl" property.'); + } +} + +async function loadPinnedBaseUrl(): Promise { + let raw: string; + try { + raw = await readFile(OPENAPI_SOURCE_PATH, "utf8"); + } catch (error) { + // A missing pin falls through to the default base URL; only a present + // but malformed pin is an error worth stopping for. + if (isRecord(error) && error.code === "ENOENT") { + return undefined; + } + throw error; + } + const parsed = JSON.parse(raw); + assertOpenApiSource(parsed); + return parsed.baseUrl; +} + +async function writeOpenApiSource(baseUrl: string): Promise { + const source: OpenApiSource = { baseUrl }; + await writeFile(OPENAPI_SOURCE_PATH, `${JSON.stringify(source, null, 2)}\n`); +} + +export function resolveOpenApiBaseUrl({ + envBaseUrl, + pinnedBaseUrl, +}: { + readonly envBaseUrl?: string; + readonly pinnedBaseUrl?: string; +}): string { + const baseUrl = envBaseUrl ?? pinnedBaseUrl ?? DEFAULT_SUPABASE_API_URL; + return baseUrl.replace(/\/+$/, ""); +} + +export function resolveOpenApiSpecUrl( + baseUrl = process.env.SUPABASE_API_URL, + version: OpenApiDocumentVersion = "v1", +): string { + const normalizedBaseUrl = resolveOpenApiBaseUrl({ envBaseUrl: baseUrl }); + return `${normalizedBaseUrl}/api/${version}-json`; +} + +export function resolveOpenApiSpecUrls( + baseUrl?: string, +): ReadonlyArray<{ readonly version: OpenApiDocumentVersion; readonly url: string }> { + return OPENAPI_DOCUMENT_VERSIONS.map((version) => ({ + version, + url: resolveOpenApiSpecUrl(baseUrl, version), + })); } export function assertOpenApiDocument(document: unknown): asserts document is OpenApiDocument { @@ -171,19 +302,199 @@ export function assertOpenApiDocument(document: unknown): asserts document is Op } } -export async function downloadOpenApiSpec(specUrl = resolveOpenApiSpecUrl()): Promise { - const response = await fetch(specUrl); +function getOpenApiVersion(document: OpenApiDocument): string { + if (typeof document.openapi !== "string") { + throw new Error('OpenAPI document is missing an "openapi" version string.'); + } + return document.openapi; +} - if (!response.ok) { - throw new Error(`Failed to download OpenAPI spec from ${specUrl}: ${response.status}`); +function getInfoVersion(document: OpenApiDocument): string { + if (!isRecord(document.info) || typeof document.info.version !== "string") { + throw new Error('OpenAPI document is missing an "info.version" string.'); } + return document.info.version; +} - const document = await response.json(); - assertOpenApiDocument(document); +export function mergeOpenApiDocuments( + documents: ReadonlyArray<{ + readonly version: OpenApiDocumentVersion; + readonly document: OpenApiDocument; + }>, +): OpenApiDocument { + const [firstEntry, ...restEntries] = documents; + if (firstEntry === undefined) { + throw new Error("mergeOpenApiDocuments requires at least one document."); + } + + const openapiVersion = getOpenApiVersion(firstEntry.document); + for (const entry of restEntries) { + const entryOpenapiVersion = getOpenApiVersion(entry.document); + if (entryOpenapiVersion !== openapiVersion) { + throw new Error( + `OpenAPI "openapi" version mismatch between ${firstEntry.version} (${openapiVersion}) and ${entry.version} (${entryOpenapiVersion}).`, + ); + } + } + + const infoVersion = getInfoVersion(firstEntry.document); + for (const entry of restEntries) { + const entryInfoVersion = getInfoVersion(entry.document); + if (entryInfoVersion !== infoVersion) { + throw new Error( + `OpenAPI "info.version" mismatch between ${firstEntry.version} (${infoVersion}) and ${entry.version} (${entryInfoVersion}).`, + ); + } + } + + for (const { version, document } of documents) { + for (const pathKey of Object.keys(document.paths)) { + if (!pathKey.startsWith(`/${version}/`)) { + throw new Error( + `OpenAPI path ${JSON.stringify(pathKey)} in the ${version} document does not start with "/${version}/".`, + ); + } + } + } + + const paths: Record = {}; + const pathVersions = new Map(); + for (const { version, document } of documents) { + for (const [pathKey, pathValue] of Object.entries(document.paths)) { + const existingVersion = pathVersions.get(pathKey); + if (existingVersion !== undefined) { + throw new Error( + `Duplicate OpenAPI path ${JSON.stringify(pathKey)} found in both the ${existingVersion} and ${version} documents.`, + ); + } + pathVersions.set(pathKey, version); + paths[pathKey] = pathValue; + } + } + + const schemas: Record = {}; + const schemaVersions = new Map(); + for (const { version, document } of documents) { + for (const [name, schema] of Object.entries(document.components?.schemas ?? {})) { + const existingVersion = schemaVersions.get(name); + if (existingVersion === undefined) { + schemaVersions.set(name, version); + schemas[name] = schema; + continue; + } + if (!valuesEqual(schemas[name], schema)) { + throw new Error( + `Conflicting OpenAPI schema ${JSON.stringify(name)} found in both the ${existingVersion} and ${version} documents.`, + ); + } + } + } + + // The merged document carries only the keys the generator consumes. + // Upstream extras (`servers`, `tags`, `components.securitySchemes`, …) + // must not reach the snapshot even transiently: generate.ts rewrites the + // file without them, so if they were written here a crash between the two + // steps would leave a plausible-looking openapi.json that disagrees with + // every healthy regeneration. + return { + openapi: openapiVersion, + info: { title: "Supabase API", version: infoVersion }, + paths, + components: { schemas }, + }; +} + +// Runs AFTER overrides are applied — this ordering is load-bearing. Prod's +// v2 document currently has 20 webhook operations sharing just 2 duplicated +// operationIds, and the overrides remove those paths. Validating before +// overrides were applied would abort every production regeneration. +export function assertMergedOpenApiDocument(document: OpenApiDocument): void { + const operationClaims = new Map>(); + + for (const [pathKey, pathValue] of Object.entries(document.paths)) { + if (!isRecord(pathValue)) { + continue; + } + for (const method of HTTP_METHOD_KEYS) { + const operation = pathValue[method]; + if (!isRecord(operation)) { + continue; + } + + const label = `${method.toUpperCase()} ${pathKey}`; + const operationId = operation.operationId; + if (typeof operationId !== "string" || operationId.length === 0) { + // generate.ts silently skips operations without an operationId; the + // documented escape hatch is adding a "remove" override for the path. + console.warn(`OpenAPI operation ${label} has no operationId; generate.ts will skip it.`); + continue; + } + + const claims = operationClaims.get(operationId); + if (claims === undefined) { + operationClaims.set(operationId, [label]); + } else { + claims.push(label); + } + + const versionPrefixMatch = /^(v\d+)-/i.exec(operationId); + if (versionPrefixMatch) { + const prefix = versionPrefixMatch[1]!.toLowerCase(); + const leadingSegment = pathKey.split("/")[1]?.toLowerCase(); + if (leadingSegment !== prefix) { + throw new Error( + `OpenAPI operationId ${JSON.stringify(operationId)} for ${label} has version prefix ${JSON.stringify(prefix)} that does not match the path's leading segment ${JSON.stringify(leadingSegment ?? "")}.`, + ); + } + } + } + } + + for (const [operationId, claims] of operationClaims) { + if (claims.length > 1) { + throw new Error( + `Duplicate OpenAPI operationId ${JSON.stringify(operationId)} claimed by: ${claims.join(", ")}.`, + ); + } + } +} + +export async function downloadOpenApiSpec(): Promise { + const envBaseUrl = process.env.SUPABASE_API_URL; + // The sidecar is consulted only when the environment does not override it, + // so an explicit SUPABASE_API_URL works even when the pin is absent or + // malformed. + const pinnedBaseUrl = envBaseUrl === undefined ? await loadPinnedBaseUrl() : undefined; + const baseUrl = resolveOpenApiBaseUrl({ envBaseUrl, pinnedBaseUrl }); + console.log(`Resolved OpenAPI base URL: ${baseUrl}`); + + const documents: Array<{ + readonly version: OpenApiDocumentVersion; + readonly document: OpenApiDocument; + }> = []; + for (const { version, url } of resolveOpenApiSpecUrls(baseUrl)) { + console.log(`Fetching ${version} OpenAPI document from ${url}`); + const response = await fetch(url); + + // Hard-fail on a missing document instead of tolerating it: a 404 on + // /api/v2-json would silently delete the whole v2 namespace from the + // generated client, and the hourly regeneration sync would auto-merge + // that deletion without anyone noticing. + if (!response.ok) { + throw new Error(`Failed to download OpenAPI spec from ${url}: ${response.status}`); + } + + const document = await response.json(); + assertOpenApiDocument(document); + documents.push({ version, document }); + } - applyOpenApiOverrides(document, await loadOpenApiOverrides()); + const mergedDocument = mergeOpenApiDocuments(documents); + applyOpenApiOverrides(mergedDocument, await loadOpenApiOverrides()); + assertMergedOpenApiDocument(mergedDocument); - await writeFile(OPENAPI_SPEC_PATH, `${JSON.stringify(document, null, 2)}\n`); + await writeFile(OPENAPI_SPEC_PATH, `${JSON.stringify(mergedDocument, null, 2)}\n`); + await writeOpenApiSource(baseUrl); } if (import.meta.main) { diff --git a/packages/api/scripts/download-openapi.unit.test.ts b/packages/api/scripts/download-openapi.unit.test.ts index 4111f8d305..a7521eb899 100644 --- a/packages/api/scripts/download-openapi.unit.test.ts +++ b/packages/api/scripts/download-openapi.unit.test.ts @@ -1,9 +1,13 @@ -import { describe, expect, test } from "vitest"; +import { describe, expect, test, vi } from "vitest"; import { applyOpenApiOverrides, + assertMergedOpenApiDocument, assertOpenApiDocument, + mergeOpenApiDocuments, + resolveOpenApiBaseUrl, resolveOpenApiSpecUrl, + resolveOpenApiSpecUrls, } from "./download-openapi.ts"; describe("download-openapi", () => { @@ -107,4 +111,269 @@ describe("download-openapi", () => { ), ).toThrow("cannot be added"); }); + + test("derives the v2 spec URL and still normalizes a trailing slash", () => { + expect(resolveOpenApiSpecUrl("https://api.supabase.com", "v2")).toBe( + "https://api.supabase.com/api/v2-json", + ); + expect(resolveOpenApiSpecUrl("https://api.supabase.com/", "v2")).toBe( + "https://api.supabase.com/api/v2-json", + ); + }); + + test("resolves both the v1 and v2 spec URLs for a single base URL", () => { + expect(resolveOpenApiSpecUrls("https://api.supabase.com")).toEqual([ + { version: "v1", url: "https://api.supabase.com/api/v1-json" }, + { version: "v2", url: "https://api.supabase.com/api/v2-json" }, + ]); + }); + + test("resolves the base URL with env > pinned > default precedence", () => { + expect( + resolveOpenApiBaseUrl({ + envBaseUrl: "https://env.supabase.com", + pinnedBaseUrl: "https://pinned.supabase.com", + }), + ).toBe("https://env.supabase.com"); + expect(resolveOpenApiBaseUrl({ pinnedBaseUrl: "https://pinned.supabase.com" })).toBe( + "https://pinned.supabase.com", + ); + expect(resolveOpenApiBaseUrl({})).toBe("https://api.supabase.com"); + }); + + test("merging a single document is an identity for its paths and schemas", () => { + const document = { + openapi: "3.0.0", + info: { title: "Some Title", version: "1.0.0" }, + paths: { "/v1/a": { get: {} } }, + components: { schemas: { Foo: { type: "string" } } }, + }; + + const merged = mergeOpenApiDocuments([{ version: "v1", document }]); + + expect(merged.paths).toEqual(document.paths); + expect(merged.components?.schemas).toEqual(document.components.schemas); + }); + + test("merges v1 and v2 documents, ordering v1 paths before v2 and unioning their schemas", () => { + const v1Document = { + openapi: "3.0.0", + info: { title: "V1 Title", version: "1.0.0" }, + paths: { "/v1/a": { get: {} }, "/v1/b": { get: {} } }, + components: { schemas: { Foo: { type: "string" } } }, + }; + const v2Document = { + openapi: "3.0.0", + info: { title: "V2 Title", version: "1.0.0" }, + paths: { "/v2/c": { get: {} } }, + components: { schemas: { Bar: { type: "number" } } }, + }; + + const merged = mergeOpenApiDocuments([ + { version: "v1", document: v1Document }, + { version: "v2", document: v2Document }, + ]); + + expect(Object.keys(merged.paths)).toEqual(["/v1/a", "/v1/b", "/v2/c"]); + expect(merged.components?.schemas).toEqual({ + Foo: { type: "string" }, + Bar: { type: "number" }, + }); + expect(merged.info).toEqual({ title: "Supabase API", version: "1.0.0" }); + }); + + test('throws when the documents\' "openapi" versions disagree', () => { + const v1Document = { openapi: "3.0.0", info: { version: "1.0.0" }, paths: { "/v1/a": {} } }; + const v2Document = { openapi: "3.1.0", info: { version: "1.0.0" }, paths: { "/v2/a": {} } }; + + expect(() => + mergeOpenApiDocuments([ + { version: "v1", document: v1Document }, + { version: "v2", document: v2Document }, + ]), + ).toThrow('OpenAPI "openapi" version mismatch between v1 (3.0.0) and v2 (3.1.0).'); + }); + + test('throws when the documents\' "info.version" disagree', () => { + const v1Document = { openapi: "3.0.0", info: { version: "1.0.0" }, paths: { "/v1/a": {} } }; + const v2Document = { openapi: "3.0.0", info: { version: "2.0.0" }, paths: { "/v2/a": {} } }; + + expect(() => + mergeOpenApiDocuments([ + { version: "v1", document: v1Document }, + { version: "v2", document: v2Document }, + ]), + ).toThrow('OpenAPI "info.version" mismatch between v1 (1.0.0) and v2 (2.0.0).'); + }); + + test("throws when a v2 document contains a path outside the /v2/ namespace", () => { + const v1Document = { openapi: "3.0.0", info: { version: "1.0.0" }, paths: { "/v1/a": {} } }; + const v2Document = { openapi: "3.0.0", info: { version: "1.0.0" }, paths: { "/v1/foo": {} } }; + + expect(() => + mergeOpenApiDocuments([ + { version: "v1", document: v1Document }, + { version: "v2", document: v2Document }, + ]), + ).toThrow('OpenAPI path "/v1/foo" in the v2 document does not start with "/v2/".'); + }); + + test("throws when the same path key appears twice across documents", () => { + // Can only happen when the same declared version is fetched/merged twice, + // since a document's own version-prefix check would otherwise reject a + // literal path belonging to a different version before this check runs. + const firstDocument = { + openapi: "3.0.0", + info: { version: "1.0.0" }, + paths: { "/v1/a": { get: {} } }, + }; + const secondDocument = { + openapi: "3.0.0", + info: { version: "1.0.0" }, + paths: { "/v1/a": { post: {} } }, + }; + + expect(() => + mergeOpenApiDocuments([ + { version: "v1", document: firstDocument }, + { version: "v1", document: secondDocument }, + ]), + ).toThrow('Duplicate OpenAPI path "/v1/a" found in both the v1 and v1 documents.'); + }); + + test("dedupes an identical duplicate schema found in both documents", () => { + const v1Document = { + openapi: "3.0.0", + info: { version: "1.0.0" }, + paths: { "/v1/a": {} }, + components: { schemas: { Shared: { type: "string" } } }, + }; + const v2Document = { + openapi: "3.0.0", + info: { version: "1.0.0" }, + paths: { "/v2/a": {} }, + components: { schemas: { Shared: { type: "string" } } }, + }; + + const merged = mergeOpenApiDocuments([ + { version: "v1", document: v1Document }, + { version: "v2", document: v2Document }, + ]); + + expect(merged.components?.schemas).toEqual({ Shared: { type: "string" } }); + }); + + test("throws when two documents disagree on the same schema name", () => { + const v1Document = { + openapi: "3.0.0", + info: { version: "1.0.0" }, + paths: { "/v1/a": {} }, + components: { schemas: { Shared: { type: "string" } } }, + }; + const v2Document = { + openapi: "3.0.0", + info: { version: "1.0.0" }, + paths: { "/v2/a": {} }, + components: { schemas: { Shared: { type: "number" } } }, + }; + + expect(() => + mergeOpenApiDocuments([ + { version: "v1", document: v1Document }, + { version: "v2", document: v2Document }, + ]), + ).toThrow('Conflicting OpenAPI schema "Shared" found in both the v1 and v2 documents.'); + }); + + test("throws on duplicate operationId across the v2 webhook paths (CLI-2157 platform bug)", () => { + const document = { + paths: { + "/v2/projects/{ref}/webhooks/endpoints": { + get: { operationId: "allV2ProjectsByRefWebhooks" }, + }, + "/v2/projects/{ref}/webhooks/endpoints/{id}": { + get: { operationId: "allV2ProjectsByRefWebhooks" }, + }, + }, + }; + + expect(() => assertMergedOpenApiDocument(document)).toThrow( + 'Duplicate OpenAPI operationId "allV2ProjectsByRefWebhooks" claimed by: GET /v2/projects/{ref}/webhooks/endpoints, GET /v2/projects/{ref}/webhooks/endpoints/{id}.', + ); + }); + + test("throws when an operationId's version prefix disagrees with its path", () => { + const document = { paths: { "/v2/x": { get: { operationId: "v1-x" } } } }; + + expect(() => assertMergedOpenApiDocument(document)).toThrow( + 'OpenAPI operationId "v1-x" for GET /v2/x has version prefix "v1" that does not match the path\'s leading segment "v2".', + ); + }); + + test("warns instead of throwing when an operation has no operationId", () => { + const document = { paths: { "/v1/a": { get: {} } } }; + const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {}); + + expect(() => assertMergedOpenApiDocument(document)).not.toThrow(); + expect(warnSpy).toHaveBeenCalledWith( + "OpenAPI operation GET /v1/a has no operationId; generate.ts will skip it.", + ); + + warnSpy.mockRestore(); + }); + + test("applyOpenApiOverrides tolerantly removes JSON pointers that no longer exist", () => { + const withExistingPath = { paths: { "/v1/foo": { get: {} } } }; + applyOpenApiOverrides(withExistingPath, [{ op: "remove", path: "/paths/~1v1~1foo" }]); + expect(withExistingPath.paths).toEqual({}); + + const withMissingPath = { paths: {} }; + applyOpenApiOverrides(withMissingPath, [{ op: "remove", path: "/paths/~1v1~1missing" }]); + expect(withMissingPath.paths).toEqual({}); + + const withMissingIntermediateSegment = { paths: {} }; + applyOpenApiOverrides(withMissingIntermediateSegment, [ + { op: "remove", path: "/paths/~1nope/get" }, + ]); + expect(withMissingIntermediateSegment.paths).toEqual({}); + + const withArray = { paths: {}, components: { schemas: { Foo: { enum: ["a", "b", "c"] } } } }; + applyOpenApiOverrides(withArray, [{ op: "remove", path: "/components/schemas/Foo/enum/1" }]); + expect(withArray.components.schemas.Foo.enum).toEqual(["a", "c"]); + }); + + test("rejects a remove override that carries a value", () => { + expect(() => + applyOpenApiOverrides({ paths: {} }, [{ op: "remove", path: "/paths", value: {} }]), + ).toThrow("OpenAPI remove overrides must not include a value."); + }); + + test("assertMergedOpenApiDocument passes after the webhook-collision remove overrides are applied but fails without them", () => { + const buildDocument = () => ({ + paths: { + "/v2/projects/{ref}/webhooks/endpoints": { + get: { operationId: "allV2ProjectsByRefWebhooks" }, + }, + "/v2/projects/{ref}/webhooks/endpoints/{id}": { + get: { operationId: "allV2ProjectsByRefWebhooks" }, + }, + "/v2/projects/{ref}": { + get: { operationId: "v2-get-a-project" }, + }, + }, + }); + + const overrides = [ + { op: "remove", path: "/paths/~1v2~1projects~1{ref}~1webhooks~1endpoints" }, + { op: "remove", path: "/paths/~1v2~1projects~1{ref}~1webhooks~1endpoints~1{id}" }, + ]; + + expect(() => assertMergedOpenApiDocument(buildDocument())).toThrow( + 'Duplicate OpenAPI operationId "allV2ProjectsByRefWebhooks"', + ); + + const patchedDocument = applyOpenApiOverrides(buildDocument(), overrides); + expect(Object.keys(patchedDocument.paths)).toEqual(["/v2/projects/{ref}"]); + expect(() => assertMergedOpenApiDocument(patchedDocument)).not.toThrow(); + }); }); diff --git a/packages/api/scripts/generate.ts b/packages/api/scripts/generate.ts index 8d1e52f11d..4cea516e4e 100644 --- a/packages/api/scripts/generate.ts +++ b/packages/api/scripts/generate.ts @@ -10,7 +10,7 @@ import * as SchemaRepresentation from "effect/SchemaRepresentation"; type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD"; type OpenApiHttpMethod = Lowercase; -type OpenApiDocument = { +export type OpenApiDocument = { readonly openapi: string; readonly info?: { readonly title?: string; @@ -22,7 +22,7 @@ type OpenApiDocument = { }; }; -type OpenApiOperation = { +export type OpenApiOperation = { readonly operationId?: string; readonly summary?: string; readonly description?: string; @@ -111,6 +111,8 @@ type OperationDefinition = { readonly schemaBase: string; readonly method: HttpMethod; readonly path: string; + readonly version: string; + readonly methodName: string; readonly description: string; readonly pathParams: ReadonlyArray; readonly queryParams: ReadonlyArray; @@ -142,7 +144,7 @@ function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null; } -function loadSpec(): OpenApiDocument { +export function loadSpec(): OpenApiDocument { const parsed = JSON.parse(readFileSync(sourceSpecPath, "utf8")); if (!isRecord(parsed) || !isRecord(parsed.paths)) { throw new Error(`Invalid OpenAPI document at ${sourceSpecPath}`); @@ -588,7 +590,94 @@ function buildCombinedInputSchema( }; } -function extractOperations(document: OpenApiDocument): ReadonlyArray { +// The version namespace is derived from the path (not the operationId) so +// that `/v2/...` routes land in `api.v2` regardless of how their operationId +// happens to be spelled in the upstream spec. +export function operationVersionFromPath(path: string): string { + const version = path.split("/")[1]; + if (version === undefined || !/^v\d+$/u.test(version)) { + throw new Error(`Expected a version-prefixed path, got ${path}`); + } + return version; +} + +// Strips a leading version prefix (e.g. `v1`/`V2`) from a camelized operation +// name, lowercasing the character that follows it, so `v2GetProjectConfig` +// becomes `getProjectConfig`. Operation names without a version prefix are +// returned unchanged — the path, not the operationId, is the authority on +// version. +export function operationMethodName(operationName: string): string { + const match = /^([vV]\d+)(.*)$/u.exec(operationName); + if (!match) { + return operationName; + } + + const methodBase = match[2]; + if (methodBase === undefined || methodBase.length === 0) { + return operationName; + } + + const first = methodBase.slice(0, 1).toLowerCase(); + return `${first}${methodBase.slice(1)}`; +} + +// A version prefix on the operationId is optional, but when present it must +// agree with the path-derived version — otherwise the generated namespace +// (from the path) and the SDK method name (from the operationId) would imply +// different API versions for the same operation. +function assertOperationVersionAgreement(operation: { + readonly operationId: string; + readonly operationName: string; + readonly path: string; + readonly version: string; +}): void { + const match = /^[vV]\d+/u.exec(operation.operationName); + if (!match) { + return; + } + + const operationNameVersion = match[0].toLowerCase(); + if (operationNameVersion !== operation.version) { + throw new Error( + `Operation "${operation.operationId}" at path "${operation.path}" has operationId version "${operationNameVersion}" that disagrees with the path-derived version "${operation.version}"`, + ); + } +} + +function assertUniqueOperations(operations: ReadonlyArray): void { + const byNamespaceMethod = new Map(); + const byOperationName = new Map(); + const bySchemaBase = new Map(); + + for (const operation of operations) { + const namespaceMethod = `${operation.version}.${operation.methodName}`; + const existingNamespaceMethod = byNamespaceMethod.get(namespaceMethod); + if (existingNamespaceMethod) { + throw new Error( + `Duplicate namespace method "${namespaceMethod}": "${existingNamespaceMethod.operationId}" (${existingNamespaceMethod.method} ${existingNamespaceMethod.path}) collides with "${operation.operationId}" (${operation.method} ${operation.path})`, + ); + } + byNamespaceMethod.set(namespaceMethod, operation); + + const existingOperationName = byOperationName.get(operation.operationName); + if (existingOperationName) { + throw new Error( + `Duplicate operation name "${operation.operationName}": "${existingOperationName.operationId}" (${existingOperationName.method} ${existingOperationName.path}) collides with "${operation.operationId}" (${operation.method} ${operation.path})`, + ); + } + byOperationName.set(operation.operationName, operation); + + const existingSchemaBase = bySchemaBase.get(operation.schemaBase); + if (existingSchemaBase) { + throw new Error( + `Duplicate schema base "${operation.schemaBase}": "${existingSchemaBase.operationId}" (${existingSchemaBase.method} ${existingSchemaBase.path}) collides with "${operation.operationId}" (${operation.method} ${operation.path})`, + ); + } + bySchemaBase.set(operation.schemaBase, operation); + } +} + +export function extractOperations(document: OpenApiDocument): ReadonlyArray { const operations: Array = []; for (const [pathName, pathItem] of Object.entries(document.paths)) { @@ -602,13 +691,25 @@ function extractOperations(document: OpenApiDocument): ReadonlyArray parameter.in === "path") @@ -629,7 +730,11 @@ function extractOperations(document: OpenApiDocument): ReadonlyArray left.operationId.localeCompare(right.operationId)); + const sortedOperations = operations.sort((left, right) => + left.operationId.localeCompare(right.operationId), + ); + assertUniqueOperations(sortedOperations); + return sortedOperations; } function renderSchemaSource( @@ -758,7 +863,7 @@ function renderResponse(definition: ResponseDefinition): string { return `{ kind: ${JSON.stringify(definition.kind)} }`; } -function renderContracts( +export function renderContracts( document: OpenApiDocument, operations: ReadonlyArray, ): string { @@ -818,34 +923,12 @@ export type VoidOperationDefinition = Extr `; } -function splitOperationVersion(operationName: string): { - readonly version: string; - readonly methodName: string; -} { - const match = /^((?:v|V)\d+)(.+)$/u.exec(operationName); - if (!match) { - throw new Error(`Expected a version-prefixed operation id, got ${operationName}`); - } - - const [, version, methodBase] = match; - if (version === undefined || methodBase === undefined || methodBase.length === 0) { - throw new Error(`Expected an operation method segment after the version in ${operationName}`); - } - const first = methodBase.slice(0, 1).toLowerCase(); - - return { - version, - methodName: `${first}${methodBase.slice(1)}`, - }; -} - -function renderEffectClient(operations: ReadonlyArray): string { +export function renderEffectClient(operations: ReadonlyArray): string { const versionedOperations = new Map>(); for (const operation of operations) { - const { version } = splitOperationVersion(operation.operationName); - const group = versionedOperations.get(version); + const group = versionedOperations.get(operation.version); if (group === undefined) { - versionedOperations.set(version, [operation]); + versionedOperations.set(operation.version, [operation]); } else { group.push(operation); } @@ -856,7 +939,7 @@ function renderEffectClient(operations: ReadonlyArray): str .map(([version, groupedOperations]) => { const methods = groupedOperations .map((operation) => { - const { methodName } = splitOperationVersion(operation.operationName); + const { methodName } = operation; const isEmptyInput = operation.inputSchema.type === "object" && Object.keys(operation.inputSchema.properties ?? {}).length === 0; @@ -886,7 +969,7 @@ ${methods} const executorCases = operations .map((operation) => { - const { version, methodName } = splitOperationVersion(operation.operationName); + const { version, methodName } = operation; const isEmptyInput = operation.inputSchema.type === "object" && Object.keys(operation.inputSchema.properties ?? {}).length === 0; diff --git a/packages/api/scripts/generate.unit.test.ts b/packages/api/scripts/generate.unit.test.ts index c0e2dab526..116f9bf946 100644 --- a/packages/api/scripts/generate.unit.test.ts +++ b/packages/api/scripts/generate.unit.test.ts @@ -3,12 +3,73 @@ import * as JsonSchema from "effect/JsonSchema"; import * as SchemaRepresentation from "effect/SchemaRepresentation"; import { describe, expect, test } from "vitest"; +import type { OpenApiDocument, OpenApiOperation } from "./generate.ts"; import { + extractOperations, normalizeNullableJsonSchema, normalizeQueryParameterSchema, + operationMethodName, + operationVersionFromPath, + renderContracts, + renderEffectClient, sanitizeOpenApiSchema, } from "./generate.ts"; +function jsonResponseOperation( + operationId: string, + pathParamName: string, + responseSchema: Record, +): OpenApiOperation { + return { + operationId, + parameters: [{ name: pathParamName, in: "path", required: true, schema: { type: "string" } }], + responses: { + "200": { + content: { + "application/json": { + schema: responseSchema, + }, + }, + }, + }, + }; +} + +function twoVersionFixture(): OpenApiDocument { + return { + openapi: "3.0.0", + info: { title: "Test API", version: "1.0.0" }, + paths: { + "/v1/organizations/{slug}/members": { + get: jsonResponseOperation("v1-list-organization-members", "slug", { + type: "array", + items: { type: "object", properties: {}, required: [] }, + }), + }, + "/v1/projects/{ref}": { + get: jsonResponseOperation("v1-get-a-project", "ref", { + type: "object", + properties: {}, + required: [], + }), + }, + "/v2/organizations/{slug}/members": { + get: jsonResponseOperation("v2-list-organization-members", "slug", { + type: "array", + items: { type: "object", properties: {}, required: [] }, + }), + }, + "/v2/projects/{ref}/config": { + get: jsonResponseOperation("v2-get-a-project-config", "ref", { + type: "object", + properties: {}, + required: [], + }), + }, + }, + }; +} + function renderOpenApiSchema(schema: Parameters[0]) { const normalized = normalizeNullableJsonSchema( JsonSchema.fromSchemaOpenApi3_0(sanitizeOpenApiSchema(schema)).schema, @@ -119,4 +180,102 @@ describe("generate", () => { }), ).toContain('"default": Schema.optionalKey(Schema.Json'); }); + + test("extractOperations derives version from the path and methodName from the operationId", () => { + const operations = extractOperations(twoVersionFixture()); + + expect(operations.map((operation) => operation.operationId)).toEqual([ + "v1-get-a-project", + "v1-list-organization-members", + "v2-get-a-project-config", + "v2-list-organization-members", + ]); + expect( + operations.map((operation) => ({ + version: operation.version, + methodName: operation.methodName, + })), + ).toEqual([ + { version: "v1", methodName: "getAProject" }, + { version: "v1", methodName: "listOrganizationMembers" }, + { version: "v2", methodName: "getAProjectConfig" }, + { version: "v2", methodName: "listOrganizationMembers" }, + ]); + + const membersOperations = operations.filter( + (operation) => operation.methodName === "listOrganizationMembers", + ); + expect(membersOperations).toHaveLength(2); + expect(membersOperations.map((operation) => operation.version)).toEqual(["v1", "v2"]); + }); + + test("operationMethodName strips a real v1 version prefix and passes unprefixed names through unchanged", () => { + expect(operationMethodName("v1GetABranchConfig")).toBe("getABranchConfig"); + expect(operationMethodName("v1ListAllProjects")).toBe("listAllProjects"); + expect(operationMethodName("healthCheck")).toBe("healthCheck"); + }); + + test("operationVersionFromPath reads the version segment from a versioned path", () => { + expect(operationVersionFromPath("/v2/projects/{ref}/config")).toBe("v2"); + }); + + test("operationVersionFromPath throws for a path with no version prefix", () => { + expect(() => operationVersionFromPath("/health")).toThrow( + "Expected a version-prefixed path, got /health", + ); + }); + + test("extractOperations throws when a path's version disagrees with the operationId's version prefix", () => { + const document = { + openapi: "3.0.0", + paths: { + "/v2/x": { get: jsonResponseOperation("v1-x", "x", { type: "object" }) }, + }, + }; + + expect(() => extractOperations(document)).toThrow( + 'Operation "v1-x" at path "/v2/x" has operationId version "v1" that disagrees with the path-derived version "v2"', + ); + }); + + test("extractOperations throws when two operationIds camelize to the same (version, methodName) pair", () => { + const document = { + openapi: "3.0.0", + paths: { + "/v2/a": { get: jsonResponseOperation("v2-get-config", "x", { type: "object" }) }, + "/v2/b": { get: jsonResponseOperation("v2-get--config", "x", { type: "object" }) }, + }, + }; + + expect(() => extractOperations(document)).toThrow( + 'Duplicate namespace method "v2.getConfig": "v2-get--config" (GET /v2/b) collides with "v2-get-config" (GET /v2/a)', + ); + }); + + test("renderEffectClient emits both version namespaces with the shared method name and a versioned executor case", () => { + const document = twoVersionFixture(); + const operations = extractOperations(document); + const source = renderEffectClient(operations); + + expect(source).toContain(" v1: {"); + expect(source).toContain(" v2: {"); + + const v1Block = source.slice(source.indexOf(" v1: {"), source.indexOf(" v2: {")); + const v2Block = source.slice(source.indexOf(" v2: {")); + expect(v1Block).toContain("listOrganizationMembers: ("); + expect(v2Block).toContain("listOrganizationMembers: ("); + + expect(source).toContain("api.v2.listOrganizationMembers(decoded)"); + }); + + test("renderContracts includes both versioned operation names and the raw kebab operationIds", () => { + const document = twoVersionFixture(); + const operations = extractOperations(document); + const source = renderContracts(document, operations); + + expect(source).toContain('"v1ListOrganizationMembers": {'); + expect(source).toContain('"v2ListOrganizationMembers": {'); + expect(source).toContain(' "v1-list-organization-members": "v1ListOrganizationMembers",'); + expect(source).toContain(' "v2-list-organization-members": "v2ListOrganizationMembers",'); + }); }); diff --git a/packages/api/scripts/generated-output-sync.unit.test.ts b/packages/api/scripts/generated-output-sync.unit.test.ts new file mode 100644 index 0000000000..e1c3dda7f1 --- /dev/null +++ b/packages/api/scripts/generated-output-sync.unit.test.ts @@ -0,0 +1,105 @@ +import { execFileSync } from "node:child_process"; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { describe, expect, test } from "vitest"; + +import { extractOperations, loadSpec, renderContracts, renderEffectClient } from "./generate.ts"; + +// Full-fidelity drift guard: re-renders every generated file from the +// committed openapi.json snapshot, formats the result through the same oxfmt +// the pipeline uses, and requires byte equality with the committed files. +// Unlike the operation-level bijection test in src/generated-contract-sync, +// this catches hand edits to schema definitions, parameter lists, request +// bodies, response types, and the executor switch — anything short of +// editing the snapshot and the generated output consistently, which the +// hourly upstream sync then catches. + +const scriptDir = path.dirname(fileURLToPath(import.meta.url)); +const packageDir = path.join(scriptDir, ".."); +const generatedDir = path.join(packageDir, "src", "generated"); +const oxfmtBin = path.join(packageDir, "node_modules", ".bin", "oxfmt"); + +function formatWithOxfmt(source: string, fileName: string): string { + // oxfmt runs in file mode (also what the pipeline's fmt:fix runs) rather + // than through stdin/stdout: Bun on Linux truncates a child's piped stdout + // at ~219 KB, and these renders are 600+ KB. The temp directory lives + // inside the package so oxfmt resolves the same configuration, but not + // under node_modules, which oxfmt skips by default. + const tempDir = mkdtempSync(path.join(packageDir, ".generated-output-sync-")); + try { + const tempFile = path.join(tempDir, fileName); + writeFileSync(tempFile, source); + execFileSync(oxfmtBin, [tempFile], { cwd: packageDir }); + return readFileSync(tempFile, "utf8"); + } finally { + rmSync(tempDir, { recursive: true, force: true }); + } +} + +function committedFile(fileName: string): string { + return readFileSync(path.join(generatedDir, fileName), "utf8"); +} + +function expectSameSource(rendered: string, fileName: string): void { + const committed = committedFile(fileName); + if (rendered === committed) { + return; + } + const renderedLines = rendered.split("\n"); + const committedLines = committed.split("\n"); + const limit = Math.min(renderedLines.length, committedLines.length); + let line = 0; + while (line < limit && renderedLines[line] === committedLines[line]) { + line += 1; + } + expect.fail( + `src/generated/${fileName} is not what the generator renders from the committed snapshot ` + + `(first difference at line ${line + 1}):\n` + + ` committed: ${JSON.stringify(committedLines[line] ?? "")}\n` + + ` rendered: ${JSON.stringify(renderedLines[line] ?? "")}\n` + + `Hand edits to src/generated are not allowed — run \`pnpm generate\` instead.`, + ); +} + +// Rendering contracts.ts runs the real schema codegen for every operation, +// which takes well over vitest's default 5s budget. +const RENDER_TIMEOUT_MS = 120_000; + +describe("generated output sync", () => { + const document = loadSpec(); + const operations = extractOperations(document); + + test( + "contracts.ts is byte-identical to the generator's render of the committed snapshot", + { timeout: RENDER_TIMEOUT_MS }, + () => { + expectSameSource( + formatWithOxfmt(renderContracts(document, operations), "contracts.ts"), + "contracts.ts", + ); + }, + ); + + test( + "effect-client.ts is byte-identical to the generator's render of the committed snapshot", + { timeout: RENDER_TIMEOUT_MS }, + () => { + expectSameSource( + formatWithOxfmt(renderEffectClient(operations), "effect-client.ts"), + "effect-client.ts", + ); + }, + ); + + test( + "openapi.json is byte-identical to the generator's normalized rewrite of itself", + { timeout: RENDER_TIMEOUT_MS }, + () => { + expectSameSource( + formatWithOxfmt(`${JSON.stringify(document, null, 2)}\n`, "openapi.json"), + "openapi.json", + ); + }, + ); +}); diff --git a/packages/api/scripts/openapi-overrides.json b/packages/api/scripts/openapi-overrides.json index ee82bed371..5e60739640 100644 --- a/packages/api/scripts/openapi-overrides.json +++ b/packages/api/scripts/openapi-overrides.json @@ -622,5 +622,70 @@ "op": "replace", "path": "/components/schemas/UpdateAuthConfigBody/properties/sms_test_otp/pattern", "value": "^(?:[0-9]{1,15}=(?:[0-9]+,[0-9]{1,15}=|[0-9]{2,}=)*[0-9]+,?)?$" + }, + { + "op": "remove", + "path": "/paths/~1v2~1projects~1{ref}~1webhooks~1endpoints", + "$comment": "CLI-2157: the platform's v2 spec gives all 10 project-webhook operations the shared operationId \"allV2ProjectsByRefWebhooks\" (and all 10 org-webhook operations share \"allV2OrganizationsBySlugWebhooks\") — duplicated and not version-prefixed, which breaks codegen. Remove-if-present because staging's v2-json is currently served by two backend variants that disagree on whether these paths exist." + }, + { + "op": "remove", + "path": "/paths/~1v2~1projects~1{ref}~1webhooks~1endpoints~1{id}", + "$comment": "CLI-2157: part of the project-webhook operationId collision; see the endpoints path comment above." + }, + { + "op": "remove", + "path": "/paths/~1v2~1projects~1{ref}~1webhooks~1endpoints~1{id}~1deliveries", + "$comment": "CLI-2157: part of the project-webhook operationId collision; see the endpoints path comment above." + }, + { + "op": "remove", + "path": "/paths/~1v2~1projects~1{ref}~1webhooks~1endpoints~1{id}~1test", + "$comment": "CLI-2157: part of the project-webhook operationId collision; see the endpoints path comment above." + }, + { + "op": "remove", + "path": "/paths/~1v2~1projects~1{ref}~1webhooks~1deliveries~1{id}", + "$comment": "CLI-2157: part of the project-webhook operationId collision; see the endpoints path comment above." + }, + { + "op": "remove", + "path": "/paths/~1v2~1projects~1{ref}~1webhooks~1deliveries~1{id}~1retry", + "$comment": "CLI-2157: part of the project-webhook operationId collision; see the endpoints path comment above." + }, + { + "op": "remove", + "path": "/paths/~1v2~1organizations~1{slug}~1webhooks~1endpoints", + "$comment": "CLI-2157: the platform's v2 spec gives all 10 org-webhook operations the shared operationId \"allV2OrganizationsBySlugWebhooks\" (and all 10 project-webhook operations share \"allV2ProjectsByRefWebhooks\") — duplicated and not version-prefixed, which breaks codegen. Remove-if-present because staging's v2-json is currently served by two backend variants that disagree on whether these paths exist." + }, + { + "op": "remove", + "path": "/paths/~1v2~1organizations~1{slug}~1webhooks~1endpoints~1{id}", + "$comment": "CLI-2157: part of the org-webhook operationId collision; see the endpoints path comment above." + }, + { + "op": "remove", + "path": "/paths/~1v2~1organizations~1{slug}~1webhooks~1endpoints~1{id}~1deliveries", + "$comment": "CLI-2157: part of the org-webhook operationId collision; see the endpoints path comment above." + }, + { + "op": "remove", + "path": "/paths/~1v2~1organizations~1{slug}~1webhooks~1endpoints~1{id}~1test", + "$comment": "CLI-2157: part of the org-webhook operationId collision; see the endpoints path comment above." + }, + { + "op": "remove", + "path": "/paths/~1v2~1organizations~1{slug}~1webhooks~1deliveries~1{id}", + "$comment": "CLI-2157: part of the org-webhook operationId collision; see the endpoints path comment above." + }, + { + "op": "remove", + "path": "/paths/~1v2~1organizations~1{slug}~1webhooks~1deliveries~1{id}~1retry", + "$comment": "CLI-2157: part of the org-webhook operationId collision; see the endpoints path comment above." + }, + { + "op": "remove", + "path": "/components/schemas/APIErrorObject", + "$comment": "CLI-2157: referenced only by the removed webhook paths (verified in prod and staging); removing it also makes the staging document deterministic." } ] diff --git a/packages/api/scripts/openapi-source.json b/packages/api/scripts/openapi-source.json new file mode 100644 index 0000000000..95dd824ea3 --- /dev/null +++ b/packages/api/scripts/openapi-source.json @@ -0,0 +1,3 @@ +{ + "baseUrl": "https://api.supabase.com" +} diff --git a/packages/api/src/effect.unit.test.ts b/packages/api/src/effect.unit.test.ts index 75f7380ee2..ce0a15a73e 100644 --- a/packages/api/src/effect.unit.test.ts +++ b/packages/api/src/effect.unit.test.ts @@ -442,6 +442,75 @@ describe("makeApiClient", () => { ]); }); + test("addresses same-named v1 and v2 operations independently by namespace", async () => { + const seenRequests: Array<{ method: string; url: string }> = []; + + const client = await Effect.runPromise( + makeApiClient(config).pipe( + Effect.provide( + httpClientLayer((request) => { + seenRequests.push({ + method: request.method, + url: request.url, + }); + + if (request.url === "https://api.supabase.com/v1/organizations/my-org/members") { + return Effect.succeed( + jsonResponse(request, 200, [ + { + user_id: "user-id", + user_name: "user-name", + role_name: "Owner", + mfa_enabled: false, + avatar_url: null, + }, + ]), + ); + } + + return Effect.succeed( + jsonResponse(request, 200, { + data: [], + links: { prev: null, next: null }, + }), + ); + }), + ), + ), + ); + + expect(typeof client.v1.listOrganizationMembers).toBe("function"); + expect(typeof client.v2.listOrganizationMembers).toBe("function"); + + const v1Members = await Effect.runPromise( + client.v1.listOrganizationMembers({ slug: "my-org" }), + ); + const v2Members = await Effect.runPromise( + client.v2.listOrganizationMembers({ slug: "my-org" }), + ); + + expect(v1Members).toEqual([ + { + user_id: "user-id", + user_name: "user-name", + role_name: "Owner", + mfa_enabled: false, + avatar_url: null, + }, + ]); + expect(v2Members.data).toEqual([]); + expect(seenRequests).toEqual([ + { + method: "GET", + url: "https://api.supabase.com/v1/organizations/my-org/members", + }, + { + method: "GET", + url: "https://api.supabase.com/v2/organizations/my-org/members", + }, + ]); + }); + test("serializes generated binary methods through the effect facade", async () => { let seenRequest: HttpClientRequest.HttpClientRequest | undefined; diff --git a/packages/api/src/generated-contract-sync.unit.test.ts b/packages/api/src/generated-contract-sync.unit.test.ts new file mode 100644 index 0000000000..1dc1641a04 --- /dev/null +++ b/packages/api/src/generated-contract-sync.unit.test.ts @@ -0,0 +1,184 @@ +import { readFileSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +import { describe, expect, test } from "vitest"; + +import { openApiOperationIdMap, operationDefinitions } from "./generated/contracts.ts"; +import { versionedEffectOperations } from "./generated/effect-client.ts"; + +const HTTP_METHODS = ["get", "put", "post", "delete", "patch", "head", "options", "trace"] as const; + +interface OpenApiOperationObject { + readonly operationId?: string; +} + +type OpenApiPathItem = Readonly>; + +interface OpenApiDocumentShape { + readonly paths: Readonly>; +} + +interface SnapshotOperation { + readonly path: string; + readonly method: string; + readonly operationId: string; +} + +const openApiJsonPath = join(dirname(fileURLToPath(import.meta.url)), "generated/openapi.json"); +const rawOpenApiJson = readFileSync(openApiJsonPath, "utf8"); +const openApiDocument = JSON.parse(rawOpenApiJson) as OpenApiDocumentShape; + +function extractSnapshotOperations( + document: OpenApiDocumentShape, +): ReadonlyArray { + const operations: Array = []; + for (const [path, pathItem] of Object.entries(document.paths)) { + for (const method of HTTP_METHODS) { + const operation = pathItem[method]; + if (!operation?.operationId) { + continue; + } + operations.push({ path, method: method.toUpperCase(), operationId: operation.operationId }); + } + } + return operations; +} + +function leadingPathSegment(path: string): string { + const segment = path.split("/")[1]; + if (segment === undefined) { + throw new Error(`Expected a version-prefixed path, got "${path}"`); + } + return segment; +} + +// Mirrors scripts/generate.ts's operationMethodName: strips the leading +// version prefix from the SDK operation id and lowercases the character that +// follows it, e.g. "v2GetProjectConfig" -> "getProjectConfig". +function methodNameFromSdkOperationId(sdkOperationId: string): string { + const match = /^v\d+(.+)$/.exec(sdkOperationId); + const rest = match?.[1]; + if (!rest) { + return sdkOperationId; + } + return `${rest[0]!.toLowerCase()}${rest.slice(1)}`; +} + +function isRecord(value: unknown): value is Readonly> { + return typeof value === "object" && value !== null; +} + +function stringProperty(value: unknown, key: string): string { + if (!isRecord(value)) { + throw new Error(`Expected an object while reading property "${key}"`); + } + const propertyValue = value[key]; + if (typeof propertyValue !== "string") { + throw new Error(`Expected a string property "${key}", got ${typeof propertyValue}`); + } + return propertyValue; +} + +const operationIdMap = new Map(Object.entries(openApiOperationIdMap)); +const definitionsByOperationName = new Map(Object.entries(operationDefinitions)); +const versionedOperationsByVersion = new Map( + Object.entries(versionedEffectOperations), +); + +function versionedOperationFunction(version: string, methodName: string): unknown { + const operations = versionedOperationsByVersion.get(version); + if (!isRecord(operations)) { + return undefined; + } + return operations[methodName]; +} + +const snapshotOperations = extractSnapshotOperations(openApiDocument); + +describe("generated client drift against the committed openapi.json snapshot", () => { + test("maps every snapshot operation to a matching generated contract and versioned client method", () => { + for (const { path, method, operationId } of snapshotOperations) { + const sdkOperationId = operationIdMap.get(operationId); + expect(sdkOperationId, `no openApiOperationIdMap entry for "${operationId}"`).toBeDefined(); + if (sdkOperationId === undefined) { + continue; + } + + const definition = definitionsByOperationName.get(sdkOperationId); + expect( + definition, + `no operationDefinitions entry for "${sdkOperationId}" (${method} ${path})`, + ).toBeDefined(); + + expect(stringProperty(definition, "method")).toBe(method); + expect(stringProperty(definition, "path")).toBe(path); + + const namespace = leadingPathSegment(path); + const methodName = methodNameFromSdkOperationId(sdkOperationId); + expect( + typeof versionedOperationFunction(namespace, methodName), + `versionedEffectOperations.${namespace}.${methodName} is not a function for "${sdkOperationId}" (${method} ${path})`, + ).toBe("function"); + } + }); + + test("does not carry a hand-added or stale operation in the generated contracts", () => { + const sdkOperationIdsFromSnapshot = snapshotOperations.map(({ operationId }) => + operationIdMap.get(operationId), + ); + + expect(new Set(sdkOperationIdsFromSnapshot).size).toBe(sdkOperationIdsFromSnapshot.length); + expect(sdkOperationIdsFromSnapshot.length).toBe(Object.keys(operationDefinitions).length); + expect(new Set(sdkOperationIdsFromSnapshot)).toEqual( + new Set(Object.keys(operationDefinitions)), + ); + }); + + test("does not carry a hand-added or stale method on the versioned effect client", () => { + const totalVersionedOperationFunctions = Array.from( + versionedOperationsByVersion.values(), + ).reduce( + (total, operations) => + isRecord(operations) ? total + Object.keys(operations).length : total, + 0, + ); + + const versionMethodPairsFromSnapshot = new Set( + snapshotOperations.map(({ path, operationId }) => { + const sdkOperationId = operationIdMap.get(operationId); + return `${leadingPathSegment(path)}.${ + sdkOperationId ? methodNameFromSdkOperationId(sdkOperationId) : operationId + }`; + }), + ); + + expect(versionMethodPairsFromSnapshot.size).toBe(snapshotOperations.length); + expect(totalVersionedOperationFunctions).toBe(snapshotOperations.length); + }); + + test("exposes exactly the API versions present in the snapshot as top-level namespaces", () => { + const versionsFromSnapshot = new Set( + snapshotOperations.map(({ path }) => leadingPathSegment(path)), + ); + + expect(Object.keys(versionedEffectOperations).sort()).toEqual( + Array.from(versionsFromSnapshot).sort(), + ); + expect(versionsFromSnapshot).toContain("v1"); + expect(versionsFromSnapshot).toContain("v2"); + }); + + // A byte-for-byte `JSON.stringify(parsed, null, 2) + "\n"` reproduction of + // the committed file does not hold: oxfmt collapses short arrays (e.g. + // `"tags": ["Environments"]`) onto a single line after generation, so a + // naive re-stringify diverges purely on formatting, not content. This + // instead checks that the committed bytes parse deterministically and keep + // the single trailing newline `scripts/generate.ts` writes. + test("parses the committed snapshot deterministically and keeps a single trailing newline", () => { + const reparsed = JSON.parse(readFileSync(openApiJsonPath, "utf8")) as OpenApiDocumentShape; + expect(reparsed).toEqual(openApiDocument); + expect(rawOpenApiJson.endsWith("\n")).toBe(true); + expect(rawOpenApiJson.endsWith("\n\n")).toBe(false); + }); +}); diff --git a/packages/api/src/generated/contracts.ts b/packages/api/src/generated/contracts.ts index 1cbcb9dcc7..a60b90399b 100644 --- a/packages/api/src/generated/contracts.ts +++ b/packages/api/src/generated/contracts.ts @@ -9989,6 +9989,2005 @@ export const V1VerifyDnsConfigOutput = Schema.Struct({ }), }), }); +export const V2AssignOrganizationMemberRoleInput = Schema.Struct({ + slug: Schema.String.check( + Schema.isPattern(new RegExp("^[\\w-]+$")).annotate({ + expected: "a string matching the RegExp ^[\\w-]+$", + }), + ), + user_id: Schema.String.annotate({ format: "uuid" }).check( + Schema.isPattern( + new RegExp( + "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", + ), + ).annotate({ + expected: + "a string matching the RegExp ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", + }), + ), + data: Schema.Struct({ + type: Schema.Literal("organization_member_role").annotate({ description: "Resource type." }), + attributes: Schema.Struct({ + role: Schema.Literals(["owner", "administrator", "developer", "read-only"]).annotate({ + description: + "Role name to assign. Must be one of: owner, administrator, developer, read-only. Must be on a Team or Enterprise plan to use the read-only role.", + }), + projects: Schema.optionalKey( + Schema.Array(Schema.Struct({ ref: Schema.String.annotate({ description: "Project ref" }) })) + .annotate({ + description: + "The projects to assign a project-scoped role for. If omitted, assigns an org-wide role.", + }) + .check( + Schema.isMinLength(1).annotate({ expected: "a value with a length of at least 1" }), + ), + ), + }), + }), +}); +export const V2AssignOrganizationMemberRoleOutput = Schema.Struct({ + data: Schema.Struct({ + type: Schema.Literal("organization_member_role").annotate({ description: "Resource type." }), + attributes: Schema.Struct({ + name: Schema.String.annotate({ + description: "Role name. For project-scoped assignments this is the base role name.", + }), + scope: Schema.Literals(["organization", "project"]).annotate({ + description: + "Whether this role applies org-wide or is scoped to specific projects for the user.", + }), + projects: Schema.Array(Schema.Struct({ ref: Schema.String, name: Schema.String })).annotate({ + description: "Project refs this role is scoped to. Empty array for org-level roles.", + }), + }), + }), +}); +export const V2CreateLogDrainInput = Schema.Struct({ + ref: Schema.String.check( + Schema.isMinLength(20).annotate({ expected: "a value with a length of at least 20" }), + ) + .check(Schema.isMaxLength(20).annotate({ expected: "a value with a length of at most 20" })) + .check( + Schema.isPattern(new RegExp("^[a-z]+$")).annotate({ + expected: "a string matching the RegExp ^[a-z]+$", + }), + ), + data: Schema.Struct({ + type: Schema.Literal("log_drain").annotate({ description: "Resource type." }), + attributes: Schema.Struct({ + name: Schema.String, + description: Schema.optionalKey(Schema.String), + config: Schema.Union([ + Schema.Struct({ + url: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + schema: Schema.optionalKey(Schema.String), + username: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + password: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + port: Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ expected: "a finite number" })), + Schema.Null, + ]), + ), + hostname: Schema.optionalKey(Schema.String), + }).annotate({ title: "postgres" }), + Schema.Struct({ + url: Schema.optionalKey(Schema.String), + http: Schema.optionalKey(Schema.Literals(["http1", "http2"])), + gzip: Schema.optionalKey(Schema.Boolean), + headers: Schema.optionalKey(Schema.Record(Schema.String, Schema.String)), + }).annotate({ title: "webhook" }), + Schema.Struct({ + project_id: Schema.optionalKey(Schema.String), + dataset_id: Schema.optionalKey(Schema.String), + }).annotate({ title: "bigquery" }), + Schema.Struct({ + api_key: Schema.optionalKey(Schema.String), + region: Schema.optionalKey(Schema.String), + }).annotate({ title: "datadog" }), + Schema.Struct({ + url: Schema.optionalKey(Schema.String), + username: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + password: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + headers: Schema.optionalKey(Schema.Record(Schema.String, Schema.String)), + }).annotate({ title: "loki" }), + Schema.Struct({ dsn: Schema.optionalKey(Schema.String) }).annotate({ title: "sentry" }), + Schema.Struct({ + domain: Schema.optionalKey(Schema.String), + api_token: Schema.optionalKey(Schema.String), + dataset_name: Schema.optionalKey(Schema.String), + }).annotate({ title: "axiom" }), + Schema.Struct({ + host: Schema.optionalKey(Schema.String), + port: Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(0).annotate({ + expected: "a value greater than or equal to 0", + }), + ) + .check( + Schema.isLessThanOrEqualTo(65535).annotate({ + expected: "a value less than or equal to 65535", + }), + ), + ), + tls: Schema.optionalKey(Schema.Boolean), + structured_data: Schema.optionalKey(Schema.String), + cipher_key: Schema.optionalKey(Schema.String), + ca_cert: Schema.optionalKey(Schema.String), + client_cert: Schema.optionalKey(Schema.String), + client_key: Schema.optionalKey(Schema.String), + }).annotate({ title: "syslog" }), + ]), + backend_type: Schema.Literals([ + "postgres", + "bigquery", + "clickhouse", + "webhook", + "datadog", + "loki", + "sentry", + "s3", + "axiom", + "last9", + "otlp", + "syslog", + ]), + }), + }), +}); +export const V2CreateLogDrainOutput = Schema.Struct({ + data: Schema.Struct({ + type: Schema.Literal("log_drain").annotate({ description: "Resource type." }), + id: Schema.String, + attributes: Schema.Struct({ + name: Schema.String, + description: Schema.optionalKey(Schema.String), + config: Schema.Union([ + Schema.Struct({ + url: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + schema: Schema.optionalKey(Schema.String), + username: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + password: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + port: Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ expected: "a finite number" })), + Schema.Null, + ]), + ), + hostname: Schema.optionalKey(Schema.String), + }).annotate({ title: "postgres" }), + Schema.Struct({ + url: Schema.optionalKey(Schema.String), + http: Schema.optionalKey(Schema.Literals(["http1", "http2"])), + gzip: Schema.optionalKey(Schema.Boolean), + headers: Schema.optionalKey(Schema.Record(Schema.String, Schema.String)), + }).annotate({ title: "webhook" }), + Schema.Struct({ + project_id: Schema.optionalKey(Schema.String), + dataset_id: Schema.optionalKey(Schema.String), + }).annotate({ title: "bigquery" }), + Schema.Struct({ + api_key: Schema.optionalKey(Schema.String), + region: Schema.optionalKey(Schema.String), + }).annotate({ title: "datadog" }), + Schema.Struct({ + url: Schema.optionalKey(Schema.String), + username: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + password: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + headers: Schema.optionalKey(Schema.Record(Schema.String, Schema.String)), + }).annotate({ title: "loki" }), + Schema.Struct({ dsn: Schema.optionalKey(Schema.String) }).annotate({ title: "sentry" }), + Schema.Struct({ + domain: Schema.optionalKey(Schema.String), + api_token: Schema.optionalKey(Schema.String), + dataset_name: Schema.optionalKey(Schema.String), + }).annotate({ title: "axiom" }), + Schema.Struct({ + host: Schema.optionalKey(Schema.String), + port: Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(0).annotate({ + expected: "a value greater than or equal to 0", + }), + ) + .check( + Schema.isLessThanOrEqualTo(65535).annotate({ + expected: "a value less than or equal to 65535", + }), + ), + ), + tls: Schema.optionalKey(Schema.Boolean), + structured_data: Schema.optionalKey(Schema.String), + cipher_key: Schema.optionalKey(Schema.String), + ca_cert: Schema.optionalKey(Schema.String), + client_cert: Schema.optionalKey(Schema.String), + client_key: Schema.optionalKey(Schema.String), + }).annotate({ title: "syslog" }), + ]), + backend_type: Schema.Literals([ + "postgres", + "bigquery", + "clickhouse", + "webhook", + "datadog", + "loki", + "sentry", + "s3", + "axiom", + "last9", + "otlp", + "syslog", + ]), + }), + }), +}); +export const V2CreateOrganizationInvitationsInput = Schema.Struct({ + slug: Schema.String.check( + Schema.isPattern(new RegExp("^[\\w-]+$")).annotate({ + expected: "a string matching the RegExp ^[\\w-]+$", + }), + ), + data: Schema.Array( + Schema.Struct({ + type: Schema.Literal("organization_invitation").annotate({ description: "Resource type." }), + attributes: Schema.Struct({ + email: Schema.String.annotate({ format: "email" }).check( + Schema.isPattern( + new RegExp( + "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", + ), + ).annotate({ + expected: + "a string matching the RegExp ^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", + }), + ), + role: Schema.Literals(["owner", "administrator", "developer", "read-only"]).annotate({ + description: + "Role name to assign. Must be on a Team or Enterprise plan to use the read-only role.", + }), + projects: Schema.optionalKey( + Schema.Array( + Schema.Struct({ ref: Schema.String.annotate({ description: "Project ref" }) }), + ) + .annotate({ + description: + "The projects to limit a user to. If omitted, user will have org-wide access with the provided role.", + }) + .check( + Schema.isMinLength(1).annotate({ expected: "a value with a length of at least 1" }), + ), + ), + require_sso: Schema.optionalKey(Schema.Boolean), + }), + }), + ) + .check(Schema.isMinLength(1).annotate({ expected: "a value with a length of at least 1" })) + .check(Schema.isMaxLength(50).annotate({ expected: "a value with a length of at most 50" })), +}); +export const V2CreateOrganizationInvitationsOutput = Schema.Struct({ + error: Schema.optionalKey( + Schema.Struct({ + id: Schema.optionalKey(Schema.String), + code: Schema.String, + message: Schema.String, + description: Schema.optionalKey(Schema.String), + links: Schema.optionalKey( + Schema.Record( + Schema.String, + Schema.Struct({ + href: Schema.String, + rel: Schema.optionalKey(Schema.String), + title: Schema.optionalKey(Schema.String), + type: Schema.optionalKey(Schema.String), + describedby: Schema.optionalKey(Schema.String), + meta: Schema.optionalKey( + Schema.Record(Schema.String, Schema.Json.annotate({ expected: "JSON value" })), + ), + }), + ), + ), + meta: Schema.optionalKey( + Schema.Record(Schema.String, Schema.Json.annotate({ expected: "JSON value" })), + ), + issues: Schema.optionalKey( + Schema.Array( + Schema.Struct({ + id: Schema.optionalKey(Schema.String), + code: Schema.String, + message: Schema.String, + description: Schema.optionalKey(Schema.String), + links: Schema.optionalKey( + Schema.Record( + Schema.String, + Schema.Struct({ + href: Schema.String, + rel: Schema.optionalKey(Schema.String), + title: Schema.optionalKey(Schema.String), + type: Schema.optionalKey(Schema.String), + describedby: Schema.optionalKey(Schema.String), + meta: Schema.optionalKey( + Schema.Record(Schema.String, Schema.Json.annotate({ expected: "JSON value" })), + ), + }), + ), + ), + meta: Schema.Struct({ + email: Schema.String.annotate({ format: "email" }).check( + Schema.isPattern( + new RegExp( + "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", + ), + ).annotate({ + expected: + "a string matching the RegExp ^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", + }), + ), + }), + }), + ), + ), + }), + ), + data: Schema.Array( + Schema.Struct({ + type: Schema.Literal("organization_invitation").annotate({ description: "Resource type." }), + attributes: Schema.Struct({ + email: Schema.String.annotate({ format: "email" }).check( + Schema.isPattern( + new RegExp( + "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", + ), + ).annotate({ + expected: + "a string matching the RegExp ^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", + }), + ), + }), + }), + ), +}); +export const V2CreatePrivateLinkAssociationInput = Schema.Struct({ + ref: Schema.String.check( + Schema.isMinLength(20).annotate({ expected: "a value with a length of at least 20" }), + ) + .check(Schema.isMaxLength(20).annotate({ expected: "a value with a length of at most 20" })) + .check( + Schema.isPattern(new RegExp("^[a-z]+$")).annotate({ + expected: "a string matching the RegExp ^[a-z]+$", + }), + ), + data: Schema.Struct({ + type: Schema.Literal("private_link_association").annotate({ description: "Resource type." }), + attributes: Schema.Struct({ + aws_account_id: Schema.String.annotate({ + description: "The AWS account ID to add to the project PrivateLink share.", + }) + .check( + Schema.isMinLength(12).annotate({ expected: "a value with a length of at least 12" }), + ) + .check(Schema.isMaxLength(12).annotate({ expected: "a value with a length of at most 12" })) + .check( + Schema.isPattern(new RegExp("^\\d{12}$")).annotate({ + expected: "a string matching the RegExp ^\\d{12}$", + }), + ), + account_name: Schema.optionalKey( + Schema.String.annotate({ + description: "Optional human-readable name for the AWS account.", + }).check( + Schema.isMaxLength(128).annotate({ expected: "a value with a length of at most 128" }), + ), + ), + database_identifier: Schema.optionalKey( + Schema.String.annotate({ + description: + "Identifier of the read replica this PrivateLink share should target. Omit to target the primary database.", + }), + ), + }), + }), +}); +export const V2CreatePrivateLinkAssociationOutput = Schema.Struct({ + data: Schema.Struct({ + type: Schema.Literal("private_link_association").annotate({ description: "Resource type." }), + id: Schema.String, + attributes: Schema.Struct({ + aws_account_id: Schema.String.annotate({ + description: "The AWS account ID this PrivateLink share is associated with.", + }) + .check( + Schema.isMinLength(12).annotate({ expected: "a value with a length of at least 12" }), + ) + .check(Schema.isMaxLength(12).annotate({ expected: "a value with a length of at most 12" })) + .check( + Schema.isPattern(new RegExp("^\\d{12}$")).annotate({ + expected: "a string matching the RegExp ^\\d{12}$", + }), + ), + account_name: Schema.optionalKey( + Schema.String.annotate({ description: "Human-readable name for the AWS account." }), + ), + status: Schema.Literals([ + "CREATING", + "READY", + "ASSOCIATION_REQUEST_EXPIRED", + "ASSOCIATION_ACCEPTED", + "CREATION_FAILED", + "DELETING", + ]).annotate({ + description: + "\n - `CREATING`: The PrivateLink resources and the Association are in the process of being created. The PrivateLink Share cannot be accepted yet.\n - `READY`: The PrivateLink resources have been created and the PrivateLink Share can be accepted for the duration of 12h after sharing. See `shared_at`.\n - `ASSOCIATION_REQUEST_EXPIRED`: The PrivateLink Share has not been accepted within the 12h time limit. This association can now be deleted.\n - `ASSOCIATION_ACCEPTED`: The PrivateLink Share was successfully accepted.\n - `CREATION_FAILED`: The PrivateLink resources failed to create. This likely means something went wrong on Supabase's and and support should be contacted.\n - `DELETING`: The PrivateLink resources and the Association are in the process of being deleted. The PrivateLink Share cannot be accepted yet.\n", + }), + shared_at: Schema.Union([ + Schema.String.annotate({ + description: + "The time and date at which the AWS Resource Share Association was requested from Supabase. `null` means that the association was not yet requested while the PrivateLink Association is pending.", + format: "date-time", + }), + Schema.Null, + ]), + database_type: Schema.Literals(["PRIMARY", "READ_REPLICA"]).annotate({ + description: + "Whether this PrivateLink share targets the primary database or a read replica.", + }), + database_identifier: Schema.String.annotate({ + description: + "Identifier of the database this PrivateLink share targets - the project ref for the primary, or the read replica identifier.", + }), + }), + }), +}); +export const V2DeleteLogDrainInput = Schema.Struct({ + ref: Schema.String.check( + Schema.isMinLength(20).annotate({ expected: "a value with a length of at least 20" }), + ) + .check(Schema.isMaxLength(20).annotate({ expected: "a value with a length of at most 20" })) + .check( + Schema.isPattern(new RegExp("^[a-z]+$")).annotate({ + expected: "a string matching the RegExp ^[a-z]+$", + }), + ), + id: Schema.String.annotate({ format: "uuid" }).check( + Schema.isPattern( + new RegExp( + "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", + ), + ).annotate({ + expected: + "a string matching the RegExp ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", + }), + ), +}); +export const V2DeleteOrganizationInvitationsInput = Schema.Struct({ + slug: Schema.String.check( + Schema.isPattern(new RegExp("^[\\w-]+$")).annotate({ + expected: "a string matching the RegExp ^[\\w-]+$", + }), + ), + data: Schema.Array( + Schema.Struct({ + type: Schema.Literal("organization_invitation").annotate({ description: "Resource type." }), + attributes: Schema.Struct({ + email: Schema.String.annotate({ format: "email" }).check( + Schema.isPattern( + new RegExp( + "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", + ), + ).annotate({ + expected: + "a string matching the RegExp ^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", + }), + ), + }), + }), + ) + .check(Schema.isMinLength(1).annotate({ expected: "a value with a length of at least 1" })) + .check(Schema.isMaxLength(100).annotate({ expected: "a value with a length of at most 100" })), +}); +export const V2DeleteOrganizationInvitationsOutput = Schema.Struct({ + data: Schema.Array( + Schema.Struct({ + type: Schema.Literal("organization_invitation").annotate({ description: "Resource type." }), + attributes: Schema.Struct({ + email: Schema.String.annotate({ format: "email" }).check( + Schema.isPattern( + new RegExp( + "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", + ), + ).annotate({ + expected: + "a string matching the RegExp ^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", + }), + ), + }), + }), + ), +}); +export const V2DeletePrivateLinkAssociationInput = Schema.Struct({ + ref: Schema.String.check( + Schema.isMinLength(20).annotate({ expected: "a value with a length of at least 20" }), + ) + .check(Schema.isMaxLength(20).annotate({ expected: "a value with a length of at most 20" })) + .check( + Schema.isPattern(new RegExp("^[a-z]+$")).annotate({ + expected: "a string matching the RegExp ^[a-z]+$", + }), + ), + aws_account_id: Schema.String, +}); +export const V2DeletePrivateLinkAssociationForDatabaseInput = Schema.Struct({ + ref: Schema.String.check( + Schema.isMinLength(20).annotate({ expected: "a value with a length of at least 20" }), + ) + .check(Schema.isMaxLength(20).annotate({ expected: "a value with a length of at most 20" })) + .check( + Schema.isPattern(new RegExp("^[a-z]+$")).annotate({ + expected: "a string matching the RegExp ^[a-z]+$", + }), + ), + aws_account_id: Schema.String, + database_identifier: Schema.String, +}); +export const V2GetProjectConfigInput = Schema.Struct({ + ref: Schema.String.check( + Schema.isMinLength(20).annotate({ expected: "a value with a length of at least 20" }), + ) + .check(Schema.isMaxLength(20).annotate({ expected: "a value with a length of at most 20" })) + .check( + Schema.isPattern(new RegExp("^[a-z]+$")).annotate({ + expected: "a string matching the RegExp ^[a-z]+$", + }), + ), +}); +export const V2GetProjectConfigOutput = Schema.Struct({ + data: Schema.Struct({ + type: Schema.Literal("project_config").annotate({ description: "Resource type." }), + id: Schema.String.annotate({ description: "Project ref." }), + attributes: Schema.Struct({ + database: Schema.Struct({ + ssl_enforced: Schema.Boolean.annotate({ + description: "Whether the database rejects plaintext connections", + }), + network_restrictions: Schema.Struct({ + entitlement: Schema.Literals(["disallowed", "allowed"]), + status: Schema.Literals(["stored", "applied"]).annotate({ + description: "Whether the allowlist below is applied to the project or only stored.", + }), + allowed_cidrs: Schema.Array( + Schema.Struct({ address: Schema.String, type: Schema.Literals(["v4", "v6"]) }), + ), + updated_at: Schema.optionalKey(Schema.String), + applied_at: Schema.optionalKey(Schema.String), + }), + postgres_settings: Schema.Struct({ + effective_cache_size: Schema.optionalKey(Schema.String), + logical_decoding_work_mem: Schema.optionalKey(Schema.String), + log_autovacuum_min_duration: Schema.optionalKey( + Schema.String.annotate({ description: "Default unit: ms" }).check( + Schema.isPattern(new RegExp("^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$")).annotate( + { + expected: + "a string matching the RegExp ^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$", + }, + ), + ), + ), + log_checkpoints: Schema.optionalKey(Schema.Boolean), + log_connections: Schema.optionalKey(Schema.Boolean), + log_disconnections: Schema.optionalKey(Schema.Boolean), + log_duration: Schema.optionalKey(Schema.Boolean), + log_lock_waits: Schema.optionalKey(Schema.Boolean), + log_recovery_conflict_waits: Schema.optionalKey(Schema.Boolean), + log_replication_commands: Schema.optionalKey(Schema.Boolean), + log_startup_progress_interval: Schema.optionalKey( + Schema.String.annotate({ description: "Default unit: ms" }).check( + Schema.isPattern(new RegExp("^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$")).annotate( + { + expected: + "a string matching the RegExp ^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$", + }, + ), + ), + ), + log_temp_files: Schema.optionalKey(Schema.String), + maintenance_work_mem: Schema.optionalKey(Schema.String), + track_activity_query_size: Schema.optionalKey(Schema.String), + max_connections: Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(1).annotate({ + expected: "a value greater than or equal to 1", + }), + ) + .check( + Schema.isLessThanOrEqualTo(262143).annotate({ + expected: "a value less than or equal to 262143", + }), + ), + ), + max_locks_per_transaction: Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(10).annotate({ + expected: "a value greater than or equal to 10", + }), + ) + .check( + Schema.isLessThanOrEqualTo(2147483640).annotate({ + expected: "a value less than or equal to 2147483640", + }), + ), + ), + max_logical_replication_workers: Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(0).annotate({ + expected: "a value greater than or equal to 0", + }), + ) + .check( + Schema.isLessThanOrEqualTo(262143).annotate({ + expected: "a value less than or equal to 262143", + }), + ), + ), + max_parallel_maintenance_workers: Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(0).annotate({ + expected: "a value greater than or equal to 0", + }), + ) + .check( + Schema.isLessThanOrEqualTo(1024).annotate({ + expected: "a value less than or equal to 1024", + }), + ), + ), + max_parallel_workers: Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(0).annotate({ + expected: "a value greater than or equal to 0", + }), + ) + .check( + Schema.isLessThanOrEqualTo(1024).annotate({ + expected: "a value less than or equal to 1024", + }), + ), + ), + max_parallel_workers_per_gather: Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(0).annotate({ + expected: "a value greater than or equal to 0", + }), + ) + .check( + Schema.isLessThanOrEqualTo(1024).annotate({ + expected: "a value less than or equal to 1024", + }), + ), + ), + max_replication_slots: Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + ), + max_slot_wal_keep_size: Schema.optionalKey(Schema.String), + max_standby_archive_delay: Schema.optionalKey(Schema.String), + max_standby_streaming_delay: Schema.optionalKey(Schema.String), + max_sync_workers_per_subscription: Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(0).annotate({ + expected: "a value greater than or equal to 0", + }), + ) + .check( + Schema.isLessThanOrEqualTo(262143).annotate({ + expected: "a value less than or equal to 262143", + }), + ), + ), + max_wal_size: Schema.optionalKey(Schema.String), + max_wal_senders: Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + ), + max_worker_processes: Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(0).annotate({ + expected: "a value greater than or equal to 0", + }), + ) + .check( + Schema.isLessThanOrEqualTo(262143).annotate({ + expected: "a value less than or equal to 262143", + }), + ), + ), + session_replication_role: Schema.optionalKey( + Schema.Literals(["origin", "replica", "local"]), + ), + shared_buffers: Schema.optionalKey(Schema.String), + statement_timeout: Schema.optionalKey( + Schema.String.annotate({ description: "Default unit: ms" }).check( + Schema.isPattern(new RegExp("^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$")).annotate( + { + expected: + "a string matching the RegExp ^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$", + }, + ), + ), + ), + track_commit_timestamp: Schema.optionalKey(Schema.Boolean), + wal_keep_size: Schema.optionalKey(Schema.String), + wal_sender_timeout: Schema.optionalKey( + Schema.String.annotate({ description: "Default unit: ms" }).check( + Schema.isPattern(new RegExp("^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$")).annotate( + { + expected: + "a string matching the RegExp ^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$", + }, + ), + ), + ), + work_mem: Schema.optionalKey(Schema.String), + checkpoint_timeout: Schema.optionalKey( + Schema.String.annotate({ description: "Default unit: s" }).check( + Schema.isPattern(new RegExp("^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$")).annotate( + { + expected: + "a string matching the RegExp ^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$", + }, + ), + ), + ), + hot_standby_feedback: Schema.optionalKey(Schema.Boolean), + cron_log_statement: Schema.optionalKey(Schema.Boolean), + }).annotate({ + description: + "Postgres parameter overrides. Empty when the project runs entirely on defaults.", + }), + }), + pooler: Schema.Struct({ + pool_mode: Schema.Literals(["transaction", "session", "statement"]), + ignore_startup_parameters: Schema.String, + server_idle_timeout: Schema.Number.check( + Schema.isInt().annotate({ expected: "an integer" }), + ) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + server_lifetime: Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + query_wait_timeout: Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + reserve_pool_size: Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + default_pool_size: Schema.Number.annotate({ + description: + "Defaults to the pooler's size for the project's compute when not overridden.", + }) + .check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + max_client_conn: Schema.Number.annotate({ + description: + "Defaults to the pooler's size for the project's compute when not overridden.", + }) + .check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + }), + auth: Schema.Record(Schema.String, Schema.Json.annotate({ expected: "JSON value" })).annotate( + { + description: + "Effective Auth config, keyed by lowercased GoTrue setting name and resolved through the `gotrue_config` view, so a setting the project has never overridden is reported at its platform default. Secrets are returned as an HMAC of their value, never in plaintext.", + }, + ), + api: Schema.Struct({ + db_schema: Schema.String.annotate({ description: "Schemas exposed through the Data API" }), + db_extra_search_path: Schema.String, + max_rows: Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + db_pool_acquisition_timeout: Schema.Number.check( + Schema.isInt().annotate({ expected: "an integer" }), + ) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + db_pool: Schema.Union([ + Schema.Number.annotate({ + description: + "If `null`, no pool size is written to the project's PostgREST config and PostgREST's own default applies. The platform does not pick a value here.", + }) + .check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + Schema.Null, + ]), + }), + realtime: Schema.Struct({ + private_only: Schema.Boolean, + max_concurrent_users: Schema.Number.check( + Schema.isInt().annotate({ expected: "an integer" }), + ) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + max_events_per_second: Schema.Number.check( + Schema.isInt().annotate({ expected: "an integer" }), + ) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + max_bytes_per_second: Schema.Number.check( + Schema.isInt().annotate({ expected: "an integer" }), + ) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + max_channels_per_client: Schema.Number.check( + Schema.isInt().annotate({ expected: "an integer" }), + ) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + max_joins_per_second: Schema.Number.check( + Schema.isInt().annotate({ expected: "an integer" }), + ) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + max_presence_events_per_second: Schema.Number.check( + Schema.isInt().annotate({ expected: "an integer" }), + ) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + max_payload_size_in_kb: Schema.Number.check( + Schema.isInt().annotate({ expected: "an integer" }), + ) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + presence_enabled: Schema.Boolean, + suspend: Schema.Boolean, + connection_pool: Schema.Number.annotate({ + description: + "Defaults to Realtime's pool size for the project's compute when not overridden.", + }) + .check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + postgres_changes_pool: Schema.Union([ + Schema.Number.annotate({ + description: "If `null`, no override is stored and Realtime applies its own default.", + }) + .check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + Schema.Null, + ]), + }), + storage: Schema.Struct({ + file_size_limit: Schema.Number.annotate({ format: "int64" }) + .check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + features: Schema.Struct({ + image_transformation: Schema.Struct({ enabled: Schema.Boolean }), + s3_protocol: Schema.Struct({ enabled: Schema.Boolean }), + purge_cache: Schema.Struct({ enabled: Schema.Boolean }), + iceberg_catalog: Schema.Struct({ + enabled: Schema.Boolean, + max_namespaces: Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + max_tables: Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + max_catalogs: Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + }), + vector_buckets: Schema.Struct({ + enabled: Schema.Boolean, + max_buckets: Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + max_indexes: Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(-9007199254740991).annotate({ + expected: "a value greater than or equal to -9007199254740991", + }), + ) + .check( + Schema.isLessThanOrEqualTo(9007199254740991).annotate({ + expected: "a value less than or equal to 9007199254740991", + }), + ), + }), + }), + capabilities: Schema.Struct({ list_v2: Schema.Boolean, iceberg_catalog: Schema.Boolean }), + upstream_target: Schema.Literals(["main", "canary"]), + migration_version: Schema.String, + database_pool_mode: Schema.String, + }).annotate({ + description: + "Read from the storage service's admin API rather than the middleware DB, so unlike the rest of this resource it reflects the tenant's live config.", + }), + }), + }), +}); +export const V2ListLogDrainsInput = Schema.Struct({ + ref: Schema.String.check( + Schema.isMinLength(20).annotate({ expected: "a value with a length of at least 20" }), + ) + .check(Schema.isMaxLength(20).annotate({ expected: "a value with a length of at most 20" })) + .check( + Schema.isPattern(new RegExp("^[a-z]+$")).annotate({ + expected: "a string matching the RegExp ^[a-z]+$", + }), + ), +}); +export const V2ListLogDrainsOutput = Schema.Struct({ + data: Schema.Array( + Schema.Struct({ + type: Schema.Literal("log_drain").annotate({ description: "Resource type." }), + id: Schema.String, + attributes: Schema.Struct({ + name: Schema.String, + description: Schema.optionalKey(Schema.String), + config: Schema.Union([ + Schema.Struct({ + url: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + schema: Schema.optionalKey(Schema.String), + username: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + password: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + port: Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ expected: "a finite number" })), + Schema.Null, + ]), + ), + hostname: Schema.optionalKey(Schema.String), + }).annotate({ title: "postgres" }), + Schema.Struct({ + url: Schema.optionalKey(Schema.String), + http: Schema.optionalKey(Schema.Literals(["http1", "http2"])), + gzip: Schema.optionalKey(Schema.Boolean), + headers: Schema.optionalKey(Schema.Record(Schema.String, Schema.String)), + }).annotate({ title: "webhook" }), + Schema.Struct({ + project_id: Schema.optionalKey(Schema.String), + dataset_id: Schema.optionalKey(Schema.String), + }).annotate({ title: "bigquery" }), + Schema.Struct({ + api_key: Schema.optionalKey(Schema.String), + region: Schema.optionalKey(Schema.String), + }).annotate({ title: "datadog" }), + Schema.Struct({ + url: Schema.optionalKey(Schema.String), + username: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + password: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + headers: Schema.optionalKey(Schema.Record(Schema.String, Schema.String)), + }).annotate({ title: "loki" }), + Schema.Struct({ dsn: Schema.optionalKey(Schema.String) }).annotate({ title: "sentry" }), + Schema.Struct({ + domain: Schema.optionalKey(Schema.String), + api_token: Schema.optionalKey(Schema.String), + dataset_name: Schema.optionalKey(Schema.String), + }).annotate({ title: "axiom" }), + Schema.Struct({ + host: Schema.optionalKey(Schema.String), + port: Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(0).annotate({ + expected: "a value greater than or equal to 0", + }), + ) + .check( + Schema.isLessThanOrEqualTo(65535).annotate({ + expected: "a value less than or equal to 65535", + }), + ), + ), + tls: Schema.optionalKey(Schema.Boolean), + structured_data: Schema.optionalKey(Schema.String), + cipher_key: Schema.optionalKey(Schema.String), + ca_cert: Schema.optionalKey(Schema.String), + client_cert: Schema.optionalKey(Schema.String), + client_key: Schema.optionalKey(Schema.String), + }).annotate({ title: "syslog" }), + ]), + backend_type: Schema.Literals([ + "postgres", + "bigquery", + "clickhouse", + "webhook", + "datadog", + "loki", + "sentry", + "s3", + "axiom", + "last9", + "otlp", + "syslog", + ]), + }), + }), + ), +}); +export const V2ListOrganizationGithubConnectionsInput = Schema.Struct({ + slug: Schema.String.check( + Schema.isPattern(new RegExp("^[\\w-]+$")).annotate({ + expected: "a string matching the RegExp ^[\\w-]+$", + }), + ), + page: Schema.optionalKey( + Schema.Struct({ + size: Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(1).annotate({ + expected: "a value greater than or equal to 1", + }), + ) + .check( + Schema.isLessThanOrEqualTo(100).annotate({ + expected: "a value less than or equal to 100", + }), + ), + ), + after: Schema.optionalKey( + Schema.String.annotate({ description: "Project ref" }) + .check( + Schema.isMinLength(20).annotate({ expected: "a value with a length of at least 20" }), + ) + .check( + Schema.isMaxLength(20).annotate({ expected: "a value with a length of at most 20" }), + ) + .check( + Schema.isPattern(new RegExp("^[a-z]+$")).annotate({ + expected: "a string matching the RegExp ^[a-z]+$", + }), + ), + ), + before: Schema.optionalKey( + Schema.String.annotate({ description: "Project ref" }) + .check( + Schema.isMinLength(20).annotate({ expected: "a value with a length of at least 20" }), + ) + .check( + Schema.isMaxLength(20).annotate({ expected: "a value with a length of at most 20" }), + ) + .check( + Schema.isPattern(new RegExp("^[a-z]+$")).annotate({ + expected: "a string matching the RegExp ^[a-z]+$", + }), + ), + ), + }), + ), + filter: Schema.optionalKey( + Schema.Struct({ + project_ref: Schema.optionalKey( + Schema.String.annotate({ description: "Project ref" }) + .check( + Schema.isMinLength(20).annotate({ expected: "a value with a length of at least 20" }), + ) + .check( + Schema.isMaxLength(20).annotate({ expected: "a value with a length of at most 20" }), + ) + .check( + Schema.isPattern(new RegExp("^[a-z]+$")).annotate({ + expected: "a string matching the RegExp ^[a-z]+$", + }), + ), + ), + }), + ), +}); +export const V2ListOrganizationGithubConnectionsOutput = Schema.Struct({ + data: Schema.Array( + Schema.Struct({ + type: Schema.Literal("github_connection").annotate({ description: "Resource type." }), + id: Schema.String.annotate({ description: "Connection id." }), + attributes: Schema.Struct({ + inserted_at: Schema.String.annotate({ description: "When the connection was created" }), + updated_at: Schema.String.annotate({ description: "When the connection was last updated" }), + installation_id: Schema.Number.annotate({ + description: "GitHub App installation id", + }).check(Schema.isFinite().annotate({ expected: "a finite number" })), + workdir: Schema.String.annotate({ + description: "Directory within the repository the project lives in", + }), + supabase_changes_only: Schema.Boolean.annotate({ + description: "Whether branches are only created for changes under `supabase/`", + }), + branch_limit: Schema.Number.annotate({ + description: "Maximum number of preview branches", + }).check(Schema.isFinite().annotate({ expected: "a finite number" })), + new_branch_per_pr: Schema.Boolean.annotate({ + description: "Whether a preview branch is created for every pull request", + }), + project: Schema.Struct({ + id: Schema.Number.check(Schema.isFinite().annotate({ expected: "a finite number" })), + ref: Schema.String.annotate({ description: "Project ref" }) + .check( + Schema.isMinLength(20).annotate({ expected: "a value with a length of at least 20" }), + ) + .check( + Schema.isMaxLength(20).annotate({ expected: "a value with a length of at most 20" }), + ) + .check( + Schema.isPattern(new RegExp("^[a-z]+$")).annotate({ + expected: "a string matching the RegExp ^[a-z]+$", + }), + ), + name: Schema.String, + }).annotate({ description: "The connected Supabase project" }), + repository: Schema.Struct({ + id: Schema.Number.check(Schema.isFinite().annotate({ expected: "a finite number" })), + name: Schema.String, + }).annotate({ description: "The connected GitHub repository" }), + user: Schema.Union([ + Schema.Struct({ + id: Schema.Number.check(Schema.isFinite().annotate({ expected: "a finite number" })), + username: Schema.String, + primary_email: Schema.Union([Schema.String, Schema.Null]), + }).annotate({ description: "The user who created the connection, if still known" }), + Schema.Null, + ]), + }), + }), + ), + links: Schema.Struct({ + first: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ description: "URL path to the first page if available." }), + Schema.Null, + ]), + ), + prev: Schema.Union([ + Schema.String.annotate({ description: "URL path to the previous page." }), + Schema.Null, + ]), + next: Schema.Union([ + Schema.String.annotate({ description: "URL path to the next page." }), + Schema.Null, + ]), + last: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ description: "URL path to the last page if available." }), + Schema.Null, + ]), + ), + }), +}); +export const V2ListOrganizationMembersInput = Schema.Struct({ + slug: Schema.String.check( + Schema.isPattern(new RegExp("^[\\w-]+$")).annotate({ + expected: "a string matching the RegExp ^[\\w-]+$", + }), + ), + page: Schema.optionalKey( + Schema.Struct({ + size: Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(1).annotate({ + expected: "a value greater than or equal to 1", + }), + ) + .check( + Schema.isLessThanOrEqualTo(100).annotate({ + expected: "a value less than or equal to 100", + }), + ), + ), + after: Schema.optionalKey( + Schema.String.annotate({ format: "uuid" }).check( + Schema.isPattern( + new RegExp( + "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", + ), + ).annotate({ + expected: + "a string matching the RegExp ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", + }), + ), + ), + before: Schema.optionalKey( + Schema.String.annotate({ format: "uuid" }).check( + Schema.isPattern( + new RegExp( + "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", + ), + ).annotate({ + expected: + "a string matching the RegExp ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", + }), + ), + ), + }), + ), + filter: Schema.optionalKey( + Schema.Struct({ + username: Schema.optionalKey(Schema.String), + primary_email: Schema.optionalKey( + Schema.String.annotate({ format: "email" }).check( + Schema.isPattern( + new RegExp( + "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", + ), + ).annotate({ + expected: + "a string matching the RegExp ^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", + }), + ), + ), + }), + ), +}); +export const V2ListOrganizationMembersOutput = Schema.Struct({ + data: Schema.Array( + Schema.Struct({ + type: Schema.Literal("organization_member").annotate({ description: "Resource type." }), + id: Schema.String.annotate({ format: "uuid" }).check( + Schema.isPattern( + new RegExp( + "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$", + ), + ).annotate({ + expected: + "a string matching the RegExp ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$", + }), + ), + attributes: Schema.Struct({ + username: Schema.Union([ + Schema.String.annotate({ description: "Member's username" }), + Schema.Null, + ]), + primary_email: Schema.Union([ + Schema.String.annotate({ description: "Member's primary email" }), + Schema.Null, + ]), + mfa_enabled: Schema.Boolean.annotate({ + description: "Whether Multi-Factor Authentication is enabled for this member", + }), + is_sso_user: Schema.Boolean.annotate({ + description: "Whether this member is a Single Sign-On user", + }), + avatar_url: Schema.Union([ + Schema.String.annotate({ description: "Member's avatar URL" }), + Schema.Null, + ]), + roles: Schema.Array( + Schema.Struct({ + name: Schema.String.annotate({ + description: "Role name. For project-scoped roles this is the base role name.", + }), + scope: Schema.Literals(["organization", "project"]).annotate({ + description: + "Whether this role applies org-wide or is scoped to specific projects for the user.", + }), + projects: Schema.Array( + Schema.Struct({ ref: Schema.String, name: Schema.String }), + ).annotate({ + description: "Project refs this role is scoped to. Empty array for org-level roles.", + }), + }), + ).annotate({ + description: + "Roles assigned to this member. Includes both org-level and project-scoped roles.", + }), + }), + }), + ), + links: Schema.Struct({ + first: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ description: "URL path to the first page if available." }), + Schema.Null, + ]), + ), + prev: Schema.Union([ + Schema.String.annotate({ description: "URL path to the previous page." }), + Schema.Null, + ]), + next: Schema.Union([ + Schema.String.annotate({ description: "URL path to the next page." }), + Schema.Null, + ]), + last: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ description: "URL path to the last page if available." }), + Schema.Null, + ]), + ), + }), +}); +export const V2ListOrganizationProjectsInput = Schema.Struct({ + slug: Schema.String.check( + Schema.isPattern(new RegExp("^[\\w-]+$")).annotate({ + expected: "a string matching the RegExp ^[\\w-]+$", + }), + ), + page: Schema.optionalKey( + Schema.Struct({ + size: Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(1).annotate({ + expected: "a value greater than or equal to 1", + }), + ) + .check( + Schema.isLessThanOrEqualTo(100).annotate({ + expected: "a value less than or equal to 100", + }), + ), + ), + after: Schema.optionalKey( + Schema.String.check( + Schema.isMinLength(1).annotate({ expected: "a value with a length of at least 1" }), + ), + ), + before: Schema.optionalKey( + Schema.String.check( + Schema.isMinLength(1).annotate({ expected: "a value with a length of at least 1" }), + ), + ), + }), + ), + sort: Schema.optionalKey(Schema.Literals(["inserted_at", "-inserted_at"])), + search: Schema.optionalKey( + Schema.String.check( + Schema.isMinLength(1).annotate({ expected: "a value with a length of at least 1" }), + ), + ), +}); +export const V2ListOrganizationProjectsOutput = Schema.Struct({ + data: Schema.Array( + Schema.Struct({ + type: Schema.Literal("project").annotate({ description: "Resource type." }), + id: Schema.String.annotate({ description: "Project ref" }) + .check( + Schema.isMinLength(20).annotate({ expected: "a value with a length of at least 20" }), + ) + .check(Schema.isMaxLength(20).annotate({ expected: "a value with a length of at most 20" })) + .check( + Schema.isPattern(new RegExp("^[a-z]+$")).annotate({ + expected: "a string matching the RegExp ^[a-z]+$", + }), + ), + attributes: Schema.Struct({ + name: Schema.String.annotate({ description: "Project name" }), + status: Schema.Literals([ + "INACTIVE", + "ACTIVE_HEALTHY", + "ACTIVE_UNHEALTHY", + "COMING_UP", + "UNKNOWN", + "GOING_DOWN", + "INIT_FAILED", + "REMOVED", + "RESTORING", + "UPGRADING", + "PAUSING", + "RESTORE_FAILED", + "RESTARTING", + "PAUSE_FAILED", + "RESIZING", + ]).annotate({ description: "Project status" }), + cloud_provider: Schema.String.annotate({ + description: "Cloud provider hosting the project", + }), + region: Schema.String.annotate({ description: "Region the project is hosted in" }), + inserted_at: Schema.String.annotate({ description: "When the project was created" }), + databases: Schema.Array( + Schema.Struct({ + cloud_provider: Schema.String, + identifier: Schema.String, + region: Schema.Union([Schema.String, Schema.Null]), + status: Schema.Literals([ + "ACTIVE_HEALTHY", + "ACTIVE_UNHEALTHY", + "COMING_UP", + "GOING_DOWN", + "INIT_FAILED", + "REMOVED", + "RESTORING", + "UNKNOWN", + "INIT_READ_REPLICA", + "INIT_READ_REPLICA_FAILED", + "RESTARTING", + "RESIZING", + ]), + type: Schema.Literals(["PRIMARY", "READ_REPLICA"]), + infra_compute_size: Schema.optionalKey( + Schema.Literals([ + "pico", + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge", + "4xlarge", + "8xlarge", + "12xlarge", + "16xlarge", + "24xlarge", + "24xlarge_optimized_memory", + "24xlarge_optimized_cpu", + "24xlarge_high_memory", + "48xlarge", + "48xlarge_optimized_memory", + "48xlarge_optimized_cpu", + "48xlarge_high_memory", + ]), + ), + disk_volume_size_gb: Schema.optionalKey( + Schema.Number.check(Schema.isFinite().annotate({ expected: "a finite number" })), + ), + disk_type: Schema.optionalKey(Schema.Literals(["gp3", "io2"])), + disk_throughput_mbps: Schema.optionalKey( + Schema.Number.check(Schema.isFinite().annotate({ expected: "a finite number" })), + ), + disk_last_modified_at: Schema.optionalKey(Schema.String), + }), + ).annotate({ + description: "The project's databases including compute and disk attributes.", + }), + }), + }), + ), + links: Schema.Struct({ + first: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ description: "URL path to the first page if available." }), + Schema.Null, + ]), + ), + prev: Schema.Union([ + Schema.String.annotate({ description: "URL path to the previous page." }), + Schema.Null, + ]), + next: Schema.Union([ + Schema.String.annotate({ description: "URL path to the next page." }), + Schema.Null, + ]), + last: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ description: "URL path to the last page if available." }), + Schema.Null, + ]), + ), + }), +}); +export const V2ListOrganizationRolesInput = Schema.Struct({ + slug: Schema.String.check( + Schema.isPattern(new RegExp("^[\\w-]+$")).annotate({ + expected: "a string matching the RegExp ^[\\w-]+$", + }), + ), +}); +export const V2ListOrganizationRolesOutput = Schema.Struct({ + data: Schema.Array( + Schema.Struct({ + type: Schema.Literal("organization_role").annotate({ description: "Resource type." }), + attributes: Schema.Struct({ name: Schema.String.annotate({ description: "Role name." }) }), + }), + ), +}); +export const V2ListPrivateLinkAssociationsInput = Schema.Struct({ + ref: Schema.String.check( + Schema.isMinLength(20).annotate({ expected: "a value with a length of at least 20" }), + ) + .check(Schema.isMaxLength(20).annotate({ expected: "a value with a length of at most 20" })) + .check( + Schema.isPattern(new RegExp("^[a-z]+$")).annotate({ + expected: "a string matching the RegExp ^[a-z]+$", + }), + ), +}); +export const V2ListPrivateLinkAssociationsOutput = Schema.Struct({ + data: Schema.Array( + Schema.Struct({ + type: Schema.Literal("private_link_association").annotate({ description: "Resource type." }), + id: Schema.String, + attributes: Schema.Struct({ + aws_account_id: Schema.String.annotate({ + description: "The AWS account ID this PrivateLink share is associated with.", + }) + .check( + Schema.isMinLength(12).annotate({ expected: "a value with a length of at least 12" }), + ) + .check( + Schema.isMaxLength(12).annotate({ expected: "a value with a length of at most 12" }), + ) + .check( + Schema.isPattern(new RegExp("^\\d{12}$")).annotate({ + expected: "a string matching the RegExp ^\\d{12}$", + }), + ), + account_name: Schema.optionalKey( + Schema.String.annotate({ description: "Human-readable name for the AWS account." }), + ), + status: Schema.Literals([ + "CREATING", + "READY", + "ASSOCIATION_REQUEST_EXPIRED", + "ASSOCIATION_ACCEPTED", + "CREATION_FAILED", + "DELETING", + ]).annotate({ + description: + "\n - `CREATING`: The PrivateLink resources and the Association are in the process of being created. The PrivateLink Share cannot be accepted yet.\n - `READY`: The PrivateLink resources have been created and the PrivateLink Share can be accepted for the duration of 12h after sharing. See `shared_at`.\n - `ASSOCIATION_REQUEST_EXPIRED`: The PrivateLink Share has not been accepted within the 12h time limit. This association can now be deleted.\n - `ASSOCIATION_ACCEPTED`: The PrivateLink Share was successfully accepted.\n - `CREATION_FAILED`: The PrivateLink resources failed to create. This likely means something went wrong on Supabase's and and support should be contacted.\n - `DELETING`: The PrivateLink resources and the Association are in the process of being deleted. The PrivateLink Share cannot be accepted yet.\n", + }), + shared_at: Schema.Union([ + Schema.String.annotate({ + description: + "The time and date at which the AWS Resource Share Association was requested from Supabase. `null` means that the association was not yet requested while the PrivateLink Association is pending.", + format: "date-time", + }), + Schema.Null, + ]), + database_type: Schema.Literals(["PRIMARY", "READ_REPLICA"]).annotate({ + description: + "Whether this PrivateLink share targets the primary database or a read replica.", + }), + database_identifier: Schema.String.annotate({ + description: + "Identifier of the database this PrivateLink share targets - the project ref for the primary, or the read replica identifier.", + }), + }), + }), + ), +}); +export const V2PreviewAProjectTransferInput = Schema.Struct({ + ref: Schema.String.check( + Schema.isMinLength(20).annotate({ expected: "a value with a length of at least 20" }), + ) + .check(Schema.isMaxLength(20).annotate({ expected: "a value with a length of at most 20" })) + .check( + Schema.isPattern(new RegExp("^[a-z]+$")).annotate({ + expected: "a string matching the RegExp ^[a-z]+$", + }), + ), + data: Schema.Struct({ + type: Schema.Literal("project_transfer_input").annotate({ description: "Resource type." }), + attributes: Schema.Struct({ target_organization_slug: Schema.String }), + }), +}); +export const V2PreviewAProjectTransferOutput = Schema.Struct({ + data: Schema.Struct({ + type: Schema.Literal("project_transfer_result").annotate({ description: "Resource type." }), + attributes: Schema.Struct({ + valid: Schema.Boolean, + warnings: Schema.Array(Schema.Struct({ key: Schema.String, message: Schema.String })), + errors: Schema.Array(Schema.Struct({ key: Schema.String, message: Schema.String })), + info: Schema.Array(Schema.Struct({ key: Schema.String, message: Schema.String })), + }), + }), +}); +export const V2TransferAProjectInput = Schema.Struct({ + ref: Schema.String.check( + Schema.isMinLength(20).annotate({ expected: "a value with a length of at least 20" }), + ) + .check(Schema.isMaxLength(20).annotate({ expected: "a value with a length of at most 20" })) + .check( + Schema.isPattern(new RegExp("^[a-z]+$")).annotate({ + expected: "a string matching the RegExp ^[a-z]+$", + }), + ), + data: Schema.Struct({ + type: Schema.Literal("project_transfer_input").annotate({ description: "Resource type." }), + attributes: Schema.Struct({ target_organization_slug: Schema.String }), + }), +}); +export const V2UpdateLogDrainInput = Schema.Struct({ + ref: Schema.String.check( + Schema.isMinLength(20).annotate({ expected: "a value with a length of at least 20" }), + ) + .check(Schema.isMaxLength(20).annotate({ expected: "a value with a length of at most 20" })) + .check( + Schema.isPattern(new RegExp("^[a-z]+$")).annotate({ + expected: "a string matching the RegExp ^[a-z]+$", + }), + ), + id: Schema.String.annotate({ format: "uuid" }).check( + Schema.isPattern( + new RegExp( + "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", + ), + ).annotate({ + expected: + "a string matching the RegExp ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", + }), + ), + data: Schema.Struct({ + type: Schema.Literal("log_drain").annotate({ description: "Resource type." }), + attributes: Schema.Struct({ + name: Schema.optionalKey(Schema.String), + description: Schema.optionalKey(Schema.String), + config: Schema.optionalKey( + Schema.Union([ + Schema.Struct({ + url: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + schema: Schema.optionalKey(Schema.String), + username: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + password: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + port: Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ expected: "a finite number" })), + Schema.Null, + ]), + ), + hostname: Schema.optionalKey(Schema.String), + }).annotate({ title: "postgres" }), + Schema.Struct({ + url: Schema.optionalKey(Schema.String), + http: Schema.optionalKey(Schema.Literals(["http1", "http2"])), + gzip: Schema.optionalKey(Schema.Boolean), + headers: Schema.optionalKey(Schema.Record(Schema.String, Schema.String)), + }).annotate({ title: "webhook" }), + Schema.Struct({ + project_id: Schema.optionalKey(Schema.String), + dataset_id: Schema.optionalKey(Schema.String), + }).annotate({ title: "bigquery" }), + Schema.Struct({ + api_key: Schema.optionalKey(Schema.String), + region: Schema.optionalKey(Schema.String), + }).annotate({ title: "datadog" }), + Schema.Struct({ + url: Schema.optionalKey(Schema.String), + username: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + password: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + headers: Schema.optionalKey(Schema.Record(Schema.String, Schema.String)), + }).annotate({ title: "loki" }), + Schema.Struct({ dsn: Schema.optionalKey(Schema.String) }).annotate({ title: "sentry" }), + Schema.Struct({ + domain: Schema.optionalKey(Schema.String), + api_token: Schema.optionalKey(Schema.String), + dataset_name: Schema.optionalKey(Schema.String), + }).annotate({ title: "axiom" }), + Schema.Struct({ + host: Schema.optionalKey(Schema.String), + port: Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(0).annotate({ + expected: "a value greater than or equal to 0", + }), + ) + .check( + Schema.isLessThanOrEqualTo(65535).annotate({ + expected: "a value less than or equal to 65535", + }), + ), + ), + tls: Schema.optionalKey(Schema.Boolean), + structured_data: Schema.optionalKey(Schema.String), + cipher_key: Schema.optionalKey(Schema.String), + ca_cert: Schema.optionalKey(Schema.String), + client_cert: Schema.optionalKey(Schema.String), + client_key: Schema.optionalKey(Schema.String), + }).annotate({ title: "syslog" }), + ]), + ), + backend_type: Schema.Literals([ + "postgres", + "bigquery", + "clickhouse", + "webhook", + "datadog", + "loki", + "sentry", + "s3", + "axiom", + "last9", + "otlp", + "syslog", + ]), + }), + }), +}); +export const V2UpdateLogDrainOutput = Schema.Struct({ + data: Schema.Struct({ + type: Schema.Literal("log_drain").annotate({ description: "Resource type." }), + id: Schema.String, + attributes: Schema.Struct({ + name: Schema.String, + description: Schema.optionalKey(Schema.String), + config: Schema.Union([ + Schema.Struct({ + url: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + schema: Schema.optionalKey(Schema.String), + username: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + password: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + port: Schema.optionalKey( + Schema.Union([ + Schema.Number.check(Schema.isFinite().annotate({ expected: "a finite number" })), + Schema.Null, + ]), + ), + hostname: Schema.optionalKey(Schema.String), + }).annotate({ title: "postgres" }), + Schema.Struct({ + url: Schema.optionalKey(Schema.String), + http: Schema.optionalKey(Schema.Literals(["http1", "http2"])), + gzip: Schema.optionalKey(Schema.Boolean), + headers: Schema.optionalKey(Schema.Record(Schema.String, Schema.String)), + }).annotate({ title: "webhook" }), + Schema.Struct({ + project_id: Schema.optionalKey(Schema.String), + dataset_id: Schema.optionalKey(Schema.String), + }).annotate({ title: "bigquery" }), + Schema.Struct({ + api_key: Schema.optionalKey(Schema.String), + region: Schema.optionalKey(Schema.String), + }).annotate({ title: "datadog" }), + Schema.Struct({ + url: Schema.optionalKey(Schema.String), + username: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + password: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + headers: Schema.optionalKey(Schema.Record(Schema.String, Schema.String)), + }).annotate({ title: "loki" }), + Schema.Struct({ dsn: Schema.optionalKey(Schema.String) }).annotate({ title: "sentry" }), + Schema.Struct({ + domain: Schema.optionalKey(Schema.String), + api_token: Schema.optionalKey(Schema.String), + dataset_name: Schema.optionalKey(Schema.String), + }).annotate({ title: "axiom" }), + Schema.Struct({ + host: Schema.optionalKey(Schema.String), + port: Schema.optionalKey( + Schema.Number.check(Schema.isInt().annotate({ expected: "an integer" })) + .check( + Schema.isGreaterThanOrEqualTo(0).annotate({ + expected: "a value greater than or equal to 0", + }), + ) + .check( + Schema.isLessThanOrEqualTo(65535).annotate({ + expected: "a value less than or equal to 65535", + }), + ), + ), + tls: Schema.optionalKey(Schema.Boolean), + structured_data: Schema.optionalKey(Schema.String), + cipher_key: Schema.optionalKey(Schema.String), + ca_cert: Schema.optionalKey(Schema.String), + client_cert: Schema.optionalKey(Schema.String), + client_key: Schema.optionalKey(Schema.String), + }).annotate({ title: "syslog" }), + ]), + backend_type: Schema.Literals([ + "postgres", + "bigquery", + "clickhouse", + "webhook", + "datadog", + "loki", + "sentry", + "s3", + "axiom", + "last9", + "otlp", + "syslog", + ]), + }), + }), +}); export const V1ApplyAMigrationOutput = Schema.Void; export const V1ApplyProjectAddonOutput = Schema.Void; export const V1AuthorizeUserOutput = Schema.Void; @@ -10027,6 +12026,10 @@ export const V1UndoOutput = Schema.Void; export const V1UpdateRealtimeConfigOutput = Schema.Void; export const V1UpdateStorageConfigOutput = Schema.Void; export const V1UpsertAMigrationOutput = Schema.Void; +export const V2DeleteLogDrainOutput = Schema.Void; +export const V2DeletePrivateLinkAssociationOutput = Schema.Void; +export const V2DeletePrivateLinkAssociationForDatabaseOutput = Schema.Void; +export const V2TransferAProjectOutput = Schema.Void; export const openApiOperationIdMap = { "v1-accept-invite-external-jit-access": "v1AcceptInviteExternalJitAccess", @@ -10199,6 +12202,24 @@ export const openApiOperationIdMap = { "v1-upgrade-postgres-version": "v1UpgradePostgresVersion", "v1-upsert-a-migration": "v1UpsertAMigration", "v1-verify-dns-config": "v1VerifyDnsConfig", + "v2-assign-organization-member-role": "v2AssignOrganizationMemberRole", + "v2-create-log-drain": "v2CreateLogDrain", + "v2-create-organization-invitations": "v2CreateOrganizationInvitations", + "v2-create-private-link-association": "v2CreatePrivateLinkAssociation", + "v2-delete-log-drain": "v2DeleteLogDrain", + "v2-delete-organization-invitations": "v2DeleteOrganizationInvitations", + "v2-delete-private-link-association": "v2DeletePrivateLinkAssociation", + "v2-delete-private-link-association-for-database": "v2DeletePrivateLinkAssociationForDatabase", + "v2-get-project-config": "v2GetProjectConfig", + "v2-list-log-drains": "v2ListLogDrains", + "v2-list-organization-github-connections": "v2ListOrganizationGithubConnections", + "v2-list-organization-members": "v2ListOrganizationMembers", + "v2-list-organization-projects": "v2ListOrganizationProjects", + "v2-list-organization-roles": "v2ListOrganizationRoles", + "v2-list-private-link-associations": "v2ListPrivateLinkAssociations", + "v2-preview-a-project-transfer": "v2PreviewAProjectTransfer", + "v2-transfer-a-project": "v2TransferAProject", + "v2-update-log-drain": "v2UpdateLogDrain", } as const; export const operationDefinitions = { @@ -12910,6 +14931,250 @@ export const operationDefinitions = { inputSchema: V1VerifyDnsConfigInput, outputSchema: V1VerifyDnsConfigOutput, }, + v2AssignOrganizationMemberRole: { + id: "v2AssignOrganizationMemberRole", + description: + "Assigns an org-wide role when projects is omitted, or creates a project-scoped assignment when projects is provided. Uses an org-level role template id from GET /v2/organizations/{slug}/roles. Stale role assignments are automatically cleaned up: if a role no longer has any projects, it is deleted; overlapping project assignments in other roles are automatically removed to avoid duplication.", + method: "PATCH", + path: "/v2/organizations/{slug}/members/{user_id}/roles", + pathParams: ["slug", "user_id"], + queryParams: [], + headerParams: [], + requestBody: { kind: "json", contentType: "application/json", fields: ["data"] }, + response: { kind: "json" }, + inputSchema: V2AssignOrganizationMemberRoleInput, + outputSchema: V2AssignOrganizationMemberRoleOutput, + }, + v2CreateLogDrain: { + id: "v2CreateLogDrain", + description: "Create a log drain for a project", + method: "POST", + path: "/v2/projects/{ref}/analytics/log-drains", + pathParams: ["ref"], + queryParams: [], + headerParams: [], + requestBody: { kind: "json", contentType: "application/json", fields: ["data"] }, + response: { kind: "json" }, + inputSchema: V2CreateLogDrainInput, + outputSchema: V2CreateLogDrainOutput, + }, + v2CreateOrganizationInvitations: { + id: "v2CreateOrganizationInvitations", + description: + "Creates member invitations for an organization. Each invitation can have different role and project scope settings.", + method: "POST", + path: "/v2/organizations/{slug}/members/invitations", + pathParams: ["slug"], + queryParams: [], + headerParams: [], + requestBody: { kind: "json", contentType: "application/json", fields: ["data"] }, + response: { kind: "json" }, + inputSchema: V2CreateOrganizationInvitationsInput, + outputSchema: V2CreateOrganizationInvitationsOutput, + }, + v2CreatePrivateLinkAssociation: { + id: "v2CreatePrivateLinkAssociation", + description: + "Adds an AWS account to the project's PrivateLink configuration and schedules the AWS resources to be created.", + method: "POST", + path: "/v2/projects/{ref}/private-link/associations", + pathParams: ["ref"], + queryParams: [], + headerParams: [], + requestBody: { kind: "json", contentType: "application/json", fields: ["data"] }, + response: { kind: "json" }, + inputSchema: V2CreatePrivateLinkAssociationInput, + outputSchema: V2CreatePrivateLinkAssociationOutput, + }, + v2DeleteLogDrain: { + id: "v2DeleteLogDrain", + description: "Delete a project log drain", + method: "DELETE", + path: "/v2/projects/{ref}/analytics/log-drains/{id}", + pathParams: ["ref", "id"], + queryParams: [], + headerParams: [], + requestBody: { kind: "none" }, + response: { kind: "void" }, + inputSchema: V2DeleteLogDrainInput, + outputSchema: V2DeleteLogDrainOutput, + }, + v2DeleteOrganizationInvitations: { + id: "v2DeleteOrganizationInvitations", + description: "Bulk delete member invitations for an organization by email address.", + method: "DELETE", + path: "/v2/organizations/{slug}/members/invitations", + pathParams: ["slug"], + queryParams: [], + headerParams: [], + requestBody: { kind: "json", contentType: "application/json", fields: ["data"] }, + response: { kind: "json" }, + inputSchema: V2DeleteOrganizationInvitationsInput, + outputSchema: V2DeleteOrganizationInvitationsOutput, + }, + v2DeletePrivateLinkAssociation: { + id: "v2DeletePrivateLinkAssociation", + description: + "Removes an AWS account from the project's PrivateLink configuration (targeting the primary database). Cleans up the associated AWS resources.", + method: "DELETE", + path: "/v2/projects/{ref}/private-link/associations/aws-account/{aws_account_id}", + pathParams: ["ref", "aws_account_id"], + queryParams: [], + headerParams: [], + requestBody: { kind: "none" }, + response: { kind: "void" }, + inputSchema: V2DeletePrivateLinkAssociationInput, + outputSchema: V2DeletePrivateLinkAssociationOutput, + }, + v2DeletePrivateLinkAssociationForDatabase: { + id: "v2DeletePrivateLinkAssociationForDatabase", + description: + "Removes an AWS account from the project's PrivateLink configuration for the given read replica. Cleans up the associated AWS resources.", + method: "DELETE", + path: "/v2/projects/{ref}/private-link/associations/aws-account/{aws_account_id}/database/{database_identifier}", + pathParams: ["ref", "aws_account_id", "database_identifier"], + queryParams: [], + headerParams: [], + requestBody: { kind: "none" }, + response: { kind: "void" }, + inputSchema: V2DeletePrivateLinkAssociationForDatabaseInput, + outputSchema: V2DeletePrivateLinkAssociationForDatabaseOutput, + }, + v2GetProjectConfig: { + id: "v2GetProjectConfig", + description: + "Returns the project's database, pooler, Auth, Data API, Realtime and Storage configuration — the same configuration a branch inherits from its base project. Each is the effective config, so a setting the project has never overridden is reported at its platform default rather than as null. Auth secrets are returned as an HMAC of their value. `storage` is read live from the storage service; the rest come from this platform's own records.", + method: "GET", + path: "/v2/projects/{ref}/config", + pathParams: ["ref"], + queryParams: [], + headerParams: [], + requestBody: { kind: "none" }, + response: { kind: "json" }, + inputSchema: V2GetProjectConfigInput, + outputSchema: V2GetProjectConfigOutput, + }, + v2ListLogDrains: { + id: "v2ListLogDrains", + description: "List project log drains", + method: "GET", + path: "/v2/projects/{ref}/analytics/log-drains", + pathParams: ["ref"], + queryParams: [], + headerParams: [], + requestBody: { kind: "none" }, + response: { kind: "json" }, + inputSchema: V2ListLogDrainsInput, + outputSchema: V2ListLogDrainsOutput, + }, + v2ListOrganizationGithubConnections: { + id: "v2ListOrganizationGithubConnections", + description: + "Returns a cursor-paginated list of the GitHub connections of the organization's projects.\n\nUse `page[after]` and `page[before]` to navigate pages and `page[size]` to control the page size.\nPaging walks the organization projects, so a page holds at most `page[size]` connections and can hold fewer (or none) when some of its projects are not connected.\nFollow `links.next` until it is `null` rather than stopping on a short page.\n\nUse `filter[project_ref]` to narrow the list down to a single project.", + method: "GET", + path: "/v2/organizations/{slug}/integrations/github/connections", + pathParams: ["slug"], + queryParams: ["page", "filter"], + headerParams: [], + requestBody: { kind: "none" }, + response: { kind: "json" }, + inputSchema: V2ListOrganizationGithubConnectionsInput, + outputSchema: V2ListOrganizationGithubConnectionsOutput, + }, + v2ListOrganizationMembers: { + id: "v2ListOrganizationMembers", + description: + "Returns a cursor-paginated list of organization members including their roles and project-scoped permissions.", + method: "GET", + path: "/v2/organizations/{slug}/members", + pathParams: ["slug"], + queryParams: ["page", "filter"], + headerParams: [], + requestBody: { kind: "none" }, + response: { kind: "json" }, + inputSchema: V2ListOrganizationMembersInput, + outputSchema: V2ListOrganizationMembersOutput, + }, + v2ListOrganizationProjects: { + id: "v2ListOrganizationProjects", + description: + "Returns a cursor-paginated list of projects for the specified organization, including their databases.\n\nUse `page[after]` and `page[before]` to navigate pages and `page[size]` to control the number of projects returned per page.", + method: "GET", + path: "/v2/organizations/{slug}/projects", + pathParams: ["slug"], + queryParams: ["page", "sort", "search"], + headerParams: [], + requestBody: { kind: "none" }, + response: { kind: "json" }, + inputSchema: V2ListOrganizationProjectsInput, + outputSchema: V2ListOrganizationProjectsOutput, + }, + v2ListOrganizationRoles: { + id: "v2ListOrganizationRoles", + description: "Returns a list of org-level roles for the organization.", + method: "GET", + path: "/v2/organizations/{slug}/roles", + pathParams: ["slug"], + queryParams: [], + headerParams: [], + requestBody: { kind: "none" }, + response: { kind: "json" }, + inputSchema: V2ListOrganizationRolesInput, + outputSchema: V2ListOrganizationRolesOutput, + }, + v2ListPrivateLinkAssociations: { + id: "v2ListPrivateLinkAssociations", + description: "List AWS accounts attached to the project PrivateLink share", + method: "GET", + path: "/v2/projects/{ref}/private-link/associations", + pathParams: ["ref"], + queryParams: [], + headerParams: [], + requestBody: { kind: "none" }, + response: { kind: "json" }, + inputSchema: V2ListPrivateLinkAssociationsInput, + outputSchema: V2ListPrivateLinkAssociationsOutput, + }, + v2PreviewAProjectTransfer: { + id: "v2PreviewAProjectTransfer", + description: + "Previews transferring a project to a different organizations, shows eligibility and impact", + method: "POST", + path: "/v2/projects/{ref}/transfers/previews", + pathParams: ["ref"], + queryParams: [], + headerParams: [], + requestBody: { kind: "json", contentType: "application/json", fields: ["data"] }, + response: { kind: "json" }, + inputSchema: V2PreviewAProjectTransferInput, + outputSchema: V2PreviewAProjectTransferOutput, + }, + v2TransferAProject: { + id: "v2TransferAProject", + description: "Transfers a project to a different organization", + method: "POST", + path: "/v2/projects/{ref}/transfers", + pathParams: ["ref"], + queryParams: [], + headerParams: [], + requestBody: { kind: "json", contentType: "application/json", fields: ["data"] }, + response: { kind: "void" }, + inputSchema: V2TransferAProjectInput, + outputSchema: V2TransferAProjectOutput, + }, + v2UpdateLogDrain: { + id: "v2UpdateLogDrain", + description: "Update a project log drain", + method: "PUT", + path: "/v2/projects/{ref}/analytics/log-drains/{id}", + pathParams: ["ref", "id"], + queryParams: [], + headerParams: [], + requestBody: { kind: "json", contentType: "application/json", fields: ["data"] }, + response: { kind: "json" }, + inputSchema: V2UpdateLogDrainInput, + outputSchema: V2UpdateLogDrainOutput, + }, } as const; export type OpenApiOperationId = keyof typeof openApiOperationIdMap; diff --git a/packages/api/src/generated/effect-client.ts b/packages/api/src/generated/effect-client.ts index f8651d8acf..1d7dbd2e14 100644 --- a/packages/api/src/generated/effect-client.ts +++ b/packages/api/src/generated/effect-client.ts @@ -2340,6 +2340,260 @@ export const versionedEffectOperations = { ); }), }, + v2: { + assignOrganizationMemberRole: ( + input: typeof operationDefinitions.v2AssignOrganizationMemberRole.inputSchema.Type, + ): Effect.Effect< + typeof operationDefinitions.v2AssignOrganizationMemberRole.outputSchema.Type, + SupabaseApiError, + SupabaseApiClient + > => + Effect.gen(function* () { + const client = yield* SupabaseApiClient; + return yield* client.execute<"v2AssignOrganizationMemberRole">( + operationDefinitions.v2AssignOrganizationMemberRole, + input, + ); + }), + createLogDrain: ( + input: typeof operationDefinitions.v2CreateLogDrain.inputSchema.Type, + ): Effect.Effect< + typeof operationDefinitions.v2CreateLogDrain.outputSchema.Type, + SupabaseApiError, + SupabaseApiClient + > => + Effect.gen(function* () { + const client = yield* SupabaseApiClient; + return yield* client.execute<"v2CreateLogDrain">( + operationDefinitions.v2CreateLogDrain, + input, + ); + }), + createOrganizationInvitations: ( + input: typeof operationDefinitions.v2CreateOrganizationInvitations.inputSchema.Type, + ): Effect.Effect< + typeof operationDefinitions.v2CreateOrganizationInvitations.outputSchema.Type, + SupabaseApiError, + SupabaseApiClient + > => + Effect.gen(function* () { + const client = yield* SupabaseApiClient; + return yield* client.execute<"v2CreateOrganizationInvitations">( + operationDefinitions.v2CreateOrganizationInvitations, + input, + ); + }), + createPrivateLinkAssociation: ( + input: typeof operationDefinitions.v2CreatePrivateLinkAssociation.inputSchema.Type, + ): Effect.Effect< + typeof operationDefinitions.v2CreatePrivateLinkAssociation.outputSchema.Type, + SupabaseApiError, + SupabaseApiClient + > => + Effect.gen(function* () { + const client = yield* SupabaseApiClient; + return yield* client.execute<"v2CreatePrivateLinkAssociation">( + operationDefinitions.v2CreatePrivateLinkAssociation, + input, + ); + }), + deleteLogDrain: ( + input: typeof operationDefinitions.v2DeleteLogDrain.inputSchema.Type, + ): Effect.Effect< + typeof operationDefinitions.v2DeleteLogDrain.outputSchema.Type, + SupabaseApiError, + SupabaseApiClient + > => + Effect.gen(function* () { + const client = yield* SupabaseApiClient; + return yield* client.execute<"v2DeleteLogDrain">( + operationDefinitions.v2DeleteLogDrain, + input, + ); + }), + deleteOrganizationInvitations: ( + input: typeof operationDefinitions.v2DeleteOrganizationInvitations.inputSchema.Type, + ): Effect.Effect< + typeof operationDefinitions.v2DeleteOrganizationInvitations.outputSchema.Type, + SupabaseApiError, + SupabaseApiClient + > => + Effect.gen(function* () { + const client = yield* SupabaseApiClient; + return yield* client.execute<"v2DeleteOrganizationInvitations">( + operationDefinitions.v2DeleteOrganizationInvitations, + input, + ); + }), + deletePrivateLinkAssociation: ( + input: typeof operationDefinitions.v2DeletePrivateLinkAssociation.inputSchema.Type, + ): Effect.Effect< + typeof operationDefinitions.v2DeletePrivateLinkAssociation.outputSchema.Type, + SupabaseApiError, + SupabaseApiClient + > => + Effect.gen(function* () { + const client = yield* SupabaseApiClient; + return yield* client.execute<"v2DeletePrivateLinkAssociation">( + operationDefinitions.v2DeletePrivateLinkAssociation, + input, + ); + }), + deletePrivateLinkAssociationForDatabase: ( + input: typeof operationDefinitions.v2DeletePrivateLinkAssociationForDatabase.inputSchema.Type, + ): Effect.Effect< + typeof operationDefinitions.v2DeletePrivateLinkAssociationForDatabase.outputSchema.Type, + SupabaseApiError, + SupabaseApiClient + > => + Effect.gen(function* () { + const client = yield* SupabaseApiClient; + return yield* client.execute<"v2DeletePrivateLinkAssociationForDatabase">( + operationDefinitions.v2DeletePrivateLinkAssociationForDatabase, + input, + ); + }), + getProjectConfig: ( + input: typeof operationDefinitions.v2GetProjectConfig.inputSchema.Type, + ): Effect.Effect< + typeof operationDefinitions.v2GetProjectConfig.outputSchema.Type, + SupabaseApiError, + SupabaseApiClient + > => + Effect.gen(function* () { + const client = yield* SupabaseApiClient; + return yield* client.execute<"v2GetProjectConfig">( + operationDefinitions.v2GetProjectConfig, + input, + ); + }), + listLogDrains: ( + input: typeof operationDefinitions.v2ListLogDrains.inputSchema.Type, + ): Effect.Effect< + typeof operationDefinitions.v2ListLogDrains.outputSchema.Type, + SupabaseApiError, + SupabaseApiClient + > => + Effect.gen(function* () { + const client = yield* SupabaseApiClient; + return yield* client.execute<"v2ListLogDrains">( + operationDefinitions.v2ListLogDrains, + input, + ); + }), + listOrganizationGithubConnections: ( + input: typeof operationDefinitions.v2ListOrganizationGithubConnections.inputSchema.Type, + ): Effect.Effect< + typeof operationDefinitions.v2ListOrganizationGithubConnections.outputSchema.Type, + SupabaseApiError, + SupabaseApiClient + > => + Effect.gen(function* () { + const client = yield* SupabaseApiClient; + return yield* client.execute<"v2ListOrganizationGithubConnections">( + operationDefinitions.v2ListOrganizationGithubConnections, + input, + ); + }), + listOrganizationMembers: ( + input: typeof operationDefinitions.v2ListOrganizationMembers.inputSchema.Type, + ): Effect.Effect< + typeof operationDefinitions.v2ListOrganizationMembers.outputSchema.Type, + SupabaseApiError, + SupabaseApiClient + > => + Effect.gen(function* () { + const client = yield* SupabaseApiClient; + return yield* client.execute<"v2ListOrganizationMembers">( + operationDefinitions.v2ListOrganizationMembers, + input, + ); + }), + listOrganizationProjects: ( + input: typeof operationDefinitions.v2ListOrganizationProjects.inputSchema.Type, + ): Effect.Effect< + typeof operationDefinitions.v2ListOrganizationProjects.outputSchema.Type, + SupabaseApiError, + SupabaseApiClient + > => + Effect.gen(function* () { + const client = yield* SupabaseApiClient; + return yield* client.execute<"v2ListOrganizationProjects">( + operationDefinitions.v2ListOrganizationProjects, + input, + ); + }), + listOrganizationRoles: ( + input: typeof operationDefinitions.v2ListOrganizationRoles.inputSchema.Type, + ): Effect.Effect< + typeof operationDefinitions.v2ListOrganizationRoles.outputSchema.Type, + SupabaseApiError, + SupabaseApiClient + > => + Effect.gen(function* () { + const client = yield* SupabaseApiClient; + return yield* client.execute<"v2ListOrganizationRoles">( + operationDefinitions.v2ListOrganizationRoles, + input, + ); + }), + listPrivateLinkAssociations: ( + input: typeof operationDefinitions.v2ListPrivateLinkAssociations.inputSchema.Type, + ): Effect.Effect< + typeof operationDefinitions.v2ListPrivateLinkAssociations.outputSchema.Type, + SupabaseApiError, + SupabaseApiClient + > => + Effect.gen(function* () { + const client = yield* SupabaseApiClient; + return yield* client.execute<"v2ListPrivateLinkAssociations">( + operationDefinitions.v2ListPrivateLinkAssociations, + input, + ); + }), + previewAProjectTransfer: ( + input: typeof operationDefinitions.v2PreviewAProjectTransfer.inputSchema.Type, + ): Effect.Effect< + typeof operationDefinitions.v2PreviewAProjectTransfer.outputSchema.Type, + SupabaseApiError, + SupabaseApiClient + > => + Effect.gen(function* () { + const client = yield* SupabaseApiClient; + return yield* client.execute<"v2PreviewAProjectTransfer">( + operationDefinitions.v2PreviewAProjectTransfer, + input, + ); + }), + transferAProject: ( + input: typeof operationDefinitions.v2TransferAProject.inputSchema.Type, + ): Effect.Effect< + typeof operationDefinitions.v2TransferAProject.outputSchema.Type, + SupabaseApiError, + SupabaseApiClient + > => + Effect.gen(function* () { + const client = yield* SupabaseApiClient; + return yield* client.execute<"v2TransferAProject">( + operationDefinitions.v2TransferAProject, + input, + ); + }), + updateLogDrain: ( + input: typeof operationDefinitions.v2UpdateLogDrain.inputSchema.Type, + ): Effect.Effect< + typeof operationDefinitions.v2UpdateLogDrain.outputSchema.Type, + SupabaseApiError, + SupabaseApiClient + > => + Effect.gen(function* () { + const client = yield* SupabaseApiClient; + return yield* client.execute<"v2UpdateLogDrain">( + operationDefinitions.v2UpdateLogDrain, + input, + ); + }), + }, } as const; export type GeneratedEffectOperations = typeof versionedEffectOperations; @@ -3031,5 +3285,79 @@ export function executeApiClientOperation( return Schema.decodeUnknownEffect(operationDefinitions.v1VerifyDnsConfig.inputSchema)( input, ).pipe(Effect.flatMap((decoded) => api.v1.verifyDnsConfig(decoded))); + case "v2AssignOrganizationMemberRole": + return Schema.decodeUnknownEffect( + operationDefinitions.v2AssignOrganizationMemberRole.inputSchema, + )(input).pipe(Effect.flatMap((decoded) => api.v2.assignOrganizationMemberRole(decoded))); + case "v2CreateLogDrain": + return Schema.decodeUnknownEffect(operationDefinitions.v2CreateLogDrain.inputSchema)( + input, + ).pipe(Effect.flatMap((decoded) => api.v2.createLogDrain(decoded))); + case "v2CreateOrganizationInvitations": + return Schema.decodeUnknownEffect( + operationDefinitions.v2CreateOrganizationInvitations.inputSchema, + )(input).pipe(Effect.flatMap((decoded) => api.v2.createOrganizationInvitations(decoded))); + case "v2CreatePrivateLinkAssociation": + return Schema.decodeUnknownEffect( + operationDefinitions.v2CreatePrivateLinkAssociation.inputSchema, + )(input).pipe(Effect.flatMap((decoded) => api.v2.createPrivateLinkAssociation(decoded))); + case "v2DeleteLogDrain": + return Schema.decodeUnknownEffect(operationDefinitions.v2DeleteLogDrain.inputSchema)( + input, + ).pipe(Effect.flatMap((decoded) => api.v2.deleteLogDrain(decoded))); + case "v2DeleteOrganizationInvitations": + return Schema.decodeUnknownEffect( + operationDefinitions.v2DeleteOrganizationInvitations.inputSchema, + )(input).pipe(Effect.flatMap((decoded) => api.v2.deleteOrganizationInvitations(decoded))); + case "v2DeletePrivateLinkAssociation": + return Schema.decodeUnknownEffect( + operationDefinitions.v2DeletePrivateLinkAssociation.inputSchema, + )(input).pipe(Effect.flatMap((decoded) => api.v2.deletePrivateLinkAssociation(decoded))); + case "v2DeletePrivateLinkAssociationForDatabase": + return Schema.decodeUnknownEffect( + operationDefinitions.v2DeletePrivateLinkAssociationForDatabase.inputSchema, + )(input).pipe( + Effect.flatMap((decoded) => api.v2.deletePrivateLinkAssociationForDatabase(decoded)), + ); + case "v2GetProjectConfig": + return Schema.decodeUnknownEffect(operationDefinitions.v2GetProjectConfig.inputSchema)( + input, + ).pipe(Effect.flatMap((decoded) => api.v2.getProjectConfig(decoded))); + case "v2ListLogDrains": + return Schema.decodeUnknownEffect(operationDefinitions.v2ListLogDrains.inputSchema)( + input, + ).pipe(Effect.flatMap((decoded) => api.v2.listLogDrains(decoded))); + case "v2ListOrganizationGithubConnections": + return Schema.decodeUnknownEffect( + operationDefinitions.v2ListOrganizationGithubConnections.inputSchema, + )(input).pipe(Effect.flatMap((decoded) => api.v2.listOrganizationGithubConnections(decoded))); + case "v2ListOrganizationMembers": + return Schema.decodeUnknownEffect(operationDefinitions.v2ListOrganizationMembers.inputSchema)( + input, + ).pipe(Effect.flatMap((decoded) => api.v2.listOrganizationMembers(decoded))); + case "v2ListOrganizationProjects": + return Schema.decodeUnknownEffect( + operationDefinitions.v2ListOrganizationProjects.inputSchema, + )(input).pipe(Effect.flatMap((decoded) => api.v2.listOrganizationProjects(decoded))); + case "v2ListOrganizationRoles": + return Schema.decodeUnknownEffect(operationDefinitions.v2ListOrganizationRoles.inputSchema)( + input, + ).pipe(Effect.flatMap((decoded) => api.v2.listOrganizationRoles(decoded))); + case "v2ListPrivateLinkAssociations": + return Schema.decodeUnknownEffect( + operationDefinitions.v2ListPrivateLinkAssociations.inputSchema, + )(input).pipe(Effect.flatMap((decoded) => api.v2.listPrivateLinkAssociations(decoded))); + case "v2PreviewAProjectTransfer": + return Schema.decodeUnknownEffect(operationDefinitions.v2PreviewAProjectTransfer.inputSchema)( + input, + ).pipe(Effect.flatMap((decoded) => api.v2.previewAProjectTransfer(decoded))); + case "v2TransferAProject": + return Schema.decodeUnknownEffect(operationDefinitions.v2TransferAProject.inputSchema)( + input, + ).pipe(Effect.flatMap((decoded) => api.v2.transferAProject(decoded))); + case "v2UpdateLogDrain": + return Schema.decodeUnknownEffect(operationDefinitions.v2UpdateLogDrain.inputSchema)( + input, + ).pipe(Effect.flatMap((decoded) => api.v2.updateLogDrain(decoded))); } } diff --git a/packages/api/src/generated/openapi.json b/packages/api/src/generated/openapi.json index 07f8909630..97c4816183 100644 --- a/packages/api/src/generated/openapi.json +++ b/packages/api/src/generated/openapi.json @@ -1,7 +1,7 @@ { "openapi": "3.0.0", "info": { - "title": "Supabase API (v1)", + "title": "Supabase API", "version": "1.0.0" }, "paths": { @@ -11241,3738 +11241,5066 @@ "x-fga-permissions": [["organization_projects_read"]], "x-oauth-scope": "projects:read" } - } - }, - "components": { - "schemas": { - "BranchDetailResponse": { - "type": "object", - "properties": { - "ref": { - "type": "string" + }, + "/v2/projects/{ref}/analytics/log-drains": { + "get": { + "operationId": "v2-list-log-drains", + "parameters": [ + { + "name": "ref", + "required": true, + "in": "path", + "description": "Project ref", + "schema": { + "minLength": 20, + "maxLength": 20, + "pattern": "^[a-z]+$", + "example": "abcdefghijklmnopqrst", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListLogDrainsResponse" + } + } + } }, - "postgres_version": { - "type": "string" + "401": { + "description": "Unauthorized" }, - "postgres_engine": { - "type": "string" + "403": { + "description": "Forbidden action" }, - "release_channel": { - "type": "string" + "429": { + "description": "Rate limit exceeded" }, - "status": { - "type": "string", - "enum": [ - "INACTIVE", - "ACTIVE_HEALTHY", - "ACTIVE_UNHEALTHY", - "COMING_UP", - "UNKNOWN", - "GOING_DOWN", - "INIT_FAILED", - "REMOVED", - "RESTORING", - "UPGRADING", - "PAUSING", - "RESTORE_FAILED", - "RESTARTING", - "PAUSE_FAILED", - "RESIZING" - ] + "500": { + "description": "Failed to fetch log drains" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "List project log drains", + "tags": ["Analytics"], + "x-badges": [ + { + "name": "OAuth scope: analytics_config:read", + "position": "after" + } + ], + "x-endpoint-owners": ["analytics"], + "x-fga-permissions": [["analytics_config_read"]], + "x-oauth-scope": "analytics_config:read" + }, + "post": { + "operationId": "v2-create-log-drain", + "parameters": [ + { + "name": "ref", + "required": true, + "in": "path", + "description": "Project ref", + "schema": { + "minLength": 20, + "maxLength": 20, + "pattern": "^[a-z]+$", + "example": "abcdefghijklmnopqrst", + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateLogDrainRequestOpenApi" + } + } + } + }, + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LogDrainResponse" + } + } + } }, - "db_host": { - "type": "string" + "401": { + "description": "Unauthorized" }, - "db_port": { - "type": "integer", - "exclusiveMinimum": true, - "maximum": 9007199254740991, - "minimum": 0 + "402": { + "description": "This feature requires the Pro, Team, or Enterprise organization plan.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlanGateErrorBodyV2" + } + } + } }, - "db_user": { - "type": "string" + "403": { + "description": "Forbidden action" }, - "db_pass": { - "type": "string" + "429": { + "description": "Rate limit exceeded" }, - "jwt_secret": { - "type": "string" + "500": { + "description": "Failed to create a log drain" } }, - "required": [ - "ref", - "postgres_version", - "postgres_engine", - "release_channel", - "status", - "db_host", - "db_port" - ] - }, - "UpdateBranchBody": { - "type": "object", - "properties": { - "branch_name": { - "type": "string" + "security": [ + { + "bearer": [] + } + ], + "summary": "Create a log drain for a project", + "tags": ["Analytics"], + "x-allowed-plans": ["Pro", "Team", "Enterprise"], + "x-badges": [ + { + "name": "Only available on Pro, Team, Enterprise", + "position": "before" }, - "git_branch": { - "type": "string" + { + "name": "OAuth scope: analytics_config:write", + "position": "after" + } + ], + "x-endpoint-owners": ["analytics"], + "x-fga-permissions": [["analytics_config_write"]], + "x-oauth-scope": "analytics_config:write" + } + }, + "/v2/projects/{ref}/analytics/log-drains/{id}": { + "put": { + "operationId": "v2-update-log-drain", + "parameters": [ + { + "name": "ref", + "required": true, + "in": "path", + "description": "Project ref", + "schema": { + "minLength": 20, + "maxLength": 20, + "pattern": "^[a-z]+$", + "example": "abcdefghijklmnopqrst", + "type": "string" + } }, - "reset_on_push": { - "description": "This field is deprecated and will be ignored. Use v1-reset-a-branch endpoint directly instead.", - "deprecated": true, - "type": "boolean" + { + "name": "id", + "required": true, + "in": "path", + "description": "Log drains identifier", + "schema": { + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateLogDrainRequestOpenApi" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LogDrainResponse" + } + } + } }, - "persistent": { - "type": "boolean" + "401": { + "description": "Unauthorized" }, - "status": { - "type": "string", - "enum": [ - "CREATING_PROJECT", - "RUNNING_MIGRATIONS", - "MIGRATIONS_PASSED", - "MIGRATIONS_FAILED", - "FUNCTIONS_DEPLOYED", - "FUNCTIONS_FAILED" - ] + "403": { + "description": "Forbidden action" }, - "request_review": { - "type": "boolean" + "429": { + "description": "Rate limit exceeded" }, - "notify_url": { - "type": "string", - "format": "uri", - "description": "HTTP endpoint to receive branch status updates." + "500": { + "description": "Failed to update log drain" } }, - "example": { - "branch_name": "preview-login-page", - "git_branch": "feature/login-page", - "persistent": true, - "request_review": true, - "notify_url": "https://example.com/webhooks/branches" - } + "security": [ + { + "bearer": [] + } + ], + "summary": "Update a project log drain", + "tags": ["Analytics"], + "x-badges": [ + { + "name": "OAuth scope: analytics_config:write", + "position": "after" + } + ], + "x-endpoint-owners": ["analytics"], + "x-fga-permissions": [["analytics_config_write"]], + "x-oauth-scope": "analytics_config:write" }, - "BranchResponse": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - }, - "name": { - "type": "string" - }, - "project_ref": { - "type": "string" - }, - "parent_project_ref": { - "type": "string" - }, - "is_default": { - "type": "boolean" - }, - "git_branch": { - "type": "string" - }, - "pr_number": { - "type": "integer", - "format": "int32", - "minimum": -9007199254740991, - "maximum": 9007199254740991 - }, - "latest_check_run_id": { - "description": "This field is deprecated and will not be populated.", - "deprecated": true, - "type": "number" - }, - "persistent": { - "type": "boolean" + "delete": { + "operationId": "v2-delete-log-drain", + "parameters": [ + { + "name": "ref", + "required": true, + "in": "path", + "description": "Project ref", + "schema": { + "minLength": 20, + "maxLength": 20, + "pattern": "^[a-z]+$", + "example": "abcdefghijklmnopqrst", + "type": "string" + } }, - "status": { - "type": "string", - "enum": [ - "CREATING_PROJECT", - "RUNNING_MIGRATIONS", - "MIGRATIONS_PASSED", - "MIGRATIONS_FAILED", - "FUNCTIONS_DEPLOYED", - "FUNCTIONS_FAILED" - ], - "description": "This field is deprecated. List action runs to get branch status instead.", - "deprecated": true + { + "name": "id", + "required": true, + "in": "path", + "description": "Log drains identifier", + "schema": { + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "" }, - "created_at": { - "type": "string", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + "401": { + "description": "Unauthorized" }, - "updated_at": { - "type": "string", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + "403": { + "description": "Forbidden action" }, - "review_requested_at": { - "type": "string", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + "429": { + "description": "Rate limit exceeded" }, - "with_data": { - "type": "boolean" + "500": { + "description": "Failed to delete a log drain" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Delete a project log drain", + "tags": ["Analytics"], + "x-badges": [ + { + "name": "OAuth scope: analytics_config:write", + "position": "after" + } + ], + "x-endpoint-owners": ["analytics"], + "x-fga-permissions": [["analytics_config_write"]], + "x-oauth-scope": "analytics_config:write" + } + }, + "/v2/projects/{ref}/config": { + "get": { + "description": "Returns the project's database, pooler, Auth, Data API, Realtime and Storage configuration — the same configuration a branch inherits from its base project. Each is the effective config, so a setting the project has never overridden is reported at its platform default rather than as null. Auth secrets are returned as an HMAC of their value. `storage` is read live from the storage service; the rest come from this platform's own records.", + "operationId": "v2-get-project-config", + "parameters": [ + { + "name": "ref", + "required": true, + "in": "path", + "description": "Project ref", + "schema": { + "minLength": 20, + "maxLength": 20, + "pattern": "^[a-z]+$", + "example": "abcdefghijklmnopqrst", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V2ProjectConfigResponse" + } + } + } }, - "notify_url": { - "type": "string", - "format": "uri" + "401": { + "description": "Unauthorized" }, - "deletion_scheduled_at": { - "type": "string", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + "403": { + "description": "Forbidden action" }, - "preview_project_status": { - "type": "string", - "enum": [ - "INACTIVE", - "ACTIVE_HEALTHY", - "ACTIVE_UNHEALTHY", - "COMING_UP", - "UNKNOWN", - "GOING_DOWN", - "INIT_FAILED", - "REMOVED", - "RESTORING", - "UPGRADING", - "PAUSING", - "RESTORE_FAILED", - "RESTARTING", - "PAUSE_FAILED", - "RESIZING" - ] + "429": { + "description": "Rate limit exceeded" } }, - "required": [ - "id", - "name", - "project_ref", - "parent_project_ref", - "is_default", - "persistent", - "status", - "created_at", - "updated_at", - "with_data" + "security": [ + { + "bearer": [] + } + ], + "summary": "[Alpha] Get a project's service configuration", + "tags": ["Projects"], + "x-endpoint-owners": ["management-api", "infra"], + "x-fga-permissions": [ + [ + "database_config_read", + "database_read", + "database_ssl_config_read", + "database_network_restrictions_read", + "auth_config_read", + "data_api_config_read", + "realtime_config_read", + "storage_config_read" + ] ] - }, - "BranchDeleteResponse": { - "type": "object", - "properties": { - "message": { - "type": "string", - "enum": ["ok"] + } + }, + "/v2/projects/{ref}/transfers/previews": { + "post": { + "operationId": "v2-preview-a-project-transfer", + "parameters": [ + { + "name": "ref", + "required": true, + "in": "path", + "description": "Project ref", + "schema": { + "minLength": 20, + "maxLength": 20, + "pattern": "^[a-z]+$", + "example": "abcdefghijklmnopqrst", + "type": "string" + } } - }, - "required": ["message"] - }, - "BranchActionBody": { - "type": "object", - "properties": { - "migration_version": { - "type": "string" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V2TransferProjectBody" + } + } } }, - "example": { - "migration_version": "20250312000000" - } - }, - "BranchUpdateResponse": { - "type": "object", - "properties": { - "workflow_run_id": { - "type": "string" - }, - "message": { - "type": "string", - "enum": ["ok"] - } - }, - "required": ["workflow_run_id", "message"] - }, - "BranchRestoreResponse": { - "type": "object", - "properties": { - "message": { - "type": "string", - "enum": ["Branch restoration initiated"] + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V2PreviewProjectTransferResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden action" + }, + "429": { + "description": "Rate limit exceeded" } }, - "required": ["message"] - }, - "V1ProjectWithDatabaseResponse": { - "type": "object", - "properties": { - "id": { - "type": "string", - "deprecated": true, - "description": "Deprecated: Use `ref` instead." - }, - "ref": { - "type": "string", - "minLength": 20, - "maxLength": 20, - "pattern": "^[a-z]+$", + "security": [ + { + "bearer": [] + } + ], + "summary": "Previews transferring a project to a different organizations, shows eligibility and impact", + "tags": ["Projects"], + "x-endpoint-owners": ["management-api"], + "x-fga-permissions": [["project_admin_read"]] + } + }, + "/v2/projects/{ref}/transfers": { + "post": { + "operationId": "v2-transfer-a-project", + "parameters": [ + { + "name": "ref", + "required": true, + "in": "path", "description": "Project ref", - "example": "abcdefghijklmnopqrst" + "schema": { + "minLength": 20, + "maxLength": 20, + "pattern": "^[a-z]+$", + "example": "abcdefghijklmnopqrst", + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V2TransferProjectBody" + } + } + } + }, + "responses": { + "200": { + "description": "" }, - "organization_id": { - "type": "string", - "description": "Deprecated: Use `organization_slug` instead.", - "deprecated": true + "401": { + "description": "Unauthorized" }, - "organization_slug": { - "type": "string", - "pattern": "^[\\w-]+$", - "description": "Organization slug", - "example": "tsrqponmlkjihgfedcba" + "403": { + "description": "Forbidden action" }, - "name": { - "type": "string", - "description": "Name of your project" + "429": { + "description": "Rate limit exceeded" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Transfers a project to a different organization", + "tags": ["Projects"], + "x-endpoint-owners": ["management-api"], + "x-fga-permissions": [["organization_admin_write"]] + } + }, + "/v2/projects/{ref}/private-link/associations": { + "get": { + "operationId": "v2-list-private-link-associations", + "parameters": [ + { + "name": "ref", + "required": true, + "in": "path", + "description": "Project ref", + "schema": { + "minLength": 20, + "maxLength": 20, + "pattern": "^[a-z]+$", + "example": "abcdefghijklmnopqrst", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V2ListPrivateLinkAssociationsResponse" + } + } + } }, - "region": { - "type": "string", - "description": "Region of your project" + "401": { + "description": "Unauthorized" }, - "created_at": { - "type": "string", - "description": "Creation timestamp" + "403": { + "description": "Forbidden action" }, - "status": { - "type": "string", - "enum": [ - "INACTIVE", - "ACTIVE_HEALTHY", - "ACTIVE_UNHEALTHY", - "COMING_UP", - "UNKNOWN", - "GOING_DOWN", - "INIT_FAILED", - "REMOVED", - "RESTORING", - "UPGRADING", - "PAUSING", - "RESTORE_FAILED", - "RESTARTING", - "PAUSE_FAILED", - "RESIZING" - ] + "429": { + "description": "Rate limit exceeded" }, - "database": { - "type": "object", - "properties": { - "host": { - "type": "string", - "description": "Database host" - }, - "version": { - "type": "string", - "description": "Database version" - }, - "postgres_engine": { - "type": "string", - "description": "Database engine" - }, - "release_channel": { - "type": "string", - "description": "Release channel" - } - }, - "required": ["host", "version", "postgres_engine", "release_channel"] + "500": { + "description": "Failed to retrieve AWS accounts for project" } }, - "required": [ - "id", - "ref", - "organization_id", - "organization_slug", - "name", - "region", - "created_at", - "status", - "database" - ] + "security": [ + { + "bearer": [] + } + ], + "summary": "List AWS accounts attached to the project PrivateLink share", + "tags": ["Projects"], + "x-endpoint-owners": ["platform-networking", "management-api"], + "x-fga-permissions": [["project_admin_read"]] }, - "V1CreateProjectBody": { - "type": "object", - "properties": { - "db_pass": { - "type": "string", - "description": "Database password" - }, - "name": { - "type": "string", - "maxLength": 256, - "description": "Name of your project" + "post": { + "description": "Adds an AWS account to the project's PrivateLink configuration and schedules the AWS resources to be created.", + "operationId": "v2-create-private-link-association", + "parameters": [ + { + "name": "ref", + "required": true, + "in": "path", + "description": "Project ref", + "schema": { + "minLength": 20, + "maxLength": 20, + "pattern": "^[a-z]+$", + "example": "abcdefghijklmnopqrst", + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V2CreatePrivateLinkAssociationRequest" + } + } + } + }, + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V2PrivateLinkAssociationResponse" + } + } + } }, - "organization_id": { - "deprecated": true, - "description": "Deprecated: Use `organization_slug` instead.", - "type": "string" + "401": { + "description": "Unauthorized" }, - "organization_slug": { - "type": "string", - "pattern": "^[\\w-]+$", - "description": "Organization slug", - "example": "tsrqponmlkjihgfedcba" - }, - "plan": { - "deprecated": true, - "description": "Subscription Plan is now set on organization level and is ignored in this request", - "type": "string", - "enum": ["free", "pro"] - }, - "region": { - "description": "Region you want your server to reside in. Use region_selection instead.", - "deprecated": true, - "enum": [ - "us-east-1", - "us-east-2", - "us-west-1", - "us-west-2", - "ap-east-1", - "ap-southeast-1", - "ap-northeast-1", - "ap-northeast-2", - "ap-southeast-2", - "eu-west-1", - "eu-west-2", - "eu-west-3", - "eu-north-1", - "eu-central-1", - "eu-central-2", - "ca-central-1", - "ap-south-1", - "sa-east-1" - ], - "type": "string" - }, - "region_selection": { - "description": "Region selection. Only one of region or region_selection can be specified.", - "oneOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["specific"] - }, - "code": { - "type": "string", - "description": "Specific region code. The codes supported are not a stable API, and should be retrieved from the /available-regions endpoint.", - "enum": [ - "us-east-1", - "us-east-2", - "us-west-1", - "us-west-2", - "ap-east-1", - "ap-southeast-1", - "ap-northeast-1", - "ap-northeast-2", - "ap-southeast-2", - "eu-west-1", - "eu-west-2", - "eu-west-3", - "eu-north-1", - "eu-central-1", - "eu-central-2", - "ca-central-1", - "ap-south-1", - "sa-east-1" - ] - } - }, - "required": ["type", "code"] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["smartGroup"] - }, - "code": { - "type": "string", - "enum": ["americas", "emea", "apac"], - "description": "The Smart Region Group's code. The codes supported are not a stable API, and should be retrieved from the /available-regions endpoint." - } - }, - "required": ["type", "code"] + "402": { + "description": "This feature requires the Team, or Enterprise organization plan.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlanGateErrorBodyV2" + } } - ] - }, - "kps_enabled": { - "deprecated": true, - "description": "This field is deprecated and is ignored in this request", - "type": "boolean" - }, - "desired_instance_size": { - "description": "Desired instance size. Omit this field to always default to the smallest possible size.", - "type": "string", - "enum": [ - "nano", - "micro", - "small", - "medium", - "large", - "xlarge", - "2xlarge", - "4xlarge", - "8xlarge", - "12xlarge", - "16xlarge", - "24xlarge", - "24xlarge_optimized_memory", - "24xlarge_optimized_cpu", - "24xlarge_high_memory", - "48xlarge", - "48xlarge_optimized_memory", - "48xlarge_optimized_cpu", - "48xlarge_high_memory" - ] - }, - "template_url": { - "description": "Template URL used to create the project from the CLI.", - "type": "string", - "format": "uri" + } }, - "release_channel": { - "deprecated": true, - "type": "null" + "403": { + "description": "Forbidden action" }, - "postgres_engine": { - "deprecated": true, - "type": "null" + "429": { + "description": "Rate limit exceeded" }, - "high_availability": { - "description": "[Experimental] Whether to enable high availability for the project.", - "type": "boolean" + "500": { + "description": "Failed to add AWS account to PrivateLink share" } }, - "required": ["db_pass", "name", "organization_slug"], - "example": { - "db_pass": "correct-horse-battery-staple", - "name": "acme-prod", - "organization_slug": "tsrqponmlkjihgfedcba", - "region": "us-east-1" - }, - "additionalProperties": false - }, - "V1ProjectResponse": { - "type": "object", - "properties": { - "id": { - "type": "string", - "deprecated": true, - "description": "Deprecated: Use `ref` instead." - }, - "ref": { - "type": "string", - "minLength": 20, - "maxLength": 20, - "pattern": "^[a-z]+$", + "security": [ + { + "bearer": [] + } + ], + "summary": "Add an AWS account to the project PrivateLink share", + "tags": ["Projects"], + "x-allowed-plans": ["Team", "Enterprise"], + "x-badges": [ + { + "name": "Only available on Team, Enterprise", + "position": "before" + } + ], + "x-endpoint-owners": ["platform-networking", "management-api"], + "x-fga-permissions": [["project_admin_write"]] + } + }, + "/v2/projects/{ref}/private-link/associations/aws-account/{aws_account_id}": { + "delete": { + "description": "Removes an AWS account from the project's PrivateLink configuration (targeting the primary database). Cleans up the associated AWS resources.", + "operationId": "v2-delete-private-link-association", + "parameters": [ + { + "name": "ref", + "required": true, + "in": "path", "description": "Project ref", - "example": "abcdefghijklmnopqrst" - }, - "organization_id": { - "type": "string", - "description": "Deprecated: Use `organization_slug` instead.", - "deprecated": true + "schema": { + "minLength": 20, + "maxLength": 20, + "pattern": "^[a-z]+$", + "example": "abcdefghijklmnopqrst", + "type": "string" + } }, - "organization_slug": { - "type": "string", - "pattern": "^[\\w-]+$", - "description": "Organization slug", - "example": "tsrqponmlkjihgfedcba" + { + "name": "aws_account_id", + "required": true, + "in": "path", + "description": "AWS account ID used in PrivateLink association", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "" }, - "name": { - "type": "string", - "description": "Name of your project" + "401": { + "description": "Unauthorized" }, - "region": { - "type": "string", - "description": "Region of your project" + "403": { + "description": "Forbidden action" }, - "created_at": { - "type": "string", - "description": "Creation timestamp" + "429": { + "description": "Rate limit exceeded" }, - "status": { - "type": "string", - "enum": [ - "INACTIVE", - "ACTIVE_HEALTHY", - "ACTIVE_UNHEALTHY", - "COMING_UP", - "UNKNOWN", - "GOING_DOWN", - "INIT_FAILED", - "REMOVED", - "RESTORING", - "UPGRADING", - "PAUSING", - "RESTORE_FAILED", - "RESTARTING", - "PAUSE_FAILED", - "RESIZING" - ] + "500": { + "description": "Failed to remove AWS account from PrivateLink share" } }, - "required": [ - "id", - "ref", - "organization_id", - "organization_slug", - "name", - "region", - "created_at", - "status" - ] - }, - "RegionsInfo": { - "type": "object", - "properties": { - "recommendations": { - "type": "object", - "properties": { - "smartGroup": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "code": { - "type": "string", - "enum": ["americas", "emea", "apac"] - }, - "type": { - "type": "string", - "enum": ["smartGroup"] - } + "security": [ + { + "bearer": [] + } + ], + "summary": "Remove an AWS account from the project PrivateLink share", + "tags": ["Projects"], + "x-endpoint-owners": ["platform-networking", "management-api"], + "x-fga-permissions": [["project_admin_write"]] + } + }, + "/v2/projects/{ref}/private-link/associations/aws-account/{aws_account_id}/database/{database_identifier}": { + "delete": { + "description": "Removes an AWS account from the project's PrivateLink configuration for the given read replica. Cleans up the associated AWS resources.", + "operationId": "v2-delete-private-link-association-for-database", + "parameters": [ + { + "name": "ref", + "required": true, + "in": "path", + "description": "Project ref", + "schema": { + "minLength": 20, + "maxLength": 20, + "pattern": "^[a-z]+$", + "example": "abcdefghijklmnopqrst", + "type": "string" + } + }, + { + "name": "aws_account_id", + "required": true, + "in": "path", + "description": "AWS account ID used in PrivateLink association", + "schema": { + "type": "string" + } + }, + { + "name": "database_identifier", + "required": true, + "in": "path", + "description": "Identifier of the read replica this PrivateLink association targets", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden action" + }, + "429": { + "description": "Rate limit exceeded" + }, + "500": { + "description": "Failed to remove AWS account from PrivateLink share" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Remove an AWS account from a specific database PrivateLink share", + "tags": ["Projects"], + "x-endpoint-owners": ["platform-networking", "management-api"], + "x-fga-permissions": [["project_admin_write"]] + } + }, + "/v2/organizations/{slug}/members": { + "get": { + "description": "Returns a cursor-paginated list of organization members including their roles and project-scoped permissions.", + "operationId": "v2-list-organization-members", + "parameters": [ + { + "name": "slug", + "required": true, + "in": "path", + "description": "Organization slug", + "schema": { + "pattern": "^[\\w-]+$", + "example": "tsrqponmlkjihgfedcba", + "type": "string" + } + }, + { + "name": "page", + "required": false, + "in": "query", + "schema": { + "properties": { + "size": { + "type": "integer", + "minimum": 1, + "maximum": 100 }, - "required": ["name", "code", "type"] - }, - "specific": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "code": { - "type": "string", - "enum": [ - "us-east-1", - "us-east-2", - "us-west-1", - "us-west-2", - "ap-southeast-1", - "ap-northeast-1", - "ap-northeast-2", - "ap-east-1", - "ap-southeast-2", - "eu-west-1", - "eu-west-2", - "eu-west-3", - "eu-north-1", - "eu-central-1", - "eu-central-2", - "ca-central-1", - "ap-south-1", - "sa-east-1" - ] - }, - "type": { - "type": "string", - "enum": ["specific"] - }, - "provider": { - "type": "string", - "enum": ["AWS", "AWS_K8S", "AWS_NIMBUS"] - }, - "status": { - "type": "string", - "enum": ["capacity", "other"] - } - }, - "required": ["name", "code", "type", "provider"] + "after": { + "type": "string", + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" + }, + "before": { + "type": "string", + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" } - } + }, + "type": "object" }, - "required": ["smartGroup", "specific"] + "style": "deepObject" }, - "all": { - "type": "object", - "properties": { - "smartGroup": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "code": { - "type": "string", - "enum": ["americas", "emea", "apac"] - }, - "type": { - "type": "string", - "enum": ["smartGroup"] - } - }, - "required": ["name", "code", "type"] + { + "name": "filter", + "required": false, + "in": "query", + "schema": { + "properties": { + "username": { + "type": "string" + }, + "primary_email": { + "type": "string", + "format": "email", + "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" } }, - "specific": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "code": { - "type": "string", - "enum": [ - "us-east-1", - "us-east-2", - "us-west-1", - "us-west-2", - "ap-southeast-1", - "ap-northeast-1", - "ap-northeast-2", - "ap-east-1", - "ap-southeast-2", - "eu-west-1", - "eu-west-2", - "eu-west-3", - "eu-north-1", - "eu-central-1", - "eu-central-2", - "ca-central-1", - "ap-south-1", - "sa-east-1" - ] - }, - "type": { - "type": "string", - "enum": ["specific"] - }, - "provider": { - "type": "string", - "enum": ["AWS", "AWS_K8S", "AWS_NIMBUS"] - }, - "status": { - "type": "string", - "enum": ["capacity", "other"] - } - }, - "required": ["name", "code", "type", "provider"] + "type": "object" + }, + "style": "deepObject" + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V2ListMembersResponse" } } - }, - "required": ["smartGroup", "specific"] + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden action" + }, + "429": { + "description": "Rate limit exceeded" } }, - "required": ["recommendations", "all"] - }, - "OrganizationResponseV1": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Deprecated: Use `slug` instead.", - "deprecated": true - }, - "slug": { - "type": "string", - "pattern": "^[\\w-]+$", + "security": [ + { + "bearer": [] + } + ], + "summary": "List members of an organization", + "tags": ["Organizations"], + "x-badges": [ + { + "name": "OAuth scope: organizations:read", + "position": "after" + } + ], + "x-endpoint-owners": ["management-api"], + "x-fga-permissions": [["members_read"]], + "x-oauth-scope": "organizations:read" + } + }, + "/v2/organizations/{slug}/members/{user_id}/roles": { + "patch": { + "description": "Assigns an org-wide role when projects is omitted, or creates a project-scoped assignment when projects is provided. Uses an org-level role template id from GET /v2/organizations/{slug}/roles. Stale role assignments are automatically cleaned up: if a role no longer has any projects, it is deleted; overlapping project assignments in other roles are automatically removed to avoid duplication.", + "operationId": "v2-assign-organization-member-role", + "parameters": [ + { + "name": "slug", + "required": true, + "in": "path", "description": "Organization slug", - "example": "tsrqponmlkjihgfedcba" + "schema": { + "pattern": "^[\\w-]+$", + "example": "tsrqponmlkjihgfedcba", + "type": "string" + } }, - "name": { - "type": "string" + { + "name": "user_id", + "required": true, + "in": "path", + "schema": { + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", + "type": "string" + } } - }, - "required": ["id", "slug", "name"] - }, - "CreateOrganizationV1": { - "type": "object", - "properties": { - "name": { - "type": "string", - "maxLength": 256 + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V2AssignOrganizationMemberRoleRequest" + } + } } }, - "required": ["name"], - "example": { - "name": "Acme" - }, - "additionalProperties": false - }, - "OAuthTokenBody": { - "type": "object", - "properties": { - "grant_type": { - "type": "string", - "enum": [ - "authorization_code", - "refresh_token", - "urn:ietf:params:oauth:grant-type:jwt-bearer" - ] - }, - "client_id": { - "type": "string", - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - }, - "client_secret": { - "type": "string" - }, - "code": { - "type": "string" - }, - "code_verifier": { - "type": "string" + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrganizationMemberRoleResponse" + } + } + } }, - "redirect_uri": { - "type": "string" + "401": { + "description": "Unauthorized" }, - "refresh_token": { - "type": "string" + "402": { + "description": "This feature requires the Enterprise organization plan.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlanGateErrorBodyV2" + } + } + } }, - "assertion": { - "description": "IDJAG assertion JWT for grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer. Beta - available on Team and Enterprise plans only.", - "type": "string" + "403": { + "description": "Forbidden action" }, - "resource": { - "description": "Resource indicator for MCP (Model Context Protocol) clients", - "type": "string", - "format": "uri" + "429": { + "description": "Rate limit exceeded" }, - "scope": { - "type": "string" + "500": { + "description": "Failed to assign organization member role" } }, - "example": { - "grant_type": "authorization_code", - "client_id": "66666666-6666-4666-8666-666666666666", - "client_secret": "sb_secret_live_example_9f4d3a206b2e4a7e8c91", - "code": "oauth_code_9f4d3a206b2e4a7e8c91", - "code_verifier": "qW0Z6d9pQnW0mL1dK1q9wFq6Yz2nV5rA8jT3mP7sH4c", - "redirect_uri": "https://app.acme.com/auth/callback", - "scope": "projects:read projects:write" - }, - "additionalProperties": false - }, - "OAuthTokenResponse": { - "type": "object", - "properties": { - "access_token": { - "type": "string" + "security": [ + { + "bearer": [] + } + ], + "summary": "Assign or change an organization member role", + "tags": ["Organizations"], + "x-allowed-plans": ["Enterprise"], + "x-badges": [ + { + "name": "Only available on Enterprise", + "position": "before" + } + ], + "x-endpoint-owners": ["management-api"], + "x-fga-permissions": [["organization_admin_write"]] + } + }, + "/v2/organizations/{slug}/roles": { + "get": { + "description": "Returns a list of org-level roles for the organization.", + "operationId": "v2-list-organization-roles", + "parameters": [ + { + "name": "slug", + "required": true, + "in": "path", + "description": "Organization slug", + "schema": { + "pattern": "^[\\w-]+$", + "example": "tsrqponmlkjihgfedcba", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V2ListRolesResponse" + } + } + } }, - "refresh_token": { - "description": "The `urn:ietf:params:oauth:grant-type:jwt-bearer` grant type issues access tokens only, no refresh token is returned and the token cannot be revoked via `/v1/oauth/revoke`.", - "type": "string" + "401": { + "description": "Unauthorized" }, - "expires_in": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 + "403": { + "description": "Forbidden action" }, - "token_type": { - "type": "string", - "enum": ["Bearer"] + "429": { + "description": "Rate limit exceeded" } }, - "required": ["access_token", "expires_in", "token_type"], - "additionalProperties": false - }, - "OAuthRevokeTokenBody": { - "type": "object", - "properties": { - "client_id": { - "type": "string", - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - }, - "client_secret": { - "type": "string" - }, - "refresh_token": { - "type": "string" + "security": [ + { + "bearer": [] } - }, - "required": ["client_id", "client_secret", "refresh_token"], - "example": { - "client_id": "66666666-6666-4666-8666-666666666666", - "client_secret": "sb_secret_live_example_9f4d3a206b2e4a7e8c91", - "refresh_token": "oauth_refresh_9f4d3a206b2e4a7e8c91" - }, - "additionalProperties": false - }, - "SnippetList": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "inserted_at": { - "type": "string" - }, - "updated_at": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["sql"] - }, - "visibility": { - "type": "string", - "enum": ["user", "project", "org", "public"] - }, - "name": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "project": { - "type": "object", - "properties": { - "id": { - "type": "number" - }, - "name": { - "type": "string" - } - }, - "required": ["id", "name"] - }, - "owner": { - "type": "object", - "properties": { - "id": { - "type": "number" - }, - "username": { - "type": "string" - } - }, - "required": ["id", "username"] - }, - "updated_by": { - "type": "object", - "properties": { - "id": { - "type": "number" - }, - "username": { - "type": "string" - } - }, - "required": ["id", "username"] - }, - "favorite": { - "type": "boolean" - } - }, - "required": [ - "id", - "inserted_at", - "updated_at", - "type", - "visibility", - "name", - "description", - "project", - "owner", - "updated_by", - "favorite" - ] + ], + "summary": "List roles of an organization", + "tags": ["Organizations"], + "x-badges": [ + { + "name": "OAuth scope: organizations:read", + "position": "after" + } + ], + "x-endpoint-owners": ["management-api"], + "x-fga-permissions": [["members_read"]], + "x-oauth-scope": "organizations:read" + } + }, + "/v2/organizations/{slug}/members/invitations": { + "post": { + "description": "Creates member invitations for an organization. Each invitation can have different role and project scope settings.", + "operationId": "v2-create-organization-invitations", + "parameters": [ + { + "name": "slug", + "required": true, + "in": "path", + "description": "Organization slug", + "schema": { + "pattern": "^[\\w-]+$", + "example": "tsrqponmlkjihgfedcba", + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V2CreateInvitationsRequest" + } } - }, - "cursor": { - "type": "string" } }, - "required": ["data"] - }, - "SnippetResponse": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "inserted_at": { - "type": "string" - }, - "updated_at": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["sql"] - }, - "visibility": { - "type": "string", - "enum": ["user", "project", "org", "public"] - }, - "name": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "project": { - "type": "object", - "properties": { - "id": { - "type": "number" - }, - "name": { - "type": "string" + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V2CreateInvitationsResponse" + } } - }, - "required": ["id", "name"] + } }, - "owner": { - "type": "object", - "properties": { - "id": { - "type": "number" - }, - "username": { - "type": "string" - } - }, - "required": ["id", "username"] + "401": { + "description": "Unauthorized" }, - "updated_by": { - "type": "object", - "properties": { - "id": { - "type": "number" - }, - "username": { - "type": "string" + "402": { + "description": "This feature requires the Enterprise organization plan.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlanGateErrorBodyV2" + } } - }, - "required": ["id", "username"] + } }, - "favorite": { - "type": "boolean" + "403": { + "description": "Forbidden action" }, - "content": { - "type": "object", - "properties": { - "favorite": { - "deprecated": true, - "description": "Deprecated: Rely on root-level favorite property instead.", - "type": "boolean" - }, - "schema_version": { - "type": "string" - }, - "sql": { - "type": "string" - } - }, - "required": ["schema_version", "sql"] + "429": { + "description": "Rate limit exceeded" } }, - "required": [ - "id", - "inserted_at", - "updated_at", - "type", - "visibility", - "name", - "description", - "project", - "owner", - "updated_by", - "favorite", - "content" - ] - }, - "V1ProfileResponse": { - "type": "object", - "properties": { - "gotrue_id": { - "type": "string" - }, - "primary_email": { - "type": "string" + "security": [ + { + "bearer": [] + } + ], + "summary": "Creates organization invitations", + "tags": ["Organizations Members Invitations"], + "x-allowed-plans": ["Enterprise"], + "x-badges": [ + { + "name": "OAuth scope: organizations:write", + "position": "after" }, - "username": { - "type": "string" + { + "name": "Only available on Enterprise", + "position": "before" } - }, - "required": ["gotrue_id", "primary_email", "username"] + ], + "x-endpoint-owners": ["management-api"], + "x-fga-permissions": [["members_write"]], + "x-oauth-scope": "organizations:write" }, - "ListActionRunResponse": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "branch_id": { - "type": "string" - }, - "run_steps": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "enum": ["clone", "pull", "health", "configure", "migrate", "seed", "deploy"] - }, - "status": { - "type": "string", - "enum": [ - "CREATED", - "DEAD", - "EXITED", - "PAUSED", - "REMOVING", - "RESTARTING", - "RUNNING" - ] - }, - "created_at": { - "type": "string" - }, - "updated_at": { - "type": "string" - } - }, - "required": ["name", "status", "created_at", "updated_at"] - } - }, - "git_config": { - "nullable": true - }, - "workdir": { - "type": "string", - "nullable": true - }, - "check_run_id": { - "type": "number", - "nullable": true - }, - "created_at": { - "type": "string" - }, - "updated_at": { + "delete": { + "description": "Bulk delete member invitations for an organization by email address.", + "operationId": "v2-delete-organization-invitations", + "parameters": [ + { + "name": "slug", + "required": true, + "in": "path", + "description": "Organization slug", + "schema": { + "pattern": "^[\\w-]+$", + "example": "tsrqponmlkjihgfedcba", "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V2DeleteInvitationsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V2DeleteInvitationsResponse" + } + } + } }, - "required": [ - "id", - "branch_id", - "run_steps", - "workdir", - "check_run_id", - "created_at", - "updated_at" - ] - } - }, - "ActionRunResponse": { - "type": "object", - "properties": { - "id": { - "type": "string" + "401": { + "description": "Unauthorized" }, - "branch_id": { - "type": "string" + "402": { + "description": "This feature requires the Enterprise organization plan.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlanGateErrorBodyV2" + } + } + } }, - "run_steps": { - "type": "array", - "items": { - "type": "object", + "403": { + "description": "Forbidden action" + }, + "429": { + "description": "Rate limit exceeded" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Deletes organization invitations by email", + "tags": ["Organizations Members Invitations"], + "x-allowed-plans": ["Enterprise"], + "x-badges": [ + { + "name": "OAuth scope: organizations:write", + "position": "after" + }, + { + "name": "Only available on Enterprise", + "position": "before" + } + ], + "x-endpoint-owners": ["management-api"], + "x-fga-permissions": [["members_write"]], + "x-oauth-scope": "organizations:write" + } + }, + "/v2/organizations/{slug}/projects": { + "get": { + "description": "Returns a cursor-paginated list of projects for the specified organization, including their databases.\n\nUse `page[after]` and `page[before]` to navigate pages and `page[size]` to control the number of projects returned per page.", + "operationId": "v2-list-organization-projects", + "parameters": [ + { + "name": "slug", + "required": true, + "in": "path", + "description": "Organization slug", + "schema": { + "pattern": "^[\\w-]+$", + "example": "tsrqponmlkjihgfedcba", + "type": "string" + } + }, + { + "name": "page", + "required": false, + "in": "query", + "schema": { "properties": { - "name": { - "type": "string", - "enum": ["clone", "pull", "health", "configure", "migrate", "seed", "deploy"] + "size": { + "type": "integer", + "minimum": 1, + "maximum": 100 }, - "status": { + "after": { "type": "string", - "enum": [ - "CREATED", - "DEAD", - "EXITED", - "PAUSED", - "REMOVING", - "RESTARTING", - "RUNNING" - ] - }, - "created_at": { - "type": "string" + "minLength": 1 }, - "updated_at": { - "type": "string" + "before": { + "type": "string", + "minLength": 1 } }, - "required": ["name", "status", "created_at", "updated_at"] - } - }, - "git_config": { - "nullable": true - }, - "workdir": { - "type": "string", - "nullable": true - }, - "check_run_id": { - "type": "number", - "nullable": true + "type": "object" + }, + "style": "deepObject" }, - "created_at": { - "type": "string" + { + "name": "sort", + "required": false, + "in": "query", + "description": "Sort order by creation time: `inserted_at` (oldest first) or `-inserted_at` (newest first). Defaults to `inserted_at`.", + "schema": { + "example": "-inserted_at", + "type": "string", + "enum": ["inserted_at", "-inserted_at"] + } }, - "updated_at": { - "type": "string" + { + "name": "search", + "required": false, + "in": "query", + "description": "Case-insensitive substring match on the project name.", + "schema": { + "minLength": 1, + "type": "string" + } } - }, - "required": [ - "id", - "branch_id", - "run_steps", - "workdir", - "check_run_id", - "created_at", - "updated_at" - ] - }, - "UpdateRunStatusBody": { - "type": "object", - "properties": { - "clone": { - "type": "string", - "enum": ["CREATED", "DEAD", "EXITED", "PAUSED", "REMOVING", "RESTARTING", "RUNNING"] - }, - "pull": { - "type": "string", - "enum": ["CREATED", "DEAD", "EXITED", "PAUSED", "REMOVING", "RESTARTING", "RUNNING"] - }, - "health": { - "type": "string", - "enum": ["CREATED", "DEAD", "EXITED", "PAUSED", "REMOVING", "RESTARTING", "RUNNING"] - }, - "configure": { - "type": "string", - "enum": ["CREATED", "DEAD", "EXITED", "PAUSED", "REMOVING", "RESTARTING", "RUNNING"] + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V2ListProjectsResponse" + } + } + } }, - "migrate": { - "type": "string", - "enum": ["CREATED", "DEAD", "EXITED", "PAUSED", "REMOVING", "RESTARTING", "RUNNING"] + "401": { + "description": "Unauthorized" }, - "seed": { - "type": "string", - "enum": ["CREATED", "DEAD", "EXITED", "PAUSED", "REMOVING", "RESTARTING", "RUNNING"] + "403": { + "description": "Forbidden action" }, - "deploy": { - "type": "string", - "enum": ["CREATED", "DEAD", "EXITED", "PAUSED", "REMOVING", "RESTARTING", "RUNNING"] + "429": { + "description": "Rate limit exceeded" } }, - "example": { - "clone": "RUNNING", - "configure": "RUNNING", - "migrate": "RUNNING", - "deploy": "CREATED" - } - }, - "UpdateRunStatusResponse": { - "type": "object", - "properties": { - "message": { - "type": "string", - "enum": ["ok"] + "security": [ + { + "bearer": [] + } + ], + "summary": "List projects of an organization", + "tags": ["Organizations"], + "x-badges": [ + { + "name": "OAuth scope: projects:read", + "position": "after" + } + ], + "x-endpoint-owners": ["management-api"], + "x-fga-permissions": [["organization_projects_read"]], + "x-oauth-scope": "projects:read" + } + }, + "/v2/organizations/{slug}/integrations/github/connections": { + "get": { + "description": "Returns a cursor-paginated list of the GitHub connections of the organization's projects.\n\nUse `page[after]` and `page[before]` to navigate pages and `page[size]` to control the page size.\nPaging walks the organization projects, so a page holds at most `page[size]` connections and can hold fewer (or none) when some of its projects are not connected.\nFollow `links.next` until it is `null` rather than stopping on a short page.\n\nUse `filter[project_ref]` to narrow the list down to a single project.", + "operationId": "v2-list-organization-github-connections", + "parameters": [ + { + "name": "slug", + "required": true, + "in": "path", + "description": "Organization slug", + "schema": { + "pattern": "^[\\w-]+$", + "example": "tsrqponmlkjihgfedcba", + "type": "string" + } + }, + { + "name": "page", + "required": false, + "in": "query", + "schema": { + "properties": { + "size": { + "type": "integer", + "minimum": 1, + "maximum": 100 + }, + "after": { + "type": "string", + "minLength": 20, + "maxLength": 20, + "pattern": "^[a-z]+$", + "description": "Project ref", + "example": "abcdefghijklmnopqrst" + }, + "before": { + "type": "string", + "minLength": 20, + "maxLength": 20, + "pattern": "^[a-z]+$", + "description": "Project ref", + "example": "abcdefghijklmnopqrst" + } + }, + "type": "object" + }, + "style": "deepObject" + }, + { + "name": "filter", + "required": false, + "in": "query", + "schema": { + "properties": { + "project_ref": { + "type": "string", + "minLength": 20, + "maxLength": 20, + "pattern": "^[a-z]+$", + "description": "Project ref", + "example": "abcdefghijklmnopqrst" + } + }, + "type": "object" + }, + "style": "deepObject" + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V2ListGitHubConnectionsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden action" + }, + "429": { + "description": "Rate limit exceeded" } }, - "required": ["message"] - }, - "ApiKeyResponse": { + "security": [ + { + "bearer": [] + } + ], + "summary": "List GitHub connections of an organization", + "tags": ["Organizations"], + "x-badges": [ + { + "name": "OAuth scope: projects:read", + "position": "after" + } + ], + "x-endpoint-owners": ["management-api", "dev-workflows"], + "x-fga-permissions": [["organization_projects_read"]], + "x-oauth-scope": "projects:read" + } + } + }, + "components": { + "schemas": { + "BranchDetailResponse": { "type": "object", "properties": { - "api_key": { - "type": "string", - "nullable": true - }, - "id": { - "type": "string", - "nullable": true + "ref": { + "type": "string" }, - "type": { - "type": "string", - "enum": ["legacy", "publishable", "secret", null], - "nullable": true + "postgres_version": { + "type": "string" }, - "prefix": { - "type": "string", - "nullable": true + "postgres_engine": { + "type": "string" }, - "name": { + "release_channel": { "type": "string" }, - "description": { + "status": { "type": "string", - "nullable": true + "enum": [ + "INACTIVE", + "ACTIVE_HEALTHY", + "ACTIVE_UNHEALTHY", + "COMING_UP", + "UNKNOWN", + "GOING_DOWN", + "INIT_FAILED", + "REMOVED", + "RESTORING", + "UPGRADING", + "PAUSING", + "RESTORE_FAILED", + "RESTARTING", + "PAUSE_FAILED", + "RESIZING" + ] }, - "hash": { - "type": "string", - "nullable": true + "db_host": { + "type": "string" }, - "secret_jwt_template": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {}, - "nullable": true + "db_port": { + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991, + "minimum": 0 }, - "inserted_at": { - "type": "string", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", - "nullable": true + "db_user": { + "type": "string" }, - "updated_at": { - "type": "string", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", - "nullable": true + "db_pass": { + "type": "string" + }, + "jwt_secret": { + "type": "string" } }, - "required": ["name"] + "required": [ + "ref", + "postgres_version", + "postgres_engine", + "release_channel", + "status", + "db_host", + "db_port" + ] }, - "LegacyApiKeysResponse": { + "UpdateBranchBody": { "type": "object", "properties": { - "enabled": { + "branch_name": { + "type": "string" + }, + "git_branch": { + "type": "string" + }, + "reset_on_push": { + "description": "This field is deprecated and will be ignored. Use v1-reset-a-branch endpoint directly instead.", + "deprecated": true, + "type": "boolean" + }, + "persistent": { + "type": "boolean" + }, + "status": { + "type": "string", + "enum": [ + "CREATING_PROJECT", + "RUNNING_MIGRATIONS", + "MIGRATIONS_PASSED", + "MIGRATIONS_FAILED", + "FUNCTIONS_DEPLOYED", + "FUNCTIONS_FAILED" + ] + }, + "request_review": { "type": "boolean" + }, + "notify_url": { + "type": "string", + "format": "uri", + "description": "HTTP endpoint to receive branch status updates." } }, - "required": ["enabled"] + "example": { + "branch_name": "preview-login-page", + "git_branch": "feature/login-page", + "persistent": true, + "request_review": true, + "notify_url": "https://example.com/webhooks/branches" + } }, - "CreateApiKeyBody": { + "BranchResponse": { "type": "object", "properties": { - "type": { + "id": { "type": "string", - "enum": ["publishable", "secret"] - }, - "name": { - "type": "string", - "minLength": 4, - "maxLength": 64, - "pattern": "^[a-z_][a-z0-9_]+$" - }, - "description": { - "type": "string", - "nullable": true + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, - "secret_jwt_template": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {}, - "nullable": true - } - }, - "required": ["type", "name"], - "example": { - "type": "secret", - "name": "ci_secret_key", - "description": "CI deploy key" - } - }, - "UpdateApiKeyBody": { - "type": "object", - "properties": { "name": { - "type": "string", - "minLength": 4, - "maxLength": 64, - "pattern": "^[a-z_][a-z0-9_]+$" - }, - "description": { - "type": "string", - "nullable": true + "type": "string" }, - "secret_jwt_template": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {}, - "nullable": true - } - }, - "example": { - "name": "ci_secret_key_rotated", - "description": "Rotated after March release" - } - }, - "CreateBranchBody": { - "type": "object", - "properties": { - "branch_name": { - "type": "string", - "minLength": 1 + "project_ref": { + "type": "string" }, - "git_branch": { + "parent_project_ref": { "type": "string" }, "is_default": { "type": "boolean" }, + "git_branch": { + "type": "string" + }, + "pr_number": { + "type": "integer", + "format": "int32", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "latest_check_run_id": { + "description": "This field is deprecated and will not be populated.", + "deprecated": true, + "type": "number" + }, "persistent": { "type": "boolean" }, - "region": { - "type": "string" - }, - "desired_instance_size": { + "status": { "type": "string", "enum": [ - "pico", - "nano", - "micro", - "small", - "medium", - "large", - "xlarge", - "2xlarge", - "4xlarge", - "8xlarge", - "12xlarge", - "16xlarge", - "24xlarge", - "24xlarge_optimized_memory", - "24xlarge_optimized_cpu", - "24xlarge_high_memory", - "48xlarge", - "48xlarge_optimized_memory", - "48xlarge_optimized_cpu", - "48xlarge_high_memory" - ] + "CREATING_PROJECT", + "RUNNING_MIGRATIONS", + "MIGRATIONS_PASSED", + "MIGRATIONS_FAILED", + "FUNCTIONS_DEPLOYED", + "FUNCTIONS_FAILED" + ], + "description": "This field is deprecated. List action runs to get branch status instead.", + "deprecated": true }, - "release_channel": { + "created_at": { "type": "string", - "enum": ["internal", "alpha", "beta", "ga", "withdrawn", "preview"], - "description": "Release channel. If not provided, GA will be used." + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, - "postgres_engine": { + "updated_at": { "type": "string", - "enum": ["15", "17", "17-oriole"], - "description": "Postgres engine version. If not provided, the latest version will be used." + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, - "secrets": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "review_requested_at": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "with_data": { "type": "boolean" }, "notify_url": { "type": "string", - "format": "uri", - "description": "HTTP endpoint to receive branch status updates." + "format": "uri" + }, + "deletion_scheduled_at": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + }, + "preview_project_status": { + "type": "string", + "enum": [ + "INACTIVE", + "ACTIVE_HEALTHY", + "ACTIVE_UNHEALTHY", + "COMING_UP", + "UNKNOWN", + "GOING_DOWN", + "INIT_FAILED", + "REMOVED", + "RESTORING", + "UPGRADING", + "PAUSING", + "RESTORE_FAILED", + "RESTARTING", + "PAUSE_FAILED", + "RESIZING" + ] + } + }, + "required": [ + "id", + "name", + "project_ref", + "parent_project_ref", + "is_default", + "persistent", + "status", + "created_at", + "updated_at", + "with_data" + ] + }, + "BranchDeleteResponse": { + "type": "object", + "properties": { + "message": { + "type": "string", + "enum": ["ok"] + } + }, + "required": ["message"] + }, + "BranchActionBody": { + "type": "object", + "properties": { + "migration_version": { + "type": "string" } }, - "required": ["branch_name"], "example": { - "branch_name": "preview-login-page", - "git_branch": "feature/login-page", - "persistent": true, - "with_data": false, - "notify_url": "https://example.com/webhooks/branches" + "migration_version": "20250312000000" } }, - "UpdateCustomHostnameResponseJsonValue": { - "description": "Any JSON-serializable value", - "anyOf": [ - { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "boolean" - } - ], - "nullable": true - }, - { - "type": "array", - "items": { - "$ref": "#/components/schemas/UpdateCustomHostnameResponseJsonValue" - } + "BranchUpdateResponse": { + "type": "object", + "properties": { + "workflow_run_id": { + "type": "string" }, - { - "type": "object", - "additionalProperties": { - "$ref": "#/components/schemas/UpdateCustomHostnameResponseJsonValue" - } + "message": { + "type": "string", + "enum": ["ok"] } - ] + }, + "required": ["workflow_run_id", "message"] }, - "UpdateCustomHostnameResponse": { + "BranchRestoreResponse": { "type": "object", "properties": { - "status": { + "message": { "type": "string", - "enum": [ - "1_not_started", - "2_initiated", - "3_challenge_verified", - "4_origin_setup_completed", - "5_services_reconfigured" - ] - }, - "custom_hostname": { - "type": "string" - }, - "data": { - "type": "object", - "properties": { - "success": { - "type": "boolean" - }, - "errors": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UpdateCustomHostnameResponseJsonValue" - } - }, - "messages": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UpdateCustomHostnameResponseJsonValue" - } - }, - "result": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "hostname": { - "type": "string" - }, - "ssl": { - "type": "object", - "properties": { - "status": { - "type": "string" - }, - "validation_records": { - "type": "array", - "items": { - "type": "object", - "properties": { - "txt_name": { - "type": "string" - }, - "txt_value": { - "type": "string" - } - }, - "required": ["txt_name", "txt_value"] - } - }, - "validation_errors": { - "type": "array", - "items": { - "type": "object", - "properties": { - "message": { - "type": "string" - } - }, - "required": ["message"] - } - } - }, - "required": ["status"] - }, - "ownership_verification": { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "name": { - "type": "string" - }, - "value": { - "type": "string" - } - }, - "required": ["type", "name", "value"] - }, - "custom_origin_server": { - "type": "string" - }, - "verification_errors": { - "type": "array", - "items": { - "type": "string" - } - }, - "status": { - "type": "string" - } - }, - "required": ["id", "hostname", "ssl", "custom_origin_server", "status"] - } - }, - "required": ["success", "errors", "messages", "result"] - } - }, - "required": ["data"] - }, - "UpdateCustomHostnameBody": { - "type": "object", - "properties": { - "custom_hostname": { - "type": "string", - "minLength": 1, - "maxLength": 253 + "enum": ["Branch restoration initiated"] } }, - "required": ["custom_hostname"], - "example": { - "custom_hostname": "docs.example.com" - } + "required": ["message"] }, - "JitAccessRequestRequest": { + "V1ProjectWithDatabaseResponse": { "type": "object", "properties": { - "state": { + "id": { "type": "string", - "enum": ["enabled", "disabled"] - } - }, - "required": ["state"], - "example": { - "state": "enabled" - } - }, - "NetworkBanResponse": { - "type": "object", - "properties": { - "banned_ipv4_addresses": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": ["banned_ipv4_addresses"] - }, - "NetworkBanResponseEnriched": { - "type": "object", - "properties": { - "banned_ipv4_addresses": { - "type": "array", - "items": { - "type": "object", - "properties": { - "banned_address": { - "type": "string" - }, - "identifier": { - "type": "string" - }, - "type": { - "type": "string" - } - }, - "required": ["banned_address", "identifier", "type"] - } - } - }, - "required": ["banned_ipv4_addresses"] - }, - "RemoveNetworkBanRequest": { - "type": "object", - "properties": { - "ipv4_addresses": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of IP addresses to unban." + "deprecated": true, + "description": "Deprecated: Use `ref` instead." }, - "requester_ip": { - "default": false, - "description": "Include requester's public IP in the list of addresses to unban.", - "type": "boolean" + "ref": { + "type": "string", + "minLength": 20, + "maxLength": 20, + "pattern": "^[a-z]+$", + "description": "Project ref", + "example": "abcdefghijklmnopqrst" }, - "identifier": { - "type": "string" - } - }, - "required": ["ipv4_addresses"], - "example": { - "ipv4_addresses": ["203.0.113.10"], - "requester_ip": false - } - }, - "NetworkRestrictionsResponse": { - "type": "object", - "properties": { - "entitlement": { + "organization_id": { "type": "string", - "enum": ["disallowed", "allowed"] + "description": "Deprecated: Use `organization_slug` instead.", + "deprecated": true }, - "config": { - "type": "object", - "properties": { - "dbAllowedCidrs": { - "type": "array", - "items": { - "type": "string" - } - }, - "dbAllowedCidrsV6": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "dbAllowedCidrs": ["203.0.113.0/24"], - "dbAllowedCidrsV6": ["2001:db8::/32"] - }, - "description": "At any given point in time, this is the config that the user has requested be applied to their project. The `status` field indicates if it has been applied to the project, or is pending. When an updated config is received, the applied config is moved to `old_config`." + "organization_slug": { + "type": "string", + "pattern": "^[\\w-]+$", + "description": "Organization slug", + "example": "tsrqponmlkjihgfedcba" }, - "old_config": { - "description": "Populated when a new config has been received, but not registered as successfully applied to a project.", - "type": "object", - "properties": { - "dbAllowedCidrs": { - "type": "array", - "items": { - "type": "string" - } - }, - "dbAllowedCidrsV6": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "dbAllowedCidrs": ["203.0.113.0/24"], - "dbAllowedCidrsV6": ["2001:db8::/32"] - } + "name": { + "type": "string", + "description": "Name of your project" }, - "status": { + "region": { "type": "string", - "enum": ["stored", "applied"] + "description": "Region of your project" }, - "updated_at": { + "created_at": { "type": "string", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + "description": "Creation timestamp" }, - "applied_at": { + "status": { "type": "string", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" - } - }, - "required": ["entitlement", "config", "status"] - }, - "NetworkRestrictionsRequest": { - "type": "object", - "properties": { - "dbAllowedCidrs": { - "type": "array", - "items": { - "type": "string" - } + "enum": [ + "INACTIVE", + "ACTIVE_HEALTHY", + "ACTIVE_UNHEALTHY", + "COMING_UP", + "UNKNOWN", + "GOING_DOWN", + "INIT_FAILED", + "REMOVED", + "RESTORING", + "UPGRADING", + "PAUSING", + "RESTORE_FAILED", + "RESTARTING", + "PAUSE_FAILED", + "RESIZING" + ] }, - "dbAllowedCidrsV6": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "dbAllowedCidrs": ["203.0.113.0/24"], - "dbAllowedCidrsV6": ["2001:db8::/32"] - } - }, - "NetworkRestrictionsPatchRequest": { - "type": "object", - "properties": { - "add": { + "database": { "type": "object", "properties": { - "dbAllowedCidrs": { - "type": "array", - "items": { - "type": "string" - } + "host": { + "type": "string", + "description": "Database host" }, - "dbAllowedCidrsV6": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "remove": { - "type": "object", - "properties": { - "dbAllowedCidrs": { - "type": "array", - "items": { - "type": "string" - } + "version": { + "type": "string", + "description": "Database version" }, - "dbAllowedCidrsV6": { - "type": "array", - "items": { - "type": "string" - } + "postgres_engine": { + "type": "string", + "description": "Database engine" + }, + "release_channel": { + "type": "string", + "description": "Release channel" } - } + }, + "required": ["host", "version", "postgres_engine", "release_channel"] } }, - "example": { - "add": { - "dbAllowedCidrs": ["203.0.113.0/24"] - }, - "remove": { - "dbAllowedCidrs": ["198.51.100.0/24"] - } - } + "required": [ + "id", + "ref", + "organization_id", + "organization_slug", + "name", + "region", + "created_at", + "status", + "database" + ] }, - "NetworkRestrictionsV2Response": { + "V1CreateProjectBody": { "type": "object", "properties": { - "entitlement": { + "db_pass": { "type": "string", - "enum": ["disallowed", "allowed"] - }, - "config": { - "type": "object", - "properties": { - "dbAllowedCidrs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "address": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["v4", "v6"] - } - }, - "required": ["address", "type"] - } - } - }, - "description": "At any given point in time, this is the config that the user has requested be applied to their project. The `status` field indicates if it has been applied to the project, or is pending. When an updated config is received, the applied config is moved to `old_config`." - }, - "old_config": { - "description": "Populated when a new config has been received, but not registered as successfully applied to a project.", - "type": "object", - "properties": { - "dbAllowedCidrs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "address": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["v4", "v6"] - } - }, - "required": ["address", "type"] - } - } - } + "description": "Database password" }, - "updated_at": { + "name": { "type": "string", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + "maxLength": 256, + "description": "Name of your project" }, - "applied_at": { - "type": "string", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + "organization_id": { + "deprecated": true, + "description": "Deprecated: Use `organization_slug` instead.", + "type": "string" }, - "status": { - "type": "string", - "enum": ["stored", "applied"] - } - }, - "required": ["entitlement", "config", "status"] - }, - "PgsodiumConfigResponse": { - "type": "object", - "properties": { - "root_key": { - "type": "string", - "description": "The pgsodium root key: 32 bytes, hex-encoded (64 characters)." - } - }, - "required": ["root_key"], - "example": { - "root_key": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" - } - }, - "UpdatePgsodiumConfigBody": { - "type": "object", - "properties": { - "root_key": { + "organization_slug": { "type": "string", - "description": "The pgsodium root key: 32 bytes, hex-encoded (64 characters)." - } - }, - "required": ["root_key"], - "example": { - "root_key": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" - } - }, - "PostgrestConfigWithJWTSecretResponse": { - "type": "object", - "properties": { - "db_schema": { - "type": "string" + "pattern": "^[\\w-]+$", + "description": "Organization slug", + "example": "tsrqponmlkjihgfedcba" }, - "max_rows": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 + "plan": { + "deprecated": true, + "description": "Subscription Plan is now set on organization level and is ignored in this request", + "type": "string", + "enum": ["free", "pro"] }, - "db_extra_search_path": { + "region": { + "description": "Region you want your server to reside in. Use region_selection instead.", + "deprecated": true, + "enum": [ + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + "ap-east-1", + "ap-southeast-1", + "ap-northeast-1", + "ap-northeast-2", + "ap-southeast-2", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "eu-north-1", + "eu-central-1", + "eu-central-2", + "ca-central-1", + "ap-south-1", + "sa-east-1" + ], "type": "string" }, - "db_pool": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991, - "description": "If `null`, the value is automatically configured based on compute size.", - "nullable": true - }, - "db_pool_acquisition_timeout": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991, - "description": "If `null`, the value is automatically configured to 10.", - "nullable": true + "region_selection": { + "description": "Region selection. Only one of region or region_selection can be specified.", + "oneOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["specific"] + }, + "code": { + "type": "string", + "description": "Specific region code. The codes supported are not a stable API, and should be retrieved from the /available-regions endpoint.", + "enum": [ + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + "ap-east-1", + "ap-southeast-1", + "ap-northeast-1", + "ap-northeast-2", + "ap-southeast-2", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "eu-north-1", + "eu-central-1", + "eu-central-2", + "ca-central-1", + "ap-south-1", + "sa-east-1" + ] + } + }, + "required": ["type", "code"] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["smartGroup"] + }, + "code": { + "type": "string", + "enum": ["americas", "emea", "apac"], + "description": "The Smart Region Group's code. The codes supported are not a stable API, and should be retrieved from the /available-regions endpoint." + } + }, + "required": ["type", "code"] + } + ] }, - "jwt_secret": { - "type": "string" - } - }, - "required": [ - "db_schema", - "max_rows", - "db_extra_search_path", - "db_pool", - "db_pool_acquisition_timeout" - ] - }, - "V1UpdatePostgrestConfigBody": { - "type": "object", - "properties": { - "db_extra_search_path": { - "type": "string" + "kps_enabled": { + "deprecated": true, + "description": "This field is deprecated and is ignored in this request", + "type": "boolean" }, - "db_schema": { - "type": "string" + "desired_instance_size": { + "description": "Desired instance size. Omit this field to always default to the smallest possible size.", + "type": "string", + "enum": [ + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge", + "4xlarge", + "8xlarge", + "12xlarge", + "16xlarge", + "24xlarge", + "24xlarge_optimized_memory", + "24xlarge_optimized_cpu", + "24xlarge_high_memory", + "48xlarge", + "48xlarge_optimized_memory", + "48xlarge_optimized_cpu", + "48xlarge_high_memory" + ] }, - "max_rows": { - "type": "integer", - "minimum": 0, - "maximum": 1000000 + "template_url": { + "description": "Template URL used to create the project from the CLI.", + "type": "string", + "format": "uri" }, - "db_pool": { - "type": "integer", - "minimum": 0, - "maximum": 1000 + "release_channel": { + "deprecated": true, + "type": "null" }, - "db_pool_acquisition_timeout": { - "type": "integer", - "minimum": 0, - "maximum": 60 + "postgres_engine": { + "deprecated": true, + "type": "null" + }, + "high_availability": { + "description": "[Experimental] Whether to enable high availability for the project.", + "type": "boolean" } }, + "required": ["db_pass", "name", "organization_slug"], "example": { - "db_schema": "public,storage", - "db_pool": 20, - "max_rows": 1000 - } - }, - "V1PostgrestConfigResponse": { - "type": "object", - "properties": { - "db_schema": { - "type": "string" - }, - "max_rows": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 - }, - "db_extra_search_path": { - "type": "string" - }, - "db_pool": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991, - "description": "If `null`, the value is automatically configured based on compute size.", - "nullable": true - }, - "db_pool_acquisition_timeout": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991, - "description": "If `null`, the value is automatically configured to 10.", - "nullable": true - } + "db_pass": "correct-horse-battery-staple", + "name": "acme-prod", + "organization_slug": "tsrqponmlkjihgfedcba", + "region": "us-east-1" }, - "required": [ - "db_schema", - "max_rows", - "db_extra_search_path", - "db_pool", - "db_pool_acquisition_timeout" - ] + "additionalProperties": false }, - "V1ProjectRefResponse": { + "V1ProjectResponse": { "type": "object", "properties": { "id": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 + "type": "string", + "deprecated": true, + "description": "Deprecated: Use `ref` instead." }, "ref": { - "type": "string" + "type": "string", + "minLength": 20, + "maxLength": 20, + "pattern": "^[a-z]+$", + "description": "Project ref", + "example": "abcdefghijklmnopqrst" }, - "name": { - "type": "string" - } - }, - "required": ["id", "ref", "name"] - }, - "V1UpdateProjectBody": { - "type": "object", - "properties": { - "name": { + "organization_id": { "type": "string", - "minLength": 1, - "maxLength": 256 - } - }, - "required": ["name"], - "example": { - "name": "Acme Platform" - } - }, - "SecretResponse": { - "type": "object", - "properties": { + "description": "Deprecated: Use `organization_slug` instead.", + "deprecated": true + }, + "organization_slug": { + "type": "string", + "pattern": "^[\\w-]+$", + "description": "Organization slug", + "example": "tsrqponmlkjihgfedcba" + }, "name": { - "type": "string" + "type": "string", + "description": "Name of your project" }, - "value": { - "type": "string" + "region": { + "type": "string", + "description": "Region of your project" }, - "updated_at": { - "type": "string" + "created_at": { + "type": "string", + "description": "Creation timestamp" + }, + "status": { + "type": "string", + "enum": [ + "INACTIVE", + "ACTIVE_HEALTHY", + "ACTIVE_UNHEALTHY", + "COMING_UP", + "UNKNOWN", + "GOING_DOWN", + "INIT_FAILED", + "REMOVED", + "RESTORING", + "UPGRADING", + "PAUSING", + "RESTORE_FAILED", + "RESTARTING", + "PAUSE_FAILED", + "RESIZING" + ] } }, - "required": ["name", "value"] - }, - "CreateSecretBody": { - "maxItems": 100, - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "maxLength": 256, - "pattern": "^(?!SUPABASE_).*", - "description": "Secret name must not start with the SUPABASE_ prefix." - }, - "value": { - "type": "string", - "maxLength": 24576 - } - }, - "required": ["name", "value"] - }, - "example": [ - { - "name": "OPENAI_API_KEY", - "value": "sk-example-secret" - }, - { - "name": "STRIPE_WEBHOOK_SECRET", - "value": "whsec_example" - } + "required": [ + "id", + "ref", + "organization_id", + "organization_slug", + "name", + "region", + "created_at", + "status" ] }, - "DeleteSecretsBody": { - "type": "array", - "items": { - "type": "string" - }, - "example": ["OPENAI_API_KEY"] - }, - "SslEnforcementResponse": { + "RegionsInfo": { "type": "object", "properties": { - "currentConfig": { + "recommendations": { "type": "object", "properties": { - "database": { - "type": "boolean" + "smartGroup": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "code": { + "type": "string", + "enum": ["americas", "emea", "apac"] + }, + "type": { + "type": "string", + "enum": ["smartGroup"] + } + }, + "required": ["name", "code", "type"] + }, + "specific": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "code": { + "type": "string", + "enum": [ + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + "ap-southeast-1", + "ap-northeast-1", + "ap-northeast-2", + "ap-east-1", + "ap-southeast-2", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "eu-north-1", + "eu-central-1", + "eu-central-2", + "ca-central-1", + "ap-south-1", + "sa-east-1" + ] + }, + "type": { + "type": "string", + "enum": ["specific"] + }, + "provider": { + "type": "string", + "enum": ["AWS", "AWS_K8S", "AWS_NIMBUS"] + }, + "status": { + "type": "string", + "enum": ["capacity", "other"] + } + }, + "required": ["name", "code", "type", "provider"] + } } }, - "required": ["database"] + "required": ["smartGroup", "specific"] }, - "appliedSuccessfully": { - "type": "boolean" - } - }, - "required": ["currentConfig", "appliedSuccessfully"] - }, - "SslEnforcementRequest": { - "type": "object", - "properties": { - "requestedConfig": { + "all": { "type": "object", "properties": { - "database": { - "type": "boolean" + "smartGroup": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "code": { + "type": "string", + "enum": ["americas", "emea", "apac"] + }, + "type": { + "type": "string", + "enum": ["smartGroup"] + } + }, + "required": ["name", "code", "type"] + } + }, + "specific": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "code": { + "type": "string", + "enum": [ + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + "ap-southeast-1", + "ap-northeast-1", + "ap-northeast-2", + "ap-east-1", + "ap-southeast-2", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "eu-north-1", + "eu-central-1", + "eu-central-2", + "ca-central-1", + "ap-south-1", + "sa-east-1" + ] + }, + "type": { + "type": "string", + "enum": ["specific"] + }, + "provider": { + "type": "string", + "enum": ["AWS", "AWS_K8S", "AWS_NIMBUS"] + }, + "status": { + "type": "string", + "enum": ["capacity", "other"] + } + }, + "required": ["name", "code", "type", "provider"] + } } }, - "required": ["database"] + "required": ["smartGroup", "specific"] } }, - "required": ["requestedConfig"], - "example": { - "requestedConfig": { - "database": true - } - } + "required": ["recommendations", "all"] }, - "TypescriptResponse": { + "OrganizationResponseV1": { "type": "object", "properties": { - "types": { + "id": { + "type": "string", + "description": "Deprecated: Use `slug` instead.", + "deprecated": true + }, + "slug": { + "type": "string", + "pattern": "^[\\w-]+$", + "description": "Organization slug", + "example": "tsrqponmlkjihgfedcba" + }, + "name": { "type": "string" } }, - "required": ["types"] + "required": ["id", "slug", "name"] }, - "VanitySubdomainConfigResponse": { + "CreateOrganizationV1": { "type": "object", "properties": { - "status": { - "type": "string", - "enum": ["not-used", "custom-domain-used", "active"] - }, - "custom_domain": { + "name": { "type": "string", - "minLength": 1 + "maxLength": 256 } }, - "required": ["status"] + "required": ["name"], + "example": { + "name": "Acme" + }, + "additionalProperties": false }, - "PlanGateErrorBody": { + "OAuthTokenBody": { "type": "object", "properties": { - "message": { + "grant_type": { "type": "string", - "description": "Human-readable explanation of the plan gate" + "enum": [ + "authorization_code", + "refresh_token", + "urn:ietf:params:oauth:grant-type:jwt-bearer" + ] }, - "error": { - "description": "Present on entitlement denials. Other errors with this status code (validation, billing state) carry only message.", - "type": "object", - "properties": { - "code": { - "type": "string", - "description": "Machine-readable marker for plan-gated denials", - "enum": ["entitlement_required"] - }, - "feature": { - "type": "string", - "description": "Entitlement feature key that failed the check" - }, - "upgrade_url": { - "description": "Billing page URL for the organization, present when the org is resolvable", - "type": "string" - } - }, - "required": ["code", "feature"] - } - }, - "required": ["message"] - }, - "VanitySubdomainBody": { - "type": "object", - "properties": { - "vanity_subdomain": { + "client_id": { "type": "string", - "maxLength": 63 + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" + }, + "client_secret": { + "type": "string" + }, + "code": { + "type": "string" + }, + "code_verifier": { + "type": "string" + }, + "redirect_uri": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "assertion": { + "description": "IDJAG assertion JWT for grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer. Beta - available on Team and Enterprise plans only.", + "type": "string" + }, + "resource": { + "description": "Resource indicator for MCP (Model Context Protocol) clients", + "type": "string", + "format": "uri" + }, + "scope": { + "type": "string" } }, - "required": ["vanity_subdomain"], "example": { - "vanity_subdomain": "acme-prod" - } - }, - "SubdomainAvailabilityResponse": { - "type": "object", - "properties": { - "available": { - "type": "boolean" - } + "grant_type": "authorization_code", + "client_id": "66666666-6666-4666-8666-666666666666", + "client_secret": "sb_secret_live_example_9f4d3a206b2e4a7e8c91", + "code": "oauth_code_9f4d3a206b2e4a7e8c91", + "code_verifier": "qW0Z6d9pQnW0mL1dK1q9wFq6Yz2nV5rA8jT3mP7sH4c", + "redirect_uri": "https://app.acme.com/auth/callback", + "scope": "projects:read projects:write" }, - "required": ["available"] + "additionalProperties": false }, - "ActivateVanitySubdomainResponse": { + "OAuthTokenResponse": { "type": "object", "properties": { - "custom_domain": { + "access_token": { "type": "string" - } - }, - "required": ["custom_domain"] - }, - "UpgradeDatabaseBody": { - "type": "object", - "properties": { - "target_version": { + }, + "refresh_token": { + "description": "The `urn:ietf:params:oauth:grant-type:jwt-bearer` grant type issues access tokens only, no refresh token is returned and the token cannot be revoked via `/v1/oauth/revoke`.", "type": "string" }, - "release_channel": { + "expires_in": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "token_type": { "type": "string", - "enum": ["internal", "alpha", "beta", "ga", "withdrawn", "preview"] + "enum": ["Bearer"] } }, - "required": ["target_version"], - "example": { - "target_version": "17", - "release_channel": "ga" - } + "required": ["access_token", "expires_in", "token_type"], + "additionalProperties": false }, - "ProjectUpgradeInitiateResponse": { + "OAuthRevokeTokenBody": { "type": "object", "properties": { - "tracking_id": { + "client_id": { + "type": "string", + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" + }, + "client_secret": { + "type": "string" + }, + "refresh_token": { "type": "string" } }, - "required": ["tracking_id"] + "required": ["client_id", "client_secret", "refresh_token"], + "example": { + "client_id": "66666666-6666-4666-8666-666666666666", + "client_secret": "sb_secret_live_example_9f4d3a206b2e4a7e8c91", + "refresh_token": "oauth_refresh_9f4d3a206b2e4a7e8c91" + }, + "additionalProperties": false }, - "ProjectUpgradeEligibilityResponse": { + "SnippetList": { "type": "object", "properties": { - "eligible": { - "type": "boolean" - }, - "current_app_version": { - "type": "string" - }, - "current_app_version_release_channel": { - "type": "string", - "enum": ["internal", "alpha", "beta", "ga", "withdrawn", "preview"] - }, - "latest_app_version": { - "type": "string" - }, - "target_upgrade_versions": { + "data": { "type": "array", "items": { "type": "object", "properties": { - "postgres_version": { + "id": { + "type": "string" + }, + "inserted_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "type": { "type": "string", - "enum": ["13", "14", "15", "17", "17-oriole"] + "enum": ["sql"] }, - "release_channel": { + "visibility": { "type": "string", - "enum": ["internal", "alpha", "beta", "ga", "withdrawn", "preview"] + "enum": ["user", "project", "org", "public"] }, - "app_version": { + "name": { "type": "string" - } - }, - "required": ["postgres_version", "release_channel", "app_version"] - } - }, - "duration_estimate_hours": { - "type": "number" - }, - "legacy_auth_custom_roles": { - "type": "array", - "items": { - "type": "string" - } - }, - "objects_to_be_dropped": { - "type": "array", - "items": { - "type": "string" - }, - "deprecated": true, - "description": "Use validation_errors instead." - }, - "unsupported_extensions": { - "type": "array", - "items": { - "type": "string" - }, - "deprecated": true, - "description": "Use validation_errors instead." - }, - "user_defined_objects_in_internal_schemas": { - "type": "array", - "items": { - "type": "string" - }, - "deprecated": true, - "description": "Use validation_errors instead." - }, - "validation_errors": { - "type": "array", - "items": { - "anyOf": [ - { + }, + "description": { + "type": "string", + "nullable": true + }, + "project": { "type": "object", "properties": { - "type": { - "type": "string", - "enum": ["objects_depending_on_pg_cron"] + "id": { + "type": "number" }, - "dependents": { - "type": "array", - "items": { - "type": "string" - } + "name": { + "type": "string" } }, - "required": ["type", "dependents"] + "required": ["id", "name"] }, - { + "owner": { "type": "object", "properties": { - "type": { - "type": "string", - "enum": ["indexes_referencing_ll_to_earth"] - }, - "schema_name": { - "type": "string" - }, - "table_name": { - "type": "string" + "id": { + "type": "number" }, - "index_name": { + "username": { "type": "string" } }, - "required": ["type", "schema_name", "table_name", "index_name"] + "required": ["id", "username"] }, - { + "updated_by": { "type": "object", "properties": { - "type": { - "type": "string", - "enum": ["function_using_obsolete_lang"] - }, - "schema_name": { - "type": "string" - }, - "function_name": { - "type": "string" + "id": { + "type": "number" }, - "lang_name": { + "username": { "type": "string" } }, - "required": ["type", "schema_name", "function_name", "lang_name"] + "required": ["id", "username"] }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["unsupported_extension"] - }, - "extension_name": { - "type": "string" - } - }, - "required": ["type", "extension_name"] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["unsupported_fdw_handler"] - }, - "fdw_name": { - "type": "string" - }, - "fdw_handler_name": { - "type": "string" - } - }, - "required": ["type", "fdw_name", "fdw_handler_name"] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["unlogged_table_with_persistent_sequence"] - }, - "schema_name": { - "type": "string" - }, - "table_name": { - "type": "string" - }, - "sequence_name": { - "type": "string" - } - }, - "required": ["type", "schema_name", "table_name", "sequence_name"] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["user_defined_objects_in_internal_schemas"] - }, - "obj_type": { - "anyOf": [ - { - "type": "string", - "enum": ["table"] - }, - { - "type": "string", - "enum": ["function"] - } - ] - }, - "schema_name": { - "type": "string" - }, - "obj_name": { - "type": "string" - } - }, - "required": ["type", "obj_type", "schema_name", "obj_name"] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["active_replication_slot"] - }, - "slot_name": { - "type": "string" - } - }, - "required": ["type", "slot_name"] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["x86_architecture"] - } - }, - "required": ["type"] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["project_hibernating"] - } - }, - "required": ["type"] + "favorite": { + "type": "boolean" } + }, + "required": [ + "id", + "inserted_at", + "updated_at", + "type", + "visibility", + "name", + "description", + "project", + "owner", + "updated_by", + "favorite" ] } }, - "warnings": { - "type": "array", - "items": { - "oneOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["pg_graphql_introspection_change"] - } - }, - "required": ["type"] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["ltree_reindex_required"] - } - }, - "required": ["type"] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["operator_estimator_gate"] - } - }, - "required": ["type"] - } - ] - } + "cursor": { + "type": "string" } }, - "required": [ - "eligible", - "current_app_version", - "current_app_version_release_channel", - "latest_app_version", - "target_upgrade_versions", - "duration_estimate_hours", - "legacy_auth_custom_roles", - "objects_to_be_dropped", - "unsupported_extensions", - "user_defined_objects_in_internal_schemas", - "validation_errors", - "warnings" - ] + "required": ["data"] }, - "DatabaseUpgradeStatusResponse": { + "SnippetResponse": { "type": "object", "properties": { - "databaseUpgradeStatus": { + "id": { + "type": "string" + }, + "inserted_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["sql"] + }, + "visibility": { + "type": "string", + "enum": ["user", "project", "org", "public"] + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "project": { "type": "object", "properties": { - "initiated_at": { - "type": "string" + "id": { + "type": "number" }, - "latest_status_at": { + "name": { "type": "string" - }, - "target_version": { + } + }, + "required": ["id", "name"] + }, + "owner": { + "type": "object", + "properties": { + "id": { "type": "number" }, - "error": { - "type": "string", - "enum": [ - "1_upgraded_instance_launch_failed", - "2_volume_detachchment_from_upgraded_instance_failed", - "3_volume_attachment_to_original_instance_failed", - "4_data_upgrade_initiation_failed", - "5_data_upgrade_completion_failed", - "6_volume_detachchment_from_original_instance_failed", - "7_volume_attachment_to_upgraded_instance_failed", - "8_upgrade_completion_failed", - "9_post_physical_backup_failed" - ] - }, - "progress": { - "type": "string", - "enum": [ - "0_requested", - "1_started", - "2_launched_upgraded_instance", - "3_detached_volume_from_upgraded_instance", - "4_attached_volume_to_original_instance", - "5_initiated_data_upgrade", - "6_completed_data_upgrade", - "7_detached_volume_from_original_instance", - "8_attached_volume_to_upgraded_instance", - "9_completed_upgrade", - "10_completed_post_physical_backup" - ] - }, - "status": { - "type": "number" + "username": { + "type": "string" } }, - "required": ["initiated_at", "latest_status_at", "target_version", "status"], - "nullable": true - } - }, - "required": ["databaseUpgradeStatus"] - }, - "ReadOnlyStatusResponse": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean" + "required": ["id", "username"] }, - "override_enabled": { + "updated_by": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "username": { + "type": "string" + } + }, + "required": ["id", "username"] + }, + "favorite": { "type": "boolean" }, - "override_active_until": { - "type": "string" - } - }, - "required": ["enabled", "override_enabled", "override_active_until"] - }, - "SetUpReadReplicaBody": { - "type": "object", - "properties": { - "read_replica_region": { - "type": "string", - "enum": [ - "us-east-1", - "us-east-2", - "us-west-1", - "us-west-2", - "ap-east-1", - "ap-southeast-1", - "ap-northeast-1", - "ap-northeast-2", - "ap-southeast-2", - "eu-west-1", - "eu-west-2", - "eu-west-3", - "eu-north-1", - "eu-central-1", - "eu-central-2", - "ca-central-1", - "ap-south-1", - "sa-east-1" - ], - "description": "Region you want your read replica to reside in" + "content": { + "type": "object", + "properties": { + "favorite": { + "deprecated": true, + "description": "Deprecated: Rely on root-level favorite property instead.", + "type": "boolean" + }, + "schema_version": { + "type": "string" + }, + "sql": { + "type": "string" + } + }, + "required": ["schema_version", "sql"] } }, - "required": ["read_replica_region"], - "example": { - "read_replica_region": "us-west-1" - } + "required": [ + "id", + "inserted_at", + "updated_at", + "type", + "visibility", + "name", + "description", + "project", + "owner", + "updated_by", + "favorite", + "content" + ] }, - "RemoveReadReplicaBody": { + "V1ProfileResponse": { "type": "object", "properties": { - "database_identifier": { + "gotrue_id": { + "type": "string" + }, + "primary_email": { + "type": "string" + }, + "username": { "type": "string" } }, - "required": ["database_identifier"], - "example": { - "database_identifier": "abcdefghijklmnopqrst-rr-us-west-1-abcde" - } + "required": ["gotrue_id", "primary_email", "username"] }, - "V1ServiceHealthResponse": { - "type": "object", - "properties": { - "name": { - "type": "string", - "enum": [ - "auth", - "db", - "db_postgres_user", - "pooler", - "realtime", - "rest", - "storage", - "pg_bouncer" - ] - }, - "healthy": { - "type": "boolean", - "deprecated": true, - "description": "Deprecated. Use `status` instead." - }, - "status": { - "type": "string", - "enum": ["COMING_UP", "ACTIVE_HEALTHY", "UNHEALTHY"] - }, - "info": { - "anyOf": [ - { + "ListActionRunResponse": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "branch_id": { + "type": "string" + }, + "run_steps": { + "type": "array", + "items": { "type": "object", "properties": { "name": { "type": "string", - "enum": ["GoTrue"] + "enum": ["clone", "pull", "health", "configure", "migrate", "seed", "deploy"] }, - "version": { - "type": "string" + "status": { + "type": "string", + "enum": [ + "CREATED", + "DEAD", + "EXITED", + "PAUSED", + "REMOVING", + "RESTARTING", + "RUNNING" + ] }, - "description": { + "created_at": { "type": "string" - } - }, - "required": ["name", "version", "description"] - }, - { - "type": "object", - "properties": { - "healthy": { - "type": "boolean", - "deprecated": true, - "description": "Deprecated. Use `status` instead." - }, - "db_connected": { - "type": "boolean" - }, - "replication_connected": { - "type": "boolean" }, - "connected_cluster": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 - } - }, - "required": [ - "healthy", - "db_connected", - "replication_connected", - "connected_cluster" - ] - }, - { - "type": "object", - "properties": { - "db_schema": { + "updated_at": { "type": "string" } }, - "required": ["db_schema"] + "required": ["name", "status", "created_at", "updated_at"] } - ] + }, + "git_config": { + "nullable": true + }, + "workdir": { + "type": "string", + "nullable": true + }, + "check_run_id": { + "type": "number", + "nullable": true + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } }, - "error": { - "type": "string" - } - }, - "required": ["name", "healthy", "status"] + "required": [ + "id", + "branch_id", + "run_steps", + "workdir", + "check_run_id", + "created_at", + "updated_at" + ] + } }, - "SigningKeyResponse": { + "ActionRunResponse": { "type": "object", "properties": { "id": { - "type": "string", - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - }, - "algorithm": { - "type": "string", - "enum": ["EdDSA", "ES256", "RS256", "HS256"] - }, - "status": { - "type": "string", - "enum": ["in_use", "previously_used", "revoked", "standby"] - }, - "public_jwk": { - "nullable": true + "type": "string" }, - "created_at": { - "type": "string", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + "branch_id": { + "type": "string" }, - "updated_at": { + "run_steps": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "enum": ["clone", "pull", "health", "configure", "migrate", "seed", "deploy"] + }, + "status": { + "type": "string", + "enum": [ + "CREATED", + "DEAD", + "EXITED", + "PAUSED", + "REMOVING", + "RESTARTING", + "RUNNING" + ] + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "required": ["name", "status", "created_at", "updated_at"] + } + }, + "git_config": { + "nullable": true + }, + "workdir": { + "type": "string", + "nullable": true + }, + "check_run_id": { + "type": "number", + "nullable": true + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "required": [ + "id", + "branch_id", + "run_steps", + "workdir", + "check_run_id", + "created_at", + "updated_at" + ] + }, + "UpdateRunStatusBody": { + "type": "object", + "properties": { + "clone": { + "type": "string", + "enum": ["CREATED", "DEAD", "EXITED", "PAUSED", "REMOVING", "RESTARTING", "RUNNING"] + }, + "pull": { + "type": "string", + "enum": ["CREATED", "DEAD", "EXITED", "PAUSED", "REMOVING", "RESTARTING", "RUNNING"] + }, + "health": { + "type": "string", + "enum": ["CREATED", "DEAD", "EXITED", "PAUSED", "REMOVING", "RESTARTING", "RUNNING"] + }, + "configure": { + "type": "string", + "enum": ["CREATED", "DEAD", "EXITED", "PAUSED", "REMOVING", "RESTARTING", "RUNNING"] + }, + "migrate": { + "type": "string", + "enum": ["CREATED", "DEAD", "EXITED", "PAUSED", "REMOVING", "RESTARTING", "RUNNING"] + }, + "seed": { + "type": "string", + "enum": ["CREATED", "DEAD", "EXITED", "PAUSED", "REMOVING", "RESTARTING", "RUNNING"] + }, + "deploy": { + "type": "string", + "enum": ["CREATED", "DEAD", "EXITED", "PAUSED", "REMOVING", "RESTARTING", "RUNNING"] + } + }, + "example": { + "clone": "RUNNING", + "configure": "RUNNING", + "migrate": "RUNNING", + "deploy": "CREATED" + } + }, + "UpdateRunStatusResponse": { + "type": "object", + "properties": { + "message": { + "type": "string", + "enum": ["ok"] + } + }, + "required": ["message"] + }, + "ApiKeyResponse": { + "type": "object", + "properties": { + "api_key": { + "type": "string", + "nullable": true + }, + "id": { + "type": "string", + "nullable": true + }, + "type": { + "type": "string", + "enum": ["legacy", "publishable", "secret", null], + "nullable": true + }, + "prefix": { + "type": "string", + "nullable": true + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "hash": { + "type": "string", + "nullable": true + }, + "secret_jwt_template": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {}, + "nullable": true + }, + "inserted_at": { "type": "string", "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "nullable": true + }, + "updated_at": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "nullable": true } }, - "required": ["id", "algorithm", "status", "public_jwk", "created_at", "updated_at"], - "additionalProperties": false + "required": ["name"] }, - "CreateSigningKeyBody": { + "LegacyApiKeysResponse": { "type": "object", "properties": { - "algorithm": { + "enabled": { + "type": "boolean" + } + }, + "required": ["enabled"] + }, + "CreateApiKeyBody": { + "type": "object", + "properties": { + "type": { "type": "string", - "enum": ["EdDSA", "ES256", "RS256", "HS256"] + "enum": ["publishable", "secret"] }, - "status": { + "name": { "type": "string", - "enum": ["in_use", "standby"] + "minLength": 4, + "maxLength": 64, + "pattern": "^[a-z_][a-z0-9_]+$" }, - "private_jwk": { - "oneOf": [ - { - "type": "object", - "properties": { - "kid": { - "type": "string", - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - }, - "use": { - "type": "string", - "enum": ["sig"] - }, - "key_ops": { - "minItems": 2, - "maxItems": 2, - "type": "array", - "items": { - "type": "string", - "enum": ["sign", "verify"] - } - }, - "ext": { - "type": "boolean", - "enum": [true] - }, - "kty": { - "type": "string", - "enum": ["RSA"] - }, - "alg": { - "type": "string", - "enum": ["RS256"] - }, - "n": { - "type": "string" - }, - "e": { - "type": "string", - "enum": ["AQAB"] - }, - "d": { - "type": "string" - }, - "p": { - "type": "string" - }, - "q": { - "type": "string" - }, - "dp": { - "type": "string" - }, - "dq": { - "type": "string" - }, - "qi": { - "type": "string" - } - }, - "required": ["kty", "n", "e", "d", "p", "q", "dp", "dq", "qi"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "kid": { - "type": "string", - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - }, - "use": { - "type": "string", - "enum": ["sig"] - }, - "key_ops": { - "minItems": 2, - "maxItems": 2, - "type": "array", - "items": { - "type": "string", - "enum": ["sign", "verify"] - } - }, - "ext": { - "type": "boolean", - "enum": [true] - }, - "kty": { - "type": "string", - "enum": ["EC"] - }, - "alg": { - "type": "string", - "enum": ["ES256"] - }, - "crv": { - "type": "string", - "enum": ["P-256"] - }, - "x": { - "type": "string" - }, - "y": { - "type": "string" - }, - "d": { - "type": "string" - } - }, - "required": ["kty", "crv", "x", "y", "d"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "kid": { - "type": "string", - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - }, - "use": { - "type": "string", - "enum": ["sig"] - }, - "key_ops": { - "minItems": 2, - "maxItems": 2, - "type": "array", - "items": { - "type": "string", - "enum": ["sign", "verify"] - } - }, - "ext": { - "type": "boolean", - "enum": [true] - }, - "kty": { - "type": "string", - "enum": ["OKP"] - }, - "alg": { - "type": "string", - "enum": ["EdDSA"] - }, - "crv": { - "type": "string", - "enum": ["Ed25519"] - }, - "x": { - "type": "string" - }, - "d": { - "type": "string" - } - }, - "required": ["kty", "crv", "x", "d"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "kid": { - "type": "string", - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - }, - "use": { - "type": "string", - "enum": ["sig"] - }, - "key_ops": { - "minItems": 2, - "maxItems": 2, - "type": "array", - "items": { - "type": "string", - "enum": ["sign", "verify"] - } - }, - "ext": { - "type": "boolean", - "enum": [true] - }, - "kty": { - "type": "string", - "enum": ["oct"] - }, - "alg": { - "type": "string", - "enum": ["HS256"] - }, - "k": { - "type": "string", - "minLength": 16 - } - }, - "required": ["kty", "k"], - "additionalProperties": false - } - ] + "description": { + "type": "string", + "nullable": true + }, + "secret_jwt_template": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {}, + "nullable": true } }, - "required": ["algorithm"], + "required": ["type", "name"], "example": { - "algorithm": "RS256", - "status": "standby" - }, - "additionalProperties": false - }, - "SigningKeysResponse": { - "type": "object", - "properties": { - "keys": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - }, - "algorithm": { - "type": "string", - "enum": ["EdDSA", "ES256", "RS256", "HS256"] - }, - "status": { - "type": "string", - "enum": ["in_use", "previously_used", "revoked", "standby"] - }, - "public_jwk": { - "nullable": true - }, - "created_at": { - "type": "string", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" - } - }, - "required": ["id", "algorithm", "status", "public_jwk", "created_at", "updated_at"], - "additionalProperties": false - } - } - }, - "required": ["keys"], - "additionalProperties": false + "type": "secret", + "name": "ci_secret_key", + "description": "CI deploy key" + } }, - "UpdateSigningKeyBody": { + "UpdateApiKeyBody": { "type": "object", "properties": { - "status": { + "name": { "type": "string", - "enum": ["in_use", "previously_used", "revoked", "standby"] + "minLength": 4, + "maxLength": 64, + "pattern": "^[a-z_][a-z0-9_]+$" + }, + "description": { + "type": "string", + "nullable": true + }, + "secret_jwt_template": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {}, + "nullable": true } }, - "required": ["status"], "example": { - "status": "standby" - }, - "additionalProperties": false + "name": "ci_secret_key_rotated", + "description": "Rotated after March release" + } }, - "AuthConfigResponse": { + "CreateBranchBody": { "type": "object", "properties": { - "api_max_request_duration": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991, - "nullable": true + "branch_name": { + "type": "string", + "minLength": 1 }, - "db_max_pool_size": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991, - "nullable": true + "git_branch": { + "type": "string" }, - "db_max_pool_size_unit": { - "type": "string", - "enum": ["connections", "percent", null], - "nullable": true + "is_default": { + "type": "boolean" }, - "disable_signup": { - "type": "boolean", - "nullable": true + "persistent": { + "type": "boolean" }, - "external_anonymous_users_enabled": { - "type": "boolean", - "nullable": true + "region": { + "type": "string" }, - "external_apple_additional_client_ids": { + "desired_instance_size": { "type": "string", - "nullable": true - }, - "external_apple_client_id": { - "type": "string", - "nullable": true - }, - "external_apple_email_optional": { - "type": "boolean", - "nullable": true - }, - "external_apple_enabled": { - "type": "boolean", - "nullable": true + "enum": [ + "pico", + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge", + "4xlarge", + "8xlarge", + "12xlarge", + "16xlarge", + "24xlarge", + "24xlarge_optimized_memory", + "24xlarge_optimized_cpu", + "24xlarge_high_memory", + "48xlarge", + "48xlarge_optimized_memory", + "48xlarge_optimized_cpu", + "48xlarge_high_memory" + ] }, - "external_apple_secret": { + "release_channel": { "type": "string", - "nullable": true + "enum": ["internal", "alpha", "beta", "ga", "withdrawn", "preview"], + "description": "Release channel. If not provided, GA will be used." }, - "external_azure_client_id": { + "postgres_engine": { "type": "string", - "nullable": true + "enum": ["15", "17", "17-oriole"], + "description": "Postgres engine version. If not provided, the latest version will be used." }, - "external_azure_email_optional": { - "type": "boolean", - "nullable": true + "secrets": { + "type": "object", + "additionalProperties": { + "type": "string" + } }, - "external_azure_enabled": { - "type": "boolean", - "nullable": true + "with_data": { + "type": "boolean" }, - "external_azure_secret": { + "notify_url": { "type": "string", + "format": "uri", + "description": "HTTP endpoint to receive branch status updates." + } + }, + "required": ["branch_name"], + "example": { + "branch_name": "preview-login-page", + "git_branch": "feature/login-page", + "persistent": true, + "with_data": false, + "notify_url": "https://example.com/webhooks/branches" + } + }, + "UpdateCustomHostnameResponseJsonValue": { + "description": "Any JSON-serializable value", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ], "nullable": true }, - "external_azure_url": { - "type": "string", - "nullable": true + { + "type": "array", + "items": { + "$ref": "#/components/schemas/UpdateCustomHostnameResponseJsonValue" + } }, - "external_bitbucket_client_id": { + { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/UpdateCustomHostnameResponseJsonValue" + } + } + ] + }, + "UpdateCustomHostnameResponse": { + "type": "object", + "properties": { + "status": { "type": "string", - "nullable": true - }, - "external_bitbucket_email_optional": { - "type": "boolean", - "nullable": true - }, - "external_bitbucket_enabled": { - "type": "boolean", - "nullable": true + "enum": [ + "1_not_started", + "2_initiated", + "3_challenge_verified", + "4_origin_setup_completed", + "5_services_reconfigured" + ] }, - "external_bitbucket_secret": { - "type": "string", - "nullable": true + "custom_hostname": { + "type": "string" }, - "external_discord_client_id": { + "data": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UpdateCustomHostnameResponseJsonValue" + } + }, + "messages": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UpdateCustomHostnameResponseJsonValue" + } + }, + "result": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "hostname": { + "type": "string" + }, + "ssl": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "validation_records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "txt_name": { + "type": "string" + }, + "txt_value": { + "type": "string" + } + }, + "required": ["txt_name", "txt_value"] + } + }, + "validation_errors": { + "type": "array", + "items": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + }, + "required": ["message"] + } + } + }, + "required": ["status"] + }, + "ownership_verification": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": ["type", "name", "value"] + }, + "custom_origin_server": { + "type": "string" + }, + "verification_errors": { + "type": "array", + "items": { + "type": "string" + } + }, + "status": { + "type": "string" + } + }, + "required": ["id", "hostname", "ssl", "custom_origin_server", "status"] + } + }, + "required": ["success", "errors", "messages", "result"] + } + }, + "required": ["data"] + }, + "UpdateCustomHostnameBody": { + "type": "object", + "properties": { + "custom_hostname": { "type": "string", - "nullable": true - }, - "external_discord_email_optional": { - "type": "boolean", - "nullable": true - }, - "external_discord_enabled": { - "type": "boolean", - "nullable": true - }, - "external_discord_secret": { + "minLength": 1, + "maxLength": 253 + } + }, + "required": ["custom_hostname"], + "example": { + "custom_hostname": "docs.example.com" + } + }, + "JitAccessRequestRequest": { + "type": "object", + "properties": { + "state": { "type": "string", - "nullable": true - }, - "external_email_enabled": { - "type": "boolean", - "nullable": true - }, - "external_facebook_client_id": { - "type": "string", - "nullable": true - }, - "external_facebook_email_optional": { - "type": "boolean", - "nullable": true - }, - "external_facebook_enabled": { - "type": "boolean", - "nullable": true + "enum": ["enabled", "disabled"] + } + }, + "required": ["state"], + "example": { + "state": "enabled" + } + }, + "NetworkBanResponse": { + "type": "object", + "properties": { + "banned_ipv4_addresses": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["banned_ipv4_addresses"] + }, + "NetworkBanResponseEnriched": { + "type": "object", + "properties": { + "banned_ipv4_addresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "banned_address": { + "type": "string" + }, + "identifier": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": ["banned_address", "identifier", "type"] + } + } + }, + "required": ["banned_ipv4_addresses"] + }, + "RemoveNetworkBanRequest": { + "type": "object", + "properties": { + "ipv4_addresses": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of IP addresses to unban." }, - "external_facebook_secret": { - "type": "string", - "nullable": true + "requester_ip": { + "default": false, + "description": "Include requester's public IP in the list of addresses to unban.", + "type": "boolean" }, - "external_figma_client_id": { + "identifier": { + "type": "string" + } + }, + "required": ["ipv4_addresses"], + "example": { + "ipv4_addresses": ["203.0.113.10"], + "requester_ip": false + } + }, + "NetworkRestrictionsResponse": { + "type": "object", + "properties": { + "entitlement": { "type": "string", - "nullable": true - }, - "external_figma_email_optional": { - "type": "boolean", - "nullable": true + "enum": ["disallowed", "allowed"] }, - "external_figma_enabled": { - "type": "boolean", - "nullable": true + "config": { + "type": "object", + "properties": { + "dbAllowedCidrs": { + "type": "array", + "items": { + "type": "string" + } + }, + "dbAllowedCidrsV6": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "dbAllowedCidrs": ["203.0.113.0/24"], + "dbAllowedCidrsV6": ["2001:db8::/32"] + }, + "description": "At any given point in time, this is the config that the user has requested be applied to their project. The `status` field indicates if it has been applied to the project, or is pending. When an updated config is received, the applied config is moved to `old_config`." }, - "external_figma_secret": { - "type": "string", - "nullable": true + "old_config": { + "description": "Populated when a new config has been received, but not registered as successfully applied to a project.", + "type": "object", + "properties": { + "dbAllowedCidrs": { + "type": "array", + "items": { + "type": "string" + } + }, + "dbAllowedCidrsV6": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "dbAllowedCidrs": ["203.0.113.0/24"], + "dbAllowedCidrsV6": ["2001:db8::/32"] + } }, - "external_github_client_id": { + "status": { "type": "string", - "nullable": true - }, - "external_github_email_optional": { - "type": "boolean", - "nullable": true - }, - "external_github_enabled": { - "type": "boolean", - "nullable": true + "enum": ["stored", "applied"] }, - "external_github_secret": { + "updated_at": { "type": "string", - "nullable": true + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, - "external_gitlab_client_id": { + "applied_at": { "type": "string", - "nullable": true - }, - "external_gitlab_email_optional": { - "type": "boolean", - "nullable": true + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + } + }, + "required": ["entitlement", "config", "status"] + }, + "NetworkRestrictionsRequest": { + "type": "object", + "properties": { + "dbAllowedCidrs": { + "type": "array", + "items": { + "type": "string" + } }, - "external_gitlab_enabled": { - "type": "boolean", - "nullable": true + "dbAllowedCidrsV6": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "dbAllowedCidrs": ["203.0.113.0/24"], + "dbAllowedCidrsV6": ["2001:db8::/32"] + } + }, + "NetworkRestrictionsPatchRequest": { + "type": "object", + "properties": { + "add": { + "type": "object", + "properties": { + "dbAllowedCidrs": { + "type": "array", + "items": { + "type": "string" + } + }, + "dbAllowedCidrsV6": { + "type": "array", + "items": { + "type": "string" + } + } + } }, - "external_gitlab_secret": { - "type": "string", - "nullable": true + "remove": { + "type": "object", + "properties": { + "dbAllowedCidrs": { + "type": "array", + "items": { + "type": "string" + } + }, + "dbAllowedCidrsV6": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "example": { + "add": { + "dbAllowedCidrs": ["203.0.113.0/24"] }, - "external_gitlab_url": { + "remove": { + "dbAllowedCidrs": ["198.51.100.0/24"] + } + } + }, + "NetworkRestrictionsV2Response": { + "type": "object", + "properties": { + "entitlement": { "type": "string", - "nullable": true + "enum": ["disallowed", "allowed"] }, - "external_google_additional_client_ids": { - "type": "string", - "nullable": true - }, - "external_google_client_id": { - "type": "string", - "nullable": true - }, - "external_google_email_optional": { - "type": "boolean", - "nullable": true + "config": { + "type": "object", + "properties": { + "dbAllowedCidrs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["v4", "v6"] + } + }, + "required": ["address", "type"] + } + } + }, + "description": "At any given point in time, this is the config that the user has requested be applied to their project. The `status` field indicates if it has been applied to the project, or is pending. When an updated config is received, the applied config is moved to `old_config`." }, - "external_google_enabled": { - "type": "boolean", - "nullable": true + "old_config": { + "description": "Populated when a new config has been received, but not registered as successfully applied to a project.", + "type": "object", + "properties": { + "dbAllowedCidrs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["v4", "v6"] + } + }, + "required": ["address", "type"] + } + } + } }, - "external_google_secret": { + "updated_at": { "type": "string", - "nullable": true - }, - "external_google_skip_nonce_check": { - "type": "boolean", - "nullable": true + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, - "external_kakao_client_id": { + "applied_at": { "type": "string", - "nullable": true - }, - "external_kakao_email_optional": { - "type": "boolean", - "nullable": true - }, - "external_kakao_enabled": { - "type": "boolean", - "nullable": true + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, - "external_kakao_secret": { + "status": { "type": "string", - "nullable": true - }, - "external_keycloak_client_id": { + "enum": ["stored", "applied"] + } + }, + "required": ["entitlement", "config", "status"] + }, + "PgsodiumConfigResponse": { + "type": "object", + "properties": { + "root_key": { "type": "string", - "nullable": true - }, - "external_keycloak_email_optional": { - "type": "boolean", - "nullable": true - }, - "external_keycloak_enabled": { - "type": "boolean", - "nullable": true - }, - "external_keycloak_secret": { + "description": "The pgsodium root key: 32 bytes, hex-encoded (64 characters)." + } + }, + "required": ["root_key"], + "example": { + "root_key": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + } + }, + "UpdatePgsodiumConfigBody": { + "type": "object", + "properties": { + "root_key": { "type": "string", - "nullable": true + "description": "The pgsodium root key: 32 bytes, hex-encoded (64 characters)." + } + }, + "required": ["root_key"], + "example": { + "root_key": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + } + }, + "PostgrestConfigWithJWTSecretResponse": { + "type": "object", + "properties": { + "db_schema": { + "type": "string" }, - "external_keycloak_url": { - "type": "string", - "nullable": true + "max_rows": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 }, - "external_linkedin_oidc_client_id": { - "type": "string", - "nullable": true + "db_extra_search_path": { + "type": "string" }, - "external_linkedin_oidc_email_optional": { - "type": "boolean", + "db_pool": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "description": "If `null`, the value is automatically configured based on compute size.", "nullable": true }, - "external_linkedin_oidc_enabled": { - "type": "boolean", + "db_pool_acquisition_timeout": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "description": "If `null`, the value is automatically configured to 10.", "nullable": true }, - "external_linkedin_oidc_secret": { - "type": "string", - "nullable": true + "jwt_secret": { + "type": "string" + } + }, + "required": [ + "db_schema", + "max_rows", + "db_extra_search_path", + "db_pool", + "db_pool_acquisition_timeout" + ] + }, + "V1UpdatePostgrestConfigBody": { + "type": "object", + "properties": { + "db_extra_search_path": { + "type": "string" }, - "external_slack_oidc_client_id": { - "type": "string", - "nullable": true + "db_schema": { + "type": "string" }, - "external_slack_oidc_email_optional": { - "type": "boolean", - "nullable": true + "max_rows": { + "type": "integer", + "minimum": 0, + "maximum": 1000000 }, - "external_slack_oidc_enabled": { - "type": "boolean", - "nullable": true + "db_pool": { + "type": "integer", + "minimum": 0, + "maximum": 1000 }, - "external_slack_oidc_secret": { - "type": "string", - "nullable": true + "db_pool_acquisition_timeout": { + "type": "integer", + "minimum": 0, + "maximum": 60 + } + }, + "example": { + "db_schema": "public,storage", + "db_pool": 20, + "max_rows": 1000 + } + }, + "V1PostgrestConfigResponse": { + "type": "object", + "properties": { + "db_schema": { + "type": "string" }, - "external_notion_client_id": { - "type": "string", - "nullable": true + "max_rows": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 }, - "external_notion_email_optional": { - "type": "boolean", - "nullable": true + "db_extra_search_path": { + "type": "string" }, - "external_notion_enabled": { - "type": "boolean", + "db_pool": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "description": "If `null`, the value is automatically configured based on compute size.", "nullable": true }, - "external_notion_secret": { - "type": "string", + "db_pool_acquisition_timeout": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "description": "If `null`, the value is automatically configured to 10.", "nullable": true + } + }, + "required": [ + "db_schema", + "max_rows", + "db_extra_search_path", + "db_pool", + "db_pool_acquisition_timeout" + ] + }, + "V1ProjectRefResponse": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 }, - "external_phone_enabled": { - "type": "boolean", - "nullable": true + "ref": { + "type": "string" }, - "external_slack_client_id": { + "name": { + "type": "string" + } + }, + "required": ["id", "ref", "name"] + }, + "V1UpdateProjectBody": { + "type": "object", + "properties": { + "name": { "type": "string", - "nullable": true - }, - "external_slack_email_optional": { - "type": "boolean", - "nullable": true + "minLength": 1, + "maxLength": 256 + } + }, + "required": ["name"], + "example": { + "name": "Acme Platform" + } + }, + "SecretResponse": { + "type": "object", + "properties": { + "name": { + "type": "string" }, - "external_slack_enabled": { - "type": "boolean", - "nullable": true + "value": { + "type": "string" }, - "external_slack_secret": { - "type": "string", - "nullable": true + "updated_at": { + "type": "string" + } + }, + "required": ["name", "value"] + }, + "CreateSecretBody": { + "maxItems": 100, + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "maxLength": 256, + "pattern": "^(?!SUPABASE_).*", + "description": "Secret name must not start with the SUPABASE_ prefix." + }, + "value": { + "type": "string", + "maxLength": 24576 + } }, - "external_spotify_client_id": { - "type": "string", - "nullable": true + "required": ["name", "value"] + }, + "example": [ + { + "name": "OPENAI_API_KEY", + "value": "sk-example-secret" }, - "external_spotify_email_optional": { - "type": "boolean", - "nullable": true + { + "name": "STRIPE_WEBHOOK_SECRET", + "value": "whsec_example" + } + ] + }, + "DeleteSecretsBody": { + "type": "array", + "items": { + "type": "string" + }, + "example": ["OPENAI_API_KEY"] + }, + "SslEnforcementResponse": { + "type": "object", + "properties": { + "currentConfig": { + "type": "object", + "properties": { + "database": { + "type": "boolean" + } + }, + "required": ["database"] }, - "external_spotify_enabled": { - "type": "boolean", - "nullable": true + "appliedSuccessfully": { + "type": "boolean" + } + }, + "required": ["currentConfig", "appliedSuccessfully"] + }, + "SslEnforcementRequest": { + "type": "object", + "properties": { + "requestedConfig": { + "type": "object", + "properties": { + "database": { + "type": "boolean" + } + }, + "required": ["database"] + } + }, + "required": ["requestedConfig"], + "example": { + "requestedConfig": { + "database": true + } + } + }, + "TypescriptResponse": { + "type": "object", + "properties": { + "types": { + "type": "string" + } + }, + "required": ["types"] + }, + "VanitySubdomainConfigResponse": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": ["not-used", "custom-domain-used", "active"] }, - "external_spotify_secret": { + "custom_domain": { "type": "string", - "nullable": true + "minLength": 1 + } + }, + "required": ["status"] + }, + "PlanGateErrorBody": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Human-readable explanation of the plan gate" }, - "external_twitch_client_id": { + "error": { + "description": "Present on entitlement denials. Other errors with this status code (validation, billing state) carry only message.", + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "Machine-readable marker for plan-gated denials", + "enum": ["entitlement_required"] + }, + "feature": { + "type": "string", + "description": "Entitlement feature key that failed the check" + }, + "upgrade_url": { + "description": "Billing page URL for the organization, present when the org is resolvable", + "type": "string" + } + }, + "required": ["code", "feature"] + } + }, + "required": ["message"] + }, + "VanitySubdomainBody": { + "type": "object", + "properties": { + "vanity_subdomain": { "type": "string", - "nullable": true + "maxLength": 63 + } + }, + "required": ["vanity_subdomain"], + "example": { + "vanity_subdomain": "acme-prod" + } + }, + "SubdomainAvailabilityResponse": { + "type": "object", + "properties": { + "available": { + "type": "boolean" + } + }, + "required": ["available"] + }, + "ActivateVanitySubdomainResponse": { + "type": "object", + "properties": { + "custom_domain": { + "type": "string" + } + }, + "required": ["custom_domain"] + }, + "UpgradeDatabaseBody": { + "type": "object", + "properties": { + "target_version": { + "type": "string" }, - "external_twitch_email_optional": { - "type": "boolean", - "nullable": true + "release_channel": { + "type": "string", + "enum": ["internal", "alpha", "beta", "ga", "withdrawn", "preview"] + } + }, + "required": ["target_version"], + "example": { + "target_version": "17", + "release_channel": "ga" + } + }, + "ProjectUpgradeInitiateResponse": { + "type": "object", + "properties": { + "tracking_id": { + "type": "string" + } + }, + "required": ["tracking_id"] + }, + "ProjectUpgradeEligibilityResponse": { + "type": "object", + "properties": { + "eligible": { + "type": "boolean" }, - "external_twitch_enabled": { - "type": "boolean", - "nullable": true + "current_app_version": { + "type": "string" }, - "external_twitch_secret": { + "current_app_version_release_channel": { "type": "string", - "nullable": true + "enum": ["internal", "alpha", "beta", "ga", "withdrawn", "preview"] }, - "external_twitter_client_id": { - "type": "string", - "nullable": true - }, - "external_twitter_email_optional": { - "type": "boolean", - "nullable": true - }, - "external_twitter_enabled": { - "type": "boolean", - "nullable": true - }, - "external_twitter_secret": { - "type": "string", - "nullable": true + "latest_app_version": { + "type": "string" }, - "external_x_client_id": { - "type": "string", - "nullable": true + "target_upgrade_versions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "postgres_version": { + "type": "string", + "enum": ["13", "14", "15", "17", "17-oriole"] + }, + "release_channel": { + "type": "string", + "enum": ["internal", "alpha", "beta", "ga", "withdrawn", "preview"] + }, + "app_version": { + "type": "string" + } + }, + "required": ["postgres_version", "release_channel", "app_version"] + } }, - "external_x_email_optional": { - "type": "boolean", - "nullable": true + "duration_estimate_hours": { + "type": "number" }, - "external_x_enabled": { - "type": "boolean", - "nullable": true + "legacy_auth_custom_roles": { + "type": "array", + "items": { + "type": "string" + } }, - "external_x_secret": { - "type": "string", - "nullable": true + "objects_to_be_dropped": { + "type": "array", + "items": { + "type": "string" + }, + "deprecated": true, + "description": "Use validation_errors instead." }, - "external_workos_client_id": { - "type": "string", - "nullable": true + "unsupported_extensions": { + "type": "array", + "items": { + "type": "string" + }, + "deprecated": true, + "description": "Use validation_errors instead." }, - "external_workos_enabled": { - "type": "boolean", - "nullable": true + "user_defined_objects_in_internal_schemas": { + "type": "array", + "items": { + "type": "string" + }, + "deprecated": true, + "description": "Use validation_errors instead." }, - "external_workos_secret": { - "type": "string", - "nullable": true + "validation_errors": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["objects_depending_on_pg_cron"] + }, + "dependents": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["type", "dependents"] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["indexes_referencing_ll_to_earth"] + }, + "schema_name": { + "type": "string" + }, + "table_name": { + "type": "string" + }, + "index_name": { + "type": "string" + } + }, + "required": ["type", "schema_name", "table_name", "index_name"] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["function_using_obsolete_lang"] + }, + "schema_name": { + "type": "string" + }, + "function_name": { + "type": "string" + }, + "lang_name": { + "type": "string" + } + }, + "required": ["type", "schema_name", "function_name", "lang_name"] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["unsupported_extension"] + }, + "extension_name": { + "type": "string" + } + }, + "required": ["type", "extension_name"] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["unsupported_fdw_handler"] + }, + "fdw_name": { + "type": "string" + }, + "fdw_handler_name": { + "type": "string" + } + }, + "required": ["type", "fdw_name", "fdw_handler_name"] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["unlogged_table_with_persistent_sequence"] + }, + "schema_name": { + "type": "string" + }, + "table_name": { + "type": "string" + }, + "sequence_name": { + "type": "string" + } + }, + "required": ["type", "schema_name", "table_name", "sequence_name"] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["user_defined_objects_in_internal_schemas"] + }, + "obj_type": { + "anyOf": [ + { + "type": "string", + "enum": ["table"] + }, + { + "type": "string", + "enum": ["function"] + } + ] + }, + "schema_name": { + "type": "string" + }, + "obj_name": { + "type": "string" + } + }, + "required": ["type", "obj_type", "schema_name", "obj_name"] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["active_replication_slot"] + }, + "slot_name": { + "type": "string" + } + }, + "required": ["type", "slot_name"] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["x86_architecture"] + } + }, + "required": ["type"] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["project_hibernating"] + } + }, + "required": ["type"] + } + ] + } }, - "external_workos_url": { - "type": "string", - "nullable": true - }, - "external_web3_solana_enabled": { - "type": "boolean", - "nullable": true - }, - "external_web3_ethereum_enabled": { - "type": "boolean", - "nullable": true - }, - "external_zoom_client_id": { - "type": "string", - "nullable": true - }, - "external_zoom_email_optional": { - "type": "boolean", - "nullable": true - }, - "external_zoom_enabled": { - "type": "boolean", - "nullable": true - }, - "external_zoom_secret": { - "type": "string", - "nullable": true - }, - "hook_custom_access_token_enabled": { - "type": "boolean", - "nullable": true - }, - "hook_custom_access_token_uri": { - "type": "string", - "nullable": true - }, - "hook_custom_access_token_secrets": { - "type": "string", - "nullable": true - }, - "hook_mfa_verification_attempt_enabled": { - "type": "boolean", - "nullable": true - }, - "hook_mfa_verification_attempt_uri": { - "type": "string", - "nullable": true - }, - "hook_mfa_verification_attempt_secrets": { - "type": "string", - "nullable": true - }, - "hook_password_verification_attempt_enabled": { - "type": "boolean", - "nullable": true - }, - "hook_password_verification_attempt_uri": { - "type": "string", - "nullable": true - }, - "hook_password_verification_attempt_secrets": { - "type": "string", + "warnings": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["pg_graphql_introspection_change"] + } + }, + "required": ["type"] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["ltree_reindex_required"] + } + }, + "required": ["type"] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["operator_estimator_gate"] + } + }, + "required": ["type"] + } + ] + } + } + }, + "required": [ + "eligible", + "current_app_version", + "current_app_version_release_channel", + "latest_app_version", + "target_upgrade_versions", + "duration_estimate_hours", + "legacy_auth_custom_roles", + "objects_to_be_dropped", + "unsupported_extensions", + "user_defined_objects_in_internal_schemas", + "validation_errors", + "warnings" + ] + }, + "DatabaseUpgradeStatusResponse": { + "type": "object", + "properties": { + "databaseUpgradeStatus": { + "type": "object", + "properties": { + "initiated_at": { + "type": "string" + }, + "latest_status_at": { + "type": "string" + }, + "target_version": { + "type": "number" + }, + "error": { + "type": "string", + "enum": [ + "1_upgraded_instance_launch_failed", + "2_volume_detachchment_from_upgraded_instance_failed", + "3_volume_attachment_to_original_instance_failed", + "4_data_upgrade_initiation_failed", + "5_data_upgrade_completion_failed", + "6_volume_detachchment_from_original_instance_failed", + "7_volume_attachment_to_upgraded_instance_failed", + "8_upgrade_completion_failed", + "9_post_physical_backup_failed" + ] + }, + "progress": { + "type": "string", + "enum": [ + "0_requested", + "1_started", + "2_launched_upgraded_instance", + "3_detached_volume_from_upgraded_instance", + "4_attached_volume_to_original_instance", + "5_initiated_data_upgrade", + "6_completed_data_upgrade", + "7_detached_volume_from_original_instance", + "8_attached_volume_to_upgraded_instance", + "9_completed_upgrade", + "10_completed_post_physical_backup" + ] + }, + "status": { + "type": "number" + } + }, + "required": ["initiated_at", "latest_status_at", "target_version", "status"], "nullable": true + } + }, + "required": ["databaseUpgradeStatus"] + }, + "ReadOnlyStatusResponse": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" }, - "hook_send_sms_enabled": { - "type": "boolean", - "nullable": true + "override_enabled": { + "type": "boolean" }, - "hook_send_sms_uri": { + "override_active_until": { + "type": "string" + } + }, + "required": ["enabled", "override_enabled", "override_active_until"] + }, + "SetUpReadReplicaBody": { + "type": "object", + "properties": { + "read_replica_region": { "type": "string", - "nullable": true - }, - "hook_send_sms_secrets": { + "enum": [ + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + "ap-east-1", + "ap-southeast-1", + "ap-northeast-1", + "ap-northeast-2", + "ap-southeast-2", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "eu-north-1", + "eu-central-1", + "eu-central-2", + "ca-central-1", + "ap-south-1", + "sa-east-1" + ], + "description": "Region you want your read replica to reside in" + } + }, + "required": ["read_replica_region"], + "example": { + "read_replica_region": "us-west-1" + } + }, + "RemoveReadReplicaBody": { + "type": "object", + "properties": { + "database_identifier": { + "type": "string" + } + }, + "required": ["database_identifier"], + "example": { + "database_identifier": "abcdefghijklmnopqrst-rr-us-west-1-abcde" + } + }, + "V1ServiceHealthResponse": { + "type": "object", + "properties": { + "name": { "type": "string", - "nullable": true + "enum": [ + "auth", + "db", + "db_postgres_user", + "pooler", + "realtime", + "rest", + "storage", + "pg_bouncer" + ] }, - "hook_send_email_enabled": { + "healthy": { "type": "boolean", - "nullable": true + "deprecated": true, + "description": "Deprecated. Use `status` instead." }, - "hook_send_email_uri": { + "status": { "type": "string", - "nullable": true + "enum": ["COMING_UP", "ACTIVE_HEALTHY", "UNHEALTHY"] }, - "hook_send_email_secrets": { - "type": "string", - "nullable": true - }, - "hook_before_user_created_enabled": { - "type": "boolean", - "nullable": true - }, - "hook_before_user_created_uri": { - "type": "string", - "nullable": true - }, - "hook_before_user_created_secrets": { - "type": "string", - "nullable": true - }, - "hook_after_user_created_enabled": { - "type": "boolean", - "nullable": true - }, - "hook_after_user_created_uri": { - "type": "string", - "nullable": true - }, - "hook_after_user_created_secrets": { - "type": "string", - "nullable": true - }, - "jwt_exp": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991, - "nullable": true - }, - "mailer_allow_unverified_email_sign_ins": { - "type": "boolean", - "nullable": true - }, - "mailer_autoconfirm": { - "type": "boolean", - "nullable": true - }, - "mailer_otp_exp": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 - }, - "mailer_otp_length": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991, - "nullable": true - }, - "mailer_secure_email_change_enabled": { - "type": "boolean", - "nullable": true - }, - "mailer_subjects_confirmation": { - "type": "string", - "nullable": true - }, - "mailer_subjects_email_change": { - "type": "string", - "nullable": true - }, - "mailer_subjects_invite": { - "type": "string", - "nullable": true - }, - "mailer_subjects_magic_link": { - "type": "string", - "nullable": true - }, - "mailer_subjects_reauthentication": { - "type": "string", - "nullable": true - }, - "mailer_subjects_recovery": { - "type": "string", - "nullable": true - }, - "mailer_subjects_password_changed_notification": { - "type": "string", - "nullable": true - }, - "mailer_subjects_email_changed_notification": { - "type": "string", - "nullable": true - }, - "mailer_subjects_phone_changed_notification": { - "type": "string", - "nullable": true - }, - "mailer_subjects_mfa_factor_enrolled_notification": { - "type": "string", - "nullable": true - }, - "mailer_subjects_mfa_factor_unenrolled_notification": { - "type": "string", - "nullable": true - }, - "mailer_subjects_identity_linked_notification": { - "type": "string", - "nullable": true - }, - "mailer_subjects_identity_unlinked_notification": { - "type": "string", - "nullable": true - }, - "mailer_templates_confirmation_content": { - "type": "string", - "nullable": true - }, - "mailer_templates_email_change_content": { - "type": "string", - "nullable": true - }, - "mailer_templates_invite_content": { - "type": "string", - "nullable": true - }, - "mailer_templates_magic_link_content": { - "type": "string", - "nullable": true - }, - "mailer_templates_reauthentication_content": { - "type": "string", - "nullable": true + "info": { + "anyOf": [ + { + "type": "object", + "properties": { + "name": { + "type": "string", + "enum": ["GoTrue"] + }, + "version": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": ["name", "version", "description"] + }, + { + "type": "object", + "properties": { + "healthy": { + "type": "boolean", + "deprecated": true, + "description": "Deprecated. Use `status` instead." + }, + "db_connected": { + "type": "boolean" + }, + "replication_connected": { + "type": "boolean" + }, + "connected_cluster": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + } + }, + "required": [ + "healthy", + "db_connected", + "replication_connected", + "connected_cluster" + ] + }, + { + "type": "object", + "properties": { + "db_schema": { + "type": "string" + } + }, + "required": ["db_schema"] + } + ] }, - "mailer_templates_recovery_content": { + "error": { + "type": "string" + } + }, + "required": ["name", "healthy", "status"] + }, + "SigningKeyResponse": { + "type": "object", + "properties": { + "id": { "type": "string", - "nullable": true + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, - "mailer_templates_password_changed_notification_content": { + "algorithm": { "type": "string", - "nullable": true + "enum": ["EdDSA", "ES256", "RS256", "HS256"] }, - "mailer_templates_email_changed_notification_content": { + "status": { "type": "string", - "nullable": true + "enum": ["in_use", "previously_used", "revoked", "standby"] }, - "mailer_templates_phone_changed_notification_content": { - "type": "string", + "public_jwk": { "nullable": true }, - "mailer_templates_mfa_factor_enrolled_notification_content": { + "created_at": { "type": "string", - "nullable": true + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, - "mailer_templates_mfa_factor_unenrolled_notification_content": { + "updated_at": { "type": "string", - "nullable": true - }, - "mailer_templates_identity_linked_notification_content": { + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + } + }, + "required": ["id", "algorithm", "status", "public_jwk", "created_at", "updated_at"], + "additionalProperties": false + }, + "CreateSigningKeyBody": { + "type": "object", + "properties": { + "algorithm": { "type": "string", - "nullable": true + "enum": ["EdDSA", "ES256", "RS256", "HS256"] }, - "mailer_templates_identity_unlinked_notification_content": { + "status": { "type": "string", - "nullable": true - }, - "mailer_notifications_password_changed_enabled": { - "type": "boolean", - "nullable": true - }, - "mailer_notifications_email_changed_enabled": { - "type": "boolean", - "nullable": true - }, - "mailer_notifications_phone_changed_enabled": { - "type": "boolean", - "nullable": true - }, - "mailer_notifications_mfa_factor_enrolled_enabled": { - "type": "boolean", - "nullable": true - }, - "mailer_notifications_mfa_factor_unenrolled_enabled": { - "type": "boolean", - "nullable": true + "enum": ["in_use", "standby"] }, - "mailer_notifications_identity_linked_enabled": { - "type": "boolean", - "nullable": true + "private_jwk": { + "oneOf": [ + { + "type": "object", + "properties": { + "kid": { + "type": "string", + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" + }, + "use": { + "type": "string", + "enum": ["sig"] + }, + "key_ops": { + "minItems": 2, + "maxItems": 2, + "type": "array", + "items": { + "type": "string", + "enum": ["sign", "verify"] + } + }, + "ext": { + "type": "boolean", + "enum": [true] + }, + "kty": { + "type": "string", + "enum": ["RSA"] + }, + "alg": { + "type": "string", + "enum": ["RS256"] + }, + "n": { + "type": "string" + }, + "e": { + "type": "string", + "enum": ["AQAB"] + }, + "d": { + "type": "string" + }, + "p": { + "type": "string" + }, + "q": { + "type": "string" + }, + "dp": { + "type": "string" + }, + "dq": { + "type": "string" + }, + "qi": { + "type": "string" + } + }, + "required": ["kty", "n", "e", "d", "p", "q", "dp", "dq", "qi"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "kid": { + "type": "string", + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" + }, + "use": { + "type": "string", + "enum": ["sig"] + }, + "key_ops": { + "minItems": 2, + "maxItems": 2, + "type": "array", + "items": { + "type": "string", + "enum": ["sign", "verify"] + } + }, + "ext": { + "type": "boolean", + "enum": [true] + }, + "kty": { + "type": "string", + "enum": ["EC"] + }, + "alg": { + "type": "string", + "enum": ["ES256"] + }, + "crv": { + "type": "string", + "enum": ["P-256"] + }, + "x": { + "type": "string" + }, + "y": { + "type": "string" + }, + "d": { + "type": "string" + } + }, + "required": ["kty", "crv", "x", "y", "d"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "kid": { + "type": "string", + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" + }, + "use": { + "type": "string", + "enum": ["sig"] + }, + "key_ops": { + "minItems": 2, + "maxItems": 2, + "type": "array", + "items": { + "type": "string", + "enum": ["sign", "verify"] + } + }, + "ext": { + "type": "boolean", + "enum": [true] + }, + "kty": { + "type": "string", + "enum": ["OKP"] + }, + "alg": { + "type": "string", + "enum": ["EdDSA"] + }, + "crv": { + "type": "string", + "enum": ["Ed25519"] + }, + "x": { + "type": "string" + }, + "d": { + "type": "string" + } + }, + "required": ["kty", "crv", "x", "d"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "kid": { + "type": "string", + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" + }, + "use": { + "type": "string", + "enum": ["sig"] + }, + "key_ops": { + "minItems": 2, + "maxItems": 2, + "type": "array", + "items": { + "type": "string", + "enum": ["sign", "verify"] + } + }, + "ext": { + "type": "boolean", + "enum": [true] + }, + "kty": { + "type": "string", + "enum": ["oct"] + }, + "alg": { + "type": "string", + "enum": ["HS256"] + }, + "k": { + "type": "string", + "minLength": 16 + } + }, + "required": ["kty", "k"], + "additionalProperties": false + } + ] + } + }, + "required": ["algorithm"], + "example": { + "algorithm": "RS256", + "status": "standby" + }, + "additionalProperties": false + }, + "SigningKeysResponse": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" + }, + "algorithm": { + "type": "string", + "enum": ["EdDSA", "ES256", "RS256", "HS256"] + }, + "status": { + "type": "string", + "enum": ["in_use", "previously_used", "revoked", "standby"] + }, + "public_jwk": { + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + } + }, + "required": ["id", "algorithm", "status", "public_jwk", "created_at", "updated_at"], + "additionalProperties": false + } + } + }, + "required": ["keys"], + "additionalProperties": false + }, + "UpdateSigningKeyBody": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": ["in_use", "previously_used", "revoked", "standby"] + } + }, + "required": ["status"], + "example": { + "status": "standby" + }, + "additionalProperties": false + }, + "AuthConfigResponse": { + "type": "object", + "properties": { + "api_max_request_duration": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "nullable": true + }, + "db_max_pool_size": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "nullable": true + }, + "db_max_pool_size_unit": { + "type": "string", + "enum": ["connections", "percent", null], + "nullable": true + }, + "disable_signup": { + "type": "boolean", + "nullable": true + }, + "external_anonymous_users_enabled": { + "type": "boolean", + "nullable": true + }, + "external_apple_additional_client_ids": { + "type": "string", + "nullable": true + }, + "external_apple_client_id": { + "type": "string", + "nullable": true + }, + "external_apple_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_apple_enabled": { + "type": "boolean", + "nullable": true + }, + "external_apple_secret": { + "type": "string", + "nullable": true + }, + "external_azure_client_id": { + "type": "string", + "nullable": true + }, + "external_azure_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_azure_enabled": { + "type": "boolean", + "nullable": true + }, + "external_azure_secret": { + "type": "string", + "nullable": true + }, + "external_azure_url": { + "type": "string", + "nullable": true + }, + "external_bitbucket_client_id": { + "type": "string", + "nullable": true + }, + "external_bitbucket_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_bitbucket_enabled": { + "type": "boolean", + "nullable": true + }, + "external_bitbucket_secret": { + "type": "string", + "nullable": true + }, + "external_discord_client_id": { + "type": "string", + "nullable": true + }, + "external_discord_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_discord_enabled": { + "type": "boolean", + "nullable": true + }, + "external_discord_secret": { + "type": "string", + "nullable": true + }, + "external_email_enabled": { + "type": "boolean", + "nullable": true + }, + "external_facebook_client_id": { + "type": "string", + "nullable": true + }, + "external_facebook_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_facebook_enabled": { + "type": "boolean", + "nullable": true + }, + "external_facebook_secret": { + "type": "string", + "nullable": true + }, + "external_figma_client_id": { + "type": "string", + "nullable": true + }, + "external_figma_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_figma_enabled": { + "type": "boolean", + "nullable": true + }, + "external_figma_secret": { + "type": "string", + "nullable": true + }, + "external_github_client_id": { + "type": "string", + "nullable": true + }, + "external_github_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_github_enabled": { + "type": "boolean", + "nullable": true + }, + "external_github_secret": { + "type": "string", + "nullable": true + }, + "external_gitlab_client_id": { + "type": "string", + "nullable": true + }, + "external_gitlab_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_gitlab_enabled": { + "type": "boolean", + "nullable": true + }, + "external_gitlab_secret": { + "type": "string", + "nullable": true + }, + "external_gitlab_url": { + "type": "string", + "nullable": true + }, + "external_google_additional_client_ids": { + "type": "string", + "nullable": true + }, + "external_google_client_id": { + "type": "string", + "nullable": true + }, + "external_google_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_google_enabled": { + "type": "boolean", + "nullable": true + }, + "external_google_secret": { + "type": "string", + "nullable": true + }, + "external_google_skip_nonce_check": { + "type": "boolean", + "nullable": true + }, + "external_kakao_client_id": { + "type": "string", + "nullable": true + }, + "external_kakao_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_kakao_enabled": { + "type": "boolean", + "nullable": true + }, + "external_kakao_secret": { + "type": "string", + "nullable": true + }, + "external_keycloak_client_id": { + "type": "string", + "nullable": true + }, + "external_keycloak_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_keycloak_enabled": { + "type": "boolean", + "nullable": true + }, + "external_keycloak_secret": { + "type": "string", + "nullable": true + }, + "external_keycloak_url": { + "type": "string", + "nullable": true + }, + "external_linkedin_oidc_client_id": { + "type": "string", + "nullable": true + }, + "external_linkedin_oidc_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_linkedin_oidc_enabled": { + "type": "boolean", + "nullable": true + }, + "external_linkedin_oidc_secret": { + "type": "string", + "nullable": true + }, + "external_slack_oidc_client_id": { + "type": "string", + "nullable": true + }, + "external_slack_oidc_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_slack_oidc_enabled": { + "type": "boolean", + "nullable": true + }, + "external_slack_oidc_secret": { + "type": "string", + "nullable": true + }, + "external_notion_client_id": { + "type": "string", + "nullable": true + }, + "external_notion_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_notion_enabled": { + "type": "boolean", + "nullable": true + }, + "external_notion_secret": { + "type": "string", + "nullable": true + }, + "external_phone_enabled": { + "type": "boolean", + "nullable": true + }, + "external_slack_client_id": { + "type": "string", + "nullable": true + }, + "external_slack_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_slack_enabled": { + "type": "boolean", + "nullable": true + }, + "external_slack_secret": { + "type": "string", + "nullable": true + }, + "external_spotify_client_id": { + "type": "string", + "nullable": true + }, + "external_spotify_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_spotify_enabled": { + "type": "boolean", + "nullable": true + }, + "external_spotify_secret": { + "type": "string", + "nullable": true + }, + "external_twitch_client_id": { + "type": "string", + "nullable": true + }, + "external_twitch_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_twitch_enabled": { + "type": "boolean", + "nullable": true + }, + "external_twitch_secret": { + "type": "string", + "nullable": true + }, + "external_twitter_client_id": { + "type": "string", + "nullable": true + }, + "external_twitter_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_twitter_enabled": { + "type": "boolean", + "nullable": true + }, + "external_twitter_secret": { + "type": "string", + "nullable": true + }, + "external_x_client_id": { + "type": "string", + "nullable": true + }, + "external_x_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_x_enabled": { + "type": "boolean", + "nullable": true + }, + "external_x_secret": { + "type": "string", + "nullable": true + }, + "external_workos_client_id": { + "type": "string", + "nullable": true + }, + "external_workos_enabled": { + "type": "boolean", + "nullable": true + }, + "external_workos_secret": { + "type": "string", + "nullable": true + }, + "external_workos_url": { + "type": "string", + "nullable": true + }, + "external_web3_solana_enabled": { + "type": "boolean", + "nullable": true + }, + "external_web3_ethereum_enabled": { + "type": "boolean", + "nullable": true + }, + "external_zoom_client_id": { + "type": "string", + "nullable": true + }, + "external_zoom_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_zoom_enabled": { + "type": "boolean", + "nullable": true + }, + "external_zoom_secret": { + "type": "string", + "nullable": true + }, + "hook_custom_access_token_enabled": { + "type": "boolean", + "nullable": true + }, + "hook_custom_access_token_uri": { + "type": "string", + "nullable": true + }, + "hook_custom_access_token_secrets": { + "type": "string", + "nullable": true + }, + "hook_mfa_verification_attempt_enabled": { + "type": "boolean", + "nullable": true + }, + "hook_mfa_verification_attempt_uri": { + "type": "string", + "nullable": true + }, + "hook_mfa_verification_attempt_secrets": { + "type": "string", + "nullable": true + }, + "hook_password_verification_attempt_enabled": { + "type": "boolean", + "nullable": true + }, + "hook_password_verification_attempt_uri": { + "type": "string", + "nullable": true + }, + "hook_password_verification_attempt_secrets": { + "type": "string", + "nullable": true + }, + "hook_send_sms_enabled": { + "type": "boolean", + "nullable": true + }, + "hook_send_sms_uri": { + "type": "string", + "nullable": true + }, + "hook_send_sms_secrets": { + "type": "string", + "nullable": true + }, + "hook_send_email_enabled": { + "type": "boolean", + "nullable": true + }, + "hook_send_email_uri": { + "type": "string", + "nullable": true + }, + "hook_send_email_secrets": { + "type": "string", + "nullable": true + }, + "hook_before_user_created_enabled": { + "type": "boolean", + "nullable": true + }, + "hook_before_user_created_uri": { + "type": "string", + "nullable": true + }, + "hook_before_user_created_secrets": { + "type": "string", + "nullable": true + }, + "hook_after_user_created_enabled": { + "type": "boolean", + "nullable": true + }, + "hook_after_user_created_uri": { + "type": "string", + "nullable": true + }, + "hook_after_user_created_secrets": { + "type": "string", + "nullable": true + }, + "jwt_exp": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "nullable": true + }, + "mailer_allow_unverified_email_sign_ins": { + "type": "boolean", + "nullable": true + }, + "mailer_autoconfirm": { + "type": "boolean", + "nullable": true + }, + "mailer_otp_exp": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "mailer_otp_length": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "nullable": true + }, + "mailer_secure_email_change_enabled": { + "type": "boolean", + "nullable": true + }, + "mailer_subjects_confirmation": { + "type": "string", + "nullable": true + }, + "mailer_subjects_email_change": { + "type": "string", + "nullable": true + }, + "mailer_subjects_invite": { + "type": "string", + "nullable": true + }, + "mailer_subjects_magic_link": { + "type": "string", + "nullable": true + }, + "mailer_subjects_reauthentication": { + "type": "string", + "nullable": true + }, + "mailer_subjects_recovery": { + "type": "string", + "nullable": true + }, + "mailer_subjects_password_changed_notification": { + "type": "string", + "nullable": true + }, + "mailer_subjects_email_changed_notification": { + "type": "string", + "nullable": true + }, + "mailer_subjects_phone_changed_notification": { + "type": "string", + "nullable": true + }, + "mailer_subjects_mfa_factor_enrolled_notification": { + "type": "string", + "nullable": true + }, + "mailer_subjects_mfa_factor_unenrolled_notification": { + "type": "string", + "nullable": true + }, + "mailer_subjects_identity_linked_notification": { + "type": "string", + "nullable": true + }, + "mailer_subjects_identity_unlinked_notification": { + "type": "string", + "nullable": true + }, + "mailer_templates_confirmation_content": { + "type": "string", + "nullable": true + }, + "mailer_templates_email_change_content": { + "type": "string", + "nullable": true + }, + "mailer_templates_invite_content": { + "type": "string", + "nullable": true + }, + "mailer_templates_magic_link_content": { + "type": "string", + "nullable": true + }, + "mailer_templates_reauthentication_content": { + "type": "string", + "nullable": true + }, + "mailer_templates_recovery_content": { + "type": "string", + "nullable": true + }, + "mailer_templates_password_changed_notification_content": { + "type": "string", + "nullable": true + }, + "mailer_templates_email_changed_notification_content": { + "type": "string", + "nullable": true + }, + "mailer_templates_phone_changed_notification_content": { + "type": "string", + "nullable": true + }, + "mailer_templates_mfa_factor_enrolled_notification_content": { + "type": "string", + "nullable": true + }, + "mailer_templates_mfa_factor_unenrolled_notification_content": { + "type": "string", + "nullable": true + }, + "mailer_templates_identity_linked_notification_content": { + "type": "string", + "nullable": true + }, + "mailer_templates_identity_unlinked_notification_content": { + "type": "string", + "nullable": true + }, + "mailer_notifications_password_changed_enabled": { + "type": "boolean", + "nullable": true + }, + "mailer_notifications_email_changed_enabled": { + "type": "boolean", + "nullable": true + }, + "mailer_notifications_phone_changed_enabled": { + "type": "boolean", + "nullable": true + }, + "mailer_notifications_mfa_factor_enrolled_enabled": { + "type": "boolean", + "nullable": true + }, + "mailer_notifications_mfa_factor_unenrolled_enabled": { + "type": "boolean", + "nullable": true + }, + "mailer_notifications_identity_linked_enabled": { + "type": "boolean", + "nullable": true }, "mailer_notifications_identity_unlinked_enabled": { "type": "boolean", @@ -16396,4469 +17724,7002 @@ "type": "boolean", "nullable": true }, - "external_twitch_secret": { + "external_twitch_secret": { + "type": "string", + "nullable": true + }, + "external_twitter_enabled": { + "type": "boolean", + "nullable": true + }, + "external_twitter_client_id": { + "type": "string", + "nullable": true + }, + "external_twitter_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_twitter_secret": { + "type": "string", + "nullable": true + }, + "external_x_enabled": { + "type": "boolean", + "nullable": true + }, + "external_x_client_id": { + "type": "string", + "nullable": true + }, + "external_x_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_x_secret": { + "type": "string", + "nullable": true + }, + "external_workos_enabled": { + "type": "boolean", + "nullable": true + }, + "external_workos_client_id": { + "type": "string", + "nullable": true + }, + "external_workos_secret": { + "type": "string", + "nullable": true + }, + "external_workos_url": { + "type": "string", + "nullable": true + }, + "external_web3_solana_enabled": { + "type": "boolean", + "nullable": true + }, + "external_web3_ethereum_enabled": { + "type": "boolean", + "nullable": true + }, + "external_zoom_enabled": { + "type": "boolean", + "nullable": true + }, + "external_zoom_client_id": { + "type": "string", + "nullable": true + }, + "external_zoom_email_optional": { + "type": "boolean", + "nullable": true + }, + "external_zoom_secret": { + "type": "string", + "nullable": true + }, + "db_max_pool_size": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "nullable": true + }, + "db_max_pool_size_unit": { + "type": "string", + "enum": ["connections", "percent", null], + "nullable": true + }, + "api_max_request_duration": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "nullable": true + }, + "mfa_totp_enroll_enabled": { + "type": "boolean", + "nullable": true + }, + "mfa_totp_verify_enabled": { + "type": "boolean", + "nullable": true + }, + "mfa_web_authn_enroll_enabled": { + "type": "boolean", + "nullable": true + }, + "mfa_web_authn_verify_enabled": { + "type": "boolean", + "nullable": true + }, + "passkey_enabled": { + "type": "boolean" + }, + "webauthn_rp_display_name": { + "type": "string", + "nullable": true + }, + "webauthn_rp_id": { + "type": "string", + "nullable": true + }, + "webauthn_rp_origins": { + "type": "string", + "nullable": true + }, + "mfa_phone_enroll_enabled": { + "type": "boolean", + "nullable": true + }, + "mfa_phone_verify_enabled": { + "type": "boolean", + "nullable": true + }, + "mfa_phone_max_frequency": { + "type": "integer", + "minimum": 0, + "maximum": 32767, + "nullable": true + }, + "mfa_phone_otp_length": { + "type": "integer", + "minimum": 0, + "maximum": 32767, + "nullable": true + }, + "mfa_phone_template": { + "type": "string", + "nullable": true + }, + "nimbus_oauth_client_id": { + "type": "string", + "nullable": true + }, + "nimbus_oauth_client_secret": { "type": "string", "nullable": true }, - "external_twitter_enabled": { + "oauth_server_enabled": { "type": "boolean", "nullable": true }, - "external_twitter_client_id": { - "type": "string", - "nullable": true - }, - "external_twitter_email_optional": { + "oauth_server_allow_dynamic_registration": { "type": "boolean", "nullable": true }, - "external_twitter_secret": { + "oauth_server_authorization_path": { "type": "string", "nullable": true }, - "external_x_enabled": { - "type": "boolean", - "nullable": true + "custom_oauth_enabled": { + "type": "boolean" + } + }, + "example": { + "site_url": "https://app.example.com", + "disable_signup": false, + "jwt_exp": 3600 + } + }, + "CreateThirdPartyAuthBody": { + "type": "object", + "properties": { + "oidc_issuer_url": { + "type": "string" }, - "external_x_client_id": { + "jwks_url": { + "type": "string" + }, + "custom_jwks": {} + }, + "example": { + "oidc_issuer_url": "https://login.acme.com", + "jwks_url": "https://login.acme.com/.well-known/jwks.json" + } + }, + "ThirdPartyAuth": { + "type": "object", + "properties": { + "id": { "type": "string", - "nullable": true + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, - "external_x_email_optional": { - "type": "boolean", + "type": { + "type": "string" + }, + "oidc_issuer_url": { + "type": "string", "nullable": true }, - "external_x_secret": { + "jwks_url": { "type": "string", "nullable": true }, - "external_workos_enabled": { - "type": "boolean", + "custom_jwks": { "nullable": true }, - "external_workos_client_id": { - "type": "string", + "resolved_jwks": { "nullable": true }, - "external_workos_secret": { + "inserted_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "resolved_at": { "type": "string", "nullable": true + } + }, + "required": ["id", "type", "inserted_at", "updated_at"] + }, + "GetProjectAvailableRestoreVersionsResponse": { + "type": "object", + "properties": { + "available_versions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "release_channel": { + "type": "string", + "enum": ["internal", "alpha", "beta", "ga", "withdrawn", "preview"] + }, + "postgres_engine": { + "type": "string", + "enum": ["13", "14", "15", "17", "17-oriole"] + } + }, + "required": ["version", "release_channel", "postgres_engine"] + } + } + }, + "required": ["available_versions"] + }, + "ListProjectAddonsResponseJsonValue": { + "description": "Any JSON-serializable value", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ], + "nullable": true + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/ListProjectAddonsResponseJsonValue" + } + }, + { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/ListProjectAddonsResponseJsonValue" + } + } + ] + }, + "ListProjectAddonsResponse": { + "type": "object", + "properties": { + "selected_addons": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "custom_domain", + "compute_instance", + "pitr", + "ipv4", + "auth_mfa_phone", + "auth_mfa_web_authn", + "log_drain", + "etl_pipeline" + ] + }, + "variant": { + "type": "object", + "properties": { + "id": { + "anyOf": [ + { + "type": "string", + "enum": [ + "ci_micro", + "ci_small", + "ci_medium", + "ci_large", + "ci_xlarge", + "ci_2xlarge", + "ci_4xlarge", + "ci_8xlarge", + "ci_12xlarge", + "ci_16xlarge", + "ci_24xlarge", + "ci_24xlarge_optimized_cpu", + "ci_24xlarge_optimized_memory", + "ci_24xlarge_high_memory", + "ci_48xlarge", + "ci_48xlarge_optimized_cpu", + "ci_48xlarge_optimized_memory", + "ci_48xlarge_high_memory" + ] + }, + { + "type": "string", + "enum": ["cd_default"] + }, + { + "type": "string", + "enum": ["pitr_7", "pitr_14", "pitr_28"] + }, + { + "type": "string", + "enum": ["ipv4_default"] + }, + { + "type": "string", + "enum": ["auth_mfa_phone_default"] + }, + { + "type": "string", + "enum": ["auth_mfa_web_authn_default"] + }, + { + "type": "string", + "enum": ["log_drain_default"] + }, + { + "type": "string", + "enum": ["etl_pipeline_default"] + } + ] + }, + "name": { + "type": "string" + }, + "price": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["fixed", "usage"] + }, + "interval": { + "type": "string", + "enum": ["monthly", "hourly"] + }, + "amount": { + "type": "number" + } + }, + "required": ["description", "type", "interval", "amount"] + }, + "meta": { + "$ref": "#/components/schemas/ListProjectAddonsResponseJsonValue" + } + }, + "required": ["id", "name", "price"] + } + }, + "required": ["type", "variant"] + } + }, + "available_addons": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "custom_domain", + "compute_instance", + "pitr", + "ipv4", + "auth_mfa_phone", + "auth_mfa_web_authn", + "log_drain", + "etl_pipeline" + ] + }, + "name": { + "type": "string" + }, + "variants": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "anyOf": [ + { + "type": "string", + "enum": [ + "ci_micro", + "ci_small", + "ci_medium", + "ci_large", + "ci_xlarge", + "ci_2xlarge", + "ci_4xlarge", + "ci_8xlarge", + "ci_12xlarge", + "ci_16xlarge", + "ci_24xlarge", + "ci_24xlarge_optimized_cpu", + "ci_24xlarge_optimized_memory", + "ci_24xlarge_high_memory", + "ci_48xlarge", + "ci_48xlarge_optimized_cpu", + "ci_48xlarge_optimized_memory", + "ci_48xlarge_high_memory" + ] + }, + { + "type": "string", + "enum": ["cd_default"] + }, + { + "type": "string", + "enum": ["pitr_7", "pitr_14", "pitr_28"] + }, + { + "type": "string", + "enum": ["ipv4_default"] + }, + { + "type": "string", + "enum": ["auth_mfa_phone_default"] + }, + { + "type": "string", + "enum": ["auth_mfa_web_authn_default"] + }, + { + "type": "string", + "enum": ["log_drain_default"] + }, + { + "type": "string", + "enum": ["etl_pipeline_default"] + } + ] + }, + "name": { + "type": "string" + }, + "price": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["fixed", "usage"] + }, + "interval": { + "type": "string", + "enum": ["monthly", "hourly"] + }, + "amount": { + "type": "number" + } + }, + "required": ["description", "type", "interval", "amount"] + }, + "meta": { + "$ref": "#/components/schemas/ListProjectAddonsResponseJsonValue" + } + }, + "required": ["id", "name", "price"] + } + } + }, + "required": ["type", "name", "variants"] + } + } + }, + "required": ["selected_addons", "available_addons"] + }, + "ApplyProjectAddonBody": { + "type": "object", + "properties": { + "addon_variant": { + "anyOf": [ + { + "type": "string", + "enum": [ + "ci_micro", + "ci_small", + "ci_medium", + "ci_large", + "ci_xlarge", + "ci_2xlarge", + "ci_4xlarge", + "ci_8xlarge", + "ci_12xlarge", + "ci_16xlarge", + "ci_24xlarge", + "ci_24xlarge_optimized_cpu", + "ci_24xlarge_optimized_memory", + "ci_24xlarge_high_memory", + "ci_48xlarge", + "ci_48xlarge_optimized_cpu", + "ci_48xlarge_optimized_memory", + "ci_48xlarge_high_memory" + ] + }, + { + "type": "string", + "enum": ["cd_default"] + }, + { + "type": "string", + "enum": ["pitr_7", "pitr_14", "pitr_28"] + }, + { + "type": "string", + "enum": ["ipv4_default"] + } + ] }, - "external_workos_url": { + "addon_type": { "type": "string", - "nullable": true - }, - "external_web3_solana_enabled": { - "type": "boolean", - "nullable": true + "enum": [ + "custom_domain", + "compute_instance", + "pitr", + "ipv4", + "auth_mfa_phone", + "auth_mfa_web_authn", + "log_drain", + "etl_pipeline" + ] + } + }, + "required": ["addon_variant", "addon_type"], + "example": { + "addon_variant": "pitr_7", + "addon_type": "pitr" + } + }, + "ProjectClaimTokenResponse": { + "type": "object", + "properties": { + "token_alias": { + "type": "string" }, - "external_web3_ethereum_enabled": { - "type": "boolean", - "nullable": true + "expires_at": { + "type": "string" }, - "external_zoom_enabled": { - "type": "boolean", - "nullable": true + "created_at": { + "type": "string" }, - "external_zoom_client_id": { + "created_by": { "type": "string", - "nullable": true + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" + } + }, + "required": ["token_alias", "expires_at", "created_at", "created_by"] + }, + "CreateProjectClaimTokenResponse": { + "type": "object", + "properties": { + "token": { + "type": "string" }, - "external_zoom_email_optional": { - "type": "boolean", - "nullable": true + "token_alias": { + "type": "string" }, - "external_zoom_secret": { - "type": "string", - "nullable": true + "expires_at": { + "type": "string" }, - "db_max_pool_size": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991, - "nullable": true + "created_at": { + "type": "string" }, - "db_max_pool_size_unit": { + "created_by": { "type": "string", - "enum": ["connections", "percent", null], - "nullable": true - }, - "api_max_request_duration": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991, - "nullable": true - }, - "mfa_totp_enroll_enabled": { - "type": "boolean", - "nullable": true - }, - "mfa_totp_verify_enabled": { - "type": "boolean", - "nullable": true + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" + } + }, + "required": ["token", "token_alias", "expires_at", "created_at", "created_by"] + }, + "V1ProjectAdvisorsResponse": { + "type": "object", + "properties": { + "lints": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "enum": [ + "unindexed_foreign_keys", + "auth_users_exposed", + "auth_rls_initplan", + "no_primary_key", + "unused_index", + "multiple_permissive_policies", + "policy_exists_rls_disabled", + "rls_enabled_no_policy", + "duplicate_index", + "security_definer_view", + "function_search_path_mutable", + "rls_disabled_in_public", + "extension_in_public", + "rls_references_user_metadata", + "materialized_view_in_api", + "foreign_table_in_api", + "unsupported_reg_types", + "auth_otp_long_expiry", + "auth_otp_short_length", + "ssl_not_enforced", + "network_restrictions_not_set", + "password_requirements_min_length", + "pitr_not_enabled", + "auth_leaked_password_protection", + "auth_insufficient_mfa_options", + "auth_password_policy_missing", + "leaked_service_key", + "no_backup_admin", + "vulnerable_postgres_version" + ], + "type": "string" + }, + "title": { + "type": "string" + }, + "level": { + "type": "string", + "enum": ["ERROR", "WARN", "INFO"] + }, + "facing": { + "type": "string", + "enum": ["EXTERNAL"] + }, + "categories": { + "type": "array", + "items": { + "type": "string", + "enum": ["PERFORMANCE", "SECURITY"] + } + }, + "description": { + "type": "string" + }, + "detail": { + "type": "string" + }, + "remediation": { + "type": "string" + }, + "metadata": { + "type": "object", + "properties": { + "schema": { + "type": "string" + }, + "name": { + "type": "string" + }, + "entity": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["table", "view", "auth", "function", "extension", "compliance"] + }, + "fkey_name": { + "type": "string" + }, + "fkey_columns": { + "type": "array", + "items": { + "type": "number" + } + } + } + }, + "cache_key": { + "type": "string" + } + }, + "required": [ + "name", + "title", + "level", + "facing", + "categories", + "description", + "detail", + "remediation", + "cache_key" + ] + } + } + }, + "required": ["lints"] + }, + "AnalyticsResponse": { + "type": "object", + "properties": { + "result": { + "type": "array", + "items": {} }, - "mfa_web_authn_enroll_enabled": { - "type": "boolean", - "nullable": true + "error": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "code": { + "type": "number" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "properties": { + "domain": { + "type": "string" + }, + "location": { + "type": "string" + }, + "locationType": { + "type": "string" + }, + "message": { + "type": "string" + }, + "reason": { + "type": "string" + } + }, + "required": ["domain", "location", "locationType", "message", "reason"] + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": ["code", "errors", "message", "status"] + } + ] + } + } + }, + "V1GetUsageApiCountResponse": { + "type": "object", + "properties": { + "result": { + "type": "array", + "items": { + "type": "object", + "properties": { + "timestamp": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$" + }, + "total_auth_requests": { + "type": "number" + }, + "total_realtime_requests": { + "type": "number" + }, + "total_rest_requests": { + "type": "number" + }, + "total_storage_requests": { + "type": "number" + } + }, + "required": [ + "timestamp", + "total_auth_requests", + "total_realtime_requests", + "total_rest_requests", + "total_storage_requests" + ] + } }, - "mfa_web_authn_verify_enabled": { - "type": "boolean", - "nullable": true + "error": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "code": { + "type": "number" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "properties": { + "domain": { + "type": "string" + }, + "location": { + "type": "string" + }, + "locationType": { + "type": "string" + }, + "message": { + "type": "string" + }, + "reason": { + "type": "string" + } + }, + "required": ["domain", "location", "locationType", "message", "reason"] + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": ["code", "errors", "message", "status"] + } + ] + } + } + }, + "V1GetUsageApiRequestsCountResponse": { + "type": "object", + "properties": { + "result": { + "type": "array", + "items": { + "type": "object", + "properties": { + "count": { + "type": "number" + } + }, + "required": ["count"] + } }, - "passkey_enabled": { + "error": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "code": { + "type": "number" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "properties": { + "domain": { + "type": "string" + }, + "location": { + "type": "string" + }, + "locationType": { + "type": "string" + }, + "message": { + "type": "string" + }, + "reason": { + "type": "string" + } + }, + "required": ["domain", "location", "locationType", "message", "reason"] + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": ["code", "errors", "message", "status"] + } + ] + } + } + }, + "CreateRoleBody": { + "type": "object", + "properties": { + "read_only": { "type": "boolean" - }, - "webauthn_rp_display_name": { - "type": "string", - "nullable": true - }, - "webauthn_rp_id": { + } + }, + "required": ["read_only"], + "example": { + "read_only": true + } + }, + "CreateRoleResponse": { + "type": "object", + "properties": { + "role": { "type": "string", - "nullable": true + "minLength": 1 }, - "webauthn_rp_origins": { + "password": { "type": "string", - "nullable": true - }, - "mfa_phone_enroll_enabled": { - "type": "boolean", - "nullable": true - }, - "mfa_phone_verify_enabled": { - "type": "boolean", - "nullable": true - }, - "mfa_phone_max_frequency": { - "type": "integer", - "minimum": 0, - "maximum": 32767, - "nullable": true + "minLength": 1 }, - "mfa_phone_otp_length": { + "ttl_seconds": { "type": "integer", - "minimum": 0, - "maximum": 32767, - "nullable": true - }, - "mfa_phone_template": { - "type": "string", - "nullable": true - }, - "nimbus_oauth_client_id": { + "minimum": 1, + "maximum": 9007199254740991, + "format": "int64" + } + }, + "required": ["role", "password", "ttl_seconds"] + }, + "DeleteRolesResponse": { + "type": "object", + "properties": { + "message": { "type": "string", - "nullable": true + "enum": ["ok"] + } + }, + "required": ["message"] + }, + "V1ListMigrationsResponse": { + "type": "array", + "items": { + "type": "object", + "properties": { + "version": { + "type": "string", + "minLength": 1 + }, + "name": { + "type": "string" + } }, - "nimbus_oauth_client_secret": { + "required": ["version"] + } + }, + "V1CreateMigrationBody": { + "type": "object", + "properties": { + "query": { "type": "string", - "nullable": true - }, - "oauth_server_enabled": { - "type": "boolean", - "nullable": true - }, - "oauth_server_allow_dynamic_registration": { - "type": "boolean", - "nullable": true + "minLength": 1 }, - "oauth_server_authorization_path": { - "type": "string", - "nullable": true + "name": { + "type": "string" }, - "custom_oauth_enabled": { - "type": "boolean" + "rollback": { + "type": "string" } }, + "required": ["query"], "example": { - "site_url": "https://app.example.com", - "disable_signup": false, - "jwt_exp": 3600 + "query": "create table public.widgets(id bigint primary key);", + "name": "create_widgets_table", + "rollback": "drop table if exists public.widgets;" } }, - "CreateThirdPartyAuthBody": { + "V1UpsertMigrationBody": { "type": "object", "properties": { - "oidc_issuer_url": { - "type": "string" + "query": { + "type": "string", + "minLength": 1 }, - "jwks_url": { + "name": { "type": "string" }, - "custom_jwks": {} + "rollback": { + "type": "string" + } }, + "required": ["query"], "example": { - "oidc_issuer_url": "https://login.acme.com", - "jwks_url": "https://login.acme.com/.well-known/jwks.json" + "query": "create table public.widgets(id bigint primary key);", + "name": "create_widgets_table", + "rollback": "drop table if exists public.widgets;" } }, - "ThirdPartyAuth": { + "V1GetMigrationResponse": { "type": "object", "properties": { - "id": { + "version": { "type": "string", - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" + "minLength": 1 }, - "type": { + "name": { "type": "string" }, - "oidc_issuer_url": { - "type": "string", - "nullable": true - }, - "jwks_url": { - "type": "string", - "nullable": true - }, - "custom_jwks": { - "nullable": true + "statements": { + "type": "array", + "items": { + "type": "string" + } }, - "resolved_jwks": { - "nullable": true + "rollback": { + "type": "array", + "items": { + "type": "string" + } }, - "inserted_at": { + "created_by": { "type": "string" }, - "updated_at": { + "idempotency_key": { "type": "string" - }, - "resolved_at": { - "type": "string", - "nullable": true } }, - "required": ["id", "type", "inserted_at", "updated_at"] + "required": ["version"] }, - "GetProjectAvailableRestoreVersionsResponse": { + "V1PatchMigrationBody": { "type": "object", "properties": { - "available_versions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "version": { - "type": "string" - }, - "release_channel": { - "type": "string", - "enum": ["internal", "alpha", "beta", "ga", "withdrawn", "preview"] - }, - "postgres_engine": { - "type": "string", - "enum": ["13", "14", "15", "17", "17-oriole"] - } - }, - "required": ["version", "release_channel", "postgres_engine"] - } + "name": { + "type": "string" + }, + "rollback": { + "type": "string" } }, - "required": ["available_versions"] + "example": { + "name": "create_widgets_table", + "rollback": "drop table if exists public.widgets;" + } }, - "ListProjectAddonsResponseJsonValue": { - "description": "Any JSON-serializable value", - "anyOf": [ - { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "boolean" - } - ], - "nullable": true + "V1RunQueryBody": { + "type": "object", + "properties": { + "query": { + "type": "string", + "minLength": 1 }, - { + "parameters": { "type": "array", - "items": { - "$ref": "#/components/schemas/ListProjectAddonsResponseJsonValue" - } + "items": {} }, - { - "type": "object", - "additionalProperties": { - "$ref": "#/components/schemas/ListProjectAddonsResponseJsonValue" - } + "read_only": { + "type": "boolean" } - ] + }, + "required": ["query"], + "example": { + "query": "select * from pg_stat_activity limit 1;", + "read_only": true + } }, - "ListProjectAddonsResponse": { + "V1ReadOnlyQueryBody": { "type": "object", "properties": { - "selected_addons": { - "type": "array", - "items": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "custom_domain", - "compute_instance", - "pitr", - "ipv4", - "auth_mfa_phone", - "auth_mfa_web_authn", - "log_drain", - "etl_pipeline" - ] - }, - "variant": { - "type": "object", - "properties": { - "id": { - "anyOf": [ - { - "type": "string", - "enum": [ - "ci_micro", - "ci_small", - "ci_medium", - "ci_large", - "ci_xlarge", - "ci_2xlarge", - "ci_4xlarge", - "ci_8xlarge", - "ci_12xlarge", - "ci_16xlarge", - "ci_24xlarge", - "ci_24xlarge_optimized_cpu", - "ci_24xlarge_optimized_memory", - "ci_24xlarge_high_memory", - "ci_48xlarge", - "ci_48xlarge_optimized_cpu", - "ci_48xlarge_optimized_memory", - "ci_48xlarge_high_memory" - ] - }, - { - "type": "string", - "enum": ["cd_default"] - }, - { - "type": "string", - "enum": ["pitr_7", "pitr_14", "pitr_28"] - }, - { - "type": "string", - "enum": ["ipv4_default"] - }, - { - "type": "string", - "enum": ["auth_mfa_phone_default"] - }, - { - "type": "string", - "enum": ["auth_mfa_web_authn_default"] - }, - { - "type": "string", - "enum": ["log_drain_default"] - }, - { - "type": "string", - "enum": ["etl_pipeline_default"] - } - ] - }, - "name": { - "type": "string" - }, - "price": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["fixed", "usage"] - }, - "interval": { - "type": "string", - "enum": ["monthly", "hourly"] - }, - "amount": { - "type": "number" - } - }, - "required": ["description", "type", "interval", "amount"] - }, - "meta": { - "$ref": "#/components/schemas/ListProjectAddonsResponseJsonValue" - } - }, - "required": ["id", "name", "price"] - } - }, - "required": ["type", "variant"] - } + "query": { + "type": "string", + "minLength": 1 }, - "available_addons": { + "parameters": { + "type": "array", + "items": {} + } + }, + "required": ["query"], + "example": { + "query": "select * from pg_stat_activity limit 1;" + } + }, + "GetProjectDbMetadataResponse": { + "type": "object", + "properties": { + "databases": { "type": "array", "items": { "type": "object", "properties": { - "type": { - "type": "string", - "enum": [ - "custom_domain", - "compute_instance", - "pitr", - "ipv4", - "auth_mfa_phone", - "auth_mfa_web_authn", - "log_drain", - "etl_pipeline" - ] - }, "name": { "type": "string" }, - "variants": { + "schemas": { "type": "array", "items": { "type": "object", "properties": { - "id": { - "anyOf": [ - { - "type": "string", - "enum": [ - "ci_micro", - "ci_small", - "ci_medium", - "ci_large", - "ci_xlarge", - "ci_2xlarge", - "ci_4xlarge", - "ci_8xlarge", - "ci_12xlarge", - "ci_16xlarge", - "ci_24xlarge", - "ci_24xlarge_optimized_cpu", - "ci_24xlarge_optimized_memory", - "ci_24xlarge_high_memory", - "ci_48xlarge", - "ci_48xlarge_optimized_cpu", - "ci_48xlarge_optimized_memory", - "ci_48xlarge_high_memory" - ] - }, - { - "type": "string", - "enum": ["cd_default"] - }, - { - "type": "string", - "enum": ["pitr_7", "pitr_14", "pitr_28"] - }, - { - "type": "string", - "enum": ["ipv4_default"] - }, - { - "type": "string", - "enum": ["auth_mfa_phone_default"] - }, - { - "type": "string", - "enum": ["auth_mfa_web_authn_default"] - }, - { - "type": "string", - "enum": ["log_drain_default"] - }, - { + "name": { + "type": "string" + } + }, + "required": ["name"], + "additionalProperties": {} + } + } + }, + "required": ["name", "schemas"], + "additionalProperties": {} + } + } + }, + "required": ["databases"] + }, + "V1UpdatePasswordBody": { + "type": "object", + "properties": { + "password": { + "type": "string", + "minLength": 4 + } + }, + "required": ["password"], + "example": { + "password": "correct-horse-battery-staple" + } + }, + "V1UpdatePasswordResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + }, + "required": ["message"] + }, + "JitAccessResponse": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" + }, + "user_roles": { + "type": "array", + "items": { + "type": "object", + "properties": { + "role": { + "type": "string", + "minLength": 1 + }, + "expires_at": { + "type": "number" + }, + "allowed_networks": { + "type": "object", + "properties": { + "allowed_cidrs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "cidr": { "type": "string", - "enum": ["etl_pipeline_default"] + "format": "cidrv4", + "pattern": "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/([0-9]|[1-2][0-9]|3[0-2])$" } - ] - }, - "name": { - "type": "string" - }, - "price": { + }, + "required": ["cidr"] + } + }, + "allowed_cidrs_v6": { + "type": "array", + "items": { "type": "object", "properties": { - "description": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["fixed", "usage"] - }, - "interval": { + "cidr": { "type": "string", - "enum": ["monthly", "hourly"] - }, - "amount": { - "type": "number" + "format": "cidrv6", + "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$" } }, - "required": ["description", "type", "interval", "amount"] - }, - "meta": { - "$ref": "#/components/schemas/ListProjectAddonsResponseJsonValue" + "required": ["cidr"] } - }, - "required": ["id", "name", "price"] + } } + }, + "branches_only": { + "type": "boolean" } }, - "required": ["type", "name", "variants"] + "required": ["role"] } } }, - "required": ["selected_addons", "available_addons"] + "required": ["user_roles"] }, - "ApplyProjectAddonBody": { + "AuthorizeJitAccessBody": { "type": "object", "properties": { - "addon_variant": { + "role": { + "type": "string", + "minLength": 1 + }, + "rhost": { "anyOf": [ { "type": "string", - "enum": [ - "ci_micro", - "ci_small", - "ci_medium", - "ci_large", - "ci_xlarge", - "ci_2xlarge", - "ci_4xlarge", - "ci_8xlarge", - "ci_12xlarge", - "ci_16xlarge", - "ci_24xlarge", - "ci_24xlarge_optimized_cpu", - "ci_24xlarge_optimized_memory", - "ci_24xlarge_high_memory", - "ci_48xlarge", - "ci_48xlarge_optimized_cpu", - "ci_48xlarge_optimized_memory", - "ci_48xlarge_high_memory" - ] - }, - { - "type": "string", - "enum": ["cd_default"] - }, - { - "type": "string", - "enum": ["pitr_7", "pitr_14", "pitr_28"] + "format": "ipv4", + "pattern": "^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$" }, { "type": "string", - "enum": ["ipv4_default"] + "format": "ipv6", + "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$" } ] - }, - "addon_type": { - "type": "string", - "enum": [ - "custom_domain", - "compute_instance", - "pitr", - "ipv4", - "auth_mfa_phone", - "auth_mfa_web_authn", - "log_drain", - "etl_pipeline" - ] } }, - "required": ["addon_variant", "addon_type"], + "required": ["role", "rhost"], "example": { - "addon_variant": "pitr_7", - "addon_type": "pitr" + "role": "postgres", + "rhost": "203.0.113.10" } }, - "ProjectClaimTokenResponse": { + "JitAuthorizeAccessResponse": { "type": "object", "properties": { - "token_alias": { - "type": "string" - }, - "expires_at": { - "type": "string" - }, - "created_at": { - "type": "string" - }, - "created_by": { + "user_id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - } - }, - "required": ["token_alias", "expires_at", "created_at", "created_by"] - }, - "CreateProjectClaimTokenResponse": { - "type": "object", - "properties": { - "token": { - "type": "string" - }, - "token_alias": { - "type": "string" - }, - "expires_at": { - "type": "string" - }, - "created_at": { - "type": "string" }, - "created_by": { - "type": "string", - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - } - }, - "required": ["token", "token_alias", "expires_at", "created_at", "created_by"] - }, - "V1ProjectAdvisorsResponse": { - "type": "object", - "properties": { - "lints": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "enum": [ - "unindexed_foreign_keys", - "auth_users_exposed", - "auth_rls_initplan", - "no_primary_key", - "unused_index", - "multiple_permissive_policies", - "policy_exists_rls_disabled", - "rls_enabled_no_policy", - "duplicate_index", - "security_definer_view", - "function_search_path_mutable", - "rls_disabled_in_public", - "extension_in_public", - "rls_references_user_metadata", - "materialized_view_in_api", - "foreign_table_in_api", - "unsupported_reg_types", - "auth_otp_long_expiry", - "auth_otp_short_length", - "ssl_not_enforced", - "network_restrictions_not_set", - "password_requirements_min_length", - "pitr_not_enabled", - "auth_leaked_password_protection", - "auth_insufficient_mfa_options", - "auth_password_policy_missing", - "leaked_service_key", - "no_backup_admin", - "vulnerable_postgres_version" - ], - "type": "string" - }, - "title": { - "type": "string" - }, - "level": { - "type": "string", - "enum": ["ERROR", "WARN", "INFO"] - }, - "facing": { - "type": "string", - "enum": ["EXTERNAL"] - }, - "categories": { - "type": "array", - "items": { - "type": "string", - "enum": ["PERFORMANCE", "SECURITY"] + "user_role": { + "type": "object", + "properties": { + "role": { + "type": "string", + "minLength": 1 + }, + "expires_at": { + "type": "number" + }, + "allowed_networks": { + "type": "object", + "properties": { + "allowed_cidrs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "cidr": { + "type": "string", + "format": "cidrv4", + "pattern": "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/([0-9]|[1-2][0-9]|3[0-2])$" + } + }, + "required": ["cidr"] + } + }, + "allowed_cidrs_v6": { + "type": "array", + "items": { + "type": "object", + "properties": { + "cidr": { + "type": "string", + "format": "cidrv6", + "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$" + } + }, + "required": ["cidr"] + } } - }, - "description": { - "type": "string" - }, - "detail": { - "type": "string" - }, - "remediation": { - "type": "string" - }, - "metadata": { + } + }, + "branches_only": { + "type": "boolean" + } + }, + "required": ["role"] + } + }, + "required": ["user_id", "user_role"] + }, + "JitListAccessResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "anyOf": [ + { "type": "object", "properties": { - "schema": { - "type": "string" + "user_id": { + "type": "string", + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, - "name": { - "type": "string" + "primary_email": { + "type": "string", + "nullable": true }, - "entity": { + "invite_id": { + "type": "null" + }, + "expires_at": { + "type": "null" + }, + "user_roles": { + "type": "array", + "items": { + "type": "object", + "properties": { + "role": { + "type": "string", + "minLength": 1 + }, + "expires_at": { + "type": "number" + }, + "allowed_networks": { + "type": "object", + "properties": { + "allowed_cidrs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "cidr": { + "type": "string", + "format": "cidrv4", + "pattern": "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/([0-9]|[1-2][0-9]|3[0-2])$" + } + }, + "required": ["cidr"] + } + }, + "allowed_cidrs_v6": { + "type": "array", + "items": { + "type": "object", + "properties": { + "cidr": { + "type": "string", + "format": "cidrv6", + "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$" + } + }, + "required": ["cidr"] + } + } + } + }, + "branches_only": { + "type": "boolean" + } + }, + "required": ["role"] + } + } + }, + "required": ["user_id", "primary_email", "invite_id", "expires_at", "user_roles"] + }, + { + "type": "object", + "properties": { + "user_id": { + "type": "null" + }, + "primary_email": { "type": "string" }, - "type": { + "invite_id": { "type": "string", - "enum": ["table", "view", "auth", "function", "extension", "compliance"] + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, - "fkey_name": { + "expires_at": { "type": "string" }, - "fkey_columns": { + "user_roles": { "type": "array", "items": { - "type": "number" + "type": "object", + "properties": { + "role": { + "type": "string", + "minLength": 1 + }, + "expires_at": { + "type": "number" + }, + "allowed_networks": { + "type": "object", + "properties": { + "allowed_cidrs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "cidr": { + "type": "string", + "format": "cidrv4", + "pattern": "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/([0-9]|[1-2][0-9]|3[0-2])$" + } + }, + "required": ["cidr"] + } + }, + "allowed_cidrs_v6": { + "type": "array", + "items": { + "type": "object", + "properties": { + "cidr": { + "type": "string", + "format": "cidrv6", + "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$" + } + }, + "required": ["cidr"] + } + } + } + }, + "branches_only": { + "type": "boolean" + } + }, + "required": ["role"] } } - } - }, - "cache_key": { - "type": "string" + }, + "required": ["user_id", "primary_email", "invite_id", "expires_at", "user_roles"] } - }, - "required": [ - "name", - "title", - "level", - "facing", - "categories", - "description", - "detail", - "remediation", - "cache_key" ] } } }, - "required": ["lints"] + "required": ["items"] }, - "AnalyticsResponse": { + "UpdateJitAccessBody": { "type": "object", "properties": { - "result": { - "type": "array", - "items": {} + "user_id": { + "type": "string", + "minLength": 1, + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, - "error": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "code": { - "type": "number" - }, - "errors": { - "type": "array", - "items": { - "type": "object", - "properties": { - "domain": { - "type": "string" - }, - "location": { - "type": "string" - }, - "locationType": { - "type": "string" + "roles": { + "type": "array", + "items": { + "type": "object", + "properties": { + "role": { + "type": "string", + "minLength": 1 + }, + "expires_at": { + "type": "number" + }, + "allowed_networks": { + "type": "object", + "properties": { + "allowed_cidrs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "cidr": { + "type": "string", + "format": "cidrv4", + "pattern": "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/([0-9]|[1-2][0-9]|3[0-2])$" + } }, - "message": { - "type": "string" + "required": ["cidr"] + } + }, + "allowed_cidrs_v6": { + "type": "array", + "items": { + "type": "object", + "properties": { + "cidr": { + "type": "string", + "format": "cidrv6", + "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$" + } }, - "reason": { - "type": "string" - } - }, - "required": ["domain", "location", "locationType", "message", "reason"] + "required": ["cidr"] + } } - }, - "message": { - "type": "string" - }, - "status": { - "type": "string" } }, - "required": ["code", "errors", "message", "status"] - } - ] + "branches_only": { + "type": "boolean" + } + }, + "required": ["role"] + } } + }, + "required": ["user_id", "roles"], + "example": { + "user_id": "55555555-5555-4555-8555-555555555555", + "roles": [ + { + "role": "postgres", + "expires_at": 1740787200, + "allowed_networks": { + "allowed_cidrs": [ + { + "cidr": "203.0.113.0/24" + } + ] + }, + "branches_only": false + } + ] } }, - "V1GetUsageApiCountResponse": { + "InviteExternalUserJitAccessBody": { "type": "object", "properties": { - "result": { + "email": { + "type": "string", + "minLength": 1, + "format": "email", + "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" + }, + "roles": { "type": "array", "items": { "type": "object", "properties": { - "timestamp": { + "role": { "type": "string", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$" - }, - "total_auth_requests": { - "type": "number" - }, - "total_realtime_requests": { - "type": "number" + "minLength": 1 }, - "total_rest_requests": { + "expires_at": { "type": "number" }, - "total_storage_requests": { - "type": "number" - } - }, - "required": [ - "timestamp", - "total_auth_requests", - "total_realtime_requests", - "total_rest_requests", - "total_storage_requests" - ] - } - }, - "error": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "code": { - "type": "number" - }, - "errors": { - "type": "array", - "items": { - "type": "object", - "properties": { - "domain": { - "type": "string" - }, - "location": { - "type": "string" - }, - "locationType": { - "type": "string" + "allowed_networks": { + "type": "object", + "properties": { + "allowed_cidrs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "cidr": { + "type": "string", + "format": "cidrv4", + "pattern": "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/([0-9]|[1-2][0-9]|3[0-2])$" + } }, - "message": { - "type": "string" + "required": ["cidr"] + } + }, + "allowed_cidrs_v6": { + "type": "array", + "items": { + "type": "object", + "properties": { + "cidr": { + "type": "string", + "format": "cidrv6", + "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$" + } }, - "reason": { - "type": "string" - } - }, - "required": ["domain", "location", "locationType", "message", "reason"] + "required": ["cidr"] + } } - }, - "message": { - "type": "string" - }, - "status": { - "type": "string" } }, - "required": ["code", "errors", "message", "status"] - } - ] + "branches_only": { + "type": "boolean" + } + }, + "required": ["role"] + } } + }, + "required": ["email", "roles"], + "example": { + "email": "external-user@somedomain.xyz", + "roles": [ + { + "role": "postgres", + "expires_at": 1740787200, + "allowed_networks": { + "allowed_cidrs": [ + { + "cidr": "203.0.113.0/24" + } + ] + }, + "branches_only": false + } + ] } }, - "V1GetUsageApiRequestsCountResponse": { + "InviteExternalUserJitResponse": { "type": "object", "properties": { - "result": { + "email": { + "type": "string", + "format": "email", + "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" + }, + "invite_id": { + "type": "string", + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" + }, + "user_roles": { "type": "array", "items": { "type": "object", "properties": { - "count": { + "role": { + "type": "string", + "minLength": 1 + }, + "expires_at": { "type": "number" - } - }, - "required": ["count"] - } - }, - "error": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "code": { - "type": "number" - }, - "errors": { - "type": "array", - "items": { - "type": "object", - "properties": { - "domain": { - "type": "string" - }, - "location": { - "type": "string" - }, - "locationType": { - "type": "string" + }, + "allowed_networks": { + "type": "object", + "properties": { + "allowed_cidrs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "cidr": { + "type": "string", + "format": "cidrv4", + "pattern": "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/([0-9]|[1-2][0-9]|3[0-2])$" + } }, - "message": { - "type": "string" + "required": ["cidr"] + } + }, + "allowed_cidrs_v6": { + "type": "array", + "items": { + "type": "object", + "properties": { + "cidr": { + "type": "string", + "format": "cidrv6", + "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$" + } }, - "reason": { - "type": "string" - } - }, - "required": ["domain", "location", "locationType", "message", "reason"] + "required": ["cidr"] + } } - }, - "message": { - "type": "string" - }, - "status": { - "type": "string" } }, - "required": ["code", "errors", "message", "status"] - } - ] + "branches_only": { + "type": "boolean" + } + }, + "required": ["role"] + } } - } + }, + "required": ["email", "invite_id", "user_roles"] }, - "CreateRoleBody": { + "AcceptInviteExternalUserJitAccessBody": { "type": "object", "properties": { - "read_only": { - "type": "boolean" + "email": { + "type": "string", + "minLength": 1, + "format": "email", + "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" + }, + "token": { + "type": "string", + "minLength": 1 } }, - "required": ["read_only"], + "required": ["email", "token"], "example": { - "read_only": true + "email": "external-user@somedomain.xyz", + "token": "" } }, - "CreateRoleResponse": { + "FunctionResponse": { "type": "object", "properties": { - "role": { - "type": "string", - "minLength": 1 + "id": { + "type": "string" }, - "password": { + "slug": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { "type": "string", - "minLength": 1 + "enum": ["ACTIVE", "REMOVED", "THROTTLED"] }, - "ttl_seconds": { + "version": { "type": "integer", - "minimum": 1, + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "created_at": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "format": "int64" + }, + "updated_at": { + "type": "integer", + "minimum": -9007199254740991, "maximum": 9007199254740991, "format": "int64" + }, + "verify_jwt": { + "type": "boolean" + }, + "import_map": { + "type": "boolean" + }, + "entrypoint_path": { + "type": "string" + }, + "import_map_path": { + "type": "string", + "nullable": true + }, + "ezbr_sha256": { + "type": "string" } }, - "required": ["role", "password", "ttl_seconds"] + "required": ["id", "slug", "name", "status", "version", "created_at", "updated_at"] }, - "DeleteRolesResponse": { + "V1CreateFunctionBody": { "type": "object", "properties": { - "message": { + "slug": { "type": "string", - "enum": ["ok"] + "pattern": "^[A-Za-z][A-Za-z0-9_-]*$" + }, + "name": { + "type": "string" + }, + "body": { + "type": "string" + }, + "verify_jwt": { + "type": "boolean" } }, - "required": ["message"] + "required": ["slug", "name", "body"], + "example": { + "slug": "hello-world", + "name": "Hello World", + "body": "Deno.serve(() => new Response('Hello, world!'))", + "verify_jwt": true + } }, - "V1ListMigrationsResponse": { + "BulkUpdateFunctionBody": { "type": "array", "items": { "type": "object", "properties": { - "version": { + "id": { + "type": "string" + }, + "slug": { "type": "string", - "minLength": 1 + "pattern": "^[A-Za-z][A-Za-z0-9_-]*$" }, "name": { "type": "string" + }, + "status": { + "type": "string", + "enum": ["ACTIVE", "REMOVED", "THROTTLED"] + }, + "version": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "created_at": { + "type": "integer", + "format": "int64", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "verify_jwt": { + "type": "boolean" + }, + "import_map": { + "type": "boolean" + }, + "entrypoint_path": { + "type": "string" + }, + "import_map_path": { + "type": "string" + }, + "ezbr_sha256": { + "type": "string" } }, - "required": ["version"] - } + "required": ["id", "slug", "name", "status", "version"] + }, + "example": [ + { + "id": "3c078cce-ad70-4148-9f37-4da362789053", + "slug": "hello-world", + "name": "Hello World", + "status": "ACTIVE", + "version": 2, + "verify_jwt": true, + "entrypoint_path": "index.ts" + } + ] + }, + "BulkUpdateFunctionResponse": { + "type": "object", + "properties": { + "functions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string", + "enum": ["ACTIVE", "REMOVED", "THROTTLED"] + }, + "version": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "created_at": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "format": "int64" + }, + "updated_at": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "format": "int64" + }, + "verify_jwt": { + "type": "boolean" + }, + "import_map": { + "type": "boolean" + }, + "entrypoint_path": { + "type": "string" + }, + "import_map_path": { + "type": "string", + "nullable": true + }, + "ezbr_sha256": { + "type": "string" + } + }, + "required": ["id", "slug", "name", "status", "version", "created_at", "updated_at"] + } + } + }, + "required": ["functions"] }, - "V1CreateMigrationBody": { + "FunctionDeployBody": { "type": "object", "properties": { - "query": { - "type": "string", - "minLength": 1 - }, - "name": { - "type": "string" + "file": { + "type": "array", + "items": { + "type": "string", + "format": "binary" + } }, - "rollback": { - "type": "string" + "metadata": { + "type": "object", + "properties": { + "entrypoint_path": { + "type": "string" + }, + "import_map_path": { + "type": "string" + }, + "static_patterns": { + "type": "array", + "items": { + "type": "string" + } + }, + "verify_jwt": { + "type": "boolean" + }, + "name": { + "type": "string" + } + }, + "required": ["entrypoint_path"] } }, - "required": ["query"], + "required": ["file", "metadata"], "example": { - "query": "create table public.widgets(id bigint primary key);", - "name": "create_widgets_table", - "rollback": "drop table if exists public.widgets;" + "file": ["./supabase/functions/hello-world/index.ts"], + "metadata": { + "entrypoint_path": "index.ts", + "verify_jwt": true, + "name": "Hello World" + } } }, - "V1UpsertMigrationBody": { + "DeployFunctionResponse": { "type": "object", "properties": { - "query": { - "type": "string", - "minLength": 1 + "id": { + "type": "string" + }, + "slug": { + "type": "string" }, "name": { "type": "string" }, - "rollback": { + "status": { + "type": "string", + "enum": ["ACTIVE", "REMOVED", "THROTTLED"] + }, + "version": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "created_at": { + "type": "integer", + "format": "int64", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "updated_at": { + "type": "integer", + "format": "int64", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "verify_jwt": { + "type": "boolean" + }, + "import_map": { + "type": "boolean" + }, + "entrypoint_path": { + "type": "string" + }, + "import_map_path": { + "type": "string", + "nullable": true + }, + "ezbr_sha256": { "type": "string" } }, - "required": ["query"], - "example": { - "query": "create table public.widgets(id bigint primary key);", - "name": "create_widgets_table", - "rollback": "drop table if exists public.widgets;" - } + "required": ["id", "slug", "name", "status", "version"] }, - "V1GetMigrationResponse": { + "FunctionSlugResponse": { "type": "object", "properties": { - "version": { - "type": "string", - "minLength": 1 + "id": { + "type": "string" + }, + "slug": { + "type": "string" }, "name": { "type": "string" }, - "statements": { - "type": "array", - "items": { - "type": "string" - } + "status": { + "type": "string", + "enum": ["ACTIVE", "REMOVED", "THROTTLED"] }, - "rollback": { - "type": "array", - "items": { - "type": "string" - } + "version": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 }, - "created_by": { + "created_at": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "format": "int64" + }, + "updated_at": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "format": "int64" + }, + "verify_jwt": { + "type": "boolean" + }, + "import_map": { + "type": "boolean" + }, + "entrypoint_path": { "type": "string" }, - "idempotency_key": { + "import_map_path": { + "type": "string", + "nullable": true + }, + "ezbr_sha256": { "type": "string" } }, - "required": ["version"] + "required": ["id", "slug", "name", "status", "version", "created_at", "updated_at"] }, - "V1PatchMigrationBody": { + "StreamableFile": { + "type": "object", + "properties": {} + }, + "V1UpdateFunctionBody": { "type": "object", "properties": { "name": { "type": "string" }, - "rollback": { + "body": { "type": "string" + }, + "verify_jwt": { + "type": "boolean" } }, "example": { - "name": "create_widgets_table", - "rollback": "drop table if exists public.widgets;" + "name": "Hello World", + "body": "Deno.serve(() => new Response('Hello again!'))", + "verify_jwt": true } }, - "V1RunQueryBody": { + "V1StorageBucketResponse": { "type": "object", "properties": { - "query": { - "type": "string", - "minLength": 1 + "id": { + "type": "string" }, - "parameters": { - "type": "array", - "items": {} + "name": { + "type": "string" }, - "read_only": { + "owner": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "public": { "type": "boolean" } }, - "required": ["query"], - "example": { - "query": "select * from pg_stat_activity limit 1;", - "read_only": true - } + "required": ["id", "name", "owner", "created_at", "updated_at", "public"] }, - "V1ReadOnlyQueryBody": { + "DiskResponse": { "type": "object", "properties": { - "query": { - "type": "string", - "minLength": 1 + "attributes": { + "anyOf": [ + { + "type": "object", + "properties": { + "iops": { + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991, + "minimum": 0 + }, + "size_gb": { + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991, + "minimum": 0 + }, + "throughput_mibps": { + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991, + "minimum": 0 + }, + "type": { + "type": "string", + "enum": ["gp3"] + } + }, + "required": ["iops", "size_gb", "type"] + }, + { + "type": "object", + "properties": { + "iops": { + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991, + "minimum": 0 + }, + "size_gb": { + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991, + "minimum": 0 + }, + "type": { + "type": "string", + "enum": ["io2"] + } + }, + "required": ["iops", "size_gb", "type"] + } + ] }, - "parameters": { - "type": "array", - "items": {} + "last_modified_at": { + "type": "string" } }, - "required": ["query"], - "example": { - "query": "select * from pg_stat_activity limit 1;" - } + "required": ["attributes"] }, - "GetProjectDbMetadataResponse": { + "DiskRequestBody": { "type": "object", "properties": { - "databases": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "schemas": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - } - }, - "required": ["name"], - "additionalProperties": {} + "attributes": { + "oneOf": [ + { + "type": "object", + "properties": { + "iops": { + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991, + "minimum": 0 + }, + "size_gb": { + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991, + "minimum": 0 + }, + "throughput_mibps": { + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991, + "minimum": 0 + }, + "type": { + "type": "string", + "enum": ["gp3"] } - } + }, + "required": ["iops", "size_gb", "type"] }, - "required": ["name", "schemas"], - "additionalProperties": {} - } - } - }, - "required": ["databases"] - }, - "V1UpdatePasswordBody": { - "type": "object", - "properties": { - "password": { - "type": "string", - "minLength": 4 + { + "type": "object", + "properties": { + "iops": { + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991, + "minimum": 0 + }, + "size_gb": { + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991, + "minimum": 0 + }, + "type": { + "type": "string", + "enum": ["io2"] + } + }, + "required": ["iops", "size_gb", "type"] + } + ] } }, - "required": ["password"], + "required": ["attributes"], "example": { - "password": "correct-horse-battery-staple" + "attributes": { + "type": "gp3", + "size_gb": 100, + "iops": 3000, + "throughput_mibps": 125 + } } }, - "V1UpdatePasswordResponse": { + "DiskUtilMetricsResponse": { "type": "object", "properties": { - "message": { + "timestamp": { "type": "string" - } - }, - "required": ["message"] - }, - "JitAccessResponse": { - "type": "object", - "properties": { - "user_id": { - "type": "string", - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, - "user_roles": { - "type": "array", - "items": { - "type": "object", - "properties": { - "role": { - "type": "string", - "minLength": 1 - }, - "expires_at": { - "type": "number" - }, - "allowed_networks": { - "type": "object", - "properties": { - "allowed_cidrs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "cidr": { - "type": "string", - "format": "cidrv4", - "pattern": "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/([0-9]|[1-2][0-9]|3[0-2])$" - } - }, - "required": ["cidr"] - } - }, - "allowed_cidrs_v6": { - "type": "array", - "items": { - "type": "object", - "properties": { - "cidr": { - "type": "string", - "format": "cidrv6", - "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$" - } - }, - "required": ["cidr"] - } - } - } - }, - "branches_only": { - "type": "boolean" - } + "metrics": { + "type": "object", + "properties": { + "fs_size_bytes": { + "type": "number" }, - "required": ["role"] - } + "fs_avail_bytes": { + "type": "number" + }, + "fs_used_bytes": { + "type": "number" + } + }, + "required": ["fs_size_bytes", "fs_avail_bytes", "fs_used_bytes"] } }, - "required": ["user_roles"] + "required": ["timestamp", "metrics"] }, - "AuthorizeJitAccessBody": { + "DiskAutoscaleConfig": { "type": "object", "properties": { - "role": { - "type": "string", - "minLength": 1 + "growth_percent": { + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991, + "description": "Growth percentage for disk autoscaling", + "nullable": true }, - "rhost": { - "anyOf": [ - { - "type": "string", - "format": "ipv4", - "pattern": "^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$" - }, - { - "type": "string", - "format": "ipv6", - "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$" - } - ] + "min_increment_gb": { + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991, + "description": "Minimum increment size for disk autoscaling in GB", + "nullable": true + }, + "max_size_gb": { + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991, + "description": "Maximum limit the disk size will grow to in GB", + "nullable": true } }, - "required": ["role", "rhost"], - "example": { - "role": "postgres", - "rhost": "203.0.113.10" - } + "required": ["growth_percent", "min_increment_gb", "max_size_gb"] }, - "JitAuthorizeAccessResponse": { + "StorageConfigResponse": { "type": "object", "properties": { - "user_id": { - "type": "string", - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" + "fileSizeLimit": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "format": "int64" }, - "user_role": { + "features": { "type": "object", "properties": { - "role": { - "type": "string", - "minLength": 1 + "imageTransformation": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": ["enabled"] }, - "expires_at": { - "type": "number" + "s3Protocol": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": ["enabled"] }, - "allowed_networks": { + "purgeCache": { "type": "object", "properties": { - "allowed_cidrs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "cidr": { - "type": "string", - "format": "cidrv4", - "pattern": "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/([0-9]|[1-2][0-9]|3[0-2])$" - } - }, - "required": ["cidr"] - } - }, - "allowed_cidrs_v6": { - "type": "array", - "items": { - "type": "object", - "properties": { - "cidr": { - "type": "string", - "format": "cidrv6", - "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$" - } - }, - "required": ["cidr"] - } + "enabled": { + "type": "boolean" } - } + }, + "required": ["enabled"] }, - "branches_only": { - "type": "boolean" - } - }, - "required": ["role"] - } - }, - "required": ["user_id", "user_role"] - }, - "JitListAccessResponse": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "anyOf": [ - { - "type": "object", - "properties": { - "user_id": { - "type": "string", - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - }, - "primary_email": { - "type": "string", - "nullable": true - }, - "invite_id": { - "type": "null" - }, - "expires_at": { - "type": "null" - }, - "user_roles": { - "type": "array", - "items": { - "type": "object", - "properties": { - "role": { - "type": "string", - "minLength": 1 - }, - "expires_at": { - "type": "number" - }, - "allowed_networks": { - "type": "object", - "properties": { - "allowed_cidrs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "cidr": { - "type": "string", - "format": "cidrv4", - "pattern": "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/([0-9]|[1-2][0-9]|3[0-2])$" - } - }, - "required": ["cidr"] - } - }, - "allowed_cidrs_v6": { - "type": "array", - "items": { - "type": "object", - "properties": { - "cidr": { - "type": "string", - "format": "cidrv6", - "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$" - } - }, - "required": ["cidr"] - } - } - } - }, - "branches_only": { - "type": "boolean" - } - }, - "required": ["role"] - } - } + "icebergCatalog": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" }, - "required": ["user_id", "primary_email", "invite_id", "expires_at", "user_roles"] + "maxNamespaces": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "maxTables": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "maxCatalogs": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + } }, - { - "type": "object", - "properties": { - "user_id": { - "type": "null" - }, - "primary_email": { - "type": "string" - }, - "invite_id": { - "type": "string", - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" - }, - "expires_at": { - "type": "string" - }, - "user_roles": { - "type": "array", - "items": { - "type": "object", - "properties": { - "role": { - "type": "string", - "minLength": 1 - }, - "expires_at": { - "type": "number" - }, - "allowed_networks": { - "type": "object", - "properties": { - "allowed_cidrs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "cidr": { - "type": "string", - "format": "cidrv4", - "pattern": "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/([0-9]|[1-2][0-9]|3[0-2])$" - } - }, - "required": ["cidr"] - } - }, - "allowed_cidrs_v6": { - "type": "array", - "items": { - "type": "object", - "properties": { - "cidr": { - "type": "string", - "format": "cidrv6", - "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$" - } - }, - "required": ["cidr"] - } - } - } - }, - "branches_only": { - "type": "boolean" - } - }, - "required": ["role"] - } - } + "required": ["enabled", "maxNamespaces", "maxTables", "maxCatalogs"] + }, + "vectorBuckets": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" }, - "required": ["user_id", "primary_email", "invite_id", "expires_at", "user_roles"] - } - ] - } + "maxBuckets": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "maxIndexes": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + } + }, + "required": ["enabled", "maxBuckets", "maxIndexes"] + } + }, + "required": [ + "imageTransformation", + "s3Protocol", + "purgeCache", + "icebergCatalog", + "vectorBuckets" + ] + }, + "capabilities": { + "type": "object", + "properties": { + "list_v2": { + "type": "boolean" + }, + "iceberg_catalog": { + "type": "boolean" + } + }, + "required": ["list_v2", "iceberg_catalog"] + }, + "external": { + "type": "object", + "properties": { + "upstreamTarget": { + "type": "string", + "enum": ["main", "canary"] + } + }, + "required": ["upstreamTarget"] + }, + "migrationVersion": { + "type": "string" + }, + "databasePoolMode": { + "type": "string" } }, - "required": ["items"] + "required": ["fileSizeLimit", "features", "capabilities", "external", "migrationVersion"] }, - "UpdateJitAccessBody": { + "UpdateStorageConfigBody": { "type": "object", "properties": { - "user_id": { - "type": "string", - "minLength": 1, - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" + "fileSizeLimit": { + "type": "integer", + "format": "int64", + "minimum": 0, + "maximum": 536870912000 }, - "roles": { - "type": "array", - "items": { - "type": "object", - "properties": { - "role": { - "type": "string", - "minLength": 1 + "features": { + "type": "object", + "properties": { + "imageTransformation": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } }, - "expires_at": { - "type": "number" + "required": ["enabled"] + }, + "s3Protocol": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } }, - "allowed_networks": { - "type": "object", - "properties": { - "allowed_cidrs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "cidr": { - "type": "string", - "format": "cidrv4", - "pattern": "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/([0-9]|[1-2][0-9]|3[0-2])$" - } - }, - "required": ["cidr"] - } - }, - "allowed_cidrs_v6": { - "type": "array", - "items": { - "type": "object", - "properties": { - "cidr": { - "type": "string", - "format": "cidrv6", - "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$" - } - }, - "required": ["cidr"] - } - } + "required": ["enabled"] + }, + "purgeCache": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" } }, - "branches_only": { - "type": "boolean" - } + "required": ["enabled"] }, - "required": ["role"] + "icebergCatalog": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "maxNamespaces": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "maxTables": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "maxCatalogs": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + } + }, + "required": ["enabled", "maxNamespaces", "maxTables", "maxCatalogs"] + }, + "vectorBuckets": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "maxBuckets": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "maxIndexes": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + } + }, + "required": ["enabled", "maxBuckets", "maxIndexes"] + } } + }, + "external": { + "type": "object", + "properties": { + "upstreamTarget": { + "type": "string", + "enum": ["main", "canary"] + } + }, + "required": ["upstreamTarget"] } }, - "required": ["user_id", "roles"], "example": { - "user_id": "55555555-5555-4555-8555-555555555555", - "roles": [ - { - "role": "postgres", - "expires_at": 1740787200, - "allowed_networks": { - "allowed_cidrs": [ - { - "cidr": "203.0.113.0/24" - } - ] - }, - "branches_only": false + "fileSizeLimit": 10485760, + "features": { + "imageTransformation": { + "enabled": true } - ] - } + } + }, + "additionalProperties": false }, - "InviteExternalUserJitAccessBody": { + "V1PgbouncerConfigResponse": { "type": "object", "properties": { - "email": { - "type": "string", - "minLength": 1, - "format": "email", - "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" + "default_pool_size": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 }, - "roles": { - "type": "array", - "items": { - "type": "object", - "properties": { - "role": { - "type": "string", - "minLength": 1 - }, - "expires_at": { - "type": "number" - }, - "allowed_networks": { - "type": "object", - "properties": { - "allowed_cidrs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "cidr": { - "type": "string", - "format": "cidrv4", - "pattern": "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/([0-9]|[1-2][0-9]|3[0-2])$" - } - }, - "required": ["cidr"] - } - }, - "allowed_cidrs_v6": { - "type": "array", - "items": { - "type": "object", - "properties": { - "cidr": { - "type": "string", - "format": "cidrv6", - "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$" - } - }, - "required": ["cidr"] - } - } - } - }, - "branches_only": { - "type": "boolean" - } - }, - "required": ["role"] - } + "ignore_startup_parameters": { + "type": "string" + }, + "max_client_conn": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "pool_mode": { + "type": "string", + "enum": ["transaction", "session", "statement"] + }, + "connection_string": { + "type": "string" + }, + "server_idle_timeout": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "server_lifetime": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "query_wait_timeout": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "reserve_pool_size": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 } - }, - "required": ["email", "roles"], - "example": { - "email": "external-user@somedomain.xyz", - "roles": [ - { - "role": "postgres", - "expires_at": 1740787200, - "allowed_networks": { - "allowed_cidrs": [ - { - "cidr": "203.0.113.0/24" - } - ] - }, - "branches_only": false - } - ] } }, - "InviteExternalUserJitResponse": { + "SupavisorConfigResponse": { "type": "object", "properties": { - "email": { + "identifier": { + "type": "string" + }, + "database_type": { "type": "string", - "format": "email", - "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" + "enum": ["PRIMARY", "READ_REPLICA"] }, - "invite_id": { + "is_using_scram_auth": { + "type": "boolean" + }, + "db_user": { + "type": "string" + }, + "db_host": { + "type": "string" + }, + "db_port": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "db_name": { + "type": "string" + }, + "connection_string": { + "type": "string" + }, + "connectionString": { "type": "string", - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" + "description": "Use connection_string instead" }, - "user_roles": { - "type": "array", - "items": { - "type": "object", - "properties": { - "role": { - "type": "string", - "minLength": 1 - }, - "expires_at": { - "type": "number" - }, - "allowed_networks": { - "type": "object", - "properties": { - "allowed_cidrs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "cidr": { - "type": "string", - "format": "cidrv4", - "pattern": "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/([0-9]|[1-2][0-9]|3[0-2])$" - } - }, - "required": ["cidr"] - } - }, - "allowed_cidrs_v6": { - "type": "array", - "items": { - "type": "object", - "properties": { - "cidr": { - "type": "string", - "format": "cidrv6", - "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$" - } - }, - "required": ["cidr"] - } - } - } - }, - "branches_only": { - "type": "boolean" - } - }, - "required": ["role"] - } + "default_pool_size": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "nullable": true + }, + "max_client_conn": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "nullable": true + }, + "pool_mode": { + "type": "string", + "enum": ["transaction", "session"] } }, - "required": ["email", "invite_id", "user_roles"] + "required": [ + "identifier", + "database_type", + "is_using_scram_auth", + "db_user", + "db_host", + "db_port", + "db_name", + "connection_string", + "connectionString", + "default_pool_size", + "max_client_conn", + "pool_mode" + ] }, - "AcceptInviteExternalUserJitAccessBody": { + "UpdateSupavisorConfigBody": { "type": "object", "properties": { - "email": { - "type": "string", - "minLength": 1, - "format": "email", - "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" + "default_pool_size": { + "type": "integer", + "minimum": 0, + "maximum": 3000, + "nullable": true }, - "token": { + "pool_mode": { + "description": "Dedicated pooler mode for the project", "type": "string", - "minLength": 1 + "enum": ["transaction", "session"] } }, - "required": ["email", "token"], "example": { - "email": "external-user@somedomain.xyz", - "token": "" + "default_pool_size": 25, + "pool_mode": "transaction" } }, - "FunctionResponse": { + "UpdateSupavisorConfigResponse": { "type": "object", "properties": { - "id": { + "default_pool_size": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "nullable": true + }, + "pool_mode": { + "type": "string" + } + }, + "required": ["default_pool_size", "pool_mode"] + }, + "PostgresConfigResponse": { + "type": "object", + "properties": { + "effective_cache_size": { "type": "string" }, - "slug": { + "logical_decoding_work_mem": { + "type": "string" + }, + "cron.log_statement": { + "type": "boolean" + }, + "log_autovacuum_min_duration": { + "type": "string", + "description": "Default unit: ms", + "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" + }, + "log_checkpoints": { + "type": "boolean" + }, + "log_connections": { + "type": "boolean" + }, + "log_disconnections": { + "type": "boolean" + }, + "log_duration": { + "type": "boolean" + }, + "log_lock_waits": { + "type": "boolean" + }, + "log_recovery_conflict_waits": { + "type": "boolean" + }, + "log_replication_commands": { + "type": "boolean" + }, + "log_startup_progress_interval": { + "type": "string", + "description": "Default unit: ms", + "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" + }, + "log_temp_files": { + "type": "string" + }, + "maintenance_work_mem": { + "type": "string" + }, + "track_activity_query_size": { "type": "string" }, - "name": { - "type": "string" + "max_connections": { + "type": "integer", + "minimum": 1, + "maximum": 262143 + }, + "max_locks_per_transaction": { + "type": "integer", + "minimum": 10, + "maximum": 2147483640 + }, + "max_logical_replication_workers": { + "type": "integer", + "minimum": 0, + "maximum": 262143 }, - "status": { - "type": "string", - "enum": ["ACTIVE", "REMOVED", "THROTTLED"] + "max_parallel_maintenance_workers": { + "type": "integer", + "minimum": 0, + "maximum": 1024 }, - "version": { + "max_parallel_workers": { "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 + "minimum": 0, + "maximum": 1024 }, - "created_at": { + "max_parallel_workers_per_gather": { "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991, - "format": "int64" + "minimum": 0, + "maximum": 1024 }, - "updated_at": { + "max_replication_slots": { "type": "integer", "minimum": -9007199254740991, - "maximum": 9007199254740991, - "format": "int64" + "maximum": 9007199254740991 }, - "verify_jwt": { - "type": "boolean" + "max_slot_wal_keep_size": { + "type": "string" }, - "import_map": { - "type": "boolean" + "max_standby_archive_delay": { + "type": "string" }, - "entrypoint_path": { + "max_standby_streaming_delay": { "type": "string" }, - "import_map_path": { - "type": "string", - "nullable": true + "max_sync_workers_per_subscription": { + "type": "integer", + "minimum": 0, + "maximum": 262143 }, - "ezbr_sha256": { + "max_wal_size": { "type": "string" - } - }, - "required": ["id", "slug", "name", "status", "version", "created_at", "updated_at"] - }, - "V1CreateFunctionBody": { - "type": "object", - "properties": { - "slug": { + }, + "max_wal_senders": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "max_worker_processes": { + "type": "integer", + "minimum": 0, + "maximum": 262143 + }, + "session_replication_role": { "type": "string", - "pattern": "^[A-Za-z][A-Za-z0-9_-]*$" + "enum": ["origin", "replica", "local"] }, - "name": { + "shared_buffers": { "type": "string" }, - "body": { - "type": "string" + "statement_timeout": { + "type": "string", + "description": "Default unit: ms", + "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" }, - "verify_jwt": { + "track_commit_timestamp": { "type": "boolean" - } - }, - "required": ["slug", "name", "body"], - "example": { - "slug": "hello-world", - "name": "Hello World", - "body": "Deno.serve(() => new Response('Hello, world!'))", - "verify_jwt": true - } - }, - "BulkUpdateFunctionBody": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "slug": { - "type": "string", - "pattern": "^[A-Za-z][A-Za-z0-9_-]*$" - }, - "name": { - "type": "string" - }, - "status": { - "type": "string", - "enum": ["ACTIVE", "REMOVED", "THROTTLED"] - }, - "version": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 - }, - "created_at": { - "type": "integer", - "format": "int64", - "minimum": -9007199254740991, - "maximum": 9007199254740991 - }, - "verify_jwt": { - "type": "boolean" - }, - "import_map": { - "type": "boolean" - }, - "entrypoint_path": { - "type": "string" - }, - "import_map_path": { - "type": "string" - }, - "ezbr_sha256": { - "type": "string" - } - }, - "required": ["id", "slug", "name", "status", "version"] - }, - "example": [ - { - "id": "3c078cce-ad70-4148-9f37-4da362789053", - "slug": "hello-world", - "name": "Hello World", - "status": "ACTIVE", - "version": 2, - "verify_jwt": true, - "entrypoint_path": "index.ts" - } - ] - }, - "BulkUpdateFunctionResponse": { - "type": "object", - "properties": { - "functions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "slug": { - "type": "string" - }, - "name": { - "type": "string" - }, - "status": { - "type": "string", - "enum": ["ACTIVE", "REMOVED", "THROTTLED"] - }, - "version": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 - }, - "created_at": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991, - "format": "int64" - }, - "updated_at": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991, - "format": "int64" - }, - "verify_jwt": { - "type": "boolean" - }, - "import_map": { - "type": "boolean" - }, - "entrypoint_path": { - "type": "string" - }, - "import_map_path": { - "type": "string", - "nullable": true - }, - "ezbr_sha256": { - "type": "string" - } - }, - "required": ["id", "slug", "name", "status", "version", "created_at", "updated_at"] - } - } - }, - "required": ["functions"] - }, - "FunctionDeployBody": { - "type": "object", - "properties": { - "file": { - "type": "array", - "items": { - "type": "string", - "format": "binary" - } }, - "metadata": { - "type": "object", - "properties": { - "entrypoint_path": { - "type": "string" - }, - "import_map_path": { - "type": "string" - }, - "static_patterns": { - "type": "array", - "items": { - "type": "string" - } - }, - "verify_jwt": { - "type": "boolean" - }, - "name": { - "type": "string" - } - }, - "required": ["entrypoint_path"] - } - }, - "required": ["file", "metadata"], - "example": { - "file": ["./supabase/functions/hello-world/index.ts"], - "metadata": { - "entrypoint_path": "index.ts", - "verify_jwt": true, - "name": "Hello World" + "wal_keep_size": { + "type": "string" + }, + "wal_sender_timeout": { + "type": "string", + "description": "Default unit: ms", + "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" + }, + "work_mem": { + "type": "string" + }, + "checkpoint_timeout": { + "type": "string", + "description": "Default unit: s", + "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" + }, + "hot_standby_feedback": { + "type": "boolean" } } }, - "DeployFunctionResponse": { + "UpdatePostgresConfigBody": { "type": "object", "properties": { - "id": { + "effective_cache_size": { "type": "string" }, - "slug": { + "logical_decoding_work_mem": { "type": "string" }, - "name": { - "type": "string" + "cron.log_statement": { + "type": "boolean" }, - "status": { + "log_autovacuum_min_duration": { "type": "string", - "enum": ["ACTIVE", "REMOVED", "THROTTLED"] + "description": "Default unit: ms", + "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" }, - "version": { + "log_checkpoints": { + "type": "boolean" + }, + "log_connections": { + "type": "boolean" + }, + "log_disconnections": { + "type": "boolean" + }, + "log_duration": { + "type": "boolean" + }, + "log_lock_waits": { + "type": "boolean" + }, + "log_recovery_conflict_waits": { + "type": "boolean" + }, + "log_replication_commands": { + "type": "boolean" + }, + "log_startup_progress_interval": { + "type": "string", + "description": "Default unit: ms", + "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" + }, + "log_temp_files": { + "type": "string" + }, + "maintenance_work_mem": { + "type": "string" + }, + "track_activity_query_size": { + "type": "string" + }, + "max_connections": { "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 + "minimum": 1, + "maximum": 262143 }, - "created_at": { + "max_locks_per_transaction": { + "type": "integer", + "minimum": 10, + "maximum": 2147483640 + }, + "max_logical_replication_workers": { + "type": "integer", + "minimum": 0, + "maximum": 262143 + }, + "max_parallel_maintenance_workers": { + "type": "integer", + "minimum": 0, + "maximum": 1024 + }, + "max_parallel_workers": { + "type": "integer", + "minimum": 0, + "maximum": 1024 + }, + "max_parallel_workers_per_gather": { + "type": "integer", + "minimum": 0, + "maximum": 1024 + }, + "max_replication_slots": { "type": "integer", - "format": "int64", "minimum": -9007199254740991, "maximum": 9007199254740991 }, - "updated_at": { + "max_slot_wal_keep_size": { + "type": "string" + }, + "max_standby_archive_delay": { + "type": "string" + }, + "max_standby_streaming_delay": { + "type": "string" + }, + "max_sync_workers_per_subscription": { + "type": "integer", + "minimum": 0, + "maximum": 262143 + }, + "max_wal_size": { + "type": "string" + }, + "max_wal_senders": { "type": "integer", - "format": "int64", "minimum": -9007199254740991, "maximum": 9007199254740991 }, - "verify_jwt": { - "type": "boolean" + "max_worker_processes": { + "type": "integer", + "minimum": 0, + "maximum": 262143 }, - "import_map": { + "session_replication_role": { + "type": "string", + "enum": ["origin", "replica", "local"] + }, + "shared_buffers": { + "type": "string" + }, + "statement_timeout": { + "type": "string", + "description": "Default unit: ms", + "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" + }, + "track_commit_timestamp": { "type": "boolean" }, - "entrypoint_path": { + "wal_keep_size": { "type": "string" }, - "import_map_path": { + "wal_sender_timeout": { "type": "string", - "nullable": true + "description": "Default unit: ms", + "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" }, - "ezbr_sha256": { + "work_mem": { "type": "string" + }, + "checkpoint_timeout": { + "type": "string", + "description": "Default unit: s", + "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" + }, + "hot_standby_feedback": { + "type": "boolean" + }, + "restart_database": { + "type": "boolean" } }, - "required": ["id", "slug", "name", "status", "version"] + "example": { + "max_connections": 120, + "shared_buffers": "256MB", + "work_mem": "4MB", + "statement_timeout": "60000ms" + }, + "additionalProperties": false + }, + "RealtimeConfigResponse": { + "type": "object", + "properties": { + "private_only": { + "type": "boolean", + "description": "Whether to only allow private channels", + "nullable": true + }, + "connection_pool": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "description": "Sets connection pool size for Realtime Authorization", + "nullable": true + }, + "max_concurrent_users": { + "type": "integer", + "minimum": 1, + "maximum": 50000, + "description": "Sets maximum number of concurrent users rate limit", + "nullable": true + }, + "max_events_per_second": { + "type": "integer", + "minimum": 1, + "maximum": 50000, + "description": "Sets maximum number of events per second rate per channel limit", + "nullable": true + }, + "max_bytes_per_second": { + "type": "integer", + "minimum": 1, + "maximum": 10000000, + "description": "Sets maximum number of bytes per second rate per channel limit", + "nullable": true + }, + "max_channels_per_client": { + "type": "integer", + "minimum": 1, + "maximum": 10000, + "description": "Sets maximum number of channels per client rate limit", + "nullable": true + }, + "max_joins_per_second": { + "type": "integer", + "minimum": 1, + "maximum": 5000, + "description": "Sets maximum number of joins per second rate limit", + "nullable": true + }, + "max_presence_events_per_second": { + "type": "integer", + "minimum": 1, + "maximum": 5000, + "description": "Sets maximum number of presence events per second rate limit", + "nullable": true + }, + "max_payload_size_in_kb": { + "type": "integer", + "minimum": 1, + "maximum": 10000, + "description": "Sets maximum number of payload size in KB rate limit", + "nullable": true + }, + "suspend": { + "type": "boolean", + "description": "Disables the Realtime service for this project when true. Set to false to re-enable it.", + "nullable": true + }, + "presence_enabled": { + "type": "boolean", + "description": "Whether to enable presence" + } + }, + "required": [ + "private_only", + "connection_pool", + "max_concurrent_users", + "max_events_per_second", + "max_bytes_per_second", + "max_channels_per_client", + "max_joins_per_second", + "max_presence_events_per_second", + "max_payload_size_in_kb", + "suspend", + "presence_enabled" + ] }, - "FunctionSlugResponse": { + "UpdateRealtimeConfigBody": { "type": "object", "properties": { - "id": { - "type": "string" - }, - "slug": { - "type": "string" + "private_only": { + "type": "boolean", + "description": "Whether to only allow private channels" }, - "name": { - "type": "string" + "connection_pool": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "description": "Sets connection pool size for Realtime Authorization" }, - "status": { - "type": "string", - "enum": ["ACTIVE", "REMOVED", "THROTTLED"] + "max_concurrent_users": { + "type": "integer", + "minimum": 1, + "maximum": 50000, + "description": "Sets maximum number of concurrent users rate limit" }, - "version": { + "max_events_per_second": { "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 + "minimum": 1, + "maximum": 50000, + "description": "Sets maximum number of events per second rate per channel limit" }, - "created_at": { + "max_bytes_per_second": { "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991, - "format": "int64" + "minimum": 1, + "maximum": 10000000, + "description": "Sets maximum number of bytes per second rate per channel limit" }, - "updated_at": { + "max_channels_per_client": { "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991, - "format": "int64" + "minimum": 1, + "maximum": 10000, + "description": "Sets maximum number of channels per client rate limit" }, - "verify_jwt": { - "type": "boolean" + "max_joins_per_second": { + "type": "integer", + "minimum": 1, + "maximum": 5000, + "description": "Sets maximum number of joins per second rate limit" }, - "import_map": { - "type": "boolean" + "max_presence_events_per_second": { + "type": "integer", + "minimum": 1, + "maximum": 5000, + "description": "Sets maximum number of presence events per second rate limit" }, - "entrypoint_path": { - "type": "string" + "max_payload_size_in_kb": { + "type": "integer", + "minimum": 1, + "maximum": 10000, + "description": "Sets maximum number of payload size in KB rate limit" }, - "import_map_path": { - "type": "string", - "nullable": true + "suspend": { + "type": "boolean", + "description": "Disables the Realtime service for this project when true. Set to false to re-enable it." }, - "ezbr_sha256": { - "type": "string" + "presence_enabled": { + "type": "boolean", + "description": "Whether to enable presence" } }, - "required": ["id", "slug", "name", "status", "version", "created_at", "updated_at"] - }, - "StreamableFile": { - "type": "object", - "properties": {} + "example": { + "private_only": false, + "max_concurrent_users": 1000, + "max_channels_per_client": 100 + }, + "additionalProperties": false }, - "V1UpdateFunctionBody": { + "CreateProviderBody": { "type": "object", "properties": { - "name": { + "type": { + "type": "string", + "enum": ["saml"], + "description": "What type of provider will be created" + }, + "metadata_xml": { "type": "string" }, - "body": { + "metadata_url": { "type": "string" }, - "verify_jwt": { - "type": "boolean" + "domains": { + "type": "array", + "items": { + "type": "string" + } + }, + "attribute_mapping": { + "type": "object", + "properties": { + "keys": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "names": { + "type": "array", + "items": { + "type": "string" + } + }, + "default": { + "anyOf": [ + { + "type": "object", + "properties": {} + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "array": { + "type": "boolean" + } + } + } + } + }, + "required": ["keys"] + }, + "name_id_format": { + "type": "string", + "enum": [ + "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", + "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", + "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", + "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" + ] } }, + "required": ["type"], "example": { - "name": "Hello World", - "body": "Deno.serve(() => new Response('Hello again!'))", - "verify_jwt": true + "type": "saml", + "metadata_url": "https://sso.acme.com/metadata.xml", + "domains": ["acme.com"], + "attribute_mapping": { + "keys": { + "email": { + "name": "email" + }, + "first_name": { + "name": "first_name" + }, + "last_name": { + "name": "last_name" + } + } + } } }, - "V1StorageBucketResponse": { + "CreateProviderResponse": { "type": "object", "properties": { "id": { "type": "string" }, - "name": { - "type": "string" - }, - "owner": { - "type": "string" + "saml": { + "type": "object", + "properties": { + "entity_id": { + "type": "string" + }, + "metadata_url": { + "type": "string" + }, + "metadata_xml": { + "type": "string" + }, + "attribute_mapping": { + "type": "object", + "properties": { + "keys": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "names": { + "type": "array", + "items": { + "type": "string" + } + }, + "default": { + "anyOf": [ + { + "type": "object", + "properties": {} + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "array": { + "type": "boolean" + } + } + } + } + }, + "required": [] + }, + "name_id_format": { + "type": "string", + "enum": [ + "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", + "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", + "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", + "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" + ] + } + }, + "required": ["entity_id"] + }, + "domains": { + "type": "array", + "items": { + "type": "object", + "properties": { + "domain": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + } }, "created_at": { "type": "string" }, "updated_at": { "type": "string" - }, - "public": { - "type": "boolean" } }, - "required": ["id", "name", "owner", "created_at", "updated_at", "public"] + "required": ["id"] }, - "DiskResponse": { + "ListProvidersResponse": { "type": "object", "properties": { - "attributes": { - "anyOf": [ - { - "type": "object", - "properties": { - "iops": { - "type": "integer", - "exclusiveMinimum": true, - "maximum": 9007199254740991, - "minimum": 0 - }, - "size_gb": { - "type": "integer", - "exclusiveMinimum": true, - "maximum": 9007199254740991, - "minimum": 0 - }, - "throughput_mibps": { - "type": "integer", - "exclusiveMinimum": true, - "maximum": 9007199254740991, - "minimum": 0 - }, - "type": { - "type": "string", - "enum": ["gp3"] - } + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" }, - "required": ["iops", "size_gb", "type"] - }, - { - "type": "object", - "properties": { - "iops": { - "type": "integer", - "exclusiveMinimum": true, - "maximum": 9007199254740991, - "minimum": 0 - }, - "size_gb": { - "type": "integer", - "exclusiveMinimum": true, - "maximum": 9007199254740991, - "minimum": 0 + "saml": { + "type": "object", + "properties": { + "entity_id": { + "type": "string" + }, + "metadata_url": { + "type": "string" + }, + "metadata_xml": { + "type": "string" + }, + "attribute_mapping": { + "type": "object", + "properties": { + "keys": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "names": { + "type": "array", + "items": { + "type": "string" + } + }, + "default": { + "anyOf": [ + { + "type": "object", + "properties": {} + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "array": { + "type": "boolean" + } + } + } + } + }, + "required": [] + }, + "name_id_format": { + "type": "string", + "enum": [ + "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", + "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", + "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", + "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" + ] + } }, - "type": { - "type": "string", - "enum": ["io2"] + "required": ["entity_id"] + }, + "domains": { + "type": "array", + "items": { + "type": "object", + "properties": { + "domain": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } } }, - "required": ["iops", "size_gb", "type"] - } - ] - }, - "last_modified_at": { - "type": "string" + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "required": ["id"] + } } }, - "required": ["attributes"] + "required": ["items"] }, - "DiskRequestBody": { + "GetProviderResponse": { "type": "object", "properties": { - "attributes": { - "oneOf": [ - { - "type": "object", - "properties": { - "iops": { - "type": "integer", - "exclusiveMinimum": true, - "maximum": 9007199254740991, - "minimum": 0 - }, - "size_gb": { - "type": "integer", - "exclusiveMinimum": true, - "maximum": 9007199254740991, - "minimum": 0 - }, - "throughput_mibps": { - "type": "integer", - "exclusiveMinimum": true, - "maximum": 9007199254740991, - "minimum": 0 - }, - "type": { - "type": "string", - "enum": ["gp3"] - } - }, - "required": ["iops", "size_gb", "type"] + "id": { + "type": "string" + }, + "saml": { + "type": "object", + "properties": { + "entity_id": { + "type": "string" }, - { + "metadata_url": { + "type": "string" + }, + "metadata_xml": { + "type": "string" + }, + "attribute_mapping": { "type": "object", "properties": { - "iops": { - "type": "integer", - "exclusiveMinimum": true, - "maximum": 9007199254740991, - "minimum": 0 - }, - "size_gb": { - "type": "integer", - "exclusiveMinimum": true, - "maximum": 9007199254740991, - "minimum": 0 - }, - "type": { - "type": "string", - "enum": ["io2"] + "keys": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "names": { + "type": "array", + "items": { + "type": "string" + } + }, + "default": { + "anyOf": [ + { + "type": "object", + "properties": {} + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "array": { + "type": "boolean" + } + } + } } }, - "required": ["iops", "size_gb", "type"] + "required": [] + }, + "name_id_format": { + "type": "string", + "enum": [ + "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", + "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", + "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", + "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" + ] } - ] + }, + "required": ["entity_id"] + }, + "domains": { + "type": "array", + "items": { + "type": "object", + "properties": { + "domain": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + } + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" } }, - "required": ["attributes"], - "example": { - "attributes": { - "type": "gp3", - "size_gb": 100, - "iops": 3000, - "throughput_mibps": 125 - } - } + "required": ["id"] }, - "DiskUtilMetricsResponse": { + "UpdateProviderBody": { "type": "object", "properties": { - "timestamp": { + "metadata_xml": { "type": "string" }, - "metrics": { + "metadata_url": { + "type": "string" + }, + "domains": { + "type": "array", + "items": { + "type": "string" + } + }, + "attribute_mapping": { "type": "object", "properties": { - "fs_size_bytes": { - "type": "number" - }, - "fs_avail_bytes": { - "type": "number" - }, - "fs_used_bytes": { - "type": "number" + "keys": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "names": { + "type": "array", + "items": { + "type": "string" + } + }, + "default": { + "anyOf": [ + { + "type": "object", + "properties": {} + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "array": { + "type": "boolean" + } + } + } } }, - "required": ["fs_size_bytes", "fs_avail_bytes", "fs_used_bytes"] - } - }, - "required": ["timestamp", "metrics"] - }, - "DiskAutoscaleConfig": { - "type": "object", - "properties": { - "growth_percent": { - "type": "integer", - "exclusiveMinimum": 0, - "maximum": 9007199254740991, - "description": "Growth percentage for disk autoscaling", - "nullable": true - }, - "min_increment_gb": { - "type": "integer", - "exclusiveMinimum": 0, - "maximum": 9007199254740991, - "description": "Minimum increment size for disk autoscaling in GB", - "nullable": true + "required": ["keys"] }, - "max_size_gb": { - "type": "integer", - "exclusiveMinimum": 0, - "maximum": 9007199254740991, - "description": "Maximum limit the disk size will grow to in GB", - "nullable": true + "name_id_format": { + "type": "string", + "enum": [ + "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", + "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", + "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", + "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" + ] } }, - "required": ["growth_percent", "min_increment_gb", "max_size_gb"] + "example": { + "metadata_url": "https://sso.acme.com/metadata.xml", + "domains": ["acme.com", "contractors.acme.com"] + } }, - "StorageConfigResponse": { + "UpdateProviderResponse": { "type": "object", "properties": { - "fileSizeLimit": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991, - "format": "int64" + "id": { + "type": "string" }, - "features": { + "saml": { "type": "object", "properties": { - "imageTransformation": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean" - } - }, - "required": ["enabled"] - }, - "s3Protocol": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean" - } - }, - "required": ["enabled"] + "entity_id": { + "type": "string" }, - "purgeCache": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean" - } - }, - "required": ["enabled"] + "metadata_url": { + "type": "string" }, - "icebergCatalog": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean" - }, - "maxNamespaces": { - "type": "integer", - "minimum": 0, - "maximum": 9007199254740991 - }, - "maxTables": { - "type": "integer", - "minimum": 0, - "maximum": 9007199254740991 - }, - "maxCatalogs": { - "type": "integer", - "minimum": 0, - "maximum": 9007199254740991 - } - }, - "required": ["enabled", "maxNamespaces", "maxTables", "maxCatalogs"] + "metadata_xml": { + "type": "string" }, - "vectorBuckets": { + "attribute_mapping": { "type": "object", "properties": { - "enabled": { - "type": "boolean" - }, - "maxBuckets": { - "type": "integer", - "minimum": 0, - "maximum": 9007199254740991 - }, - "maxIndexes": { - "type": "integer", - "minimum": 0, - "maximum": 9007199254740991 + "keys": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "names": { + "type": "array", + "items": { + "type": "string" + } + }, + "default": { + "anyOf": [ + { + "type": "object", + "properties": {} + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "array": { + "type": "boolean" + } + } + } } }, - "required": ["enabled", "maxBuckets", "maxIndexes"] - } - }, - "required": [ - "imageTransformation", - "s3Protocol", - "purgeCache", - "icebergCatalog", - "vectorBuckets" - ] - }, - "capabilities": { - "type": "object", - "properties": { - "list_v2": { - "type": "boolean" + "required": [] }, - "iceberg_catalog": { - "type": "boolean" + "name_id_format": { + "type": "string", + "enum": [ + "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", + "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", + "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", + "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" + ] } }, - "required": ["list_v2", "iceberg_catalog"] + "required": ["entity_id"] }, - "external": { - "type": "object", - "properties": { - "upstreamTarget": { - "type": "string", - "enum": ["main", "canary"] + "domains": { + "type": "array", + "items": { + "type": "object", + "properties": { + "domain": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } } - }, - "required": ["upstreamTarget"] + } }, - "migrationVersion": { + "created_at": { "type": "string" }, - "databasePoolMode": { + "updated_at": { "type": "string" } }, - "required": ["fileSizeLimit", "features", "capabilities", "external", "migrationVersion"] + "required": ["id"] }, - "UpdateStorageConfigBody": { + "DeleteProviderResponse": { "type": "object", "properties": { - "fileSizeLimit": { - "type": "integer", - "format": "int64", - "minimum": 0, - "maximum": 536870912000 + "id": { + "type": "string" }, - "features": { + "saml": { "type": "object", "properties": { - "imageTransformation": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean" - } - }, - "required": ["enabled"] + "entity_id": { + "type": "string" }, - "s3Protocol": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean" - } - }, - "required": ["enabled"] + "metadata_url": { + "type": "string" }, - "purgeCache": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean" - } - }, - "required": ["enabled"] + "metadata_xml": { + "type": "string" }, - "icebergCatalog": { + "attribute_mapping": { "type": "object", "properties": { - "enabled": { - "type": "boolean" - }, - "maxNamespaces": { - "type": "integer", - "minimum": 0, - "maximum": 9007199254740991 - }, - "maxTables": { - "type": "integer", - "minimum": 0, - "maximum": 9007199254740991 - }, - "maxCatalogs": { - "type": "integer", - "minimum": 0, - "maximum": 9007199254740991 + "keys": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "names": { + "type": "array", + "items": { + "type": "string" + } + }, + "default": { + "anyOf": [ + { + "type": "object", + "properties": {} + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "array": { + "type": "boolean" + } + } + } } }, - "required": ["enabled", "maxNamespaces", "maxTables", "maxCatalogs"] + "required": [] }, - "vectorBuckets": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean" - }, - "maxBuckets": { - "type": "integer", - "minimum": 0, - "maximum": 9007199254740991 - }, - "maxIndexes": { - "type": "integer", - "minimum": 0, - "maximum": 9007199254740991 - } - }, - "required": ["enabled", "maxBuckets", "maxIndexes"] - } - } - }, - "external": { - "type": "object", - "properties": { - "upstreamTarget": { + "name_id_format": { "type": "string", - "enum": ["main", "canary"] + "enum": [ + "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", + "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", + "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", + "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" + ] } }, - "required": ["upstreamTarget"] - } - }, - "example": { - "fileSizeLimit": 10485760, - "features": { - "imageTransformation": { - "enabled": true - } - } - }, - "additionalProperties": false - }, - "V1PgbouncerConfigResponse": { - "type": "object", - "properties": { - "default_pool_size": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 - }, - "ignore_startup_parameters": { - "type": "string" - }, - "max_client_conn": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 + "required": ["entity_id"] }, - "pool_mode": { - "type": "string", - "enum": ["transaction", "session", "statement"] + "domains": { + "type": "array", + "items": { + "type": "object", + "properties": { + "domain": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + } }, - "connection_string": { + "created_at": { "type": "string" }, - "server_idle_timeout": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 - }, - "server_lifetime": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 - }, - "query_wait_timeout": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 - }, - "reserve_pool_size": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 + "updated_at": { + "type": "string" } - } + }, + "required": ["id"] }, - "SupavisorConfigResponse": { + "V1BackupsResponse": { "type": "object", "properties": { - "identifier": { + "region": { "type": "string" }, - "database_type": { - "type": "string", - "enum": ["PRIMARY", "READ_REPLICA"] - }, - "is_using_scram_auth": { + "walg_enabled": { "type": "boolean" }, - "db_user": { - "type": "string" - }, - "db_host": { - "type": "string" - }, - "db_port": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 - }, - "db_name": { - "type": "string" - }, - "connection_string": { - "type": "string" - }, - "connectionString": { - "type": "string", - "description": "Use connection_string instead" - }, - "default_pool_size": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991, - "nullable": true + "pitr_enabled": { + "type": "boolean" }, - "max_client_conn": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991, - "nullable": true + "backups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "is_physical_backup": { + "type": "boolean" + }, + "status": { + "type": "string", + "enum": ["COMPLETED", "FAILED", "PENDING", "REMOVED", "ARCHIVED", "CANCELLED"] + }, + "inserted_at": { + "type": "string" + } + }, + "required": ["id", "is_physical_backup", "status", "inserted_at"] + } }, - "pool_mode": { - "type": "string", - "enum": ["transaction", "session"] + "physical_backup_data": { + "type": "object", + "properties": { + "earliest_physical_backup_date_unix": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "latest_physical_backup_date_unix": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + } + } } }, - "required": [ - "identifier", - "database_type", - "is_using_scram_auth", - "db_user", - "db_host", - "db_port", - "db_name", - "connection_string", - "connectionString", - "default_pool_size", - "max_client_conn", - "pool_mode" - ] + "required": ["region", "walg_enabled", "pitr_enabled", "backups", "physical_backup_data"] }, - "UpdateSupavisorConfigBody": { + "V1RestorePitrBody": { "type": "object", "properties": { - "default_pool_size": { + "recovery_time_target_unix": { "type": "integer", "minimum": 0, - "maximum": 3000, - "nullable": true - }, - "pool_mode": { - "description": "Dedicated pooler mode for the project", - "type": "string", - "enum": ["transaction", "session"] - } - }, - "example": { - "default_pool_size": 25, - "pool_mode": "transaction" - } - }, - "UpdateSupavisorConfigResponse": { - "type": "object", - "properties": { - "default_pool_size": { - "type": "integer", - "minimum": -9007199254740991, "maximum": 9007199254740991, - "nullable": true - }, - "pool_mode": { - "type": "string" + "format": "int64" } }, - "required": ["default_pool_size", "pool_mode"] - }, - "PostgresConfigResponse": { - "type": "object", - "properties": { - "effective_cache_size": { - "type": "string" - }, - "logical_decoding_work_mem": { - "type": "string" - }, - "cron.log_statement": { - "type": "boolean" - }, - "log_autovacuum_min_duration": { - "type": "string", - "description": "Default unit: ms", - "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" - }, - "log_checkpoints": { - "type": "boolean" - }, - "log_connections": { - "type": "boolean" - }, - "log_disconnections": { - "type": "boolean" - }, - "log_duration": { - "type": "boolean" - }, - "log_lock_waits": { - "type": "boolean" - }, - "log_recovery_conflict_waits": { - "type": "boolean" - }, - "log_replication_commands": { - "type": "boolean" - }, - "log_startup_progress_interval": { - "type": "string", - "description": "Default unit: ms", - "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" - }, - "log_temp_files": { - "type": "string" - }, - "maintenance_work_mem": { - "type": "string" - }, - "track_activity_query_size": { - "type": "string" - }, - "max_connections": { - "type": "integer", - "minimum": 1, - "maximum": 262143 - }, - "max_locks_per_transaction": { - "type": "integer", - "minimum": 10, - "maximum": 2147483640 - }, - "max_logical_replication_workers": { - "type": "integer", - "minimum": 0, - "maximum": 262143 - }, - "max_parallel_maintenance_workers": { - "type": "integer", - "minimum": 0, - "maximum": 1024 - }, - "max_parallel_workers": { - "type": "integer", - "minimum": 0, - "maximum": 1024 - }, - "max_parallel_workers_per_gather": { - "type": "integer", - "minimum": 0, - "maximum": 1024 - }, - "max_replication_slots": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 - }, - "max_slot_wal_keep_size": { - "type": "string" - }, - "max_standby_archive_delay": { - "type": "string" - }, - "max_standby_streaming_delay": { + "required": ["recovery_time_target_unix"], + "example": { + "recovery_time_target_unix": 1740787200 + } + }, + "V1RestorePointPostBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "maxLength": 20 + } + }, + "required": ["name"], + "example": { + "name": "before-upgrade" + } + }, + "V1RestorePointResponse": { + "type": "object", + "properties": { + "name": { "type": "string" }, - "max_sync_workers_per_subscription": { - "type": "integer", - "minimum": 0, - "maximum": 262143 - }, - "max_wal_size": { - "type": "string" + "status": { + "type": "string", + "enum": ["AVAILABLE", "PENDING", "REMOVED", "FAILED"] }, - "max_wal_senders": { + "completed_on": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "nullable": true + } + }, + "required": ["name", "status", "completed_on"] + }, + "V1RestoreBackupBody": { + "type": "object", + "properties": { + "id": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 - }, - "max_worker_processes": { - "type": "integer", - "minimum": 0, - "maximum": 262143 - }, - "session_replication_role": { + } + }, + "required": ["id"], + "example": { + "id": 12345 + } + }, + "V1BackupScheduleResponse": { + "type": "object", + "properties": { + "schedule_for": { "type": "string", - "enum": ["origin", "replica", "local"] - }, - "shared_buffers": { - "type": "string" + "pattern": "^(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?$", + "description": "Time of day to schedule daily backups, in UTC. Format: HH:MM:SS.", + "example": "04:00:00" }, - "statement_timeout": { + "updated_at": { "type": "string", - "description": "Default unit: ms", - "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" - }, - "track_commit_timestamp": { - "type": "boolean" - }, - "wal_keep_size": { - "type": "string" - }, - "wal_sender_timeout": { + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$", + "description": "Timestamp of when the backup schedule was last updated.", + "example": "2026-05-04T14:40:44+00:00" + } + }, + "required": ["schedule_for", "updated_at"] + }, + "V1UpdateBackupScheduleBody": { + "type": "object", + "properties": { + "schedule_for": { "type": "string", - "description": "Default unit: ms", - "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" - }, - "work_mem": { - "type": "string" - }, - "checkpoint_timeout": { + "pattern": "^(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?$", + "description": "Time of day to schedule daily backups, in UTC. Format: HH:MM:SS.", + "example": "04:00:00" + } + }, + "required": ["schedule_for"], + "example": { + "schedule_for": "04:00:00" + } + }, + "V1UndoBody": { + "type": "object", + "properties": { + "name": { "type": "string", - "description": "Default unit: s", - "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" - }, - "hot_standby_feedback": { - "type": "boolean" + "maxLength": 20 + } + }, + "required": ["name"], + "example": { + "name": "before-upgrade" + } + }, + "V1ListEntitlementsResponse": { + "type": "object", + "properties": { + "entitlements": { + "type": "array", + "items": { + "type": "object", + "properties": { + "feature": { + "type": "object", + "properties": { + "key": { + "type": "string", + "enum": [ + "instances.compute_update_available_sizes", + "instances.read_replicas", + "instances.disk_modifications", + "instances.high_availability", + "instances.orioledb", + "replication.etl", + "storage.max_file_size", + "storage.max_file_size.configurable", + "storage.image_transformations", + "storage.vector_buckets", + "storage.iceberg_catalog", + "storage.purge_cache", + "security.audit_logs_days", + "security.questionnaire", + "security.soc2_report", + "security.iso27001_certificate", + "security.private_link", + "security.enforce_mfa", + "log.retention_days", + "custom_domain", + "vanity_subdomain", + "ipv4", + "pitr.available_variants", + "log_drains", + "audit_log_drains", + "branching_limit", + "branching_persistent", + "auth.mfa_phone", + "auth.mfa_web_authn", + "auth.mfa_enhanced_security", + "auth.hooks", + "auth.platform.sso", + "auth.custom_jwt_template", + "auth.saml_2", + "auth.user_sessions", + "auth.leaked_password_protection", + "auth.advanced_auth_settings", + "auth.performance_settings", + "auth.password_hibp", + "auth.custom_oauth.max_providers", + "backup.retention_days", + "backup.restore_to_new_project", + "backup.schedule", + "function.max_count", + "function.size_limit_mb", + "realtime.max_concurrent_users", + "realtime.max_events_per_second", + "realtime.max_joins_per_second", + "realtime.max_channels_per_client", + "realtime.max_bytes_per_second", + "realtime.max_presence_events_per_second", + "realtime.max_payload_size_in_kb", + "project_scoped_roles", + "security.member_roles", + "project_pausing", + "project_cloning", + "project_restore_after_expiry", + "assistant.advance_model", + "integrations.github_connections", + "dedicated_pooler", + "observability.dashboard_advanced_metrics", + "api.members.invitations", + "api.members.roles" + ] + }, + "type": { + "type": "string", + "enum": ["boolean", "numeric", "set"] + } + }, + "required": ["key", "type"] + }, + "hasAccess": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": ["boolean", "numeric", "set"] + }, + "config": { + "anyOf": [ + { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": ["enabled"] + }, + { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "value": { + "type": "number" + }, + "unlimited": { + "type": "boolean" + }, + "unit": { + "type": "string" + } + }, + "required": ["enabled", "value", "unlimited", "unit"] + }, + { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "set": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["enabled", "set"] + } + ] + } + }, + "required": ["feature", "hasAccess", "type", "config"] + } } - } + }, + "required": ["entitlements"] }, - "UpdatePostgresConfigBody": { + "V1OrganizationMemberResponse": { "type": "object", "properties": { - "effective_cache_size": { - "type": "string" - }, - "logical_decoding_work_mem": { - "type": "string" - }, - "cron.log_statement": { - "type": "boolean" - }, - "log_autovacuum_min_duration": { - "type": "string", - "description": "Default unit: ms", - "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" - }, - "log_checkpoints": { - "type": "boolean" - }, - "log_connections": { - "type": "boolean" - }, - "log_disconnections": { - "type": "boolean" - }, - "log_duration": { - "type": "boolean" - }, - "log_lock_waits": { - "type": "boolean" - }, - "log_recovery_conflict_waits": { - "type": "boolean" - }, - "log_replication_commands": { - "type": "boolean" - }, - "log_startup_progress_interval": { - "type": "string", - "description": "Default unit: ms", - "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" - }, - "log_temp_files": { - "type": "string" - }, - "maintenance_work_mem": { - "type": "string" - }, - "track_activity_query_size": { - "type": "string" - }, - "max_connections": { - "type": "integer", - "minimum": 1, - "maximum": 262143 - }, - "max_locks_per_transaction": { - "type": "integer", - "minimum": 10, - "maximum": 2147483640 - }, - "max_logical_replication_workers": { - "type": "integer", - "minimum": 0, - "maximum": 262143 - }, - "max_parallel_maintenance_workers": { - "type": "integer", - "minimum": 0, - "maximum": 1024 - }, - "max_parallel_workers": { - "type": "integer", - "minimum": 0, - "maximum": 1024 - }, - "max_parallel_workers_per_gather": { - "type": "integer", - "minimum": 0, - "maximum": 1024 - }, - "max_replication_slots": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 - }, - "max_slot_wal_keep_size": { - "type": "string" - }, - "max_standby_archive_delay": { + "user_id": { "type": "string" }, - "max_standby_streaming_delay": { + "user_name": { "type": "string" }, - "max_sync_workers_per_subscription": { - "type": "integer", - "minimum": 0, - "maximum": 262143 - }, - "max_wal_size": { + "email": { "type": "string" }, - "max_wal_senders": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 - }, - "max_worker_processes": { - "type": "integer", - "minimum": 0, - "maximum": 262143 - }, - "session_replication_role": { - "type": "string", - "enum": ["origin", "replica", "local"] - }, - "shared_buffers": { + "role_name": { "type": "string" }, - "statement_timeout": { - "type": "string", - "description": "Default unit: ms", - "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" - }, - "track_commit_timestamp": { + "mfa_enabled": { "type": "boolean" }, - "wal_keep_size": { - "type": "string" - }, - "wal_sender_timeout": { - "type": "string", - "description": "Default unit: ms", - "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" - }, - "work_mem": { - "type": "string" - }, - "checkpoint_timeout": { + "avatar_url": { "type": "string", - "description": "Default unit: s", - "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" - }, - "hot_standby_feedback": { - "type": "boolean" - }, - "restart_database": { - "type": "boolean" - } - }, - "example": { - "max_connections": 120, - "shared_buffers": "256MB", - "work_mem": "4MB", - "statement_timeout": "60000ms" - }, - "additionalProperties": false - }, - "RealtimeConfigResponse": { - "type": "object", - "properties": { - "private_only": { - "type": "boolean", - "description": "Whether to only allow private channels", - "nullable": true - }, - "connection_pool": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "description": "Sets connection pool size for Realtime Authorization", - "nullable": true - }, - "max_concurrent_users": { - "type": "integer", - "minimum": 1, - "maximum": 50000, - "description": "Sets maximum number of concurrent users rate limit", - "nullable": true - }, - "max_events_per_second": { - "type": "integer", - "minimum": 1, - "maximum": 50000, - "description": "Sets maximum number of events per second rate per channel limit", - "nullable": true - }, - "max_bytes_per_second": { - "type": "integer", - "minimum": 1, - "maximum": 10000000, - "description": "Sets maximum number of bytes per second rate per channel limit", - "nullable": true - }, - "max_channels_per_client": { - "type": "integer", - "minimum": 1, - "maximum": 10000, - "description": "Sets maximum number of channels per client rate limit", - "nullable": true - }, - "max_joins_per_second": { - "type": "integer", - "minimum": 1, - "maximum": 5000, - "description": "Sets maximum number of joins per second rate limit", - "nullable": true - }, - "max_presence_events_per_second": { - "type": "integer", - "minimum": 1, - "maximum": 5000, - "description": "Sets maximum number of presence events per second rate limit", - "nullable": true - }, - "max_payload_size_in_kb": { - "type": "integer", - "minimum": 1, - "maximum": 10000, - "description": "Sets maximum number of payload size in KB rate limit", - "nullable": true - }, - "suspend": { - "type": "boolean", - "description": "Disables the Realtime service for this project when true. Set to false to re-enable it.", - "nullable": true - }, - "presence_enabled": { - "type": "boolean", - "description": "Whether to enable presence" - } - }, - "required": [ - "private_only", - "connection_pool", - "max_concurrent_users", - "max_events_per_second", - "max_bytes_per_second", - "max_channels_per_client", - "max_joins_per_second", - "max_presence_events_per_second", - "max_payload_size_in_kb", - "suspend", - "presence_enabled" - ] + "nullable": true + } + }, + "required": ["user_id", "user_name", "role_name", "mfa_enabled", "avatar_url"] }, - "UpdateRealtimeConfigBody": { + "V1OrganizationSlugResponse": { "type": "object", "properties": { - "private_only": { - "type": "boolean", - "description": "Whether to only allow private channels" - }, - "connection_pool": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "description": "Sets connection pool size for Realtime Authorization" + "id": { + "type": "string" }, - "max_concurrent_users": { - "type": "integer", - "minimum": 1, - "maximum": 50000, - "description": "Sets maximum number of concurrent users rate limit" + "name": { + "type": "string" }, - "max_events_per_second": { - "type": "integer", - "minimum": 1, - "maximum": 50000, - "description": "Sets maximum number of events per second rate per channel limit" + "plan": { + "type": "string", + "enum": ["free", "pro", "team", "enterprise", "platform"] }, - "max_bytes_per_second": { - "type": "integer", - "minimum": 1, - "maximum": 10000000, - "description": "Sets maximum number of bytes per second rate per channel limit" + "opt_in_tags": { + "type": "array", + "items": { + "enum": [ + "AI_SQL_GENERATOR_OPT_IN", + "AI_DATA_GENERATOR_OPT_IN", + "AI_LOG_GENERATOR_OPT_IN" + ] + } }, - "max_channels_per_client": { - "type": "integer", - "minimum": 1, - "maximum": 10000, - "description": "Sets maximum number of channels per client rate limit" + "allowed_release_channels": { + "type": "array", + "items": { + "type": "string", + "enum": ["internal", "alpha", "beta", "ga", "withdrawn", "preview"] + } + } + }, + "required": ["id", "name", "opt_in_tags", "allowed_release_channels"] + }, + "OrganizationProjectClaimResponse": { + "type": "object", + "properties": { + "project": { + "type": "object", + "properties": { + "ref": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": ["ref", "name"] }, - "max_joins_per_second": { - "type": "integer", - "minimum": 1, - "maximum": 5000, - "description": "Sets maximum number of joins per second rate limit" + "preview": { + "type": "object", + "properties": { + "valid": { + "type": "boolean" + }, + "warnings": { + "type": "array", + "items": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": ["key", "message"] + } + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": ["key", "message"] + } + }, + "info": { + "type": "array", + "items": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": ["key", "message"] + } + }, + "members_exceeding_free_project_limit": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "limit": { + "type": "number" + } + }, + "required": ["name", "limit"] + } + }, + "source_subscription_plan": { + "type": "string", + "enum": ["free", "pro", "team", "enterprise", "platform"] + }, + "target_subscription_plan": { + "type": "string", + "enum": ["free", "pro", "team", "enterprise", "platform", null], + "nullable": true + } + }, + "required": [ + "valid", + "warnings", + "errors", + "info", + "members_exceeding_free_project_limit", + "source_subscription_plan", + "target_subscription_plan" + ] }, - "max_presence_events_per_second": { - "type": "integer", - "minimum": 1, - "maximum": 5000, - "description": "Sets maximum number of presence events per second rate limit" + "expires_at": { + "type": "string" }, - "max_payload_size_in_kb": { - "type": "integer", - "minimum": 1, - "maximum": 10000, - "description": "Sets maximum number of payload size in KB rate limit" + "created_at": { + "type": "string" }, - "suspend": { - "type": "boolean", - "description": "Disables the Realtime service for this project when true. Set to false to re-enable it." + "created_by": { + "type": "string", + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" + } + }, + "required": ["project", "preview", "expires_at", "created_at", "created_by"] + }, + "OrganizationProjectsResponse": { + "type": "object", + "properties": { + "projects": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ref": { + "type": "string" + }, + "name": { + "type": "string" + }, + "cloud_provider": { + "type": "string" + }, + "region": { + "type": "string" + }, + "is_branch": { + "type": "boolean" + }, + "status": { + "type": "string", + "enum": [ + "INACTIVE", + "ACTIVE_HEALTHY", + "ACTIVE_UNHEALTHY", + "COMING_UP", + "UNKNOWN", + "GOING_DOWN", + "INIT_FAILED", + "REMOVED", + "RESTORING", + "UPGRADING", + "PAUSING", + "RESTORE_FAILED", + "RESTARTING", + "PAUSE_FAILED", + "RESIZING" + ] + }, + "inserted_at": { + "type": "string" + }, + "databases": { + "type": "array", + "items": { + "type": "object", + "properties": { + "infra_compute_size": { + "type": "string", + "enum": [ + "pico", + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge", + "4xlarge", + "8xlarge", + "12xlarge", + "16xlarge", + "24xlarge", + "24xlarge_optimized_memory", + "24xlarge_optimized_cpu", + "24xlarge_high_memory", + "48xlarge", + "48xlarge_optimized_memory", + "48xlarge_optimized_cpu", + "48xlarge_high_memory" + ] + }, + "region": { + "type": "string" + }, + "status": { + "type": "string", + "enum": [ + "ACTIVE_HEALTHY", + "ACTIVE_UNHEALTHY", + "COMING_UP", + "GOING_DOWN", + "INIT_FAILED", + "REMOVED", + "RESTORING", + "UNKNOWN", + "INIT_READ_REPLICA", + "INIT_READ_REPLICA_FAILED", + "RESTARTING", + "RESIZING" + ] + }, + "cloud_provider": { + "type": "string" + }, + "identifier": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["PRIMARY", "READ_REPLICA"] + }, + "disk_volume_size_gb": { + "type": "number" + }, + "disk_type": { + "type": "string", + "enum": ["gp3", "io2"] + }, + "disk_throughput_mbps": { + "type": "number" + }, + "disk_last_modified_at": { + "type": "string" + } + }, + "required": ["region", "status", "cloud_provider", "identifier", "type"] + } + } + }, + "required": [ + "ref", + "name", + "cloud_provider", + "region", + "is_branch", + "status", + "inserted_at", + "databases" + ] + } }, - "presence_enabled": { - "type": "boolean", - "description": "Whether to enable presence" + "pagination": { + "type": "object", + "properties": { + "count": { + "type": "number", + "description": "Total number of projects. Use this to calculate the total number of pages." + }, + "limit": { + "type": "number", + "description": "Maximum number of projects per page" + }, + "offset": { + "type": "number", + "description": "Number of projects skipped in this response" + } + }, + "required": ["count", "limit", "offset"] } }, - "example": { - "private_only": false, - "max_concurrent_users": 1000, - "max_channels_per_client": 100 - }, - "additionalProperties": false + "required": ["projects", "pagination"] }, - "CreateProviderBody": { + "ListLogDrainsResponse": { "type": "object", "properties": { - "type": { - "type": "string", - "enum": ["saml"], - "description": "What type of provider will be created" - }, - "metadata_xml": { - "type": "string" - }, - "metadata_url": { - "type": "string" - }, - "domains": { + "data": { "type": "array", "items": { - "type": "string" - } - }, - "attribute_mapping": { - "type": "object", - "properties": { - "keys": { - "type": "object", - "additionalProperties": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Resource type.", + "enum": ["log_drain"] + }, + "id": { + "type": "string" + }, + "attributes": { "type": "object", "properties": { "name": { "type": "string" }, - "names": { - "type": "array", - "items": { - "type": "string" - } + "description": { + "type": "string" }, - "default": { + "config": { "anyOf": [ { "type": "object", - "properties": {} + "properties": { + "url": { + "type": "string", + "nullable": true + }, + "schema": { + "type": "string" + }, + "username": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + }, + "port": { + "type": "number", + "nullable": true + }, + "hostname": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "postgres" + }, + { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "http": { + "type": "string", + "enum": ["http1", "http2"] + }, + "gzip": { + "type": "boolean" + }, + "headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "additionalProperties": false, + "title": "webhook" + }, + { + "type": "object", + "properties": { + "project_id": { + "type": "string" + }, + "dataset_id": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "bigquery" + }, + { + "type": "object", + "properties": { + "api_key": { + "type": "string" + }, + "region": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "datadog" + }, + { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "username": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + }, + "headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "additionalProperties": false, + "title": "loki" + }, + { + "type": "object", + "properties": { + "dsn": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "sentry" + }, + { + "type": "object", + "properties": { + "domain": { + "type": "string" + }, + "api_token": { + "type": "string" + }, + "dataset_name": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "axiom" + }, + { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "port": { + "type": "integer", + "minimum": 0, + "maximum": 65535 + }, + "tls": { + "default": false, + "type": "boolean" + }, + "structured_data": { + "type": "string" + }, + "cipher_key": { + "type": "string" + }, + "ca_cert": { + "type": "string" + }, + "client_cert": { + "type": "string" + }, + "client_key": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "syslog" + } + ] + }, + "backend_type": { + "type": "string", + "enum": [ + "postgres", + "bigquery", + "clickhouse", + "webhook", + "datadog", + "loki", + "sentry", + "s3", + "axiom", + "last9", + "otlp", + "syslog" + ] + } + }, + "required": ["name", "config", "backend_type"] + } + }, + "required": ["type", "id", "attributes"] + } + } + }, + "required": ["data"] + }, + "CreateLogDrainRequestOpenApi": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Resource type.", + "enum": ["log_drain"] + }, + "attributes": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "config": { + "anyOf": [ + { + "type": "object", + "properties": { + "url": { + "type": "string", + "nullable": true + }, + "schema": { + "type": "string" + }, + "username": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + }, + "port": { + "type": "number", + "nullable": true + }, + "hostname": { + "type": "string" + } }, - { - "type": "number" + "additionalProperties": false, + "title": "postgres" + }, + { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "http": { + "type": "string", + "enum": ["http1", "http2"] + }, + "gzip": { + "type": "boolean" + }, + "headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } }, - { - "type": "string" + "additionalProperties": false, + "title": "webhook" + }, + { + "type": "object", + "properties": { + "project_id": { + "type": "string" + }, + "dataset_id": { + "type": "string" + } }, - { - "type": "boolean" - } - ] - }, - "array": { - "type": "boolean" - } + "additionalProperties": false, + "title": "bigquery" + }, + { + "type": "object", + "properties": { + "api_key": { + "type": "string" + }, + "region": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "datadog" + }, + { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "username": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + }, + "headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "additionalProperties": false, + "title": "loki" + }, + { + "type": "object", + "properties": { + "dsn": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "sentry" + }, + { + "type": "object", + "properties": { + "domain": { + "type": "string" + }, + "api_token": { + "type": "string" + }, + "dataset_name": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "axiom" + }, + { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "port": { + "type": "integer", + "minimum": 0, + "maximum": 65535 + }, + "tls": { + "default": false, + "type": "boolean" + }, + "structured_data": { + "type": "string" + }, + "cipher_key": { + "type": "string" + }, + "ca_cert": { + "type": "string" + }, + "client_cert": { + "type": "string" + }, + "client_key": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "syslog" + } + ] + }, + "backend_type": { + "type": "string", + "enum": [ + "postgres", + "bigquery", + "clickhouse", + "webhook", + "datadog", + "loki", + "sentry", + "s3", + "axiom", + "last9", + "otlp", + "syslog" + ] } - } + }, + "required": ["name", "config", "backend_type"] } }, - "required": ["keys"] - }, - "name_id_format": { - "type": "string", - "enum": [ - "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", - "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", - "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", - "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" - ] + "required": ["type", "attributes"] } }, - "required": ["type"], - "example": { - "type": "saml", - "metadata_url": "https://sso.acme.com/metadata.xml", - "domains": ["acme.com"], - "attribute_mapping": { - "keys": { - "email": { - "name": "email" - }, - "first_name": { - "name": "first_name" - }, - "last_name": { - "name": "last_name" - } - } - } - } + "required": ["data"] }, - "CreateProviderResponse": { + "LogDrainResponse": { "type": "object", "properties": { - "id": { - "type": "string" - }, - "saml": { + "data": { "type": "object", "properties": { - "entity_id": { - "type": "string" - }, - "metadata_url": { - "type": "string" + "type": { + "type": "string", + "description": "Resource type.", + "enum": ["log_drain"] }, - "metadata_xml": { + "id": { "type": "string" }, - "attribute_mapping": { + "attributes": { "type": "object", "properties": { - "keys": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": { - "name": { - "type": "string" + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "config": { + "anyOf": [ + { + "type": "object", + "properties": { + "url": { + "type": "string", + "nullable": true + }, + "schema": { + "type": "string" + }, + "username": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + }, + "port": { + "type": "number", + "nullable": true + }, + "hostname": { + "type": "string" + } }, - "names": { - "type": "array", - "items": { + "additionalProperties": false, + "title": "postgres" + }, + { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "http": { + "type": "string", + "enum": ["http1", "http2"] + }, + "gzip": { + "type": "boolean" + }, + "headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "additionalProperties": false, + "title": "webhook" + }, + { + "type": "object", + "properties": { + "project_id": { + "type": "string" + }, + "dataset_id": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "bigquery" + }, + { + "type": "object", + "properties": { + "api_key": { + "type": "string" + }, + "region": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "datadog" + }, + { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "username": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + }, + "headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "additionalProperties": false, + "title": "loki" + }, + { + "type": "object", + "properties": { + "dsn": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "sentry" + }, + { + "type": "object", + "properties": { + "domain": { + "type": "string" + }, + "api_token": { + "type": "string" + }, + "dataset_name": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "axiom" + }, + { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "port": { + "type": "integer", + "minimum": 0, + "maximum": 65535 + }, + "tls": { + "default": false, + "type": "boolean" + }, + "structured_data": { + "type": "string" + }, + "cipher_key": { + "type": "string" + }, + "ca_cert": { + "type": "string" + }, + "client_cert": { + "type": "string" + }, + "client_key": { "type": "string" } }, - "default": { - "anyOf": [ - { - "type": "object", - "properties": {} - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "boolean" - } - ] - }, - "array": { - "type": "boolean" - } + "additionalProperties": false, + "title": "syslog" } - } + ] + }, + "backend_type": { + "type": "string", + "enum": [ + "postgres", + "bigquery", + "clickhouse", + "webhook", + "datadog", + "loki", + "sentry", + "s3", + "axiom", + "last9", + "otlp", + "syslog" + ] } }, - "required": [] + "required": ["name", "config", "backend_type"] + } + }, + "required": ["type", "id", "attributes"] + } + }, + "required": ["data"] + }, + "PlanGateErrorBodyV2": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "HTTP status-derived error code, e.g. \"payment_required\"" }, - "name_id_format": { + "message": { "type": "string", - "enum": [ - "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", - "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", - "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", - "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" - ] + "description": "Human-readable explanation of the plan gate" } }, - "required": ["entity_id"] - }, - "domains": { - "type": "array", - "items": { - "type": "object", - "properties": { - "domain": { - "type": "string" - }, - "created_at": { - "type": "string" - }, - "updated_at": { - "type": "string" - } - } - } - }, - "created_at": { - "type": "string" - }, - "updated_at": { - "type": "string" + "required": ["code", "message"], + "description": "Plan-gate error object" } }, - "required": ["id"] + "required": ["error"] }, - "ListProvidersResponse": { + "UpdateLogDrainRequestOpenApi": { "type": "object", "properties": { - "items": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "saml": { - "type": "object", - "properties": { - "entity_id": { - "type": "string" - }, - "metadata_url": { - "type": "string" - }, - "metadata_xml": { - "type": "string" - }, - "attribute_mapping": { - "type": "object", - "properties": { - "keys": { - "type": "object", - "additionalProperties": { + "data": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Resource type.", + "enum": ["log_drain"] + }, + "attributes": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "config": { + "anyOf": [ + { + "type": "object", + "properties": { + "url": { + "type": "string", + "nullable": true + }, + "schema": { + "type": "string" + }, + "username": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + }, + "port": { + "type": "number", + "nullable": true + }, + "hostname": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "postgres" + }, + { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "http": { + "type": "string", + "enum": ["http1", "http2"] + }, + "gzip": { + "type": "boolean" + }, + "headers": { "type": "object", - "properties": { - "name": { - "type": "string" - }, - "names": { - "type": "array", - "items": { - "type": "string" - } - }, - "default": { - "anyOf": [ - { - "type": "object", - "properties": {} - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "boolean" - } - ] - }, - "array": { - "type": "boolean" - } + "additionalProperties": { + "type": "string" } } - } + }, + "additionalProperties": false, + "title": "webhook" }, - "required": [] - }, - "name_id_format": { - "type": "string", - "enum": [ - "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", - "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", - "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", - "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" - ] - } - }, - "required": ["entity_id"] - }, - "domains": { - "type": "array", - "items": { - "type": "object", - "properties": { - "domain": { - "type": "string" + { + "type": "object", + "properties": { + "project_id": { + "type": "string" + }, + "dataset_id": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "bigquery" }, - "created_at": { - "type": "string" + { + "type": "object", + "properties": { + "api_key": { + "type": "string" + }, + "region": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "datadog" }, - "updated_at": { - "type": "string" + { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "username": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + }, + "headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "additionalProperties": false, + "title": "loki" + }, + { + "type": "object", + "properties": { + "dsn": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "sentry" + }, + { + "type": "object", + "properties": { + "domain": { + "type": "string" + }, + "api_token": { + "type": "string" + }, + "dataset_name": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "axiom" + }, + { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "port": { + "type": "integer", + "minimum": 0, + "maximum": 65535 + }, + "tls": { + "default": false, + "type": "boolean" + }, + "structured_data": { + "type": "string" + }, + "cipher_key": { + "type": "string" + }, + "ca_cert": { + "type": "string" + }, + "client_cert": { + "type": "string" + }, + "client_key": { + "type": "string" + } + }, + "additionalProperties": false, + "title": "syslog" } - } + ] + }, + "backend_type": { + "type": "string", + "enum": [ + "postgres", + "bigquery", + "clickhouse", + "webhook", + "datadog", + "loki", + "sentry", + "s3", + "axiom", + "last9", + "otlp", + "syslog" + ] } }, - "created_at": { - "type": "string" - }, - "updated_at": { - "type": "string" - } - }, - "required": ["id"] - } + "required": ["backend_type"] + } + }, + "required": ["type", "attributes"] } }, - "required": ["items"] + "required": ["data"] }, - "GetProviderResponse": { + "V2ProjectConfigResponse": { "type": "object", "properties": { - "id": { - "type": "string" - }, - "saml": { + "data": { "type": "object", "properties": { - "entity_id": { - "type": "string" - }, - "metadata_url": { - "type": "string" + "type": { + "type": "string", + "description": "Resource type.", + "enum": ["project_config"] }, - "metadata_xml": { - "type": "string" + "id": { + "type": "string", + "description": "Project ref." }, - "attribute_mapping": { + "attributes": { "type": "object", "properties": { - "keys": { + "database": { "type": "object", - "additionalProperties": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "names": { - "type": "array", - "items": { + "properties": { + "ssl_enforced": { + "type": "boolean", + "description": "Whether the database rejects plaintext connections" + }, + "network_restrictions": { + "type": "object", + "properties": { + "entitlement": { + "type": "string", + "enum": ["disallowed", "allowed"] + }, + "status": { + "type": "string", + "enum": ["stored", "applied"], + "description": "Whether the allowlist below is applied to the project or only stored." + }, + "allowed_cidrs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["v4", "v6"] + } + }, + "required": ["address", "type"] + } + }, + "updated_at": { + "type": "string" + }, + "applied_at": { "type": "string" } }, - "default": { - "anyOf": [ - { - "type": "object", - "properties": {} - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "boolean" - } - ] + "required": ["entitlement", "status", "allowed_cidrs"] + }, + "postgres_settings": { + "type": "object", + "properties": { + "effective_cache_size": { + "type": "string" + }, + "logical_decoding_work_mem": { + "type": "string" + }, + "log_autovacuum_min_duration": { + "type": "string", + "description": "Default unit: ms", + "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" + }, + "log_checkpoints": { + "type": "boolean" + }, + "log_connections": { + "type": "boolean" + }, + "log_disconnections": { + "type": "boolean" + }, + "log_duration": { + "type": "boolean" + }, + "log_lock_waits": { + "type": "boolean" + }, + "log_recovery_conflict_waits": { + "type": "boolean" + }, + "log_replication_commands": { + "type": "boolean" + }, + "log_startup_progress_interval": { + "type": "string", + "description": "Default unit: ms", + "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" + }, + "log_temp_files": { + "type": "string" + }, + "maintenance_work_mem": { + "type": "string" + }, + "track_activity_query_size": { + "type": "string" + }, + "max_connections": { + "type": "integer", + "minimum": 1, + "maximum": 262143 + }, + "max_locks_per_transaction": { + "type": "integer", + "minimum": 10, + "maximum": 2147483640 + }, + "max_logical_replication_workers": { + "type": "integer", + "minimum": 0, + "maximum": 262143 + }, + "max_parallel_maintenance_workers": { + "type": "integer", + "minimum": 0, + "maximum": 1024 + }, + "max_parallel_workers": { + "type": "integer", + "minimum": 0, + "maximum": 1024 + }, + "max_parallel_workers_per_gather": { + "type": "integer", + "minimum": 0, + "maximum": 1024 + }, + "max_replication_slots": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "max_slot_wal_keep_size": { + "type": "string" + }, + "max_standby_archive_delay": { + "type": "string" + }, + "max_standby_streaming_delay": { + "type": "string" + }, + "max_sync_workers_per_subscription": { + "type": "integer", + "minimum": 0, + "maximum": 262143 + }, + "max_wal_size": { + "type": "string" + }, + "max_wal_senders": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "max_worker_processes": { + "type": "integer", + "minimum": 0, + "maximum": 262143 + }, + "session_replication_role": { + "type": "string", + "enum": ["origin", "replica", "local"] + }, + "shared_buffers": { + "type": "string" + }, + "statement_timeout": { + "type": "string", + "description": "Default unit: ms", + "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" + }, + "track_commit_timestamp": { + "type": "boolean" + }, + "wal_keep_size": { + "type": "string" + }, + "wal_sender_timeout": { + "type": "string", + "description": "Default unit: ms", + "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" + }, + "work_mem": { + "type": "string" + }, + "checkpoint_timeout": { + "type": "string", + "description": "Default unit: s", + "pattern": "^(-?[0-9]+(?:\\.[0-9]+)?)(us|ms|s|min|h|d)?$" + }, + "hot_standby_feedback": { + "type": "boolean" + }, + "cron_log_statement": { + "type": "boolean" + } }, - "array": { - "type": "boolean" - } + "description": "Postgres parameter overrides. Empty when the project runs entirely on defaults." } - } - } - }, - "required": [] - }, - "name_id_format": { - "type": "string", - "enum": [ - "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", - "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", - "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", - "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" - ] - } - }, - "required": ["entity_id"] - }, - "domains": { - "type": "array", - "items": { - "type": "object", - "properties": { - "domain": { - "type": "string" - }, - "created_at": { - "type": "string" - }, - "updated_at": { - "type": "string" - } - } - } - }, - "created_at": { - "type": "string" - }, - "updated_at": { - "type": "string" - } - }, - "required": ["id"] - }, - "UpdateProviderBody": { - "type": "object", - "properties": { - "metadata_xml": { - "type": "string" - }, - "metadata_url": { - "type": "string" - }, - "domains": { - "type": "array", - "items": { - "type": "string" - } - }, - "attribute_mapping": { - "type": "object", - "properties": { - "keys": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": { - "name": { - "type": "string" }, - "names": { - "type": "array", - "items": { + "required": ["ssl_enforced", "network_restrictions", "postgres_settings"] + }, + "pooler": { + "type": "object", + "properties": { + "pool_mode": { + "type": "string", + "enum": ["transaction", "session", "statement"] + }, + "ignore_startup_parameters": { + "type": "string" + }, + "server_idle_timeout": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "server_lifetime": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "query_wait_timeout": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "reserve_pool_size": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "default_pool_size": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "description": "Defaults to the pooler's size for the project's compute when not overridden." + }, + "max_client_conn": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "description": "Defaults to the pooler's size for the project's compute when not overridden." + } + }, + "required": [ + "pool_mode", + "ignore_startup_parameters", + "server_idle_timeout", + "server_lifetime", + "query_wait_timeout", + "reserve_pool_size", + "default_pool_size", + "max_client_conn" + ] + }, + "auth": { + "type": "object", + "additionalProperties": {}, + "description": "Effective Auth config, keyed by lowercased GoTrue setting name and resolved through the `gotrue_config` view, so a setting the project has never overridden is reported at its platform default. Secrets are returned as an HMAC of their value, never in plaintext." + }, + "api": { + "type": "object", + "properties": { + "db_schema": { + "type": "string", + "description": "Schemas exposed through the Data API" + }, + "db_extra_search_path": { "type": "string" + }, + "max_rows": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "db_pool_acquisition_timeout": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "db_pool": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "description": "If `null`, no pool size is written to the project's PostgREST config and PostgREST's own default applies. The platform does not pick a value here.", + "nullable": true + } + }, + "required": [ + "db_schema", + "db_extra_search_path", + "max_rows", + "db_pool_acquisition_timeout", + "db_pool" + ] + }, + "realtime": { + "type": "object", + "properties": { + "private_only": { + "type": "boolean" + }, + "max_concurrent_users": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "max_events_per_second": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "max_bytes_per_second": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "max_channels_per_client": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "max_joins_per_second": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "max_presence_events_per_second": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "max_payload_size_in_kb": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "presence_enabled": { + "type": "boolean" + }, + "suspend": { + "type": "boolean" + }, + "connection_pool": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "description": "Defaults to Realtime's pool size for the project's compute when not overridden." + }, + "postgres_changes_pool": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "description": "If `null`, no override is stored and Realtime applies its own default.", + "nullable": true } }, - "default": { - "anyOf": [ - { - "type": "object", - "properties": {} - }, - { - "type": "number" + "required": [ + "private_only", + "max_concurrent_users", + "max_events_per_second", + "max_bytes_per_second", + "max_channels_per_client", + "max_joins_per_second", + "max_presence_events_per_second", + "max_payload_size_in_kb", + "presence_enabled", + "suspend", + "connection_pool", + "postgres_changes_pool" + ] + }, + "storage": { + "type": "object", + "properties": { + "file_size_limit": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "format": "int64" + }, + "features": { + "type": "object", + "properties": { + "image_transformation": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": ["enabled"] + }, + "s3_protocol": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": ["enabled"] + }, + "purge_cache": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": ["enabled"] + }, + "iceberg_catalog": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "max_namespaces": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "max_tables": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "max_catalogs": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + } + }, + "required": ["enabled", "max_namespaces", "max_tables", "max_catalogs"] + }, + "vector_buckets": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "max_buckets": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "max_indexes": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + } + }, + "required": ["enabled", "max_buckets", "max_indexes"] + } }, - { - "type": "string" + "required": [ + "image_transformation", + "s3_protocol", + "purge_cache", + "iceberg_catalog", + "vector_buckets" + ] + }, + "capabilities": { + "type": "object", + "properties": { + "list_v2": { + "type": "boolean" + }, + "iceberg_catalog": { + "type": "boolean" + } }, - { - "type": "boolean" - } - ] + "required": ["list_v2", "iceberg_catalog"] + }, + "upstream_target": { + "type": "string", + "enum": ["main", "canary"] + }, + "migration_version": { + "type": "string" + }, + "database_pool_mode": { + "type": "string" + } }, - "array": { - "type": "boolean" - } + "required": [ + "file_size_limit", + "features", + "capabilities", + "upstream_target", + "migration_version", + "database_pool_mode" + ], + "description": "Read from the storage service's admin API rather than the middleware DB, so unlike the rest of this resource it reflects the tenant's live config." } - } + }, + "required": ["database", "pooler", "auth", "api", "realtime", "storage"] } }, - "required": ["keys"] - }, - "name_id_format": { - "type": "string", - "enum": [ - "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", - "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", - "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", - "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" - ] + "required": ["type", "id", "attributes"] } }, - "example": { - "metadata_url": "https://sso.acme.com/metadata.xml", - "domains": ["acme.com", "contractors.acme.com"] - } + "required": ["data"] }, - "UpdateProviderResponse": { + "V2TransferProjectBody": { "type": "object", "properties": { - "id": { - "type": "string" - }, - "saml": { + "data": { "type": "object", "properties": { - "entity_id": { - "type": "string" - }, - "metadata_url": { - "type": "string" - }, - "metadata_xml": { - "type": "string" + "type": { + "type": "string", + "description": "Resource type.", + "enum": ["project_transfer_input"] }, - "attribute_mapping": { + "attributes": { "type": "object", "properties": { - "keys": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "names": { - "type": "array", - "items": { - "type": "string" - } - }, - "default": { - "anyOf": [ - { - "type": "object", - "properties": {} - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "boolean" - } - ] - }, - "array": { - "type": "boolean" - } - } - } + "target_organization_slug": { + "type": "string" } }, - "required": [] - }, - "name_id_format": { - "type": "string", - "enum": [ - "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", - "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", - "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", - "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" - ] + "required": ["target_organization_slug"] } }, - "required": ["entity_id"] - }, - "domains": { - "type": "array", - "items": { - "type": "object", - "properties": { - "domain": { - "type": "string" - }, - "created_at": { - "type": "string" - }, - "updated_at": { - "type": "string" - } - } - } - }, - "created_at": { - "type": "string" - }, - "updated_at": { - "type": "string" + "required": ["type", "attributes"] } }, - "required": ["id"] + "required": ["data"] }, - "DeleteProviderResponse": { + "V2PreviewProjectTransferResponse": { "type": "object", "properties": { - "id": { - "type": "string" - }, - "saml": { + "data": { "type": "object", "properties": { - "entity_id": { - "type": "string" - }, - "metadata_url": { - "type": "string" - }, - "metadata_xml": { - "type": "string" + "type": { + "type": "string", + "description": "Resource type.", + "enum": ["project_transfer_result"] }, - "attribute_mapping": { + "attributes": { "type": "object", "properties": { - "keys": { - "type": "object", - "additionalProperties": { + "valid": { + "type": "boolean" + }, + "warnings": { + "type": "array", + "items": { "type": "object", "properties": { - "name": { + "key": { "type": "string" }, - "names": { - "type": "array", - "items": { - "type": "string" - } + "message": { + "type": "string" + } + }, + "required": ["key", "message"] + } + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "properties": { + "key": { + "type": "string" }, - "default": { - "anyOf": [ - { - "type": "object", - "properties": {} - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "boolean" - } - ] + "message": { + "type": "string" + } + }, + "required": ["key", "message"] + } + }, + "info": { + "type": "array", + "items": { + "type": "object", + "properties": { + "key": { + "type": "string" }, - "array": { - "type": "boolean" + "message": { + "type": "string" } - } + }, + "required": ["key", "message"] } } }, - "required": [] - }, - "name_id_format": { - "type": "string", - "enum": [ - "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", - "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", - "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", - "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" - ] + "required": ["valid", "warnings", "errors", "info"] } }, - "required": ["entity_id"] - }, - "domains": { - "type": "array", - "items": { - "type": "object", - "properties": { - "domain": { - "type": "string" - }, - "created_at": { - "type": "string" - }, - "updated_at": { - "type": "string" - } - } - } - }, - "created_at": { - "type": "string" - }, - "updated_at": { - "type": "string" + "required": ["type", "attributes"] } }, - "required": ["id"] + "required": ["data"] }, - "V1BackupsResponse": { + "V2ListPrivateLinkAssociationsResponse": { "type": "object", "properties": { - "region": { - "type": "string" - }, - "walg_enabled": { - "type": "boolean" - }, - "pitr_enabled": { - "type": "boolean" - }, - "backups": { + "data": { "type": "array", "items": { "type": "object", "properties": { - "id": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 - }, - "is_physical_backup": { - "type": "boolean" - }, - "status": { + "type": { "type": "string", - "enum": ["COMPLETED", "FAILED", "PENDING", "REMOVED", "ARCHIVED", "CANCELLED"] + "description": "Resource type.", + "enum": ["private_link_association"] }, - "inserted_at": { + "id": { "type": "string" + }, + "attributes": { + "type": "object", + "properties": { + "aws_account_id": { + "type": "string", + "minLength": 12, + "maxLength": 12, + "pattern": "^\\d{12}$", + "description": "The AWS account ID this PrivateLink share is associated with." + }, + "account_name": { + "description": "Human-readable name for the AWS account.", + "type": "string" + }, + "status": { + "type": "string", + "enum": [ + "CREATING", + "READY", + "ASSOCIATION_REQUEST_EXPIRED", + "ASSOCIATION_ACCEPTED", + "CREATION_FAILED", + "DELETING" + ], + "description": "\n - `CREATING`: The PrivateLink resources and the Association are in the process of being created. The PrivateLink Share cannot be accepted yet.\n - `READY`: The PrivateLink resources have been created and the PrivateLink Share can be accepted for the duration of 12h after sharing. See `shared_at`.\n - `ASSOCIATION_REQUEST_EXPIRED`: The PrivateLink Share has not been accepted within the 12h time limit. This association can now be deleted.\n - `ASSOCIATION_ACCEPTED`: The PrivateLink Share was successfully accepted.\n - `CREATION_FAILED`: The PrivateLink resources failed to create. This likely means something went wrong on Supabase's and and support should be contacted.\n - `DELETING`: The PrivateLink resources and the Association are in the process of being deleted. The PrivateLink Share cannot be accepted yet.\n" + }, + "shared_at": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "description": "The time and date at which the AWS Resource Share Association was requested from Supabase. `null` means that the association was not yet requested while the PrivateLink Association is pending.", + "nullable": true + }, + "database_type": { + "type": "string", + "enum": ["PRIMARY", "READ_REPLICA"], + "description": "Whether this PrivateLink share targets the primary database or a read replica." + }, + "database_identifier": { + "type": "string", + "description": "Identifier of the database this PrivateLink share targets - the project ref for the primary, or the read replica identifier." + } + }, + "required": [ + "aws_account_id", + "status", + "shared_at", + "database_type", + "database_identifier" + ] } }, - "required": ["id", "is_physical_backup", "status", "inserted_at"] - } - }, - "physical_backup_data": { - "type": "object", - "properties": { - "earliest_physical_backup_date_unix": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 - }, - "latest_physical_backup_date_unix": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 - } + "required": ["type", "id", "attributes"] } } }, - "required": ["region", "walg_enabled", "pitr_enabled", "backups", "physical_backup_data"] - }, - "V1RestorePitrBody": { - "type": "object", - "properties": { - "recovery_time_target_unix": { - "type": "integer", - "minimum": 0, - "maximum": 9007199254740991, - "format": "int64" - } - }, - "required": ["recovery_time_target_unix"], - "example": { - "recovery_time_target_unix": 1740787200 - } - }, - "V1RestorePointPostBody": { - "type": "object", - "properties": { - "name": { - "type": "string", - "maxLength": 20 - } - }, - "required": ["name"], - "example": { - "name": "before-upgrade" - } + "required": ["data"] }, - "V1RestorePointResponse": { + "V2CreatePrivateLinkAssociationRequest": { "type": "object", "properties": { - "name": { - "type": "string" - }, - "status": { - "type": "string", - "enum": ["AVAILABLE", "PENDING", "REMOVED", "FAILED"] - }, - "completed_on": { - "type": "string", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", - "nullable": true + "data": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Resource type.", + "enum": ["private_link_association"] + }, + "attributes": { + "type": "object", + "properties": { + "aws_account_id": { + "type": "string", + "minLength": 12, + "maxLength": 12, + "pattern": "^\\d{12}$", + "description": "The AWS account ID to add to the project PrivateLink share." + }, + "account_name": { + "description": "Optional human-readable name for the AWS account.", + "type": "string", + "maxLength": 128 + }, + "database_identifier": { + "description": "Identifier of the read replica this PrivateLink share should target. Omit to target the primary database.", + "type": "string" + } + }, + "required": ["aws_account_id"] + } + }, + "required": ["type", "attributes"] } }, - "required": ["name", "status", "completed_on"] + "required": ["data"] }, - "V1RestoreBackupBody": { + "V2PrivateLinkAssociationResponse": { "type": "object", "properties": { - "id": { - "type": "integer", - "minimum": -9007199254740991, - "maximum": 9007199254740991 + "data": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Resource type.", + "enum": ["private_link_association"] + }, + "id": { + "type": "string" + }, + "attributes": { + "type": "object", + "properties": { + "aws_account_id": { + "type": "string", + "minLength": 12, + "maxLength": 12, + "pattern": "^\\d{12}$", + "description": "The AWS account ID this PrivateLink share is associated with." + }, + "account_name": { + "description": "Human-readable name for the AWS account.", + "type": "string" + }, + "status": { + "type": "string", + "enum": [ + "CREATING", + "READY", + "ASSOCIATION_REQUEST_EXPIRED", + "ASSOCIATION_ACCEPTED", + "CREATION_FAILED", + "DELETING" + ], + "description": "\n - `CREATING`: The PrivateLink resources and the Association are in the process of being created. The PrivateLink Share cannot be accepted yet.\n - `READY`: The PrivateLink resources have been created and the PrivateLink Share can be accepted for the duration of 12h after sharing. See `shared_at`.\n - `ASSOCIATION_REQUEST_EXPIRED`: The PrivateLink Share has not been accepted within the 12h time limit. This association can now be deleted.\n - `ASSOCIATION_ACCEPTED`: The PrivateLink Share was successfully accepted.\n - `CREATION_FAILED`: The PrivateLink resources failed to create. This likely means something went wrong on Supabase's and and support should be contacted.\n - `DELETING`: The PrivateLink resources and the Association are in the process of being deleted. The PrivateLink Share cannot be accepted yet.\n" + }, + "shared_at": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "description": "The time and date at which the AWS Resource Share Association was requested from Supabase. `null` means that the association was not yet requested while the PrivateLink Association is pending.", + "nullable": true + }, + "database_type": { + "type": "string", + "enum": ["PRIMARY", "READ_REPLICA"], + "description": "Whether this PrivateLink share targets the primary database or a read replica." + }, + "database_identifier": { + "type": "string", + "description": "Identifier of the database this PrivateLink share targets - the project ref for the primary, or the read replica identifier." + } + }, + "required": [ + "aws_account_id", + "status", + "shared_at", + "database_type", + "database_identifier" + ] + } + }, + "required": ["type", "id", "attributes"] } }, - "required": ["id"], - "example": { - "id": 12345 - } + "required": ["data"] }, - "V1BackupScheduleResponse": { + "V2ListMembersResponse": { "type": "object", "properties": { - "schedule_for": { - "type": "string", - "pattern": "^(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?$", - "description": "Time of day to schedule daily backups, in UTC. Format: HH:MM:SS.", - "example": "04:00:00" + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Resource type.", + "enum": ["organization_member"] + }, + "id": { + "type": "string", + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$" + }, + "attributes": { + "type": "object", + "properties": { + "username": { + "type": "string", + "description": "Member's username", + "nullable": true + }, + "primary_email": { + "type": "string", + "description": "Member's primary email", + "nullable": true + }, + "mfa_enabled": { + "type": "boolean", + "description": "Whether Multi-Factor Authentication is enabled for this member" + }, + "is_sso_user": { + "type": "boolean", + "description": "Whether this member is a Single Sign-On user" + }, + "avatar_url": { + "type": "string", + "description": "Member's avatar URL", + "nullable": true + }, + "roles": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Role name. For project-scoped roles this is the base role name.", + "example": "developer" + }, + "scope": { + "type": "string", + "enum": ["organization", "project"], + "description": "Whether this role applies org-wide or is scoped to specific projects for the user." + }, + "projects": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ref": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": ["ref", "name"] + }, + "description": "Project refs this role is scoped to. Empty array for org-level roles." + } + }, + "required": ["name", "scope", "projects"] + }, + "description": "Roles assigned to this member. Includes both org-level and project-scoped roles." + } + }, + "required": [ + "username", + "primary_email", + "mfa_enabled", + "is_sso_user", + "avatar_url", + "roles" + ] + } + }, + "required": ["type", "id", "attributes"] + } }, - "updated_at": { - "type": "string", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$", - "description": "Timestamp of when the backup schedule was last updated.", - "example": "2026-05-04T14:40:44+00:00" + "links": { + "type": "object", + "properties": { + "first": { + "type": "string", + "description": "URL path to the first page if available.", + "example": "/v2/organizations/my-org/members?page[size]=10", + "nullable": true + }, + "prev": { + "type": "string", + "description": "URL path to the previous page.", + "example": "/v2/organizations/my-org/members?page[size]=10&page[before]=019adf7d-4513-74c5-bb9a-f1bc0f7a95d7", + "nullable": true + }, + "next": { + "type": "string", + "description": "URL path to the next page.", + "example": "/v2/organizations/my-org/members?page[size]=10&page[after]=019adf7d-4513-7062-b292-78b86cc470a4", + "nullable": true + }, + "last": { + "type": "string", + "description": "URL path to the last page if available.", + "example": "/v2/organizations/my-org/members?page[size]=10&page[after]=019adf7d-4513-71ba-b264-21900edb4295", + "nullable": true + } + }, + "required": ["prev", "next"] } }, - "required": ["schedule_for", "updated_at"] + "required": ["data", "links"] }, - "V1UpdateBackupScheduleBody": { + "V2AssignOrganizationMemberRoleRequest": { "type": "object", "properties": { - "schedule_for": { - "type": "string", - "pattern": "^(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?$", - "description": "Time of day to schedule daily backups, in UTC. Format: HH:MM:SS.", - "example": "04:00:00" + "data": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Resource type.", + "enum": ["organization_member_role"] + }, + "attributes": { + "type": "object", + "properties": { + "role": { + "type": "string", + "enum": ["owner", "administrator", "developer", "read-only"], + "description": "Role name to assign. Must be one of: owner, administrator, developer, read-only. Must be on a Team or Enterprise plan to use the read-only role.", + "example": "developer" + }, + "projects": { + "description": "The projects to assign a project-scoped role for. If omitted, assigns an org-wide role.", + "minItems": 1, + "type": "array", + "items": { + "type": "object", + "properties": { + "ref": { + "type": "string", + "description": "Project ref", + "example": "abcjuqabhgwjjutfvtpa" + } + }, + "required": ["ref"] + } + } + }, + "required": ["role"] + } + }, + "required": ["type", "attributes"] } }, - "required": ["schedule_for"], - "example": { - "schedule_for": "04:00:00" - } + "required": ["data"] }, - "V1UndoBody": { + "OrganizationMemberRoleResponse": { "type": "object", "properties": { - "name": { - "type": "string", - "maxLength": 20 + "data": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Resource type.", + "enum": ["organization_member_role"] + }, + "attributes": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Role name. For project-scoped assignments this is the base role name.", + "example": "developer" + }, + "scope": { + "type": "string", + "enum": ["organization", "project"], + "description": "Whether this role applies org-wide or is scoped to specific projects for the user." + }, + "projects": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ref": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": ["ref", "name"] + }, + "description": "Project refs this role is scoped to. Empty array for org-level roles." + } + }, + "required": ["name", "scope", "projects"] + } + }, + "required": ["type", "attributes"] } }, - "required": ["name"], - "example": { - "name": "before-upgrade" - } + "required": ["data"] }, - "V1ListEntitlementsResponse": { + "V2ListRolesResponse": { "type": "object", "properties": { - "entitlements": { + "data": { "type": "array", "items": { "type": "object", "properties": { - "feature": { + "type": { + "type": "string", + "description": "Resource type.", + "enum": ["organization_role"] + }, + "attributes": { "type": "object", "properties": { - "key": { - "type": "string", - "enum": [ - "instances.compute_update_available_sizes", - "instances.read_replicas", - "instances.disk_modifications", - "instances.high_availability", - "instances.orioledb", - "replication.etl", - "storage.max_file_size", - "storage.max_file_size.configurable", - "storage.image_transformations", - "storage.vector_buckets", - "storage.iceberg_catalog", - "storage.purge_cache", - "security.audit_logs_days", - "security.questionnaire", - "security.soc2_report", - "security.iso27001_certificate", - "security.private_link", - "security.enforce_mfa", - "log.retention_days", - "custom_domain", - "vanity_subdomain", - "ipv4", - "pitr.available_variants", - "log_drains", - "audit_log_drains", - "branching_limit", - "branching_persistent", - "auth.mfa_phone", - "auth.mfa_web_authn", - "auth.mfa_enhanced_security", - "auth.hooks", - "auth.platform.sso", - "auth.custom_jwt_template", - "auth.saml_2", - "auth.user_sessions", - "auth.leaked_password_protection", - "auth.advanced_auth_settings", - "auth.performance_settings", - "auth.password_hibp", - "auth.custom_oauth.max_providers", - "backup.retention_days", - "backup.restore_to_new_project", - "backup.schedule", - "function.max_count", - "function.size_limit_mb", - "realtime.max_concurrent_users", - "realtime.max_events_per_second", - "realtime.max_joins_per_second", - "realtime.max_channels_per_client", - "realtime.max_bytes_per_second", - "realtime.max_presence_events_per_second", - "realtime.max_payload_size_in_kb", - "project_scoped_roles", - "security.member_roles", - "project_pausing", - "project_cloning", - "project_restore_after_expiry", - "assistant.advance_model", - "integrations.github_connections", - "dedicated_pooler", - "observability.dashboard_advanced_metrics", - "api.members.invitations", - "api.members.roles" - ] - }, - "type": { + "name": { "type": "string", - "enum": ["boolean", "numeric", "set"] + "description": "Role name.", + "example": "developer" } }, - "required": ["key", "type"] - }, - "hasAccess": { - "type": "boolean" - }, - "type": { - "type": "string", - "enum": ["boolean", "numeric", "set"] - }, - "config": { - "anyOf": [ - { - "type": "object", - "properties": { - "enabled": { - "type": "boolean" - } - }, - "required": ["enabled"] - }, - { - "type": "object", - "properties": { - "enabled": { - "type": "boolean" - }, - "value": { - "type": "number" - }, - "unlimited": { - "type": "boolean" - }, - "unit": { - "type": "string" - } - }, - "required": ["enabled", "value", "unlimited", "unit"] - }, - { - "type": "object", - "properties": { - "enabled": { - "type": "boolean" - }, - "set": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": ["enabled", "set"] - } - ] + "required": ["name"] } }, - "required": ["feature", "hasAccess", "type", "config"] + "required": ["type", "attributes"] } } }, - "required": ["entitlements"] - }, - "V1OrganizationMemberResponse": { - "type": "object", - "properties": { - "user_id": { - "type": "string" - }, - "user_name": { - "type": "string" - }, - "email": { - "type": "string" - }, - "role_name": { - "type": "string" - }, - "mfa_enabled": { - "type": "boolean" - }, - "avatar_url": { - "type": "string", - "nullable": true - } - }, - "required": ["user_id", "user_name", "role_name", "mfa_enabled", "avatar_url"] + "required": ["data"] }, - "V1OrganizationSlugResponse": { + "V2CreateInvitationsRequest": { "type": "object", "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "plan": { - "type": "string", - "enum": ["free", "pro", "team", "enterprise", "platform"] - }, - "opt_in_tags": { - "type": "array", - "items": { - "enum": [ - "AI_SQL_GENERATOR_OPT_IN", - "AI_DATA_GENERATOR_OPT_IN", - "AI_LOG_GENERATOR_OPT_IN" - ] - } - }, - "allowed_release_channels": { + "data": { + "minItems": 1, + "maxItems": 50, "type": "array", "items": { - "type": "string", - "enum": ["internal", "alpha", "beta", "ga", "withdrawn", "preview"] + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Resource type.", + "enum": ["organization_invitation"] + }, + "attributes": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" + }, + "role": { + "type": "string", + "enum": ["owner", "administrator", "developer", "read-only"], + "description": "Role name to assign. Must be on a Team or Enterprise plan to use the read-only role.", + "example": "developer" + }, + "projects": { + "description": "The projects to limit a user to. If omitted, user will have org-wide access with the provided role.", + "minItems": 1, + "type": "array", + "items": { + "type": "object", + "properties": { + "ref": { + "type": "string", + "description": "Project ref", + "example": "abcjuqabhgwjjutfvtpa" + } + }, + "required": ["ref"] + } + }, + "require_sso": { + "type": "boolean" + } + }, + "required": ["email", "role"] + } + }, + "required": ["type", "attributes"] } } }, - "required": ["id", "name", "opt_in_tags", "allowed_release_channels"] + "required": ["data"] }, - "OrganizationProjectClaimResponse": { + "V2CreateInvitationsResponse": { "type": "object", "properties": { - "project": { + "error": { "type": "object", "properties": { - "ref": { + "id": { "type": "string" }, - "name": { + "code": { "type": "string" - } - }, - "required": ["ref", "name"] - }, - "preview": { - "type": "object", - "properties": { - "valid": { - "type": "boolean" }, - "warnings": { - "type": "array", - "items": { + "message": { + "type": "string" + }, + "description": { + "type": "string" + }, + "links": { + "type": "object", + "additionalProperties": { "type": "object", "properties": { - "key": { + "href": { "type": "string" }, - "message": { + "rel": { "type": "string" + }, + "title": { + "type": "string" + }, + "type": { + "type": "string" + }, + "describedby": { + "type": "string" + }, + "meta": { + "type": "object", + "additionalProperties": {} } }, - "required": ["key", "message"] + "required": ["href"] } }, - "errors": { + "meta": { + "type": "object", + "additionalProperties": {} + }, + "issues": { "type": "array", "items": { "type": "object", "properties": { - "key": { + "id": { + "type": "string" + }, + "code": { "type": "string" }, "message": { "type": "string" + }, + "description": { + "type": "string" + }, + "links": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "href": { + "type": "string" + }, + "rel": { + "type": "string" + }, + "title": { + "type": "string" + }, + "type": { + "type": "string" + }, + "describedby": { + "type": "string" + }, + "meta": { + "type": "object", + "additionalProperties": {} + } + }, + "required": ["href"] + } + }, + "meta": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" + } + }, + "required": ["email"] + } + }, + "required": ["code", "message", "meta"] + } + } + }, + "required": ["code", "message"] + }, + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Resource type.", + "enum": ["organization_invitation"] + }, + "attributes": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" + } + }, + "required": ["email"] + } + }, + "required": ["type", "attributes"] + } + } + }, + "required": ["data"] + }, + "V2DeleteInvitationsRequest": { + "type": "object", + "properties": { + "data": { + "minItems": 1, + "maxItems": 100, + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Resource type.", + "enum": ["organization_invitation"] + }, + "attributes": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" + } + }, + "required": ["email"] + } + }, + "required": ["type", "attributes"] + } + } + }, + "required": ["data"] + }, + "V2DeleteInvitationsResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Resource type.", + "enum": ["organization_invitation"] + }, + "attributes": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" + } + }, + "required": ["email"] + } + }, + "required": ["type", "attributes"] + } + } + }, + "required": ["data"] + }, + "V2ListProjectsResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Resource type.", + "enum": ["project"] + }, + "id": { + "type": "string", + "minLength": 20, + "maxLength": 20, + "pattern": "^[a-z]+$", + "description": "Project ref", + "example": "abcdefghijklmnopqrst" + }, + "attributes": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Project name" + }, + "status": { + "type": "string", + "enum": [ + "INACTIVE", + "ACTIVE_HEALTHY", + "ACTIVE_UNHEALTHY", + "COMING_UP", + "UNKNOWN", + "GOING_DOWN", + "INIT_FAILED", + "REMOVED", + "RESTORING", + "UPGRADING", + "PAUSING", + "RESTORE_FAILED", + "RESTARTING", + "PAUSE_FAILED", + "RESIZING" + ], + "description": "Project status" + }, + "cloud_provider": { + "type": "string", + "description": "Cloud provider hosting the project" + }, + "region": { + "type": "string", + "description": "Region the project is hosted in" + }, + "inserted_at": { + "type": "string", + "description": "When the project was created" + }, + "databases": { + "type": "array", + "items": { + "type": "object", + "properties": { + "cloud_provider": { + "type": "string" + }, + "identifier": { + "type": "string" + }, + "region": { + "type": "string", + "nullable": true + }, + "status": { + "type": "string", + "enum": [ + "ACTIVE_HEALTHY", + "ACTIVE_UNHEALTHY", + "COMING_UP", + "GOING_DOWN", + "INIT_FAILED", + "REMOVED", + "RESTORING", + "UNKNOWN", + "INIT_READ_REPLICA", + "INIT_READ_REPLICA_FAILED", + "RESTARTING", + "RESIZING" + ] + }, + "type": { + "type": "string", + "enum": ["PRIMARY", "READ_REPLICA"] + }, + "infra_compute_size": { + "type": "string", + "enum": [ + "pico", + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge", + "4xlarge", + "8xlarge", + "12xlarge", + "16xlarge", + "24xlarge", + "24xlarge_optimized_memory", + "24xlarge_optimized_cpu", + "24xlarge_high_memory", + "48xlarge", + "48xlarge_optimized_memory", + "48xlarge_optimized_cpu", + "48xlarge_high_memory" + ] + }, + "disk_volume_size_gb": { + "type": "number" + }, + "disk_type": { + "type": "string", + "enum": ["gp3", "io2"] + }, + "disk_throughput_mbps": { + "type": "number" + }, + "disk_last_modified_at": { + "type": "string" + } + }, + "required": ["cloud_provider", "identifier", "region", "status", "type"] + }, + "description": "The project's databases including compute and disk attributes." } }, - "required": ["key", "message"] + "required": [ + "name", + "status", + "cloud_provider", + "region", + "inserted_at", + "databases" + ] } }, - "info": { - "type": "array", - "items": { - "type": "object", - "properties": { - "key": { - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": ["key", "message"] - } + "required": ["type", "id", "attributes"] + } + }, + "links": { + "type": "object", + "properties": { + "first": { + "type": "string", + "description": "URL path to the first page if available.", + "example": "/v2/organizations/my-org/projects?page[size]=10", + "nullable": true }, - "members_exceeding_free_project_limit": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "limit": { - "type": "number" - } - }, - "required": ["name", "limit"] - } + "prev": { + "type": "string", + "description": "URL path to the previous page.", + "example": "/v2/organizations/my-org/projects?page[size]=10&page[before]=019adf7d-4513-74c5-bb9a-f1bc0f7a95d7", + "nullable": true }, - "source_subscription_plan": { + "next": { "type": "string", - "enum": ["free", "pro", "team", "enterprise", "platform"] + "description": "URL path to the next page.", + "example": "/v2/organizations/my-org/projects?page[size]=10&page[after]=019adf7d-4513-7062-b292-78b86cc470a4", + "nullable": true }, - "target_subscription_plan": { + "last": { "type": "string", - "enum": ["free", "pro", "team", "enterprise", "platform", null], + "description": "URL path to the last page if available.", + "example": "/v2/organizations/my-org/projects?page[size]=10&page[after]=019adf7d-4513-71ba-b264-21900edb4295", "nullable": true } }, - "required": [ - "valid", - "warnings", - "errors", - "info", - "members_exceeding_free_project_limit", - "source_subscription_plan", - "target_subscription_plan" - ] - }, - "expires_at": { - "type": "string" - }, - "created_at": { - "type": "string" - }, - "created_by": { - "type": "string", - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" + "required": ["prev", "next"] } }, - "required": ["project", "preview", "expires_at", "created_at", "created_by"] + "required": ["data", "links"] }, - "OrganizationProjectsResponse": { + "V2ListGitHubConnectionsResponse": { "type": "object", "properties": { - "projects": { + "data": { "type": "array", "items": { "type": "object", "properties": { - "ref": { - "type": "string" - }, - "name": { - "type": "string" - }, - "cloud_provider": { - "type": "string" - }, - "region": { - "type": "string" - }, - "is_branch": { - "type": "boolean" - }, - "status": { + "type": { "type": "string", - "enum": [ - "INACTIVE", - "ACTIVE_HEALTHY", - "ACTIVE_UNHEALTHY", - "COMING_UP", - "UNKNOWN", - "GOING_DOWN", - "INIT_FAILED", - "REMOVED", - "RESTORING", - "UPGRADING", - "PAUSING", - "RESTORE_FAILED", - "RESTARTING", - "PAUSE_FAILED", - "RESIZING" - ] + "description": "Resource type.", + "enum": ["github_connection"] }, - "inserted_at": { - "type": "string" + "id": { + "type": "string", + "description": "Connection id.", + "example": "7" }, - "databases": { - "type": "array", - "items": { - "type": "object", - "properties": { - "infra_compute_size": { - "type": "string", - "enum": [ - "pico", - "nano", - "micro", - "small", - "medium", - "large", - "xlarge", - "2xlarge", - "4xlarge", - "8xlarge", - "12xlarge", - "16xlarge", - "24xlarge", - "24xlarge_optimized_memory", - "24xlarge_optimized_cpu", - "24xlarge_high_memory", - "48xlarge", - "48xlarge_optimized_memory", - "48xlarge_optimized_cpu", - "48xlarge_high_memory" - ] - }, - "region": { - "type": "string" - }, - "status": { - "type": "string", - "enum": [ - "ACTIVE_HEALTHY", - "ACTIVE_UNHEALTHY", - "COMING_UP", - "GOING_DOWN", - "INIT_FAILED", - "REMOVED", - "RESTORING", - "UNKNOWN", - "INIT_READ_REPLICA", - "INIT_READ_REPLICA_FAILED", - "RESTARTING", - "RESIZING" - ] - }, - "cloud_provider": { - "type": "string" - }, - "identifier": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["PRIMARY", "READ_REPLICA"] - }, - "disk_volume_size_gb": { - "type": "number" - }, - "disk_type": { - "type": "string", - "enum": ["gp3", "io2"] + "attributes": { + "type": "object", + "properties": { + "inserted_at": { + "type": "string", + "description": "When the connection was created" + }, + "updated_at": { + "type": "string", + "description": "When the connection was last updated" + }, + "installation_id": { + "type": "number", + "description": "GitHub App installation id" + }, + "workdir": { + "type": "string", + "description": "Directory within the repository the project lives in" + }, + "supabase_changes_only": { + "type": "boolean", + "description": "Whether branches are only created for changes under `supabase/`" + }, + "branch_limit": { + "type": "number", + "description": "Maximum number of preview branches" + }, + "new_branch_per_pr": { + "type": "boolean", + "description": "Whether a preview branch is created for every pull request" + }, + "project": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "ref": { + "type": "string", + "minLength": 20, + "maxLength": 20, + "pattern": "^[a-z]+$", + "description": "Project ref", + "example": "abcdefghijklmnopqrst" + }, + "name": { + "type": "string" + } }, - "disk_throughput_mbps": { - "type": "number" + "required": ["id", "ref", "name"], + "description": "The connected Supabase project" + }, + "repository": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "name": { + "type": "string" + } }, - "disk_last_modified_at": { - "type": "string" - } + "required": ["id", "name"], + "description": "The connected GitHub repository" }, - "required": ["region", "status", "cloud_provider", "identifier", "type"] - } + "user": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "username": { + "type": "string" + }, + "primary_email": { + "type": "string", + "nullable": true + } + }, + "required": ["id", "username", "primary_email"], + "description": "The user who created the connection, if still known", + "nullable": true + } + }, + "required": [ + "inserted_at", + "updated_at", + "installation_id", + "workdir", + "supabase_changes_only", + "branch_limit", + "new_branch_per_pr", + "project", + "repository", + "user" + ] } }, - "required": [ - "ref", - "name", - "cloud_provider", - "region", - "is_branch", - "status", - "inserted_at", - "databases" - ] + "required": ["type", "id", "attributes"] } }, - "pagination": { + "links": { "type": "object", "properties": { - "count": { - "type": "number", - "description": "Total number of projects. Use this to calculate the total number of pages." + "first": { + "type": "string", + "description": "URL path to the first page if available.", + "example": "/v2/organizations/my-org/integrations/github/connections?page[size]=10", + "nullable": true }, - "limit": { - "type": "number", - "description": "Maximum number of projects per page" + "prev": { + "type": "string", + "description": "URL path to the previous page.", + "example": "/v2/organizations/my-org/integrations/github/connections?page[size]=10&page[before]=019adf7d-4513-74c5-bb9a-f1bc0f7a95d7", + "nullable": true }, - "offset": { - "type": "number", - "description": "Number of projects skipped in this response" + "next": { + "type": "string", + "description": "URL path to the next page.", + "example": "/v2/organizations/my-org/integrations/github/connections?page[size]=10&page[after]=019adf7d-4513-7062-b292-78b86cc470a4", + "nullable": true + }, + "last": { + "type": "string", + "description": "URL path to the last page if available.", + "example": "/v2/organizations/my-org/integrations/github/connections?page[size]=10&page[after]=019adf7d-4513-71ba-b264-21900edb4295", + "nullable": true } }, - "required": ["count", "limit", "offset"] + "required": ["prev", "next"] } }, - "required": ["projects", "pagination"] + "required": ["data", "links"] } } } diff --git a/packages/api/src/internal/client.unit.test.ts b/packages/api/src/internal/client.unit.test.ts index a2b1b026c5..cda2b8fd61 100644 --- a/packages/api/src/internal/client.unit.test.ts +++ b/packages/api/src/internal/client.unit.test.ts @@ -1016,4 +1016,131 @@ describe("makeSupabaseApiClient", () => { }), ).toThrow(); }); + + test("surfaces a 404 on a v2 operation as a distinguishable status error and wires the request identically to v1", async () => { + let seenRequest: HttpClientRequest.HttpClientRequest | undefined; + + const client = await Effect.runPromise( + makeSupabaseApiClient(config).pipe( + Effect.provide( + httpClientLayer((request) => { + seenRequest = request; + return Effect.succeed( + jsonResponse(request, 404, { message: "Organization not found" }), + ); + }), + ), + ), + ); + + const error = await Effect.runPromise( + client + .execute(operationDefinitions.v2ListOrganizationMembers, { slug: "my-org" }) + .pipe(Effect.flip), + ); + + expect(HttpClientError.isHttpClientError(error)).toBe(true); + if (!HttpClientError.isHttpClientError(error)) { + throw new Error("expected HttpClientError"); + } + expect(error.reason._tag).toBe("StatusCodeError"); + if (error.reason._tag !== "StatusCodeError") { + throw new Error("expected StatusCodeError"); + } + expect(error.reason.response.status).toBe(404); + + expect(seenRequest).toBeDefined(); + expect(seenRequest?.url).toBe("https://api.supabase.com/v2/organizations/my-org/members"); + expect(seenRequest?.headers.authorization).toBe("Bearer test-token"); + }); + + test("decodes a nested v2GetProjectConfig payload through the unified execute path", async () => { + const result = await Effect.runPromise( + makeSupabaseApiClient(config).pipe( + Effect.flatMap((client) => + client.execute<"v2GetProjectConfig">(operationDefinitions.v2GetProjectConfig, { + ref: "abcdefghijklmnopqrst", + }), + ), + Effect.provide( + httpClientLayer((request) => + Effect.succeed( + jsonResponse(request, 200, { + data: { + type: "project_config", + id: "abcdefghijklmnopqrst", + attributes: { + database: { + ssl_enforced: true, + network_restrictions: { + entitlement: "disallowed", + status: "stored", + allowed_cidrs: [], + }, + postgres_settings: {}, + }, + pooler: { + pool_mode: "transaction", + ignore_startup_parameters: "", + server_idle_timeout: 0, + server_lifetime: 0, + query_wait_timeout: 0, + reserve_pool_size: 0, + default_pool_size: 0, + max_client_conn: 0, + }, + auth: {}, + api: { + db_schema: "public", + db_extra_search_path: "", + max_rows: 1000, + db_pool_acquisition_timeout: 0, + db_pool: null, + }, + realtime: { + private_only: false, + max_concurrent_users: 0, + max_events_per_second: 0, + max_bytes_per_second: 0, + max_channels_per_client: 0, + max_joins_per_second: 0, + max_presence_events_per_second: 0, + max_payload_size_in_kb: 0, + presence_enabled: true, + suspend: false, + connection_pool: 0, + postgres_changes_pool: null, + }, + storage: { + file_size_limit: 0, + features: { + image_transformation: { enabled: true }, + s3_protocol: { enabled: true }, + purge_cache: { enabled: true }, + iceberg_catalog: { + enabled: false, + max_namespaces: 0, + max_tables: 0, + max_catalogs: 0, + }, + vector_buckets: { enabled: false, max_buckets: 0, max_indexes: 0 }, + }, + capabilities: { list_v2: true, iceberg_catalog: true }, + upstream_target: "main", + migration_version: "1", + database_pool_mode: "transaction", + }, + }, + }, + }), + ), + ), + ), + ), + ); + + expect(result.data.attributes.database.network_restrictions.entitlement).toBe("disallowed"); + expect(result.data.attributes.storage.upstream_target).toBe("main"); + expect(result.data.attributes.api.db_pool).toBeNull(); + }); });