From 58d63ed9f7701c2b03ce8dcb398f32b07842e423 Mon Sep 17 00:00:00 2001 From: Colum Ferry Date: Mon, 10 Aug 2026 17:13:24 +0100 Subject: [PATCH 1/7] feat(api): support v2 namespace endpoints in @supabase/api Fetch and merge both Management API OpenAPI documents (/api/v1-json and /api/v2-json), derive client namespaces from the path, and regenerate the snapshot so v2 operations are callable as api.v2.. - download-openapi.ts: two-document fetch (hard-fail on a missing doc), structural merge with collision asserts, tolerant remove override op, committed source pin in scripts/openapi-source.json (staging for now: GET /v2/projects/{ref}/config has not shipped to prod yet) - generate.ts: version namespace derived from the leading path segment, duplicate-operation hard error; v1 output is byte-identical - openapi-overrides.json: remove the v2 webhook paths (upstream spec bug: duplicated, non-version-prefixed operationIds) and APIErrorObject - api-package-sync.yml: pin hourly sync to prod, diff the source pin - generate:check script + README spec-pipeline/override/merge-gate docs --- .github/workflows/api-package-sync.yml | 6 +- packages/api/README.md | 80 +- packages/api/package.json | 1 + packages/api/scripts/download-openapi.ts | 328 +- packages/api/scripts/generate.ts | 147 +- packages/api/scripts/openapi-overrides.json | 65 + packages/api/scripts/openapi-source.json | 3 + packages/api/src/generated/contracts.ts | 2265 +++ packages/api/src/generated/effect-client.ts | 328 + packages/api/src/generated/openapi.json | 17487 +++++++++++------- 10 files changed, 13841 insertions(+), 6869 deletions(-) create mode 100644 packages/api/scripts/openapi-source.json 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/packages/api/README.md b/packages/api/README.md index d82750704a..a6e82a3bd2 100644 --- a/packages/api/README.md +++ b/packages/api/README.md @@ -2,6 +2,13 @@ Generated Supabase Management API SDK built directly from the Supabase OpenAPI spec. +> **Temporary (CLI-2157):** the committed snapshot on this branch is generated from staging +> (`api.supabase.green`) because `GET /v2/projects/{ref}/config` (`api.v2.getProjectConfig`, +> schema `V2ProjectConfigResponse`) has not shipped to production yet. Develop's hourly prod sync +> (`api-package-sync.yml`) would remove exactly that endpoint once this merges. Before merging, +> either the endpoint must ship to production or the snapshot must be regenerated from production +> by re-pointing `scripts/openapi-source.json`. + The package exposes: - `@supabase/api` for the runtime-specific Promise client helpers plus generated contracts @@ -17,8 +24,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 +44,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 +67,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 +91,67 @@ 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 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..a7d790d2b4 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": "bun run 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", diff --git a/packages/api/scripts/download-openapi.ts b/packages/api/scripts/download-openapi.ts index a6e189b2b2..e4839e407b 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,49 @@ 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 { + const parsed = JSON.parse(await readFile(OPENAPI_SOURCE_PATH, "utf8")); + 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 +291,193 @@ 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; +} + +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; +} - if (!response.ok) { - throw new Error(`Failed to download OpenAPI spec from ${specUrl}: ${response.status}`); +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 document = await response.json(); - assertOpenApiDocument(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.`, + ); + } + } + } + + return { + ...firstEntry.document, + openapi: openapiVersion, + info: { title: "Supabase API", version: infoVersion }, + paths, + components: { ...firstEntry.document.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 pinnedBaseUrl = await loadPinnedBaseUrl(); + const baseUrl = resolveOpenApiBaseUrl({ + envBaseUrl: process.env.SUPABASE_API_URL, + 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/generate.ts b/packages/api/scripts/generate.ts index 8d1e52f11d..4ee05b0bf0 100644 --- a/packages/api/scripts/generate.ts +++ b/packages/api/scripts/generate.ts @@ -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/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..c26e963e2d --- /dev/null +++ b/packages/api/scripts/openapi-source.json @@ -0,0 +1,3 @@ +{ + "baseUrl": "https://api.supabase.green" +} 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"] } } } From 8d4b7cf92aa9532162ee2aae589f033920e1a1aa Mon Sep 17 00:00:00 2001 From: Colum Ferry Date: Mon, 10 Aug 2026 17:23:18 +0100 Subject: [PATCH 2/7] test(api): cover two-document merge, tolerant remove, and path-derived namespacing --- .../api/scripts/download-openapi.unit.test.ts | 271 +++++++++++++++++- packages/api/scripts/generate.unit.test.ts | 158 ++++++++++ 2 files changed, 428 insertions(+), 1 deletion(-) 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.unit.test.ts b/packages/api/scripts/generate.unit.test.ts index c0e2dab526..6e9613e672 100644 --- a/packages/api/scripts/generate.unit.test.ts +++ b/packages/api/scripts/generate.unit.test.ts @@ -4,11 +4,71 @@ import * as SchemaRepresentation from "effect/SchemaRepresentation"; import { describe, expect, test } from "vitest"; import { + extractOperations, normalizeNullableJsonSchema, normalizeQueryParameterSchema, + operationMethodName, + operationVersionFromPath, + renderContracts, + renderEffectClient, sanitizeOpenApiSchema, } from "./generate.ts"; +function jsonResponseOperation( + operationId: string, + pathParamName: string, + responseSchema: Record, +) { + return { + operationId, + parameters: [{ name: pathParamName, in: "path", required: true, schema: { type: "string" } }], + responses: { + "200": { + content: { + "application/json": { + schema: responseSchema, + }, + }, + }, + }, + }; +} + +function twoVersionFixture() { + 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 +179,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",'); + }); }); From bfdc8b4cd6642d842627807e63a5a636d133739c Mon Sep 17 00:00:00 2001 From: Colum Ferry Date: Mon, 10 Aug 2026 17:36:39 +0100 Subject: [PATCH 3/7] test(api): assert snapshot-to-client sync and v2 operation behavior - generated-contract-sync.unit.test.ts: bijection between the committed openapi.json snapshot and the generated contracts/effect client, so a hand-edited snapshot or client fails CI - client.unit.test.ts: 404 on a v2 operation surfaces as a StatusCodeError with the response status; v2 requests carry identical auth/base-url wiring; nested V2ProjectConfigResponse payload decodes strictly - effect.unit.test.ts: same-named v1/v2 operations are separately addressable per namespace - export OpenApiDocument/OpenApiOperation types from generate.ts for typed test fixtures --- packages/api/scripts/generate.ts | 4 +- packages/api/scripts/generate.unit.test.ts | 5 +- packages/api/src/effect.unit.test.ts | 69 +++++++ .../src/generated-contract-sync.unit.test.ts | 184 ++++++++++++++++++ packages/api/src/internal/client.unit.test.ts | 128 ++++++++++++ 5 files changed, 386 insertions(+), 4 deletions(-) create mode 100644 packages/api/src/generated-contract-sync.unit.test.ts diff --git a/packages/api/scripts/generate.ts b/packages/api/scripts/generate.ts index 4ee05b0bf0..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; diff --git a/packages/api/scripts/generate.unit.test.ts b/packages/api/scripts/generate.unit.test.ts index 6e9613e672..116f9bf946 100644 --- a/packages/api/scripts/generate.unit.test.ts +++ b/packages/api/scripts/generate.unit.test.ts @@ -3,6 +3,7 @@ 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, @@ -18,7 +19,7 @@ function jsonResponseOperation( operationId: string, pathParamName: string, responseSchema: Record, -) { +): OpenApiOperation { return { operationId, parameters: [{ name: pathParamName, in: "path", required: true, schema: { type: "string" } }], @@ -34,7 +35,7 @@ function jsonResponseOperation( }; } -function twoVersionFixture() { +function twoVersionFixture(): OpenApiDocument { return { openapi: "3.0.0", info: { title: "Test API", version: "1.0.0" }, 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/internal/client.unit.test.ts b/packages/api/src/internal/client.unit.test.ts index a2b1b026c5..957c9e52d2 100644 --- a/packages/api/src/internal/client.unit.test.ts +++ b/packages/api/src/internal/client.unit.test.ts @@ -1016,4 +1016,132 @@ 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"); + }); + + // NOTE(CLI-2157): v2GetProjectConfig is staging-only until the endpoint ships to prod; delete or re-point this test if the snapshot is regenerated from prod before then. + 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(); + }); }); From 57eba91f350366ea2f0d1998cb9e7f761d81152d Mon Sep 17 00:00:00 2001 From: Colum Ferry Date: Mon, 10 Aug 2026 17:43:35 +0100 Subject: [PATCH 4/7] test(cli): stub the v2 namespace in the legacy platform API mock ApiClient now carries a v2 namespace, so the v1-only mock object no longer overlaps the ApiClient type. The legacy shell only calls v1 operations; v2 calls die loudly as wiring bugs. --- apps/cli/tests/helpers/legacy-mocks.ts | 9 +++++++++ 1 file changed, 9 insertions(+) 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); From 969c85e9b08689cf82c0e583994952d914f9363d Mon Sep 17 00:00:00 2001 From: Colum Ferry Date: Tue, 11 Aug 2026 11:23:45 +0100 Subject: [PATCH 5/7] chore(api): point the spec source at production MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GET /v2/projects/{ref}/config shipped to production (byte-identical to the staging definition the snapshot was generated from), so regenerating from prod reproduces the committed snapshot exactly — only the source pin changes. Drops the temporary staging warnings. --- packages/api/README.md | 7 ------- packages/api/scripts/openapi-source.json | 2 +- packages/api/src/internal/client.unit.test.ts | 1 - 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/packages/api/README.md b/packages/api/README.md index a6e82a3bd2..e7b836bbda 100644 --- a/packages/api/README.md +++ b/packages/api/README.md @@ -2,13 +2,6 @@ Generated Supabase Management API SDK built directly from the Supabase OpenAPI spec. -> **Temporary (CLI-2157):** the committed snapshot on this branch is generated from staging -> (`api.supabase.green`) because `GET /v2/projects/{ref}/config` (`api.v2.getProjectConfig`, -> schema `V2ProjectConfigResponse`) has not shipped to production yet. Develop's hourly prod sync -> (`api-package-sync.yml`) would remove exactly that endpoint once this merges. Before merging, -> either the endpoint must ship to production or the snapshot must be regenerated from production -> by re-pointing `scripts/openapi-source.json`. - The package exposes: - `@supabase/api` for the runtime-specific Promise client helpers plus generated contracts diff --git a/packages/api/scripts/openapi-source.json b/packages/api/scripts/openapi-source.json index c26e963e2d..95dd824ea3 100644 --- a/packages/api/scripts/openapi-source.json +++ b/packages/api/scripts/openapi-source.json @@ -1,3 +1,3 @@ { - "baseUrl": "https://api.supabase.green" + "baseUrl": "https://api.supabase.com" } diff --git a/packages/api/src/internal/client.unit.test.ts b/packages/api/src/internal/client.unit.test.ts index 957c9e52d2..cda2b8fd61 100644 --- a/packages/api/src/internal/client.unit.test.ts +++ b/packages/api/src/internal/client.unit.test.ts @@ -1054,7 +1054,6 @@ describe("makeSupabaseApiClient", () => { expect(seenRequest?.headers.authorization).toBe("Bearer test-token"); }); - // NOTE(CLI-2157): v2GetProjectConfig is staging-only until the endpoint ships to prod; delete or re-point this test if the snapshot is regenerated from prod before then. test("decodes a nested v2GetProjectConfig payload through the unified execute path", async () => { const result = await Effect.runPromise( makeSupabaseApiClient(config).pipe( From 726b11433e9829f64d23628df574bd2495a4e334 Mon Sep 17 00:00:00 2001 From: Colum Ferry Date: Tue, 11 Aug 2026 14:00:20 +0100 Subject: [PATCH 6/7] test(api): render-fidelity drift guard; normalize merge output; fix source-pin precedence Review follow-ups on #6142: - New generated-output-sync test re-renders contracts.ts, effect-client.ts and openapi.json from the committed snapshot through the same oxfmt the pipeline uses and requires byte equality, so hand edits to schemas, parameters, request bodies, response types, or the executor fail plain PR CI (the prior bijection test only covered operation-level identity) - mergeOpenApiDocuments now emits only the keys the generator consumes; upstream servers/tags/securitySchemes no longer appear even in the intermediate write between generate:spec and generate.ts, which is the state that presented as snapshot drift during review - SUPABASE_API_URL now takes precedence without reading the source pin, and a missing pin falls through to the default instead of throwing - generate:check invokes pnpm generate rather than bun run generate --- packages/api/README.md | 10 +- packages/api/package.json | 5 +- packages/api/scripts/download-openapi.ts | 35 ++++-- .../generated-output-sync.unit.test.ts | 101 ++++++++++++++++++ 4 files changed, 139 insertions(+), 12 deletions(-) create mode 100644 packages/api/scripts/generated-output-sync.unit.test.ts diff --git a/packages/api/README.md b/packages/api/README.md index e7b836bbda..cfb0e9e27e 100644 --- a/packages/api/README.md +++ b/packages/api/README.md @@ -98,7 +98,15 @@ The spec is built from two upstream OpenAPI documents, `{baseUrl}/api/v1-json` a `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`. +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: diff --git a/packages/api/package.json b/packages/api/package.json index a7d790d2b4..19d31fe6b4 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -14,7 +14,7 @@ "scripts": { "generate:spec": "bun run scripts/download-openapi.ts", "generate": "bun run generate:spec && bun run scripts/generate.ts", - "generate:check": "bun run generate && pnpm exec nx run @supabase/api:fmt:fix && git diff --exit-code -- src/generated scripts/openapi-source.json", + "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", @@ -46,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 e4839e407b..521dc83929 100644 --- a/packages/api/scripts/download-openapi.ts +++ b/packages/api/scripts/download-openapi.ts @@ -246,8 +246,19 @@ function assertOpenApiSource(value: unknown): asserts value is OpenApiSource { } } -async function loadPinnedBaseUrl(): Promise { - const parsed = JSON.parse(await readFile(OPENAPI_SOURCE_PATH, "utf8")); +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; } @@ -379,12 +390,17 @@ export function mergeOpenApiDocuments( } } + // 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 { - ...firstEntry.document, openapi: openapiVersion, info: { title: "Supabase API", version: infoVersion }, paths, - components: { ...firstEntry.document.components, schemas }, + components: { schemas }, }; } @@ -444,11 +460,12 @@ export function assertMergedOpenApiDocument(document: OpenApiDocument): void { } export async function downloadOpenApiSpec(): Promise { - const pinnedBaseUrl = await loadPinnedBaseUrl(); - const baseUrl = resolveOpenApiBaseUrl({ - envBaseUrl: process.env.SUPABASE_API_URL, - pinnedBaseUrl, - }); + 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<{ 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..00c5760b71 --- /dev/null +++ b/packages/api/scripts/generated-output-sync.unit.test.ts @@ -0,0 +1,101 @@ +import { execFileSync } from "node:child_process"; +import { readFileSync } 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 { + const formatted = execFileSync(oxfmtBin, [`--stdin-filepath=${fileName}`], { + input: source, + cwd: packageDir, + encoding: "utf8", + maxBuffer: 64 * 1024 * 1024, + }); + // oxfmt's file mode (what the pipeline runs) trims trailing blank lines to + // a single newline; its stdin mode preserves them. Normalize so the two + // modes agree. + return formatted.replace(/\n+$/, "\n"); +} + +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", + ); + }, + ); +}); From e57345649f794f1f727f333aa17703e200b8fffd Mon Sep 17 00:00:00 2001 From: Colum Ferry Date: Tue, 11 Aug 2026 14:44:38 +0100 Subject: [PATCH 7/7] test(api): format via oxfmt file mode in the render-fidelity guard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bun on Linux truncates a child process's piped stdout at ~219KB, so the stdin/stdout round-trip through oxfmt cut the 600KB+ renders mid-line on CI while passing on macOS. File mode writes and reads through the filesystem — no pipe — and is also what the pipeline's fmt:fix runs, which drops the stdin-mode trailing-newline normalization too. --- .../generated-output-sync.unit.test.ts | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/packages/api/scripts/generated-output-sync.unit.test.ts b/packages/api/scripts/generated-output-sync.unit.test.ts index 00c5760b71..e1c3dda7f1 100644 --- a/packages/api/scripts/generated-output-sync.unit.test.ts +++ b/packages/api/scripts/generated-output-sync.unit.test.ts @@ -1,5 +1,5 @@ import { execFileSync } from "node:child_process"; -import { readFileSync } from "node:fs"; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { describe, expect, test } from "vitest"; @@ -21,16 +21,20 @@ const generatedDir = path.join(packageDir, "src", "generated"); const oxfmtBin = path.join(packageDir, "node_modules", ".bin", "oxfmt"); function formatWithOxfmt(source: string, fileName: string): string { - const formatted = execFileSync(oxfmtBin, [`--stdin-filepath=${fileName}`], { - input: source, - cwd: packageDir, - encoding: "utf8", - maxBuffer: 64 * 1024 * 1024, - }); - // oxfmt's file mode (what the pipeline runs) trims trailing blank lines to - // a single newline; its stdin mode preserves them. Normalize so the two - // modes agree. - return formatted.replace(/\n+$/, "\n"); + // 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 {