diff --git a/README.md b/README.md
index bf6a0168..0d8272ef 100644
--- a/README.md
+++ b/README.md
@@ -726,6 +726,8 @@ for provider in providers:
The method returns an immutable tuple of `LinkedOAuthProvider` values and raises
`SessionChangedError` if the active session changes while the request is in flight.
+It also accepts responses from older servers that omit provider IDs and logins;
+the public result contains the provider name and linkage timestamps.
Start linking another OAuth provider to the current account:
diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml
index 641fe9aa..0ee2c076 100644
--- a/openapi/openapi.yaml
+++ b/openapi/openapi.yaml
@@ -22,9 +22,9 @@ tags:
- name: Logs
description: Project-scoped log search and activity APIs
- name: Issues
- description: 'Preview, not generally available: runtime errors grouped into issues. Where issues are not available, every endpoint answers `404` with code `feature_unavailable`.'
- - name: Autofix
- description: 'Preview, not generally available: AI diagnosis of a project''s issues and draft pull requests that fix them. Where autofix is not available, turning it on, or any request for a project that never saved settings, answers `404` with code `feature_unavailable`. Autofix is not available in local mode.'
+ description: 'Preview, not generally available: runtime errors grouped into issues, LavaFlow Code Quality findings, and problems reported for a project. Where issues are not available, every endpoint answers `404` with code `feature_unavailable`.'
+ - name: LavaFlow
+ description: 'Preview, not generally available: LavaFlow diagnoses a project''s issues and opens pull requests that fix them. It merges a fix only under `autonomy: merge`, where the project''s `lavaflow.merge` capability is available, once the fix passes review and its required checks and nothing holds it. LavaFlow sends this project''s logs and source code to an AI service that Volcano operates. Every endpoint names one project with `project_id`. Where LavaFlow is not available, every endpoint refuses a project that has no LavaFlow records: `404` with code `feature_unavailable` while LavaFlow is not offered to the project, and `403` with code `plan_required` when it is but the owner''s plan does not include it. A project with records keeps reading them and can still turn LavaFlow and skill learning off.'
- name: Functions
description: Function deployment and management
- name: Durable Functions
@@ -35,6 +35,8 @@ tags:
a start returns is an execution to poll and stop, not a result. Durable
work is metered on its own allowances: executions, and the operations each
execution performs while it runs.
+ - name: Notifications
+ description: Where a project's alerts go, by email and by a signed webhook, and when a failing function scheduler is announced.
- name: Frontends
description: Frontend deployment and management. Supports Next.js 15.x and 16.x with Node.js 22.x or 24.x inferred from package.json engines.node when the selected Node.js family satisfies the installed Next.js package engines.node constraint.
- name: Tokens
@@ -47,6 +49,8 @@ tags:
description: PostgreSQL database provisioning and management
- name: Database Branches
description: Short-lived forks of a database for development and testing
+ - name: Database Migrations
+ description: A database's migration history and the runs that apply migration files to it. Where migration runs are not available, starting a run or recording a baseline answers `404` with code `feature_unavailable`; history and runs stay readable.
- name: Database Queries
description: REST API for querying databases (SELECT, INSERT, UPDATE, DELETE)
- name: Authentication
@@ -67,10 +71,20 @@ tags:
description: OAuth login flows and provider management for end users
- name: Git Connections
description: Platform-user git provider connections for deployment source integrations
+ - name: Shares
+ description: A project's owner shares it through a link that lets anyone fork a release the owner published into a project of their own
+ - name: Forks
+ description: A visitor's own project, created from a release a share offers
+ - name: Connectors
+ description: Links from Volcano to outside services, such as Slack workspaces the Volcano app is installed in
+ - name: Slack Connections
+ description: The Volcano Slack app's installations, and Slack identities connected to Volcano accounts, which LavaFlow takes reported problems through
- name: Project Imports
description: Read-only project source discovery and import readiness checks
- name: Verified Domains
description: Domains an account has proven it owns, so it can attach any custom domain below them
+ - name: Account Sessions
+ description: Your account's own sign-ins, so a CLI login can end itself without the dashboard
- name: Storage Buckets
description: Storage bucket management (platform admin)
- name: Storage Policies
@@ -101,7 +115,7 @@ paths:
security: []
responses:
'200':
- description: List available sandbox presets
+ description: List available sandbox presets. Temporarily unavailable regions are omitted.
content:
application/json:
schema:
@@ -357,7 +371,7 @@ paths:
schema:
$ref: '#/components/schemas/SandboxDeployment'
default:
- description: Invalid source (400), denied access (401, 403), conflicting retry (409), or a temporarily unavailable deployment service (503). Code `feature_unavailable` with 404 means sandboxes or custom templates are not available in this environment.
+ description: Invalid source (400), denied access (401, 403), conflicting retry (409), or a temporarily unavailable deployment service (503). Code `feature_unavailable` with 404 means sandboxes or custom templates are not available in this environment. A deployment builds no image in a temporarily unavailable region; code `sandbox_region_unavailable` (400) means every region is unavailable.
content:
application/json:
schema:
@@ -612,7 +626,7 @@ paths:
schema:
$ref: '#/components/schemas/SandboxSession'
default:
- description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and temporarily unavailable (503). Code `feature_unavailable` with 404 means sandboxes are not available in this environment. Code `sandbox_plan_limit_exceeded` (403) means the requested resources exceed the plan. Code `sandbox_allowance_exhausted` (429) means the remaining allowance or credits cannot admit the operation.
+ description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and temporarily unavailable (503). Code `feature_unavailable` with 404 means sandboxes are not available in this environment. Code `sandbox_plan_limit_exceeded` (403) means the requested resources exceed the plan. Code `sandbox_allowance_exhausted` (429) means the remaining allowance or credits cannot admit the operation. Code `sandbox_region_unavailable` (400) means the region is temporarily unavailable for Sandboxes; choose another from `GET /sandboxes/presets`. Code `feature_unavailable` with 400 means `network.egress` `deny_all` is not available in this environment; `GET /capabilities` lists it as `sandboxes.network_isolation`. Code `feature_unavailable` with 400 means the request keeps no output while the `sandboxes.output_not_kept` capability is unavailable. Code `sandbox_limits_unsupported` (400) means the selected image predates `limits`; redeploy the template or recreate the named Sandbox, or retry once the preset is updated. Code `sandbox_limits_exceed_session` (400) means `limits.vcpus` is more than the session has; use a larger preset size or template, or lower `limits.vcpus`.
content:
application/json:
schema:
@@ -654,7 +668,80 @@ paths:
schema:
$ref: '#/components/schemas/SandboxExecutionResult'
default:
- description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and temporarily unavailable (503). Code `feature_unavailable` with 404 means sandboxes are not available in this environment. Code `sandbox_plan_limit_exceeded` (403) means the requested resources exceed the plan. Code `sandbox_allowance_exhausted` (429) means the remaining allowance or credits cannot admit the operation.
+ description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), startup hook timeout (422), capacity exhausted (429), and temporarily unavailable (503). Code `feature_unavailable` with 404 means sandboxes are not available in this environment. Code `sandbox_plan_limit_exceeded` (403) means the requested resources exceed the plan. Code `sandbox_allowance_exhausted` (429) means the remaining allowance or credits cannot admit the operation. Code `sandbox_region_unavailable` (400) means the region is temporarily unavailable for Sandboxes; choose another from `GET /sandboxes/presets`. Code `feature_unavailable` with 400 means `network.egress` `deny_all` is not available in this environment; `GET /capabilities` lists it as `sandboxes.network_isolation`. Code `sandbox_image_outdated` (409) means the template's image predates what the request needs, such as `deny_all` on a template deployed to local mode before this version; redeploy the template. No command was sent. Code `feature_unavailable` with 400 means the request keeps no output while the `sandboxes.output_not_kept` capability is unavailable. Code `sandbox_start_failed` means startup failed or timed out before the command was sent. Its status is 422 for sandbox_run_hook_timeout on a custom deployment, 429 for sandbox_allowance_exhausted or sandbox_allowance_retention_expired, and 503 for managed-preset run-hook timeouts or other or unknown startup reasons. sandbox_start_timeout means the startup wait expired; sandbox_session_expired means the session lifetime ended before dispatch. For sandbox_launch_outcome_unknown, the session isn't billed. Its startup command may already have started and can run until the session would have expired; Volcano can't reach it. Start a new session with a new key. A session whose launch outcome was unknown when it ended for an earlier reason keeps that reason, with the same caveat. Its error message includes the recorded startup reason when known, including on replay. The message is diagnostic text, not a stable machine-readable retry classification; investigate the reason before starting another billed attempt. Admission refusals include response code `sandbox_capacity_unavailable` (429), `sandbox_allowance_exhausted` (429), and `sandbox_plan_limit_exceeded` (403); no command was sent. Reusing the same Idempotency-Key replays these refusals or startup failure even after recovery; use a new key for a new attempt. A 403 or 429 without an explicit admission-refusal code or sandbox_start_failed does not prove no dispatch. Other failures may have an unknown execution outcome; do not use a new key to repeat a command with side effects.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /sandbox-session-files:
+ get:
+ tags:
+ - Sandboxes
+ summary: List workspace files
+ description: 'Lists a directory in a Sandbox session''s workspace, one page at a time. The listing never follows a symlink and never leaves the workspace. It is not a snapshot: a file that changes while it runs can appear before or after the change. Sessions started on an image built before file listing answer 409 with code `sandbox_image_outdated`; start a new session, after redeploying a custom template.'
+ operationId: listSandboxSessionFiles
+ security:
+ - UserToken: []
+ - ServiceRoleKey: []
+ - ProjectAccessToken: []
+ - AuthUserAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectIdQuery'
+ - name: session_id
+ in: query
+ required: true
+ description: The session to list. A session outside `project_id` answers like one that doesn't exist.
+ schema:
+ type: string
+ format: uuid
+ - name: path
+ in: query
+ required: false
+ description: Workspace directory to list, such as `src` or `/workspace/src`. Omit it, or pass `.` or `/workspace`, to list the workspace root. The path must be a directory; it is never reached through a symlink.
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 4096
+ - name: recursive
+ in: query
+ required: false
+ description: List every entry below the directory. When false, list only its direct entries.
+ schema:
+ type: boolean
+ default: true
+ - name: include_sha256
+ in: query
+ required: false
+ description: Add the SHA-256 digest of each regular file's content. A call reads at most 256 MiB to hash; a page ends early, with `next_cursor`, before a file that would pass that budget. A file without a digest says why in `sha256_skipped`.
+ schema:
+ type: boolean
+ default: false
+ - name: limit
+ in: query
+ required: false
+ description: Most entries to return. A page can hold fewer, so continue while `next_cursor` is present.
+ schema:
+ type: integer
+ minimum: 1
+ maximum: 10000
+ default: 10000
+ - name: cursor
+ in: query
+ required: false
+ description: Opaque cursor from the previous page's `next_cursor`. It is valid only for the same project and session; send the same `path` and `recursive` with it.
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 8192
+ responses:
+ '200':
+ description: One page of workspace entries
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SandboxFileListResult'
+ default:
+ description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflict (409), capacity exhausted (429), and temporarily unavailable (503). A project the caller can't read answers 404 exactly like one that doesn't exist, and a session outside the project answers like an unknown session. A credential for the project that lacks the `sandboxes.files.read` permission answers 403. Code `sandbox_path_not_directory` with 400 means the path is missing, is not a directory, or passes through a symlink. Code `sandbox_path_unreadable` with 400 means the session user can't list the path or pass through a directory above it. Code `sandbox_image_outdated` with 409 means the session's image predates file listing. Code `feature_unavailable` with 404 means sandboxes are not available in this environment.
content:
application/json:
schema:
@@ -817,7 +904,7 @@ paths:
schema:
$ref: '#/components/schemas/SandboxCommandResult'
default:
- description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and temporarily unavailable (503). Code `feature_unavailable` with 404 means sandboxes are not available in this environment.
+ description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and temporarily unavailable (503). Code `feature_unavailable` with 404 means sandboxes are not available in this environment. Code `sandbox_session_not_running` (409) means the session cannot accept commands and the command was not sent. The same Idempotency-Key replays this refusal even after the session resumes; use a new key once the session is running. Other failures may have an unknown outcome; reuse the original key. Code `sandbox_command_capacity` with 429 means the session is already running its maximum number of commands and started nothing; retry with the same Idempotency-Key once one finishes. Code `sandbox_session_keeps_no_output` with 400 means the session keeps no command output and the request set `keep_output` to true. Code `feature_unavailable` with 400 means the command keeps no output, by its own `keep_output` or its session's, while the `sandboxes.output_not_kept` capability is unavailable. Code `sandbox_disk_full` (409) means the session's disk had no room to record the command and it started nothing; retry with the same Idempotency-Key once there is room.
content:
application/json:
schema:
@@ -854,7 +941,7 @@ paths:
schema:
$ref: '#/components/schemas/SandboxFileResult'
default:
- description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and temporarily unavailable (503). Code `feature_unavailable` with 404 means sandboxes are not available in this environment.
+ description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found or terminated session (404), conflicting retry (409), capacity exhausted (429), and temporarily unavailable (503). Code `feature_unavailable` with 404 means sandboxes are not available in this environment.
content:
application/json:
schema:
@@ -887,7 +974,127 @@ paths:
'204':
description: Write a workspace file
default:
- description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and temporarily unavailable (503). Code `feature_unavailable` with 404 means sandboxes are not available in this environment.
+ description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found or terminated session (404), conflicting retry (409), capacity exhausted (429), and temporarily unavailable (503). Code `feature_unavailable` with 404 means sandboxes are not available in this environment. Code `sandbox_disk_full` (409) means the write did not fit on the session's disk; delete files in the session, or, for a session started with `limits.disk_mib`, start one with a larger cap. Code `sandbox_path_conflict` (409) means a cloud session has `limits.disk_mib`, whose writes run as the session user, and that user cannot write the file's directory.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /sandbox-file-archives:
+ post:
+ tags:
+ - Sandboxes
+ summary: Extract a tar archive into a session's workspace
+ description: |
+ Extracts a tar archive into a directory of a session's workspace. Send `multipart/form-data`
+ with `project_id`, `session_id` and `path`, in any order, then the archive as the file part
+ `archive`. The archive may be gzip-compressed; Volcano detects compression from its first bytes.
+ The request streams to the session, so the archive is never held whole in memory.
+
+ Each call accepts at most 32 MiB of archive, 10,000 files and directories, and 256 MiB of
+ uncompressed archive, counting tar headers, and has 2 minutes to send its archive; a slower
+ call fails and writes nothing. Split larger trees into several archives and create one after
+ another. For a single file larger than 8 MiB, use `POST /sandbox-file-parts`.
+
+ `path` must name a directory below the workspace root; a path that resolves to the root or to
+ `/`, such as `.`, `./`, `/`, `/workspace` or `/workspace/.`, is refused with
+ `sandbox_archive_invalid`. The archive may contain only regular files and directories. Entry
+ names are relative to `path`, which is created when missing; an absolute name, a `..`
+ component, a symbolic link, a
+ hard link, a sparse file, or a device refuses the whole archive. File and directory modes keep their
+ permission bits; setuid, setgid and sticky bits are dropped. A file replaces an existing file or
+ symbolic link at its path. Existing directories keep their modes. A symbolic link in the
+ destination is never followed.
+
+ The archive is checked and staged before the workspace changes, so a refused archive writes
+ nothing, and one that fails part way is undone. If a session process moves or removes a
+ directory while the archive is written, the call answers `409`, a file the archive replaced
+ there is kept in a `.sandbox-archive-*` directory at the workspace root, and files the
+ archive already placed can stay. Read-only directories the session user
+ owns still take new entries and keep their modes. Code `sandbox_archive_invalid` (400) means the archive or form is malformed or holds an
+ entry that is not allowed. Code `sandbox_archive_too_large` (413) means it exceeds a limit
+ above. Code `sandbox_path_conflict` (409) means the destination has a symbolic link or a file
+ where the archive needs a directory, a directory where it has a file, or a directory the
+ session user cannot write. Code
+ `sandbox_disk_full` (409) means the session's disk has no room for it; free space and retry. Code
+ `sandbox_image_outdated` (409) means the session started from an image that predates archive
+ writes; start a new session from a current preset, or redeploy the template. A session outside
+ `project_id`, or a project the caller cannot reach, answers 404 like an unknown session.
+ operationId: createSandboxFileArchive
+ security:
+ - UserToken: []
+ - ServiceRoleKey: []
+ - ProjectAccessToken: []
+ - AuthUserAccessToken: []
+ requestBody:
+ required: true
+ content:
+ multipart/form-data:
+ schema:
+ $ref: '#/components/schemas/SandboxFileArchiveForm'
+ responses:
+ '201':
+ description: The archive was extracted
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SandboxFileArchive'
+ default:
+ description: Request refused or unavailable. Errors include an invalid form or archive (400), unauthenticated (401), forbidden (403), an unknown project or session (404), a conflicting destination, an outdated session image or a full disk (409), an archive over a limit (413), and temporarily unavailable (503). Code `feature_unavailable` with 404 means sandboxes are not available in this environment.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /sandbox-file-parts:
+ post:
+ tags:
+ - Sandboxes
+ summary: Write one part of a large workspace file
+ description: |
+ Writes a file of up to 1 GiB into a session's workspace in parts of at most 8 MiB. Each part
+ names its `offset` in the file, the whole file's `size`, and the whole file's lowercase hex
+ `sha256`. Parts collect in a hidden staging file beside `path`; nothing appears at `path` until
+ the part that ends at `size` arrives. That part checks the whole file's size and SHA-256, then
+ moves the file into place in one step, so a partial file is never visible at `path`. The
+ response's `complete` says which part finished the file. Missing parent directories are created,
+ and a symbolic link among them is never followed. The finished file is readable and writable
+ only by the session user.
+
+ A part may start anywhere up to the bytes already received, so a failed part can be resent. A
+ part at offset 0 starts the file again. Resending the part that finished the file answers the
+ same completion while the file at `path` still matches `size` and `sha256`. Code `sandbox_file_part_out_of_order` (409) means the
+ part starts past the bytes received; resend from the last part that succeeded. Code
+ `sandbox_file_part_mismatch` (409) means the finished file differs from `size` or `sha256`; its
+ parts are discarded, so start again at offset 0. Code `sandbox_path_conflict` (409) means a
+ directory is at `path`, a file or symbolic link is where a parent directory belongs, or the
+ session user cannot write the parent directory, or, when parents are missing, the nearest
+ one that exists. Read-only directories the session user owns still take new entries and
+ keep their modes. Code
+ `sandbox_disk_full` (409) means the session's disk has no room; free space and retry. Code
+ `sandbox_image_outdated` (409) means the session started from an image that predates parted
+ writes. A staging file stays until its file completes, a part at offset 0 restarts it, or the
+ session ends. A session outside `project_id`, or a project the caller cannot reach, answers 404
+ like an unknown session.
+ operationId: createSandboxFilePart
+ security:
+ - UserToken: []
+ - ServiceRoleKey: []
+ - ProjectAccessToken: []
+ - AuthUserAccessToken: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SandboxFilePartRequest'
+ responses:
+ '201':
+ description: The part was written
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SandboxFilePart'
+ default:
+ description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), an unknown project or session (404), a part out of order, a mismatched file, a conflicting destination, an outdated session image or a full disk (409), a request body over its limit (413), and temporarily unavailable (503). Code `feature_unavailable` with 404 means sandboxes are not available in this environment.
content:
application/json:
schema:
@@ -990,7 +1197,7 @@ paths:
schema:
$ref: '#/components/schemas/SandboxAccess'
default:
- description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and temporarily unavailable (503). Code `feature_unavailable` with 404 means sandboxes are not available in this environment.
+ description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and temporarily unavailable (503). Code `feature_unavailable` with 404 means sandboxes are not available in this environment. Code `sandbox_network_isolated` (400) means the session was created with `network.egress` `deny_all`, which accepts no port access.
content:
application/json:
schema:
@@ -1018,7 +1225,7 @@ paths:
- name: redirect
in: query
required: false
- description: Validated application URL used after the provider callback.
+ description: Application URL used after the provider callback. It must be on the Volcano dashboard's origin, or `http` to `127.0.0.1` or `[::1]` with a port.
schema:
type: string
format: uri
@@ -1026,7 +1233,7 @@ paths:
- name: callback_url
in: query
required: false
- description: Same-origin browser callback used to relay provider parameters before completing the connection.
+ description: Same-origin browser callback used to relay provider parameters before completing the connection. It must be on the Volcano dashboard's origin, or `http` to `127.0.0.1` or `[::1]` with a port.
schema:
type: string
format: uri
@@ -1566,13 +1773,13 @@ paths:
- name: redirect
in: query
required: false
- description: URL to redirect the browser to after the provider callback completes.
+ description: URL to redirect the browser to after the provider callback completes. It must be on the Volcano dashboard's origin, or `http` to `127.0.0.1` or `[::1]` with a port.
schema:
type: string
- name: callback_url
in: query
required: false
- description: Same-origin browser callback used to relay provider parameters before completing the connection.
+ description: Same-origin browser callback used to relay provider parameters before completing the connection. It must be on the Volcano dashboard's origin, or `http` to `127.0.0.1` or `[::1]` with a port.
schema:
type: string
format: uri
@@ -1990,839 +2197,883 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /github/callback:
- get:
+ /user/tokens/current:
+ delete:
tags:
- - Git Connections
- summary: Complete a GitHub App connection callback
+ - Account Sessions
+ summary: Revoke the calling platform token
description: |
- Public GitHub App callback. The signed state and callback binding cookie
- bind the provider authorization to the browser that started the flow.
- operationId: gitConnectCallback
- security: []
- parameters:
- - name: code
- in: query
- required: false
- description: GitHub user authorization code.
- schema:
- type: string
- - name: state
- in: query
- required: true
- description: Signed connect state generated by startGitConnect.
- schema:
- type: string
- - name: error
- in: query
- required: false
- description: Provider error returned by GitHub.
- schema:
- type: string
+ Revokes the platform token that authenticates this request, and ends
+ the sign-in session it was created from, if any. Ending the session
+ also revokes every other token created from it. Every later request
+ with the token answers `401`.
+
+ Only a platform token (`pk-`) can call it. A project access token is
+ refused with `403`.
+ operationId: revokeCurrentUserToken
+ security:
+ - UserToken: []
responses:
- '303':
- description: Redirect back to the app after a successful or failed connect attempt
- headers:
- Location:
- description: Redirect target
- schema:
- type: string
- '400':
- description: Invalid callback request or state
+ '204':
+ description: Token revoked
+ '401':
+ description: Not authenticated, or not a platform token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
- description: Too many callback attempts from this client
+ '403':
+ description: Forbidden - a project access token cannot revoke a platform token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
- description: Failed to complete the connection
+ description: Failed to revoke the token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Git provider integration is not configured
+ '501':
+ description: Account sessions are unavailable in local mode
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects:
+ /user/sessions:
get:
tags:
- - Projects
- summary: List all projects for authenticated user
+ - Account Sessions
+ summary: List your account's sign-in sessions
description: |
- Returns projects that are not deleting or deleted, newest first.
- Supports two mutually exclusive pagination modes. Offset mode uses
- `page` and `limit`. Cursor mode uses `cursor` or `ending_before` with
- `limit`, returns `next_cursor`/`prev_cursor`, and supports a bounded
- `offset` past the cursor anchor. Supplying `limit` without `page`
- selects cursor mode. `search` applies a case-insensitive project-name
- filter in either mode. `include` optionally expands each returned
- project with its Git connection and/or aggregate health summary using
- `git_connection` and `health`. Sending `page` with `cursor` or `ending_before`,
- or sending both cursor directions, returns 400.
- operationId: listProjects
+ Lists the sign-in sessions of the account that owns the calling
+ platform token: dashboard sign-ins (`kind: browser`) and CLI logins
+ (`kind: cli`). The session the calling token was exchanged from is
+ marked `is_current: true`. A token created in the dashboard or through
+ the management API, rather than by signing in, has no session, so no
+ session is current.
+
+ Ordering and pagination match `GET /auth/user/sessions`.
+
+ Only a platform token (`pk-`) can call it. A project access token is
+ refused with `403`.
+ operationId: listAccountSessions
security:
- UserToken: []
parameters:
- - $ref: '#/components/parameters/Page'
- - $ref: '#/components/parameters/Limit'
- - $ref: '#/components/parameters/Cursor'
- - $ref: '#/components/parameters/EndingBefore'
- - $ref: '#/components/parameters/Offset'
- - $ref: '#/components/parameters/Search'
- - name: include
- in: query
- required: false
- description: Optional comma-separated project metadata expansions.
- style: form
- explode: false
- schema:
- type: array
- uniqueItems: true
- items:
- type: string
- enum:
- - git_connection
- - health
+ - $ref: '#/components/parameters/SessionListPage'
+ - $ref: '#/components/parameters/SessionListLimit'
+ - $ref: '#/components/parameters/SessionListSort'
+ - $ref: '#/components/parameters/SessionListStatus'
+ - $ref: '#/components/parameters/SessionListCursor'
+ - $ref: '#/components/parameters/SessionListEndingBefore'
+ - $ref: '#/components/parameters/SessionListOffset'
responses:
'200':
- description: Successful response
+ description: A page of the account's sessions
content:
application/json:
schema:
- $ref: '#/components/schemas/PaginatedProjects'
+ $ref: '#/components/schemas/AccountSessionList'
'400':
description: Invalid or conflicting pagination parameters
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- post:
- tags:
- - Projects
- summary: Create a new project
- description: |
- Creates a project for the authenticated user.
- Each user can create up to 1,000 projects. Requests over this cap return 403.
- operationId: createProject
- security:
- - UserToken: []
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/CreateProjectRequest'
- responses:
- '201':
- description: Project created
+ '401':
+ description: Not authenticated, or not a platform token
content:
application/json:
schema:
- $ref: '#/components/schemas/Project'
- '400':
- description: Bad request
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - a project access token cannot read account sessions
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Project limit exceeded for the user
+ '500':
+ description: Failed to list sessions
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: The selected project template is not configured in this environment
+ '501':
+ description: Account sessions are unavailable in local mode
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}:
- get:
+ delete:
tags:
- - Projects
- summary: Get project by ID
- operationId: getProject
+ - Account Sessions
+ summary: Sign out every other session
+ description: |
+ Ends every session of the account except the one the calling token
+ was exchanged from, and revokes the platform tokens exchanged from
+ them. When the calling token has no session, every session ends.
+
+ Platform tokens that were never linked to a session, such as one
+ created in the dashboard or through the management API, keep working.
+ Revoke each with `DELETE /user/tokens/current`.
+ operationId: revokeOtherAccountSessions
security:
- UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
responses:
- '200':
- description: Successful response
+ '204':
+ description: Every other session ended
+ '401':
+ description: Not authenticated, or not a platform token
content:
application/json:
schema:
- $ref: '#/components/schemas/Project'
- '404':
- description: Project not found
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - a project access token cannot end account sessions
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- patch:
+ '500':
+ description: Failed to end sessions
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '501':
+ description: Account sessions are unavailable in local mode
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /user/sessions/{sessionId}:
+ delete:
tags:
- - Projects
- summary: Update project metadata and region policy
- operationId: updateProject
+ - Account Sessions
+ summary: Sign out one session
+ description: |
+ Ends one of the account's sessions and revokes the platform tokens
+ exchanged from it. A session that is not the account's, or does not
+ exist, answers `404`.
+ operationId: revokeAccountSession
security:
- UserToken: []
- - ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/UpdateProjectRequest'
+ - name: sessionId
+ in: path
+ required: true
+ description: The session ID, from `GET /user/sessions`
+ schema:
+ type: string
responses:
- '200':
- description: Project updated
+ '204':
+ description: Session ended
+ '401':
+ description: Not authenticated, or not a platform token
content:
application/json:
schema:
- $ref: '#/components/schemas/Project'
- '400':
- description: |
- Bad request (no region selected, an unknown region, or — for a
- project holding durable functions — a region that does not offer
- durable execution)
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - a project access token cannot end account sessions
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Forbidden (for example, selecting subset regions on plan other than SUPERAGENT)
+ '404':
+ description: Session not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Project not found
+ '500':
+ description: Failed to end the session
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: Conflict (project name already exists or a resource deployment blocks a region change)
+ '501':
+ description: Account sessions are unavailable in local mode
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- delete:
+ /github/callback:
+ get:
tags:
- - Projects
- summary: Delete a project
+ - Git Connections
+ summary: Complete a GitHub App connection callback
description: |
- Starts asynchronous project deletion. The project remains available from
- `GET /projects/{id}` with `status: deleting` until cleanup finishes, but is
- removed from project lists as soon as deletion starts. After cleanup it
- returns 404.
- operationId: deleteProject
- security:
- - UserToken: []
- - ProjectAccessToken: []
+ Public GitHub App callback. The signed state and callback binding cookie
+ bind the provider authorization to the browser that started the flow.
+
+ GitHub also sends a browser here without `state` when someone installs
+ the App, changes its repository access, or asks an organization owner
+ to install it, on GitHub itself. That request connects nothing: Volcano
+ ignores `code` and `installation_id`, and redirects to the dashboard's
+ Git settings page when `setup_action` is `install`, `update`, or
+ `request`. Any other request without `state` returns 400. An empty or
+ invalid `state` is refused as before and never redirects there.
+ operationId: gitConnectCallback
+ security: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
+ - name: code
+ in: query
+ required: false
+ description: GitHub user authorization code. Ignored when `state` is absent.
+ schema:
+ type: string
+ - name: state
+ in: query
+ required: false
+ description: |
+ Signed connect state generated by startGitConnect. Absent when the
+ install started on GitHub rather than in Volcano.
+ schema:
+ type: string
+ - name: error
+ in: query
+ required: false
+ description: Provider error returned by GitHub.
+ schema:
+ type: string
+ - name: installation_id
+ in: query
+ required: false
+ description: |
+ The GitHub App installation ID GitHub adds to the redirect. Volcano
+ does not read it; a repository is connected through startGitConnect.
+ schema:
+ type: string
+ - name: setup_action
+ in: query
+ required: false
+ description: |
+ What happened on GitHub: `install`, `update`, or `request`. Without
+ `state`, one of these values redirects to the dashboard; any other
+ value, or none, returns 400. With `state`, it is ignored.
+ schema:
+ type: string
responses:
- '202':
- description: Project deletion started
- '404':
- description: Project not found
+ '302':
+ description: |
+ Sent only when `state` is absent and `setup_action` is `install`,
+ `update`, or `request`. Redirects to the dashboard's Git settings
+ page without connecting anything, setting a cookie, or echoing the
+ request's query.
+ headers:
+ Location:
+ required: true
+ description: |
+ The dashboard's Git settings page with the fixed query
+ `github_install=1`.
+ schema:
+ type: string
+ format: uri
+ Cache-Control:
+ required: true
+ description: Always `no-store`.
+ schema:
+ type: string
+ Referrer-Policy:
+ required: true
+ description: Always `no-referrer`, so the dashboard never receives the callback URL.
+ schema:
+ type: string
+ '303':
+ description: Redirect back to the app after a successful or failed connect attempt
+ headers:
+ Location:
+ description: Redirect target
+ schema:
+ type: string
+ '400':
+ description: |
+ Invalid callback request or state, including a request without
+ `state` whose `setup_action` is missing or not `install`, `update`,
+ or `request`
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/health:
+ '429':
+ description: Too many callback attempts from this client
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Failed to complete the connection
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Git provider integration is not configured
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /connectors:
get:
tags:
- - Projects
- summary: Get project health
+ - Connectors
+ summary: List connectors
description: |
- Returns a fast control-plane health snapshot for the project and its
- deployed resources. The endpoint does not run live provider probes.
- A successful request returns 200 even when the project status is
- `degraded` or `critical`; transport and authorization failures use HTTP
- errors.
- operationId: getProjectHealth
+ Lists the connectors the caller can use. A connector links Volcano to
+ an outside service. A `slack` connector is a Slack workspace the
+ Volcano app is installed in: it is listed to the person who installed
+ it there, and to anyone with a Slack identity in that workspace
+ connected to their Volcano account. Add one with
+ `POST /user/slack/installations`. The list answers whether or not
+ reporting problems from Slack is available in this environment, so
+ turning it off strands no connector.
+ operationId: listConnectors
security:
- UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
+ - AuthUserAccessToken: []
responses:
'200':
- description: Project health snapshot retrieved
+ description: The caller's connectors
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectHealthResponse'
+ $ref: '#/components/schemas/ConnectorsResponse'
'401':
- description: Unauthorized - invalid or missing token
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Access denied
+ /connectors/{connector_id}:
+ get:
+ tags:
+ - Connectors
+ summary: Get a connector
+ description: |
+ Returns one connector the caller can use, as listing connectors shows
+ it. A connector the caller cannot see answers like one that doesn't
+ exist.
+ operationId: getConnector
+ security:
+ - UserToken: []
+ - AuthUserAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ConnectorId'
+ responses:
+ '200':
+ description: The connector
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Connector'
+ '400':
+ description: Malformed connector ID
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Project not found
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Internal server error
+ '404':
+ description: No such connector. One the caller cannot see answers the same way.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/metrics/query:
- post:
+ delete:
tags:
- - Projects
- summary: Query project runtime metrics
+ - Connectors
+ summary: Remove a connector
description: |
- Evaluates a batch of named, curated runtime metric queries over one
- trailing time range. Query IDs correlate each request with its result;
- raw backend query languages are intentionally not exposed.
- operationId: queryProjectMetrics
+ Removes a connector. Removing a `slack` connector uninstalls the
+ Volcano app from the Slack workspace, for every Volcano account that
+ uses it. Only the person who installed the app there can remove it
+ (`removable` is `true` for them); anyone else can uninstall the app in
+ Slack. The workspace's channels stop reporting problems at their next
+ check, which also cancels reports still queued. The channel bindings
+ stay, and report again if the app is installed in the workspace again.
+ It works whether or not reporting problems from Slack is available in
+ this environment.
+ operationId: deleteConnector
security:
- UserToken: []
- - ProjectAccessToken: []
+ - AuthUserAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/ProjectMetricsQueryRequest'
+ - $ref: '#/components/parameters/ConnectorId'
responses:
- '200':
- description: Project runtime metric queries evaluated
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/ProjectMetricsQueryResponse'
+ '204':
+ description: Removed
'400':
- description: Invalid metric query
+ description: Malformed connector ID
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
- description: Unauthorized - invalid or missing token
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Access denied
+ description: Someone else installed the Volcano app in this Slack workspace; only they can remove it.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Project not found
+ description: No such connector. One the caller cannot see answers the same way.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Internal server error
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '503':
- description: Runtime metrics backend unavailable
+ '502':
+ description: Slack did not answer the uninstall; the connector is unchanged, so try again
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/logo:
- get:
+ /user/slack/installations:
+ post:
tags:
- - Projects
- summary: Get the project logo image
+ - Slack Connections
+ summary: Start installing the Volcano Slack app
description: |
- Returns the raw logo image stored in the project's storage folder. This
- endpoint is unauthenticated so the asset can be rendered directly in an
- `
` tag; project IDs are unguessable UUIDs and logos are
- non-sensitive branding. The `Project.logo_url` field exposes a versioned
- path to this endpoint.
- operationId: getProjectLogo
- security: []
+ Starts an installation of the Volcano app in a Slack workspace, so
+ LavaFlow can take problems reported there, and returns its Add to Slack
+ URL. Send the browser to it; Slack returns it to `GET /slack/callback`,
+ which saves the installation as a `slack` connector (`GET /connectors`).
+ Installing again replaces the workspace's installation. Enterprise Grid org-wide installs are refused. The
+ callback finishes only in the browser that started the installation.
+
+ The response also sets a short-lived HttpOnly cookie that binds the
+ callback to this browser. Installing and connecting each set their
+ own, so starting one leaves the other's callback working.
+ operationId: startSlackInstall
+ security:
+ - UserToken: []
+ - AuthUserAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/SlackRedirect'
responses:
'200':
- description: Logo image
+ description: Slack authorization URL
content:
- image/png:
- schema:
- type: string
- format: binary
- image/jpeg:
- schema:
- type: string
- format: binary
- image/gif:
+ application/json:
schema:
- type: string
- format: binary
- image/webp:
+ $ref: '#/components/schemas/SlackAuthorizationResponse'
+ '400':
+ description: '`redirect` is not on the Volcano dashboard''s origin'
+ content:
+ application/json:
schema:
- type: string
- format: binary
- image/svg+xml:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
schema:
- type: string
- format: binary
+ $ref: '#/components/schemas/Error'
'404':
- description: Project or logo not found
+ description: Code `feature_unavailable`; reporting problems from Slack is not available in this environment
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- post:
+ /user/slack/connections:
+ get:
tags:
- - Projects
- summary: Upload or replace the project logo
+ - Slack Connections
+ summary: List connected Slack identities
description: |
- Uploads an image as the project's logo, storing it in the project's
- storage folder. Accepts PNG, JPEG, GIF, WebP, or SVG up to 2 MB. Replaces any
- existing logo. Returns the updated project, whose `logo_url` reflects
- the new logo.
- operationId: uploadProjectLogo
+ Lists the caller's connected Slack identities. It answers whether or
+ not reporting problems from Slack is available in this environment, so
+ turning it off strands no connection.
+ operationId: listSlackConnections
security:
- UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- requestBody:
- required: true
- content:
- multipart/form-data:
- schema:
- type: object
- required:
- - logo
- properties:
- logo:
- type: string
- format: binary
- description: Logo image (PNG, JPEG, GIF, WebP, or SVG; max 2 MB)
+ - AuthUserAccessToken: []
responses:
'200':
- description: Logo uploaded
+ description: The caller's connected Slack identities
content:
application/json:
schema:
- $ref: '#/components/schemas/Project'
- '400':
- description: Bad request (missing file, unsupported type, or too large)
+ $ref: '#/components/schemas/SlackConnectionsResponse'
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Access denied
+ post:
+ tags:
+ - Slack Connections
+ summary: Start connecting a Slack identity
+ description: |
+ Starts connecting the caller's Slack identity to their Volcano account
+ and returns its Sign in with Slack URL. LavaFlow acts on a person's
+ Slack mention only for projects owned by an account their identity is
+ connected to. The callback finishes only in the browser that started
+ the connection, so a link forwarded to anyone else connects no one.
+ One Slack identity may connect to several accounts, and one account may
+ have several identities connected. The identity is also tied to the
+ caller's sign-in session: the channel picker and binding act only as
+ the identities this session signed in as, so on an account several
+ people share, nobody picks or binds as another person's identity. An
+ API token has no session, so it can connect an identity that reports,
+ but not pick or bind channels with it. Volcano stores the workspace and
+ user IDs, and no Slack token.
+
+ The response also sets a short-lived HttpOnly cookie that binds the
+ callback to this browser. Installing and connecting each set their
+ own, so starting one leaves the other's callback working.
+ operationId: startSlackConnect
+ security:
+ - UserToken: []
+ - AuthUserAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/SlackRedirect'
+ responses:
+ '200':
+ description: Slack authorization URL
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- '404':
- description: Project not found
+ $ref: '#/components/schemas/SlackAuthorizationResponse'
+ '400':
+ description: '`redirect` is not on the Volcano dashboard''s origin'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: Project is being deleted
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Logo storage is not configured
+ '404':
+ description: Code `feature_unavailable`; reporting problems from Slack is not available in this environment
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
+ /user/slack/connections/{connectionId}:
delete:
tags:
- - Projects
- summary: Remove the project logo
+ - Slack Connections
+ summary: Disconnect a Slack identity
description: |
- Deletes the project logo from the project's storage folder and clears its
- record. Returns the updated project with no `logo_url`.
- operationId: deleteProjectLogo
+ Disconnects one Slack identity from the caller's account. LavaFlow
+ stops acting on its mentions for the account's projects at its next
+ check, which also cancels reports still queued. It works whether or not
+ reporting problems from Slack is available in this environment.
+ operationId: deleteSlackConnection
security:
- UserToken: []
- - ProjectAccessToken: []
+ - AuthUserAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
+ - name: connectionId
+ in: path
+ required: true
+ description: The connection to remove
+ schema:
+ type: string
+ format: uuid
responses:
- '200':
- description: Logo removed
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Project'
- '403':
- description: Access denied
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '404':
- description: Project not found
+ '204':
+ description: Disconnected
+ '400':
+ description: Malformed connection ID
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: Project is being deleted
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Logo storage is not configured
+ '404':
+ description: The caller has no such connection.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/usage:
+ /user/slack/channels:
get:
tags:
- - Projects
- summary: Get usage metrics for a project
+ - Slack Connections
+ summary: List a workspace's channels for binding
description: |
- Returns project usage totals for the current usage month plus
- recent hourly and daily time series for each tracked metric.
- operationId: getProjectUsage
+ Lists the channels in a workspace, public and private, that the Volcano
+ app and one of the Slack identities the caller's sign-in session signed
+ in as are both in, to choose which ones report problems to LavaFlow.
+ Invite the app to a channel in Slack to list it. Slack Connect, shared
+ and archived channels are left out.
+ operationId: listSlackChannels
security:
- UserToken: []
- - ProjectAccessToken: []
+ - AuthUserAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
+ - name: team_id
+ in: query
+ required: true
+ description: The Slack workspace. The app must be installed in it, and one of the caller's connected Slack identities must belong to it.
+ schema:
+ $ref: '#/components/schemas/SlackTeamId'
responses:
'200':
- description: Usage metrics retrieved
+ description: Channels the app and one of the caller's connected Slack identities are both in
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectUsageResponse'
- '403':
- description: Access denied
+ $ref: '#/components/schemas/SlackChannelsResponse'
+ '400':
+ description: '`team_id` is missing or malformed'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Project not found
+ description: The app is not installed in the workspace, or the caller's sign-in session signed in as no Slack identity there. Code `feature_unavailable` means reporting problems from Slack is not available in this environment.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/shared-variables:
- put:
+ '502':
+ description: Slack did not answer, or refused the app's token; try again or reinstall the app
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /slack/callback:
+ get:
tags:
- - Projects
- summary: Replace shared variable names
+ - Slack Connections
+ summary: Complete a Slack install or connection
description: |
- Atomically replaces the complete shared function-variable list without
- changing values. Names must already exist. Validates final affected
- function environments before membership or propagation side effects.
- An empty list clears membership. Omitted names remain stored as non-shared variables.
- operationId: replaceSharedVariables
- security:
- - UserToken: []
- - ProjectAccessToken: []
+ Public callback Slack sends the browser to after Add to Slack or Sign
+ in with Slack. The signed `state` names the flow and the Volcano user
+ who started it, and the callback cookie binds it to the browser that
+ started it. Redirects to the flow's `redirect`, or to the dashboard,
+ adding `slack_connect_error=1` when the flow failed.
+ operationId: slackCallback
+ security: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- type: object
- additionalProperties: false
- required:
- - shared_variables
- not:
- required:
- - expected_shared_variables
- - expected_shared_variables_digest
- properties:
- shared_variables:
- type: array
- uniqueItems: true
- items:
- type: string
- maxLength: 256
- pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
- expected_shared_variables:
- type: array
- uniqueItems: true
- description: When present, replace only if the current complete shared list matches this list.
- items:
- type: string
- maxLength: 256
- pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
- expected_shared_variables_digest:
- type: string
- minLength: 64
- maxLength: 64
- pattern: ^[a-f0-9]{64}$
- description: SHA-256 of the sorted unique current shared names joined by a newline. Use instead of expected_shared_variables for a compact conditional replacement.
+ - name: code
+ in: query
+ required: false
+ description: Slack's authorization code
+ schema:
+ type: string
+ - name: state
+ in: query
+ required: true
+ description: The signed state the flow's start returned
+ schema:
+ type: string
+ - name: error
+ in: query
+ required: false
+ description: Slack's error, such as `access_denied`
+ schema:
+ type: string
responses:
- '204':
- description: Shared list replaced and affected function synchronization started.
+ '303':
+ description: Redirect back to the dashboard after a successful or failed attempt
+ headers:
+ Location:
+ description: Redirect target
+ schema:
+ type: string
'400':
- description: Invalid names or final function environment.
+ description: Invalid or expired state, or a browser that did not start the flow
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized
'404':
- description: Project not found
- '409':
- description: Shared list changed since it was read.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '413':
- description: Request body exceeds 4,194,304 bytes
+ description: Code `feature_unavailable`; reporting problems from Slack is not available in this environment
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Persistence or synchronization failed
- '503':
- description: Shared variable membership writes are disabled during rollout
+ '429':
+ description: Too many callback attempts from this client
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/frontend-shared-variables:
- put:
+ /projects:
+ get:
tags:
- Projects
- summary: Replace frontend shared variable names
+ summary: List all projects for authenticated user
description: |
- Atomically replaces the complete shared frontend-variable list without
- changing values. Names must already exist. Validates final affected
- frontend environments before membership or propagation side effects.
- An empty list clears membership. Omitted names remain stored outside the frontend shared list.
- operationId: replaceFrontendSharedVariables
+ Returns projects that are not deleting or deleted, newest first.
+ Supports two mutually exclusive pagination modes. Offset mode uses
+ `page` and `limit`. Cursor mode uses `cursor` or `ending_before` with
+ `limit`, returns `next_cursor`/`prev_cursor`, and supports a bounded
+ `offset` past the cursor anchor. Supplying `limit` without `page`
+ selects cursor mode. `search` applies a case-insensitive project-name
+ filter in either mode. `include` optionally expands each returned
+ project with its Git connection and/or aggregate health summary using
+ `git_connection` and `health`. Sending `page` with `cursor` or `ending_before`,
+ or sending both cursor directions, returns 400.
+ operationId: listProjects
security:
- UserToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- type: object
- additionalProperties: false
- required:
- - frontend_shared_variables
- not:
- required:
- - expected_frontend_shared_variables
- - expected_frontend_shared_variables_digest
- properties:
- frontend_shared_variables:
- type: array
- uniqueItems: true
- items:
- type: string
- maxLength: 256
- pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
- expected_frontend_shared_variables:
- type: array
- uniqueItems: true
- description: When present, replace only if the current complete frontend shared list matches this list.
- items:
- type: string
- maxLength: 256
- pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
- expected_frontend_shared_variables_digest:
- type: string
- minLength: 64
- maxLength: 64
- pattern: ^[a-f0-9]{64}$
- description: SHA-256 of the sorted unique current shared names joined by a newline. Use instead of expected_frontend_shared_variables for a compact conditional replacement.
+ - $ref: '#/components/parameters/Page'
+ - $ref: '#/components/parameters/Limit'
+ - $ref: '#/components/parameters/Cursor'
+ - $ref: '#/components/parameters/EndingBefore'
+ - $ref: '#/components/parameters/Offset'
+ - $ref: '#/components/parameters/Search'
+ - name: include
+ in: query
+ required: false
+ description: Optional comma-separated project metadata expansions.
+ style: form
+ explode: false
+ schema:
+ type: array
+ uniqueItems: true
+ items:
+ type: string
+ enum:
+ - git_connection
+ - health
responses:
- '204':
- description: Frontend shared list replaced and affected frontend synchronization started.
+ '200':
+ description: Successful response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PaginatedProjects'
'400':
- description: Invalid names or final frontend environment.
+ description: Invalid or conflicting pagination parameters
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized
- '404':
- description: Project not found
- '409':
- description: Frontend shared list changed since it was read.
+ post:
+ tags:
+ - Projects
+ summary: Create a new project
+ description: |
+ Creates a project for the authenticated user.
+ Projects have no plan limit; usage allowances apply across all of a user's projects.
+ Accounts on an older paid pricing revision keep the project cap that revision set, and
+ requests over it return 403.
+ operationId: createProject
+ security:
+ - UserToken: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateProjectRequest'
+ responses:
+ '201':
+ description: Project created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Project'
+ '400':
+ description: |
+ Bad request. A `template_source` other than `null` is refused: a project is created from a share with `POST /forks`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '413':
- description: Request body exceeds 4,194,304 bytes
+ '403':
+ description: Forbidden. The user reached a project cap (only on older paid pricing revisions that set one), the plan does not allow the requested region subset, or a template's frontend limit was reached
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Persistence or synchronization failed
- /projects/{id}/config:
+ '503':
+ description: The selected project template is not configured in this environment
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}:
get:
tags:
- Projects
- summary: Export project configuration
- description: |
- Exports the project's current user-facing configuration as a
- declarative manifest. Returns JSON by default. Request the canonical
- volcano-config.yaml rendering with `Accept: application/yaml` or
- `?format=yaml`; the YAML is returned verbatim as the raw response body
- (`Content-Type: application/yaml`) and is meant to be saved as-is.
- Variable values and write-only secrets (SMTP password, OAuth client secrets, TLS material)
- are omitted from the export; shared_variables and frontend_shared_variables contain names only; the YAML rendering adds a header comment
- describing how to set them via CLI environment interpolation.
- operationId: getProjectConfig
+ summary: Get project by ID
+ operationId: getProject
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - name: format
- in: query
- required: false
- description: Response format override. Takes precedence over the Accept header.
- schema:
- type: string
- enum:
- - json
- - yaml
responses:
'200':
- description: |
- Current project configuration. JSON by default; when YAML is
- requested the body is the canonical volcano-config.yaml document
- served verbatim with `Content-Type: application/yaml`.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/ProjectConfig'
- application/yaml:
- schema:
- type: string
- format: binary
- description: |
- Canonical volcano-config.yaml document returned verbatim,
- ready to be saved as-is. The response body is limited to
- 4,194,304 bytes, matching the configuration apply limit.
- '401':
- description: Unauthorized - invalid or missing token
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
+ $ref: '#/components/schemas/Project'
'404':
description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '413':
- description: Canonical YAML export exceeds 4,194,304 bytes
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- put:
+ patch:
tags:
- Projects
- summary: Apply project configuration
- description: |
- Validates and applies a declarative configuration manifest to the
- project, reconciling each declared section and returning a per-resource
- report. Omitted sections are untouched. Declared collection keys
- (`variables`, `buckets[].policies`, `auth.providers.oauth`,
- `auth.email.templates`, `functions[].schedulers`) are fully synced:
- resources absent from the manifest are deleted. Functions, frontends,
- databases, and buckets are never created or deleted; manifest entries
- for resources that do not exist are skipped and reported in `skipped`,
- and existing resources missing from a declared section are reported in
- `missing`. Validation failures (including plan-gate violations) return
- 422 and nothing is applied. Set `dry_run=true` to get the projected
- report without applying changes. Applies are serialized per project;
- a concurrent apply returns 409.
- operationId: applyProjectConfig
+ summary: Update project metadata and region policy
+ operationId: updateProject
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - name: dry_run
- in: query
- required: false
- description: Validate and report projected actions without applying changes.
- schema:
- type: boolean
- default: false
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectConfig'
+ $ref: '#/components/schemas/UpdateProjectRequest'
responses:
'200':
- description: |
- Apply report. Individual entries may still carry `action: error`
- for apply-phase failures (summary.errors > 0); already-applied
- changes are not rolled back.
+ description: Project updated
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectConfigApplyResult'
+ $ref: '#/components/schemas/Project'
'400':
- description: Malformed request body
+ description: |
+ Bad request (no region selected, an unknown region, or — for a
+ project holding durable functions — a region that does not offer
+ durable execution)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
+ '403':
+ description: Forbidden (for example, selecting subset regions on plan other than SUPERAGENT)
content:
application/json:
schema:
@@ -2834,47 +3085,47 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'409':
- description: Another apply is in progress for this project
+ description: Conflict (project name already exists or a resource deployment blocks a region change)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '422':
- description: Manifest validation failed; nothing was applied
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/ProjectConfigValidationErrorResponse'
- '503':
- description: Shared variable membership writes are disabled during rollout
+ delete:
+ tags:
+ - Projects
+ summary: Delete a project
+ description: |
+ Starts asynchronous project deletion. The project remains available from
+ `GET /projects/{id}` with `status: deleting` until cleanup finishes, but is
+ removed from project lists as soon as deletion starts. After cleanup it
+ returns 404.
+ operationId: deleteProject
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ responses:
+ '202':
+ description: Project deletion started
+ '404':
+ description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/source-export:
+ /projects/{id}/health:
get:
tags:
- Projects
- - Git Connections
- summary: Report the project's source-of-truth state
- operationId: getProjectSourceExport
+ summary: Get project health
description: |
- Volcano stores the source of the functions and frontend it runs for a
- project. This reports whether that source has been written to the
- connected repository, and whether the repository has taken over as the
- project's source of truth.
-
- `mode` is `platform`, `git_exporting`, `git_pending`, or `git`. Export
- enters `git_exporting` before reading stored source. GitHub's signed
- push event confirms that the initial commit reached the production
- branch. That push or a newer production push changes the mode to
- `git_pending` when it starts a deployment. `exported_at` records that
- transition.
-
- A successful Git run completes the transition when it matches the
- recorded repository, production branch, and root directory and actually
- dispatches every recorded resource. Ordinary production-branch pushes
- deploy without changing a platform-managed project's source ownership.
+ Returns a fast control-plane health snapshot for the project and its
+ deployed resources. The endpoint does not run live provider probes.
+ A successful request returns 200 even when the project status is
+ `degraded` or `critical`; transport and authorization failures use HTTP
+ errors.
+ operationId: getProjectHealth
security:
- UserToken: []
- ProjectAccessToken: []
@@ -2882,11 +3133,11 @@ paths:
- $ref: '#/components/parameters/ProjectId'
responses:
'200':
- description: The project's source-of-truth state
+ description: Project health snapshot retrieved
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectSourceExportState'
+ $ref: '#/components/schemas/ProjectHealthResponse'
'401':
description: Unauthorized - invalid or missing token
content:
@@ -2894,7 +3145,7 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Forbidden - project not owned by the caller
+ description: Access denied
content:
application/json:
schema:
@@ -2911,40 +3162,16 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '501':
- description: Source export is not available in this deployment mode
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
+ /projects/{id}/metrics/query:
post:
tags:
- Projects
- - Git Connections
- summary: Initialize an empty repository with a project's stored source
- operationId: exportProjectSource
+ summary: Query project runtime metrics
description: |
- Creates the first commit in the connected repository and pushes it
- directly to the configured production branch. The push enters the
- ordinary Git auto-deploy flow. Direct source writes remain frozen until
- that deployment succeeds and the repository becomes the source of truth.
-
- The caller confirms the production branch shown before export. Starting
- export pins that branch: later GitHub default-branch changes do not
- repoint the project. If the configured branch changed after the caller
- read it, the request fails without exporting so the caller can show and
- confirm the new value.
-
- The response lists what the export could not carry: resources with no
- successful deployment to take source from (`skipped`), and things no
- export can hand back (`omitted`) — migrations, which Volcano stores no
- copy of, and credential-shaped files, which are left for their owner to
- add.
-
- Requires a connected repository with no commits or branches, and runs
- once. Volcano never creates the repository. If GitHub did not confirm
- the push, retrying creates the same commit and adopts it when it already
- reached the repository.
+ Evaluates a batch of named, curated runtime metric queries over one
+ trailing time range. Query IDs correlate each request with its result;
+ raw backend query languages are intentionally not exposed.
+ operationId: queryProjectMetrics
security:
- UserToken: []
- ProjectAccessToken: []
@@ -2955,16 +3182,16 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/ExportProjectSourceRequest'
+ $ref: '#/components/schemas/ProjectMetricsQueryRequest'
responses:
- '201':
- description: The initial production-branch commit that was pushed
+ '200':
+ description: Project runtime metric queries evaluated
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectSourceExport'
+ $ref: '#/components/schemas/ProjectMetricsQueryResponse'
'400':
- description: Malformed request body
+ description: Invalid metric query
content:
application/json:
schema:
@@ -2976,38 +3203,13 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Forbidden - project not owned by the caller
+ description: Access denied
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Project not found, or it has no repository connected
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '409':
- description: |
- The source has already been exported, the repository has already
- taken over as the source of truth, the confirmed production branch
- is stale, a function or frontend deployment is still in progress,
- or the project has no stored source to export
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '422':
- description: |
- The repository refused the branch, or its contents cannot be laid
- out as a repository — a stored file that only ever carries
- credentials, or a layout Git auto-deploy would not read back
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '429':
- description: GitHub rate limited the request
+ description: Project not found
content:
application/json:
schema:
@@ -3018,94 +3220,67 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '501':
- description: Source export is not available in this deployment mode
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
'503':
- description: GitHub integration is not configured
+ description: Runtime metrics backend unavailable
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- delete:
+ /projects/{id}/logo:
+ get:
tags:
- Projects
- - Git Connections
- summary: Cancel an incomplete source export
- operationId: cancelProjectSourceExport
+ summary: Get the project logo image
description: |
- Restores platform source writes while the project is in
- `git_exporting` or `git_pending`. If Volcano reserved or deployed the
- root commit, export remains consumed and cannot be run again. The
- connected repository and any commit already pushed to it are unchanged.
- security:
- - UserToken: []
- - ProjectAccessToken: []
+ Returns the raw logo image stored in the project's storage folder. This
+ endpoint is unauthenticated so the asset can be rendered directly in an
+ `
` tag; project IDs are unguessable UUIDs and logos are
+ non-sensitive branding. The `Project.logo_url` field exposes a versioned
+ path to this endpoint.
+ operationId: getProjectLogo
+ security: []
parameters:
- $ref: '#/components/parameters/ProjectId'
responses:
- '204':
- description: The incomplete source transition was canceled
- '401':
- description: Unauthorized - invalid or missing token
+ '200':
+ description: Logo image
content:
- application/json:
+ image/png:
schema:
- $ref: '#/components/schemas/Error'
- '403':
- description: Forbidden - project not owned by the caller
- content:
- application/json:
+ type: string
+ format: binary
+ image/jpeg:
schema:
- $ref: '#/components/schemas/Error'
- '404':
- description: Project not found
- content:
- application/json:
+ type: string
+ format: binary
+ image/gif:
schema:
- $ref: '#/components/schemas/Error'
- '409':
- description: No incomplete transition exists, or Git already took ownership
- content:
- application/json:
+ type: string
+ format: binary
+ image/webp:
schema:
- $ref: '#/components/schemas/Error'
- '500':
- description: Internal server error
- content:
- application/json:
+ type: string
+ format: binary
+ image/svg+xml:
schema:
- $ref: '#/components/schemas/Error'
- '501':
- description: Source export is not available in this deployment mode
+ type: string
+ format: binary
+ '404':
+ description: Project or logo not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/git-connection/production-branch:
- put:
+ post:
tags:
- Projects
- - Git Connections
- summary: Set the branch a project deploys from
+ summary: Upload or replace the project logo
description: |
- Changes only the production branch, leaving the repository binding
- alone. PUT /projects/{id}/git-connection can also set it, but that is a
- full rebind: it needs connection_id, installation_id and a repository
- selector resent, and re-resolves the repository against GitHub for a
- field that does not depend on it.
-
- The branch does not have to exist. It is validated as a Git branch name
- and nothing more, so a project can be pointed at a branch that is about
- to be pushed — the case a repository created empty depends on.
-
- Setting the branch here marks it as the project's own choice, so a later
- default-branch rename on GitHub no longer moves it. Projects that never
- set one keep following the repository's default branch.
- operationId: setProjectGitProductionBranch
+ Uploads an image as the project's logo, storing it in the project's
+ storage folder. Accepts PNG, JPEG, GIF, WebP, or SVG up to 2 MB. Replaces any
+ existing logo. Returns the updated project, whose `logo_url` reflects
+ the new logo.
+ operationId: uploadProjectLogo
security:
- UserToken: []
- ProjectAccessToken: []
@@ -3114,64 +3289,61 @@ paths:
requestBody:
required: true
content:
- application/json:
+ multipart/form-data:
schema:
- $ref: '#/components/schemas/SetProjectGitProductionBranchRequest'
+ type: object
+ required:
+ - logo
+ properties:
+ logo:
+ type: string
+ format: binary
+ description: Logo image (PNG, JPEG, GIF, WebP, or SVG; max 2 MB)
responses:
'200':
- description: The project's repo connection, with the new branch
+ description: Logo uploaded
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectGitConnection'
+ $ref: '#/components/schemas/Project'
'400':
- description: |
- Malformed request body, or a production_branch that is not a valid
- Git branch name
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
+ description: Bad request (missing file, unsupported type, or too large)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Project not owned by the caller
+ description: Access denied
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: |
- Project not found, or it has no repository connected. The branch is
- part of the connection, so there is nothing to set it on until one
- exists.
+ description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
- description: A Git source transition is pending
+ description: Project is being deleted
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Failed to set the production branch
+ '503':
+ description: Logo storage is not configured
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/git-connection:
- get:
+ delete:
tags:
- Projects
- - Git Connections
- summary: Get a project's repo connection
- operationId: getProjectGitConnection
+ summary: Remove the project logo
+ description: |
+ Deletes the project logo from the project's storage folder and clears its
+ record. Returns the updated project with no `logo_url`.
+ operationId: deleteProjectLogo
security:
- UserToken: []
- ProjectAccessToken: []
@@ -3179,205 +3351,290 @@ paths:
- $ref: '#/components/parameters/ProjectId'
responses:
'200':
- description: The project's current repo connection
+ description: Logo removed
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectGitConnection'
- '401':
- description: Unauthorized - invalid or missing token
+ $ref: '#/components/schemas/Project'
+ '403':
+ description: Access denied
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Project not owned by the caller
+ '404':
+ description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Project not found, or has no repo connection
+ '409':
+ description: Project is being deleted
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Failed to get project git connection
+ '503':
+ description: Logo storage is not configured
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- put:
+ /projects/{id}/usage:
+ get:
tags:
- Projects
- - Git Connections
- summary: Connect or update a project's repo connection
+ summary: Get usage metrics for a project
description: |
- Full replace, following Vercel's model: many projects may point at the
- same repo, so this only binds the project — it never creates or
- deletes git-provider state. Used for both the initial connect and
- later edits (repo change, root directory, production branch).
- Resolves the repository_id or repo_full_name selector against the repos
- accessible through installation_id via connection_id's stored GitHub
- user token, then persists repository metadata only from that validated
- GitHub response.
- operationId: connectProjectGit
+ Returns project usage totals for the current usage month plus
+ recent hourly and daily time series for each tracked metric.
+ operationId: getProjectUsage
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/ConnectProjectGitRequest'
responses:
'200':
- description: The project's repo connection
+ description: Usage metrics retrieved
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectGitConnection'
- '400':
- description: |
- Malformed request body, no repository selector, selectors that
- identify different repositories, a production_branch that is not a
- valid Git branch name, no production_branch on a repository with no
- default branch to follow (name one to connect a repository that has
- no commits yet), or a production_branch other than the new
- repository's default in a request that also changes repository.
+ $ref: '#/components/schemas/ProjectUsageResponse'
+ '403':
+ description: Access denied
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
+ '404':
+ description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: |
- Project not owned by the caller, or the selected repository is not
- accessible through installation_id
+ /projects/{id}/shared-variables:
+ put:
+ tags:
+ - Projects
+ summary: Replace shared variable names
+ description: |
+ Atomically replaces the complete shared function-variable list without
+ changing values. Names must already exist. Validates final affected
+ function environments before membership or propagation side effects.
+ An empty list clears membership. Omitted names remain stored as non-shared variables.
+ operationId: replaceSharedVariables
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties: false
+ required:
+ - shared_variables
+ not:
+ required:
+ - expected_shared_variables
+ - expected_shared_variables_digest
+ properties:
+ shared_variables:
+ type: array
+ uniqueItems: true
+ items:
+ type: string
+ maxLength: 256
+ pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
+ expected_shared_variables:
+ type: array
+ uniqueItems: true
+ description: When present, replace only if the current complete shared list matches this list.
+ items:
+ type: string
+ maxLength: 256
+ pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
+ expected_shared_variables_digest:
+ type: string
+ minLength: 64
+ maxLength: 64
+ pattern: ^[a-f0-9]{64}$
+ description: SHA-256 of the sorted unique current shared names joined by a newline. Use instead of expected_shared_variables for a compact conditional replacement.
+ responses:
+ '204':
+ description: Shared list replaced and affected function synchronization started.
+ '400':
+ description: Invalid names or final function environment.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized
'404':
- description: Project or connection not found
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
+ description: Project not found
'409':
- description: |
- A Git source transition is pending or complete, so the recorded
- repository and root cannot be changed
+ description: Shared list changed since it was read.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Failed to connect project git
+ '413':
+ description: Request body exceeds 4,194,304 bytes
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
+ '500':
+ description: Persistence or synchronization failed
'503':
- description: Git provider integration is not configured
+ description: Shared variable membership writes are disabled during rollout
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- delete:
+ /projects/{id}/frontend-shared-variables:
+ put:
tags:
- Projects
- - Git Connections
- summary: Disconnect a project's repo connection
- operationId: disconnectProjectGit
+ summary: Replace frontend shared variable names
+ description: |
+ Atomically replaces the complete shared frontend-variable list without
+ changing values. Names must already exist. Validates final affected
+ frontend environments before membership or propagation side effects.
+ An empty list clears membership. Omitted names remain stored outside the frontend shared list.
+ operationId: replaceFrontendSharedVariables
security:
- UserToken: []
- - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties: false
+ required:
+ - frontend_shared_variables
+ not:
+ required:
+ - expected_frontend_shared_variables
+ - expected_frontend_shared_variables_digest
+ properties:
+ frontend_shared_variables:
+ type: array
+ uniqueItems: true
+ items:
+ type: string
+ maxLength: 256
+ pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
+ expected_frontend_shared_variables:
+ type: array
+ uniqueItems: true
+ description: When present, replace only if the current complete frontend shared list matches this list.
+ items:
+ type: string
+ maxLength: 256
+ pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
+ expected_frontend_shared_variables_digest:
+ type: string
+ minLength: 64
+ maxLength: 64
+ pattern: ^[a-f0-9]{64}$
+ description: SHA-256 of the sorted unique current shared names joined by a newline. Use instead of expected_frontend_shared_variables for a compact conditional replacement.
responses:
'204':
- description: Connection removed
- '401':
- description: Unauthorized - invalid or missing token
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '403':
- description: Project not owned by the caller
+ description: Frontend shared list replaced and affected frontend synchronization started.
+ '400':
+ description: Invalid names or final frontend environment.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized
'404':
- description: Project not found, or has no repo connection
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
+ description: Project not found
'409':
- description: |
- A Git source transition is pending or complete, so the recorded
- repository cannot be disconnected
+ description: Frontend shared list changed since it was read.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Failed to disconnect project git
+ '413':
+ description: Request body exceeds 4,194,304 bytes
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/git-deploy-settings:
+ '500':
+ description: Persistence or synchronization failed
+ /projects/{id}/config:
get:
tags:
- Projects
- - Git Connections
- summary: Get a project's Git auto-deploy settings
- operationId: getProjectGitDeploySettings
+ summary: Export project configuration
+ description: |
+ Exports the project's current user-facing configuration as a
+ declarative manifest. Returns JSON by default. Request the canonical
+ volcano-config.yaml rendering with `Accept: application/yaml` or
+ `?format=yaml`; the YAML is returned verbatim as the raw response body
+ (`Content-Type: application/yaml`) and is meant to be saved as-is.
+ Variable values and write-only secrets (SMTP password, OAuth client secrets, TLS material)
+ are omitted from the export; shared_variables and frontend_shared_variables contain names only; the YAML rendering adds a header comment
+ describing how to set them via CLI environment interpolation.
+ operationId: getProjectConfig
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
+ - name: format
+ in: query
+ required: false
+ description: Response format override. Takes precedence over the Accept header.
+ schema:
+ type: string
+ enum:
+ - json
+ - yaml
responses:
'200':
- description: The project's current Git auto-deploy settings
+ description: |
+ Current project configuration. JSON by default; when YAML is
+ requested the body is the canonical volcano-config.yaml document
+ served verbatim with `Content-Type: application/yaml`.
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectGitDeploySettings'
+ $ref: '#/components/schemas/ProjectConfig'
+ application/yaml:
+ schema:
+ type: string
+ format: binary
+ description: |
+ Canonical volcano-config.yaml document returned verbatim,
+ ready to be saved as-is. The response body is limited to
+ 4,194,304 bytes, matching the configuration apply limit.
'401':
description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Project not owned by the caller
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
'404':
description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Failed to get project git deploy settings
+ '413':
+ description: Canonical YAML export exceeds 4,194,304 bytes
content:
application/json:
schema:
@@ -3385,53 +3642,58 @@ paths:
put:
tags:
- Projects
- - Git Connections
- summary: Update a project's Git auto-deploy settings
+ summary: Apply project configuration
description: |
- Full replace of the project's Git auto-deploy settings: what a push to
- the connected repo's production branch deploys.
-
- Connecting a repository sets auto_deploy_enabled and deploy_functions
- to true for a project that has never called this endpoint, so a push
- deploys without any further setup. Once these settings have been saved
- here they are the project's own: connecting, rebinding, disconnecting
- and reconnecting all leave them untouched, including when they were
- saved before any repository was connected. Frontend settings are off
- until set here; the frontend need not exist when they are saved, since
- frontend_name is resolved at deploy time.
- operationId: updateProjectGitDeploySettings
+ Validates and applies a declarative configuration manifest to the
+ project, reconciling each declared section and returning a per-resource
+ report. Omitted sections are untouched. Declared collection keys
+ (`variables`, `buckets[].policies`, `auth.providers.oauth`,
+ `auth.email.templates`, `functions[].schedulers`) are fully synced:
+ resources absent from the manifest are deleted. Functions, frontends,
+ databases, and buckets are never created or deleted; manifest entries
+ for resources that do not exist are skipped and reported in `skipped`,
+ and existing resources missing from a declared section are reported in
+ `missing`. Validation failures (including plan-gate violations) return
+ 422 and nothing is applied. Set `dry_run=true` to get the projected
+ report without applying changes. Applies are serialized per project;
+ a concurrent apply returns 409.
+ operationId: applyProjectConfig
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
+ - name: dry_run
+ in: query
+ required: false
+ description: Validate and report projected actions without applying changes.
+ schema:
+ type: boolean
+ default: false
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/UpdateProjectGitDeploySettingsRequest'
+ $ref: '#/components/schemas/ProjectConfig'
responses:
'200':
- description: The project's updated Git auto-deploy settings
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/ProjectGitDeploySettings'
- '400':
- description: Malformed request body, or frontend_app_root without frontend_name
+ description: |
+ Apply report. Individual entries may still carry `action: error`
+ for apply-phase failures (summary.errors > 0); already-applied
+ changes are not rolled back.
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
+ $ref: '#/components/schemas/ProjectConfigApplyResult'
+ '400':
+ description: Malformed request body, or, with code `feature_unavailable`, the manifest creates or changes something whose capability is unavailable in this environment, such as `frontends[].frontend_routes` while `frontend_routes` is unavailable in `GET /capabilities`. Nothing was applied.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Project not owned by the caller
+ '401':
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
@@ -3443,60 +3705,59 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'409':
- description: |
- A Git source transition is pending, or this change would remove
- deploy coverage after Git has taken over
+ description: Another apply is in progress for this project
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Failed to update project git deploy settings
+ '422':
+ description: Manifest validation failed; nothing was applied
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProjectConfigValidationErrorResponse'
+ '503':
+ description: Shared variable membership writes are disabled during rollout
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/databases/{databaseName}/queries:
+ /projects/{id}/source-export:
get:
tags:
- - Databases
- summary: Get database queries
+ - Projects
+ - Git Connections
+ summary: Report the project's source-of-truth state
+ operationId: getProjectSourceExport
description: |
- Returns the database's current top queries from pg_stat_statements
- ranked by total execution time. Only data statements (SELECT, INSERT,
- UPDATE, DELETE, MERGE) are listed; statements Volcano runs to operate
- the database are left out.
+ Volcano stores the source of the functions and frontend it runs for a
+ project. This reports whether that source has been written to the
+ connected repository, and whether the repository has taken over as the
+ project's source of truth.
- **SUPERAGENT plan required.** This endpoint is only available to projects owned
- by users on the SUPERAGENT billing plan.
- operationId: getProjectDatabaseQueries
+ `mode` is `platform`, `git_exporting`, `git_pending`, or `git`. Export
+ enters `git_exporting` before reading stored source. GitHub's signed
+ push event confirms that the initial commit reached the production
+ branch. That push or a newer production push changes the mode to
+ `git_pending` when it starts a deployment. `exported_at` records that
+ transition.
+
+ A successful Git run completes the transition when it matches the
+ recorded repository, production branch, and root directory and actually
+ dispatches every recorded resource. Ordinary production-branch pushes
+ deploy without changing a platform-managed project's source ownership.
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
- - name: limit
- in: query
- description: Maximum number of queries to return.
- schema:
- type: integer
- minimum: 1
- maximum: 100
- default: 10
responses:
'200':
- description: Database query performance retrieved
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DatabaseQueryPerformanceResponse'
- '400':
- description: Bad request - invalid query parameters
+ description: The project's source-of-truth state
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
+ $ref: '#/components/schemas/ProjectSourceExportState'
'401':
description: Unauthorized - invalid or missing token
content:
@@ -3504,13 +3765,13 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Access denied
+ description: Forbidden - project not owned by the caller
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Project or database not found
+ description: Project not found
content:
application/json:
schema:
@@ -3521,86 +3782,61 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /deployments:
- get:
+ '501':
+ description: Source export is not available in this deployment mode
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ post:
tags:
- Projects
- summary: List deployments across a user's projects
+ - Git Connections
+ summary: Initialize an empty repository with a project's stored source
+ operationId: exportProjectSource
description: |
- Lists Function and Frontend deployment attempts across every project the
- user owns, newest first. Pass `project_id` to narrow the feed to a single
- project.
-
- Scope is project **ownership** (`projects.user_id`). `owner_id` names
- whose deployments to return, not who started them — the actor is
- `initiated_by_user_id`, which this endpoint does not filter on.
-
- With a user token the scope is always the authenticated user: `owner_id`
- may be omitted, or set to that same user, but naming anyone else is
- refused with 403. Service callers on the management API must pass it,
- since they have no authenticated user.
-
- The owner is not checked for existence: an id with no projects returns an
- empty page rather than `404`. Unlike `/users/{id}/usage`, this endpoint is
- polled to detect an event, so a caller needs `404` to keep meaning "this
- route is not served here" — which is how a consumer notices it is running
- against an older release. A mistyped owner therefore reads as "nothing
- deployed"; callers that need to tell those apart should verify the user
- through `GET /users/{id}` first.
+ Creates the first commit in the connected repository and pushes it
+ directly to the configured production branch. The push enters the
+ ordinary Git auto-deploy flow. Direct source writes remain frozen until
+ that deployment succeeds and the repository becomes the source of truth.
- Ordering is selectable. The default is the feed order — most recent
- attempt first. `completed_at.asc` orders by completion, oldest first, and
- considers only attempts that finished; combined with `limit=1` and a
- `status` filter it answers "when did this user first succeed" in one
- bounded query.
+ The caller confirms the production branch shown before export, and
+ optionally the repository by its `repo_id`. Starting export pins that
+ branch: later GitHub default-branch changes do not repoint the project.
+ If the connected repository or the configured branch changed after the
+ caller read it, the request fails without exporting so the caller can
+ show and confirm the new value.
- Both pagination modes are supported, selected exactly as
- `/projects/{id}/deployments` selects them: `cursor`/`ending_before` (or a
- `limit` with no `page`) uses keyset pagination; otherwise `page`/`limit`
- offset pagination. `page` with a cursor, and `cursor` with
- `ending_before`, are rejected.
+ The response lists what the export could not carry: resources with no
+ successful deployment to take source from (`skipped`), and things no
+ export can hand back (`omitted`) — migrations, which Volcano stores no
+ copy of, and credential-shaped files, which are left for their owner to
+ add.
- A cursor is bound to every filter *and* to `order`, so changing any of
- them mid-pagination rejects the cursor rather than silently skipping or
- repeating rows. The keyset position is `(created_at, id)` for
- `created_at.desc` and `(completed_at, id)` for `completed_at.asc`.
- operationId: listDeployments
+ Requires a connected repository with no commits or branches, and runs
+ once. Volcano never creates the repository. If GitHub did not confirm
+ the push, retrying creates the same commit and adopts it when it already
+ reached the repository.
security:
- UserToken: []
+ - ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/Page'
- - $ref: '#/components/parameters/Limit'
- - $ref: '#/components/parameters/Cursor'
- - $ref: '#/components/parameters/EndingBefore'
- - $ref: '#/components/parameters/Offset'
- - $ref: '#/components/parameters/DeploymentOwnerId'
- - name: project_id
- in: query
- required: false
- description: Restrict the feed to a single project owned by the user.
- schema:
- type: string
- format: uuid
- - name: created_after
- in: query
- required: false
- description: Restrict results to attempts created at or after this timestamp.
- schema:
- type: string
- format: date-time
- - $ref: '#/components/parameters/DeploymentResourceType'
- - $ref: '#/components/parameters/DeploymentStatus'
- - $ref: '#/components/parameters/DeploymentOperation'
- - $ref: '#/components/parameters/DeploymentOrder'
+ - $ref: '#/components/parameters/ProjectId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExportProjectSourceRequest'
responses:
- '200':
- description: Successful response
+ '201':
+ description: The initial production-branch commit that was pushed
content:
application/json:
schema:
- $ref: '#/components/schemas/PaginatedProjectDeployments'
+ $ref: '#/components/schemas/ProjectSourceExport'
'400':
- description: Bad request - invalid filter or pagination
+ description: Malformed request body
content:
application/json:
schema:
@@ -3612,159 +3848,100 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Forbidden - owner_id names a different user
+ description: Forbidden - project not owned by the caller
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Internal server error
+ '404':
+ description: Project not found, or it has no repository connected
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/deployments:
- get:
- tags:
- - Projects
- summary: List deployments in a project
- description: |
- Lists Function and Frontend deployment attempts across the project,
- ordered most-recent first. Each item includes a normalized resource
- reference so clients can render both resource types without extra
- fetches.
-
- Standard and durable function deployments both appear under
- `resource.type: function`, and `resource.kind` tells them apart. Pass
- `function_kind` to list one kind only; frontends are then excluded.
- Combining `function_kind` with `resource_type=frontend` is rejected.
- operationId: listProjectDeployments
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/Page'
- - $ref: '#/components/parameters/Limit'
- - $ref: '#/components/parameters/Cursor'
- - $ref: '#/components/parameters/EndingBefore'
- - $ref: '#/components/parameters/Offset'
- - $ref: '#/components/parameters/Search'
- - name: created_after
- in: query
- required: false
- description: Restrict results to attempts created at or after this timestamp.
- schema:
- type: string
- format: date-time
- - name: resource_type
- in: query
- required: false
+ '409':
description: |
- Restrict the feed to a single resource type. Omit to return both
- Function and Frontend deployments.
- schema:
- type: string
- enum:
- - function
- - frontend
- - $ref: '#/components/parameters/FunctionKindFilter'
- responses:
- '200':
- description: Successful response
+ The source has already been exported, the repository has already
+ taken over as the source of truth, the confirmed production branch
+ or repository is stale, a function or frontend deployment is still in progress,
+ a preview is serving one of the project's frontends, or the project
+ has no stored source to export
content:
application/json:
schema:
- $ref: '#/components/schemas/PaginatedProjectDeployments'
- '400':
- description: Bad request - invalid identifier or filter, or `function_kind` combined with `resource_type=frontend`
+ $ref: '#/components/schemas/Error'
+ '422':
+ description: |
+ The repository refused the branch, or its contents cannot be laid
+ out as a repository — a stored file that only ever carries
+ credentials, or a layout Git auto-deploy would not read back
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
+ '429':
+ description: GitHub rate limited the request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Forbidden - project ownership required
- content:
+ '500':
+ description: Internal server error
+ content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Internal server error
+ '501':
+ description: Source export is not available in this deployment mode
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/deployments/summary:
- get:
+ '503':
+ description: GitHub integration is not configured
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ delete:
tags:
- Projects
- summary: Summarize deployments in a project
+ - Git Connections
+ summary: Cancel an incomplete source export
+ operationId: cancelProjectSourceExport
description: |
- Summarizes deployment attempts for one comparable resource pipeline.
- Success rate uses conclusive outcomes only: active and deleted attempts
- are successful; failed and degraded attempts are failures; in-progress
- and superseded attempts are excluded. Median build duration includes
- completed, non-superseded attempts with recorded build work,
- including failed builds.
-
- With `resource_type=function`, pass `function_kind` to summarize one
- kind of function only. It is rejected with `resource_type=frontend`.
- operationId: summarizeProjectDeployments
+ Restores platform source writes while the project is in
+ `git_exporting` or `git_pending`. If Volcano reserved or deployed the
+ root commit, export remains consumed and cannot be run again. The
+ connected repository and any commit already pushed to it are unchanged.
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - name: search
- in: query
- required: false
- description: Restrict the summary to resource names containing this value.
- schema:
- type: string
- - name: resource_type
- in: query
- required: true
- description: Restrict the summary to one comparable deployment pipeline.
- schema:
- type: string
- enum:
- - function
- - frontend
- - $ref: '#/components/parameters/FunctionKindFilter'
- - name: created_after
- in: query
- required: false
- description: Restrict results to attempts created at or after this timestamp.
- schema:
- type: string
- format: date-time
responses:
- '200':
- description: Successful response
+ '204':
+ description: The incomplete source transition was canceled
+ '401':
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectDeploymentSummary'
- '400':
- description: Bad request - invalid identifier or filter, or `function_kind` combined with `resource_type=frontend`
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - project not owned by the caller
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
+ '404':
+ description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Forbidden - project ownership required
+ '409':
+ description: No incomplete transition exists, or Git already took ownership
content:
application/json:
schema:
@@ -3775,510 +3952,310 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/domains:
+ '501':
+ description: Source export is not available in this deployment mode
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /share-previews/{share_id}:
get:
tags:
- - Frontends
- summary: List all custom domains in a project
+ - Shares
+ summary: Preview what a deploy link deploys
description: |
- Project-scoped custom-domain list. Returns every active custom
- domain across every frontend in the project (excludes soft-deleted
- rows). Each item inlines the linked frontend's id and name so the
- UI does not need a second fetch to render the "Linked to" column.
- operationId: listProjectCustomDomains
- security:
- - UserToken: []
- - ProjectAccessToken: []
+ Public: needs no credential, because the link id is the credential. Answers
+ the link's current release: when it was published, its digest, the functions
+ and frontends installing it creates, the variables the visitor supplies, and
+ the functions that receive the new project's service key. Show it to a
+ visitor before they confirm, and send its `release.id` when creating the
+ project.
+
+ Counts the visit for the link's owner, unless the request comes from a
+ crawler or link preview. A link that does not exist, was switched off, or has
+ not been published yet all answer the same `404`.
+ operationId: getSharePreview
+ security: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/Page'
- - $ref: '#/components/parameters/Limit'
- - $ref: '#/components/parameters/Cursor'
- - $ref: '#/components/parameters/EndingBefore'
- - $ref: '#/components/parameters/Offset'
- - $ref: '#/components/parameters/Search'
+ - $ref: '#/components/parameters/ShareId'
responses:
'200':
- description: Successful response
+ description: The link's current release
content:
application/json:
schema:
- $ref: '#/components/schemas/PaginatedProjectCustomDomains'
+ $ref: '#/components/schemas/SharePreview'
'400':
- description: Bad request - invalid identifier
+ description: The link id is malformed
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
+ '403':
+ description: |
+ The request carried the dashboard proxy's visitor headers without a valid proof
+ from the proxy (code `proxy_credential_rejected`, the same for every kind of
+ failed proof). It is never about the caller's session.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Forbidden - project ownership required
+ '404':
+ description: The link is not available, or deploy links are not available in this environment (code `feature_unavailable`; see `GET /capabilities`). A link of a project copied from a link that no longer allows re-sharing answers the same.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '429':
+ description: Too many previews from this address; try again after `Retry-After`
+ headers:
+ Retry-After:
+ description: Seconds until the clock hour the limit counts in ends.
+ schema:
+ type: integer
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '451':
+ description: Volcano cannot serve requests from the visitor's location under US sanctions
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
- description: Internal server error
+ description: Failed to preview the deploy link
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/functions:
+ '503':
+ description: The dashboard proxy's own project is not being served right now (code `service_unavailable`); try again shortly.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /shares:
get:
tags:
- - Functions
- summary: List all functions in a project
+ - Shares
+ summary: List a project's deploy links
description: |
- Supports two mutually exclusive pagination modes. Offset mode uses `page`
- and `limit` and returns `next` (URL). Cursor mode uses `cursor` and
- `limit`, supports `search` (case-insensitive name match), and returns
- `next_cursor`/`prev_cursor`. Sending both `page` and `cursor` (or `page`
- and `search`) returns 400.
- operationId: listFunctions
+ Deploy links let anyone deploy a release the project's owner published as
+ their own new project. A link's public address is
+ `https://volcano.dev/deploy/`; the address carries no release, so it
+ cannot be edited to point at other code.
+ operationId: listShares
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/Page'
- - $ref: '#/components/parameters/Limit'
- - $ref: '#/components/parameters/Cursor'
- - $ref: '#/components/parameters/EndingBefore'
- - $ref: '#/components/parameters/Offset'
- - $ref: '#/components/parameters/Search'
+ - $ref: '#/components/parameters/ProjectIdQuery'
responses:
'200':
- description: Successful response
+ description: The project's deploy links, newest first
content:
application/json:
schema:
- $ref: '#/components/schemas/PaginatedFunctions'
+ $ref: '#/components/schemas/SharesResponse'
+ '400':
+ description: The `project_id` query parameter is missing or is not a project UUID
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'404':
description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
+ '500':
+ description: Failed to list deploy links
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
post:
tags:
- - Functions
- summary: Create or update function code
+ - Shares
+ summary: Create a deploy link
description: |
- Upload a function source bundle. Direct API clients may send the function code
- as a ZIP or tar.gz archive via multipart/form-data. The API stores a normalized tar.gz
- source archive.
- Cloud deploys should include source files and dependency manifests/lockfiles, not installed
- dependency directories. Volcano installs Node.js, Python, and Ruby dependencies during the
- function compile build.
- Source archive size is enforced by the API with `SOURCE_ARCHIVE_SIZE_LIMIT_MB`; the CLI
- does not apply its own source archive size limit. After the final container image is
- built, the publish build enforces `LAMBDA_TARGET_CONTAINER_SIZE_LIMIT_MB` before pushing.
- Uploaded source archives cannot contain symlink entries. Safe symlinks created during
- the cloud build are materialized before publish.
- Volcano builds and deploys the function asynchronously after upload. A deployment that starts
- immediately returns a Function resource with `status: provisioning`, then transitions to
- `active` or `failed`. If another deployment is running, the response preserves the resource's
- current status and exposes the queued deployment through `pending_deployment_id`.
- Existing function traffic continues to use the last known-good runtime during an update. A failed
- update keeps that runtime available and records the attempted deployment as failed.
- Only one deployment runs for a given function. A newer request supersedes any queued request
- and starts after the running deployment. Different functions and projects deploy concurrently.
- If a function with the same name already exists in the project, this operation updates that
- function's runtime, handler, and source bundle and returns `200 OK`.
- Each project can contain up to 10,000 functions. Creating a new function over this cap returns 403.
- operationId: createFunction
+ Creates a draft link for the project. It offers nothing to visitors, and its
+ preview answers `404`, until its owner publishes a release to it with
+ `POST /share-releases`. Any project can have
+ links, whether it deploys from the CLI, the dashboard or Git.
+ operationId: createShare
security:
- UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
requestBody:
required: true
content:
- multipart/form-data:
+ application/json:
schema:
- type: object
- required:
- - name
- - code
- - runtime
- properties:
- name:
- type: string
- description: DNS-safe function name (lowercase letters, numbers, hyphens; cannot start or end with hyphen)
- maxLength: 63
- pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$
- example: my-api-function
- code:
- type: string
- format: binary
- description: ZIP or tar.gz archive containing function source code plus dependency manifests/lockfiles. The API enforces SOURCE_ARCHIVE_SIZE_LIMIT_MB and stores a normalized tar.gz source archive.
- runtime:
- type: string
- enum:
- - nodejs22.x
- - nodejs24.x
- - python3.10
- - python3.11
- - python3.12
- - python3.13
- - python3.14
- - ruby3.3
- - ruby3.4
- - ruby4.0
- description: |
- Runtime environment. Required.
- - Node.js: nodejs22.x, nodejs24.x
- - Python: python3.10, python3.11, python3.12, python3.13, python3.14
- - Ruby: ruby3.3, ruby3.4, ruby4.0
- example: nodejs24.x
- handler:
- type: string
- description: |
- The name of the function to invoke. Defaults to "handler" if not specified.
- Your code must export/define a function with this name:
- - Node.js: exports.handler (in index.js)
- - Python: def handler() (in main.py)
- - Ruby: def handler() (in main.rb)
- default: handler
- example: handler
- visibility:
- allOf:
- - $ref: '#/components/schemas/FunctionVisibility'
- description: |
- Who can invoke the function. Omit it to keep the function's
- current visibility; a new function starts `private`.
- is_public:
- type: boolean
- deprecated: true
- description: |
- Deprecated alias for `visibility`: `true` means `public` and
- `false` means `authenticated`. Sending both with different
- meanings returns 400.
- invocation_mode:
- $ref: '#/components/schemas/FunctionInvocationMode'
- http_auth_mode:
- $ref: '#/components/schemas/FunctionHTTPAuthMode'
- openapi_spec:
- type: string
- description: JSON-encoded OpenAPI 3.0 or 3.1 metadata for an HTTP-mode function.
- variable_scope:
- type: string
- enum:
- - all
- - scoped
- x-enum-varnames:
- - CreateFunctionMultipartBodyVariableScopeAll
- - CreateFunctionMultipartBodyVariableScopeScoped
- description: |
- Which project variables this function receives. `all` (the default) gives it only project variables marked `shared: true`; `scoped` gives it only the variables it selects. Omitting this leaves an existing function's scope unchanged.
- variables:
- type: string
- description: |
- JSON-encoded array of project variable names this function requires, on top of the ones detected in its source. A declared name the project does not define is rejected with 400; a detected name it does not define is ignored. Only used when `variable_scope` is `scoped`. Omitting this leaves an existing function's declared names unchanged.
+ $ref: '#/components/schemas/ShareCreateRequest'
responses:
- '200':
- description: Existing function updated; its deployment was started or queued
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Function'
'201':
- description: Function created and deployment workflow started
+ description: The new deploy link
content:
application/json:
schema:
- $ref: '#/components/schemas/Function'
+ $ref: '#/components/schemas/Share'
'400':
- description: |
- Bad request (invalid file, too large, etc.), an unknown
- `visibility`, or `visibility` and `is_public` disagree
+ description: Malformed request body or an invalid suggested name
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Function limit exceeded for the project
+ '401':
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
+ '403':
description: |
- Function deletion is queued or running, the name is already held
- by a durable function — a function cannot change kind — or the
- redeploy would take a function with Frontend Function routes out
- of `public` or out of HTTP invocation mode. The request is refused
- before the deploy starts, so nothing is deployed.
+ A project access token was used.
+ A person creates, changes, publishes and deletes deploy links. Code
+ `reshare_not_allowed` means the project is a copy made from someone else's
+ deploy link, and that link, or a link it was made from in turn, does not
+ allow re-sharing or no longer exists. Code `source_unavailable` means the
+ project is a copy, and a link it was made from is not available to share
+ from right now. Code `operator_disabled` means
+ Volcano took one of the project's links down (`disabled_reason`
+ `operator`), so the project cannot be shared until that is lifted.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
+ '404':
description: |
- The owner's billing-cycle build-minutes allowance is spent. The
- error names the allowance and carries a link to the usage page.
+ Project not found or not the caller's, or deploy links are not available
+ in this environment
+ (code `feature_unavailable`; see `GET /capabilities`)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Internal server error (function deployment failed)
+ '409':
+ description: The project has reached its deploy link limit
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: |
- Build usage could not be read, so the allowance could not be
- checked. The same request succeeds once it can be.
+ '500':
+ description: Failed to create the deploy link
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/functions/{functionId}:
+ /shares/{share_id}:
get:
tags:
- - Functions
- summary: Get function by ID
- operationId: getFunction
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/FunctionId'
- responses:
- '200':
- description: Successful response
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Function'
- '404':
- description: Function not found
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- patch:
- tags:
- - Functions
- summary: Update function settings
- operationId: updateFunction
+ - Shares
+ summary: Get a deploy link
+ operationId: getShare
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/FunctionId'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/UpdateFunctionRequest'
- examples:
- makePublic:
- summary: Let anon keys invoke the function
- value:
- visibility: public
- allowSignedInUsers:
- summary: Let signed-in users of the project invoke the function
- value:
- visibility: authenticated
- makePrivate:
- summary: Allow only service keys and schedulers (the default)
- value:
- visibility: private
+ - $ref: '#/components/parameters/ShareId'
+ - $ref: '#/components/parameters/ItemProjectIdQuery'
responses:
'200':
- description: Function updated
+ description: The deploy link
content:
application/json:
schema:
- $ref: '#/components/schemas/Function'
+ $ref: '#/components/schemas/Share'
'400':
description: |
- Invalid settings: an unknown `visibility`, `visibility` and
- `is_public` disagree, or `http_auth_mode: none` on a function that
- is not `public`
+ `project_id` is malformed, or `project_id` is given and the link id is
+ malformed. Without `project_id`, a malformed link id answers 404, as an
+ unknown link does.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Function not found
+ '401':
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: |
- Function settings conflict with attached Frontend Function routes:
- a routed function must stay `public` and in HTTP invocation mode.
+ '404':
+ description: Project or deploy link not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- delete:
- tags:
- - Functions
- summary: Delete a function
- description: |
- Schedules asynchronous function deletion. If another deployment is running, the function
- preserves its current status and exposes the queued deletion through `pending_deployment_id`.
- Its status changes to `deleting` when cleanup starts. After cleanup, it returns 404 and no
- longer appears in function lists.
- operationId: deleteFunction
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/FunctionId'
- responses:
- '202':
- description: Function deletion started or queued
- '404':
- description: Function not found
+ '500':
+ description: Failed to get the deploy link
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /functions/{functionId}/invoke:
- post:
+ patch:
tags:
- - Functions
- summary: Invoke a function
- description: |
- Invoke a function. The function's `visibility` decides which credentials
- may call it, and the function does not run for any other. A `private`
- function answers every credential but a service key exactly as a
- missing one, with 404, so its name and id cannot be discovered; an anon
- key on an `authenticated` function gets 403. An SDK calling by name
- resolves it first through `GET /functions/resolve`, which answers that
- anon key with 404 instead.
-
- **With Service Key** (admin/background operations, every visibility):
- - Use for background jobs, webhooks, cron, admin operations
- - Function receives payload only (no user context)
- - Database queries bypass RLS (admin access)
-
- **With Auth User Token** (user-facing, `authenticated` or `public` functions):
- - Use for user-initiated actions
- - Includes users from anonymous sign-ins
- - Function receives payload + `__volcano_auth` context:
- ```javascript
- {
- user_id: "uuid",
- email: "user@example.com",
- project_id: "uuid",
- role: "authenticated" or "anonymous"
- }
- ```
- - Database queries enforce RLS (user-scoped data)
+ - Shares
+ summary: Edit or switch a deploy link on or off
+ description: |
+ Changes the suggested name, the status, or both. An owner can always switch a
+ link off: it works even while deploy links are not available in this
+ environment, and while the owner's account is read-only. Setting
+ `allow_reshare` to false also works in both cases, alone or with a
+ switch-off, since like a switch-off it only shares less; for a read-only
+ account these are the only changes allowed. While deploy links are not
+ available, a request that sends back the values the link already has,
+ including `status` `active` on an active link, changes nothing and answers
+ `200`.
- **With Anon Key** (`public` functions only):
- - Requires anon key permission: `functions.invoke`
- - Function must have `visibility: public`
- - Function receives payload only (no `__volcano_auth`)
-
- **Reserved payload keys:** the top-level `__volcano_auth` and
- `__volcano_http` keys are reserved. Volcano removes caller-supplied
- values for both before the function runs; only an auth user token adds
- a server-built `__volcano_auth`, and only HTTP-mode ingress sets
- `__volcano_http: true`.
+ Switching a link off also stops the installs it started that have not
+ finished, including ones still queued: each fails at its next step. The
+ visitor keeps the project, with its installation failed. Switching the link
+ back on lets only installs that have not failed yet go ahead.
- **Transport and CORS:**
- - This operation is the authenticated direct RPC endpoint and always uses the
- POST `{payload: ...}` contract, including for functions whose DNS ingress is
- configured in HTTP mode.
- - The geo-routed DNS ingress is the function's `invoke_url`. It is on a
- different domain from this API, so it cannot be derived from the API host.
- - RPC-mode DNS ingress accepts POST at `/`. HTTP-mode DNS ingress accepts GET,
- HEAD, POST, PUT, PATCH, and DELETE at `/` and nested paths.
- - Direct and RPC-mode CORS preflight advertises `POST, OPTIONS`. HTTP-mode DNS
- preflight advertises `GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS`.
- - `http_auth_mode: none` applies only to public HTTP-mode DNS ingress; this
- direct operation always requires a Volcano credential.
+ A link Volcano took down (`disabled_reason` `operator`) cannot be switched
+ back on; other edits still work, and it stays down. While any of the
+ project's links is taken down, no link of the project can be switched on or
+ allowed to be re-shared.
- **Durable functions are not invocable here.** A durable function's id
- answers 404, whatever its visibility, because a synchronous call would
- run it with no execution record, no idempotency and no concurrency
- accounting. Start one with
- `POST /durable-functions/{functionId}/executions`.
- operationId: invokeFunction
+ A request that switches the link off together with an edit while deploy links
+ are not available, or that also allows re-sharing on a copy whose source does
+ not allow it, still switches the link off, but answers `400` with code
+ `edit_dropped`: the link is off and the edit was not applied. While the
+ account is read-only, a request that switches the link off or sets
+ `allow_reshare` to false together with another edit is answered the same way:
+ the switch-off and the re-sharing change are saved, and the other edit is not.
+ A `status` the link already has is no edit, so sending the fetched link back
+ with `allow_reshare` false answers `200`; a switch-on is such another edit.
+ operationId: updateShare
security:
- - AnonKey: []
- - ServiceRoleKey: []
- - AuthUserAccessToken: []
+ - UserToken: []
parameters:
- - $ref: '#/components/parameters/FunctionId'
+ - $ref: '#/components/parameters/ShareId'
+ - $ref: '#/components/parameters/ItemProjectIdQuery'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/FunctionInvocationRequest'
- examples:
- serviceCall:
- summary: Admin/background operation (service key)
- value:
- payload:
- action: process_batch
- items:
- - 1
- - 2
- - 3
- userCall:
- summary: User-initiated call (auth token)
- value:
- payload:
- action: get_profile
- anonCall:
- summary: Public function call (anon key)
- value:
- payload:
- action: ping_public_endpoint
+ $ref: '#/components/schemas/ShareUpdateRequest'
responses:
'200':
- description: Function response (passthrough from function runtime)
- headers:
- X-Volcano-Version:
- description: Volcano API/runtime version that served this invocation (`` in production, `-` in non-production)
- schema:
- type: string
- X-Volcano-Region:
- description: Region the function ran in (for example `us-east-1`)
- schema:
- type: string
- X-Volcano-Proxy-Ms:
- description: Milliseconds Volcano spent preparing the invocation, counted from the request arriving until the function was dispatched. Present only when the function was invoked. Does not include function execution.
- schema:
- type: integer
- minimum: 0
- X-Volcano-Proxy-Handler-Ms:
- description: The part of `X-Volcano-Proxy-Ms` spent in the invoke endpoint itself. Subtract it from `X-Volcano-Proxy-Ms` to see what authentication and request validation cost. Present only when the function was invoked.
- schema:
- type: integer
- minimum: 0
- X-Volcano-Compute-Ms:
- description: Milliseconds spent running the function, from dispatch until it returned. Present only when the function was invoked. Does not include proxy preparation.
- schema:
- type: integer
- minimum: 0
+ description: The updated deploy link
content:
application/json:
schema:
- $ref: '#/components/schemas/FunctionInvocationResponse'
+ $ref: '#/components/schemas/Share'
'400':
- description: Bad request - invalid payload or function in failed state
+ description: Malformed request body or an invalid suggested name. Code `feature_unavailable` means deploy links are not available in this environment, so an edit or enabling the link is refused while switching it off still works; code `edit_dropped` means the link was switched off, or for a read-only account its re-sharing turned off, and the other edit sent with it was not saved, including a re-sharing change refused because the project is a copy whose source does not allow re-sharing, or because Volcano took one of the project's links down.
content:
application/json:
schema:
@@ -4291,467 +4268,435 @@ paths:
$ref: '#/components/schemas/Error'
'403':
description: |
- Forbidden - CORS blocked, missing `functions.invoke`, or an anon key
- on an `authenticated` function
+ A project access token was used.
+ A person creates, changes, publishes and deletes deploy links. Also
+ answered when the account is read-only and the request neither switches
+ the link off nor sets `allow_reshare` to false. Code `reshare_not_allowed` means the request switches the
+ link on or sets `allow_reshare` to true, and the project is a copy made from
+ someone else's deploy link that, or a link it was made from in turn, does
+ not allow re-sharing or no longer exists. Code `source_unavailable` means
+ it does so on a copy, and a link the copy was made from is not available
+ to share from right now. Code `operator_disabled` means
+ the request switches on a link Volcano took down
+ (`disabled_reason` `operator`), which only Volcano can lift, or switches
+ on a link or sets `allow_reshare` to true while Volcano has taken any of
+ the project's links down. Switching a link off is always allowed.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: |
- Function not found. Also returned for a `private` function to any
- credential but a service key.
+ description: Project or deploy link not found, or the project is not the caller's
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
- description: |
- Rate limit exceeded (per-function or project-wide limit), or the
- owning platform user's billing-cycle bandwidth allowance (aggregate ingress +
- egress) was exceeded.
+ '500':
+ description: Failed to update the deploy link
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
+ delete:
+ tags:
+ - Shares
+ summary: Delete a deploy link
+ description: |
+ Deletes the link, its releases and its recorded events. The address stops
+ working. Installs the link started that have not finished, including ones
+ still queued, fail at their next step. The visitor keeps the project, with
+ its installation failed. A link Volcano took down (`disabled_reason`
+ `operator`) cannot be deleted until that is lifted; deleting its project
+ still removes it.
+ operationId: deleteShare
+ security:
+ - UserToken: []
+ parameters:
+ - $ref: '#/components/parameters/ShareId'
+ - $ref: '#/components/parameters/ItemProjectIdQuery'
+ responses:
+ '204':
+ description: The deploy link was deleted
+ '400':
description: |
- Function still provisioning or rate limiting service unavailable.
- A freshly deployed (or updated) function may briefly report
- `provisioning` and reject invocations until the background status
- reconciler observes its deployment workflow completing and transitions
- it to `active`. This is expected for a few seconds after deploy; clients
- should retry.
+ `project_id` is malformed, or `project_id` is given and the link id is
+ malformed. Without `project_id`, a malformed link id answers 404, as an
+ unknown link does.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- default:
- description: Function response (passthrough; status code/body/headers come from the function)
- headers:
- X-Volcano-Version:
- description: Volcano API/runtime version that served this invocation (`` in production, `-` in non-production)
- schema:
- type: string
- X-Volcano-Region:
- description: Region the function ran in (for example `us-east-1`)
- schema:
- type: string
- X-Volcano-Proxy-Ms:
- description: Milliseconds Volcano spent preparing the invocation, counted from the request arriving until the function was dispatched. Present only when the function was invoked. Does not include function execution.
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
schema:
- type: integer
- minimum: 0
- X-Volcano-Proxy-Handler-Ms:
- description: The part of `X-Volcano-Proxy-Ms` spent in the invoke endpoint itself. Subtract it from `X-Volcano-Proxy-Ms` to see what authentication and request validation cost. Present only when the function was invoked.
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: |
+ A project access token was used.
+ A person creates, changes, publishes and deletes deploy links. Code
+ `operator_disabled` means Volcano took the link down (`disabled_reason`
+ `operator`), so it is kept until Volcano lifts that.
+ content:
+ application/json:
schema:
- type: integer
- minimum: 0
- X-Volcano-Compute-Ms:
- description: Milliseconds spent running the function, from dispatch until it returned. Present only when the function was invoked. Does not include proxy preparation.
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Project or deploy link not found, or the project is not the caller's
+ content:
+ application/json:
schema:
- type: integer
- minimum: 0
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Failed to delete the deploy link
content:
application/json:
schema:
- $ref: '#/components/schemas/FunctionInvocationResponse'
- /durable-functions/{functionId}/executions:
- post:
+ $ref: '#/components/schemas/Error'
+ /share-release-drafts:
+ get:
tags:
- - Durable Functions
- summary: Start a durable execution from an application
- description: |
- Starts an execution of a durable function using an application
- credential, and returns its handle.
-
- This is the durable counterpart of `POST /functions/{functionId}/invoke`,
- and it is the endpoint an application calls. Like that one, it is not
- project-scoped: an anon key, a service key and an auth user token each
- carry their own project. The project-scoped collection under
- `/projects/{id}/durable-functions/...` remains the owner's management
- surface.
-
- **With a service key:** any durable function in the project.
-
- **With an auth user token:** a durable function whose `visibility` is
- `authenticated` or `public`.
+ - Shares
+ summary: Show what publishing a deploy link would release
+ description: |
+ Builds the project's deployed functions and frontends the way a release
+ would, without storing anything, and reports what it would carry: the
+ functions and frontends, the project variables every project created from
+ the release gets (empty unless the visitor gives a value), the functions
+ whose code reads `VOLCANO_SERVICE_KEY`, and what is left out (resources with
+ no stored source, databases, sandboxes, dotenv and key files). Review it,
+ then publish with its `draft_id`, and its variables and service key
+ functions confirmed.
- **With an anon key:** requires the `functions.invoke` permission, and
- the function must have `visibility: public`.
-
- A `private` durable function answers every credential but a service key
- exactly as a missing one, with 404.
-
- Starting is all this endpoint does. Reading a result or stopping an
- execution requires the project owner's token, because an anon key is
- shared by everyone who loads the page and an execution is addressed by
- id alone.
-
- Send `X-Volcano-Execution-Name` to make the start idempotent: repeating
- a start with the same name returns the existing execution instead of
- beginning a second one.
-
- Each execution counts once against the project's durable execution
- allowance, however many times the start is retried under the same
- execution name, and the number in flight at once is capped by the plan.
- The operations the execution performs are counted against the durable
- operations allowance when it finishes.
- operationId: startDurableExecutionFromApplication
+ Every call runs a full build and counts against the account's hourly
+ release build budget, which drafts and publishes share. Fetch it when the
+ owner opens the publish step, not on every focus or poll.
+ operationId: getShareReleaseDraft
security:
- - AnonKey: []
- - ServiceRoleKey: []
- - AuthUserAccessToken: []
+ - UserToken: []
parameters:
- - $ref: '#/components/parameters/DurableFunctionId'
- - name: X-Volcano-Execution-Name
- in: header
- required: false
- description: |
- Idempotency key for this execution. Generated when omitted. A repeat
- under a name that already names a running execution returns that
- execution and is not charged again.
-
- Letters, digits, `-`, `_` and `.`, up to 255 characters. Anything
- else is rejected with `400`.
- schema:
- type: string
- maxLength: 255
- pattern: ^[A-Za-z0-9._-]+$
- requestBody:
- required: false
- content:
- application/json:
- schema:
- description: Input passed to the function, up to 256 KiB.
+ - $ref: '#/components/parameters/ShareIdQuery'
+ - $ref: '#/components/parameters/ItemProjectIdQuery'
responses:
- '202':
- description: Execution accepted and started
+ '200':
+ description: What a release would carry
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableExecution'
+ $ref: '#/components/schemas/ShareReleaseDraft'
'400':
- description: Payload is not valid JSON, or the execution name is invalid
+ description: |
+ `project_id` is malformed, or `project_id` is given and the link id is
+ malformed. Without `project_id`, a malformed link id answers 404, as an
+ unknown link does.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
- description: |
- Missing or invalid credential. Also returned for a platform user
- token, which is not an application credential; project owners start
- executions through the project-scoped collection.
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: |
- The anon key lacks `functions.invoke` or the function is
- `authenticated`, or the request's origin is refused by the project's
- CORS policy.
+ A project access token was used.
+ A person creates, changes, publishes and deletes deploy links. Code
+ `reshare_not_allowed` means the project is a copy made from someone else's
+ deploy link, and that link, or a link it was made from in turn, does not
+ allow re-sharing or no longer exists. Code `source_unavailable` means the
+ project is a copy, and a link it was made from is not available to share
+ from right now. Code `operator_disabled` means
+ Volcano took one of the project's links down (`disabled_reason`
+ `operator`), so the project cannot be shared until that is lifted.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: |
- Durable function not found. Also returned for a standard function's
- id, for a durable function in another project, and for a `private`
- one to any credential but a service key, so the response cannot be
- used to tell those apart.
+ Project or deploy link not found, or the project is not the caller's, or
+ publishing is not available in this environment (code
+ `feature_unavailable`). A local server without stored
+ source archives cannot publish, even where `GET /capabilities` lists
+ `shares` as available for managing links.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
+ '422':
description: |
- Function is not deployed yet, or has no deployed region. Also
- returned when two starts under the same execution name raced and
- both released it, which is retryable as it stands, and with `code`
- `execution_name_held` when an unfinished start this caller may not
- resume holds the execution name, which needs a name of its own.
+ The project cannot be released as it is: it has no deployed function or
+ frontend with stored source, a function's settings would be refused, it
+ has more than 100 variables a release would carry or more than 100
+ functions reading `VOLCANO_SERVICE_KEY`, or the release would be larger
+ than an install reads.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '413':
- description: Payload is larger than 256 KiB
+ '429':
+ description: |
+ This account started too many release builds this hour (30, drafts and
+ publishes together; code `release_builds_limited`). Try again after
+ `Retry-After`.
+ headers:
+ Retry-After:
+ description: Seconds until the clock hour the budget counts in ends.
+ schema:
+ type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
- description: |
- The project has too many executions in flight for its plan, the
- function invocation rate limit was exceeded, the project is over
- its bandwidth cap, or the account is out of one of its
- billing-cycle durable allowances: executions, operations, or
- compute. Operations and compute are counted once an execution
- finishes, so a refusal on either never interrupts an execution
- already running — it declines the next start.
+ '500':
+ description: Failed to build the release draft
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
description: |
- Durable execution is not available in this environment, or the
- plan terms for the start could not be read. The first means the
- capability is paused or this deployment cannot serve it, so it is
- not one to retry in a loop; the second is transient.
+ Release builds on this server are busy (code `builds_busy`); try again after
+ `Retry-After`.
+ headers:
+ Retry-After:
+ description: Seconds to wait before trying again.
+ schema:
+ type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /durable-functions/{functionId}/executions/{executionId}/messages:
- post:
+ /share-releases:
+ get:
tags:
- - Durable Functions
- summary: Send a message to a durable execution from an application
+ - Shares
+ summary: List a deploy link's releases
description: |
- Sends a named message to a running execution. The workflow receives it
- from `ctx.waitForMessage` with the same name. A message sent before
- anything waits for its name is kept, and each wait takes the oldest
- one, so messages arrive in the order they were sent.
-
- Messages never decide an approval: a workflow waiting in
- `ctx.waitForApproval` is not resumed by one.
-
- **With a service key:** any execution in the project.
-
- **With an auth user token:** an execution the user started, or one
- whose `X-Volcano-Client-Token` the request carries, of a durable
- function whose `visibility` is `authenticated` or `public`.
-
- **With an anon key:** an execution whose `X-Volcano-Client-Token` the
- request carries, of a function with `visibility: public`.
-
- Any other execution answers `404`, as a missing one does.
-
- Send `Idempotency-Key` to make a retry safe: a repeat with a key the
- same sender has used on the execution returns the first message with
- `200` and sends nothing.
- operationId: sendDurableMessageFromApplication
+ Pages the link's releases, newest first. Follow `next_cursor` while
+ `has_more` is true.
+ operationId: listShareReleases
security:
- - AnonKey: []
- - ServiceRoleKey: []
- - AuthUserAccessToken: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/DurableFunctionId'
- - $ref: '#/components/parameters/DurableExecutionId'
- - $ref: '#/components/parameters/DurableMessageIdempotencyKey'
- - $ref: '#/components/parameters/DurableClientToken'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/SendDurableMessageRequest'
+ - $ref: '#/components/parameters/ShareIdQuery'
+ - $ref: '#/components/parameters/ItemProjectIdQuery'
+ - $ref: '#/components/parameters/Limit'
+ - $ref: '#/components/parameters/ShareReleaseCursor'
responses:
'200':
- description: A message with this `Idempotency-Key` was already sent; it is returned
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DurableMessage'
- '201':
- description: |
- Message sent. `status` is `delivered` when a wait took it at once,
- `delivering` when a wait took it and the handover is still being
- confirmed, and `queued` when it is kept for the next wait.
+ description: A page of the link's releases
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableMessage'
+ $ref: '#/components/schemas/PaginatedShareReleases'
'400':
- description: The name, data or idempotency key is invalid
+ description: |
+ `project_id` is malformed, or `project_id` is given and the link id is
+ malformed, or `limit` or `cursor` is invalid, such as a cursor issued for
+ another share or page size. Without `project_id`, a malformed link id
+ answers 404, as an unknown link does.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
- description: Missing or invalid credential
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '403':
- description: |
- The anon key lacks `functions.invoke`, the service key is scoped
- without it, or the function is `authenticated` and the request
- carries an anon key. Also returned when the request's origin is
- refused by the project's CORS policy.
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: |
- Durable function or execution not found, or the credential cannot
- reach the execution. A `private` function answers every credential
- but a service key this way.
+ description: Project or deploy link not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: |
- The message cannot be sent. `code` says why:
-
- - `execution_not_running`: the execution has finished.
- - `too_many_queued_messages`: the execution already holds the
- maximum number of messages nothing has taken.
+ '500':
+ description: Failed to list the deploy link's releases
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '413':
- description: The request body is larger than 72 KiB
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '429':
- description: |
- Too many messages sent to this execution, the function's or the
- project's function rate limit, which sends share with invocations
- and starts, or the project is over its bandwidth cap.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '503':
- description: The plan terms for the request could not be read. Retry with backoff.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- get:
+ post:
tags:
- - Durable Functions
- summary: List a durable execution's messages from an application
+ - Shares
+ summary: Publish a deploy link release
description: |
- Lists the messages sent to and published by an execution, oldest
- first. Pass the last `seq` you read as `after` to read only what came
- next; that is how a client catches up after a live subscription
- reconnects.
+ Snapshots the project's deployed functions and frontends into an immutable
+ release and makes it the link's current release in one step, so visitors see
+ either the previous release or this one. Visitors install exactly the stored
+ release; later deploys to the project change nothing until the owner
+ publishes again.
- Access follows the same rules as sending.
- operationId: listDurableMessagesFromApplication
+ Send the reviewed draft's `draft_id`, its variables and the functions that
+ receive the new project's `VOLCANO_SERVICE_KEY`, as confirmed from the
+ draft. Both lists must be exactly the draft's: a release carries every
+ variable, since leaving one out would only break the code that reads it. If
+ a fresh build is not the reviewed draft, because the project was redeployed
+ or changed since, or the lists differ from it, nothing is published and the
+ answer is `409` with code `draft_changed` and the new draft. A
+ release carries variable names, never values, and no database. A publish is
+ a full build and counts against the account's hourly release build budget,
+ which it shares with the draft.
+ operationId: publishShareRelease
security:
- - AnonKey: []
- - ServiceRoleKey: []
- - AuthUserAccessToken: []
- parameters:
- - $ref: '#/components/parameters/DurableFunctionId'
- - $ref: '#/components/parameters/DurableExecutionId'
- - $ref: '#/components/parameters/DurableClientToken'
- - $ref: '#/components/parameters/DurableMessageDirectionFilter'
- - $ref: '#/components/parameters/DurableMessageNameFilter'
- - $ref: '#/components/parameters/DurableMessageAfter'
- - $ref: '#/components/parameters/DurableMessageLimit'
+ - UserToken: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ShareReleaseCreateRequest'
responses:
- '200':
- description: Successful response
+ '201':
+ description: The published release, now the link's current release
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableMessageList'
+ $ref: '#/components/schemas/ShareRelease'
'400':
- description: A filter is invalid
+ description: |
+ The body names an existing link but is otherwise malformed, such as an
+ unknown field or a `variables` entry of the wrong type. A body that is not
+ JSON, or whose `share_id` is missing or malformed, answers 404, as an
+ unknown link does.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
- description: Missing or invalid credential
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: |
- The anon key lacks `functions.invoke`, the service key is scoped
- without it, or the function is `authenticated` and the request
- carries an anon key. Also returned when the request's origin is
- refused by the project's CORS policy.
+ A project access token was used.
+ A person creates, changes, publishes and deletes deploy links. Code
+ `reshare_not_allowed` means the project is a copy made from someone else's
+ deploy link, and that link, or a link it was made from in turn, does not
+ allow re-sharing or no longer exists. Code `source_unavailable` means the
+ project is a copy, and a link it was made from is not available to share
+ from right now. Code `operator_disabled` means
+ Volcano took one of the project's links down (`disabled_reason`
+ `operator`), so the project cannot be shared until that is lifted.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: |
- Durable function or execution not found, or the credential cannot
- reach the execution.
+ Project or deploy link not found, including a body that names no
+ well-formed `share_id`, or the project is not the caller's, or publishing
+ is not available in this environment (code `feature_unavailable`). A local server without stored
+ source archives cannot publish, even where `GET /capabilities` lists
+ `shares` as available for managing links.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: |
+ What was confirmed does not match a fresh build of the project (code
+ `draft_changed`). The body carries the fresh draft in `draft`; review it
+ and publish again. `error` names the confirmed variables the draft does
+ not have, the draft variables left out, or the service key functions the
+ draft expects. It says the
+ project changed when the confirmation matches the fresh draft but its
+ `draft_id` is not the one sent: the project changed since the draft was
+ reviewed, or while the release was being built.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ShareDraftChangedError'
+ '422':
+ description: |
+ The project cannot be released as it is: it has no deployed function or
+ frontend with stored source, a function's settings would be refused, it
+ has more than 100 variables a release would carry or more than 100
+ functions reading `VOLCANO_SERVICE_KEY`, or the release would be larger
+ than an install reads.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: |
- The function's or the project's function rate limit, which lists
- share with invocations and starts, or the project is over its
- bandwidth cap.
+ This account started too many release builds this hour (30, drafts and
+ publishes together; code `release_builds_limited`). Try again after
+ `Retry-After`.
+ headers:
+ Retry-After:
+ description: Seconds until the clock hour the budget counts in ends.
+ schema:
+ type: integer
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Failed to publish the release
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
- description: The plan terms for the request could not be read. Retry with backoff.
+ description: |
+ Release builds on this server are busy (code `builds_busy`); try again after
+ `Retry-After`.
+ headers:
+ Retry-After:
+ description: Seconds to wait before trying again.
+ schema:
+ type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /functions/resolve:
+ /share-stats:
get:
tags:
- - Functions
- summary: Resolve function name for invocation
+ - Shares
+ summary: Get a deploy link's click and deploy counts
description: |
- Resolves a DNS-safe function name to its function ID and invocation URL within the caller's project.
-
- SDKs use this endpoint internally to invoke by function name while routing by function ID.
- Invoke the returned `invoke_url` as-is. It does not share a domain with the API, so a host
- built from the API URL will not reach the function. When the deployment serves no public
- invocation domain, as in local development, `invoke_url` is omitted and callers invoke
- through `POST /functions/{functionId}/invoke`.
-
- **With Service Key**:
- - Allowed
-
- **With Auth User Token**:
- - Allowed for `authenticated` and `public` functions
- - A `private` function answers 404, exactly as a missing one
-
- **With Anon Key**:
- - Requires anon key permission: `functions.invoke`
- - Function must have `visibility: public`; any other answers 404
- operationId: resolveFunctionForInvocation
+ Counts what happened at the link: clicks, previews, confirmations, projects
+ created, and how many became ready or failed. Informational only. Visitors
+ are counted from a salted hash and no address is stored. Events are kept
+ for 90 days, so a `days` above 90 is rejected with `400`.
+ operationId: getShareStats
security:
- - AnonKey: []
- - ServiceRoleKey: []
- - AuthUserAccessToken: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - name: name
+ - $ref: '#/components/parameters/ShareIdQuery'
+ - $ref: '#/components/parameters/ItemProjectIdQuery'
+ - name: days
in: query
- required: true
+ required: false
+ description: How many days back to count. Defaults to 30.
schema:
- type: string
- maxLength: 63
- pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$
- description: DNS-safe function name (lowercase letters, numbers, hyphens; cannot start or end with hyphen)
- example: my-function
+ type: integer
+ minimum: 1
+ maximum: 90
+ default: 30
responses:
'200':
- description: Function resolved successfully
+ description: The link's event counts
content:
application/json:
schema:
- $ref: '#/components/schemas/ResolveFunctionResponse'
+ $ref: '#/components/schemas/ShareStats'
'400':
- description: Bad request - missing or invalid function name
+ description: |
+ `days` is outside 1 to 90, `project_id` is malformed, or `project_id` is
+ given and the link id is malformed. Without `project_id`, a malformed link
+ id answers 404, as an unknown link does.
content:
application/json:
schema:
@@ -4762,210 +4707,228 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: |
- Forbidden - CORS blocked, or missing `functions.invoke` permission
- for anon key
+ '404':
+ description: Project or deploy link not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: |
- Function not found. Also returned for a `private` function with an
- auth user token, and a non-public one with an anon key. A durable
- function is never resolvable here: it is started through
- `POST /durable-functions/{functionId}/executions`, not invoked.
+ '500':
+ description: Failed to get the deploy link stats
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/logs/activity:
+ /forks:
post:
tags:
- - Logs
- summary: Get project log activity
+ - Forks
+ summary: Fork a share into a project of your own
description: |
- Retrieve bucketed log counts for one resource type in the project. Set
- `resource.type` to `function`, `frontend`, or `database`. Add
- `resource.ids` to filter to one or more resources, and add
- `resource.deployments.ids` to count deployment logs instead of runtime
- logs for functions and frontends. Deployment logs are not supported for
- databases. Database logs are a SUPERAGENT feature; `resource.type=database`
- from a HOBBY project owner returns 403. The activity window is limited
- to the plan's retention window (HOBBY: 1 day, SUPERAGENT: 30 days); older start
- times are clamped to that window. Buckets are aligned to UTC clock
- intervals and count events in the half-open window
- `[start_time, end_time)`.
- operationId: getProjectLogActivity
+ Creates a project in the caller's account from the release a share offers,
+ and queues its install: the release's functions and frontends, never the
+ owner's data, variable values, keys or sign-in settings. Every variable the
+ release declares is created; one the visitor gives no value for is created
+ empty. Installation is asynchronous: poll the project until
+ `template_installation.status` is `ready`. A `201` without
+ `template_installation` means nothing is being installed.
+
+ The fork is checked against what the release recorded when it was published
+ (its functions, frontends and variables, and the plan's room for them); the
+ release's archive is read and checked by the install. A stored archive that
+ fails those checks fails the install with `failure_code` `source_invalid`
+ rather than refusing the request.
+
+ Send the `release_id` that `GET /share-previews/{share_id}` returned. If the
+ share moved to a new release since, nothing is created and the answer is
+ `409` with code `release_changed`.
+ operationId: createFork
security:
- UserToken: []
- - ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
+ - name: Idempotency-Key
+ in: header
+ required: false
+ description: |
+ Makes a fork safe to retry. A repeat with the same key from the same
+ account answers `201` with the project the first request created, without
+ confirming, counting or creating anything again. Reusing a key for a
+ different request (another name, share, release or set of variable names
+ with a value) answers `409` with code `idempotency_key_reused`. Variable
+ values are not compared. The key is kept as long as the project exists.
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 255
+ pattern: ^[!-~]+$
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/LogActivityRequest'
+ $ref: '#/components/schemas/ForkCreateRequest'
responses:
- '200':
- description: Successful response
+ '201':
+ description: The project was created and its install queued
content:
application/json:
schema:
- $ref: '#/components/schemas/LogActivityResponse'
+ $ref: '#/components/schemas/Project'
'400':
- description: Bad request - invalid query parameter
+ description: The request body is malformed.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
- description: Unauthorized - invalid or missing token
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Forbidden - project ownership required
+ description: |
+ The release would exceed the plan's limits for frontends and functions, or the
+ account may not create projects. Code `proxy_credential_rejected` means the
+ request carried the dashboard proxy's visitor headers without a valid proof
+ from the proxy; it is never about the caller's session.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Project or resource not found
+ description: |
+ The share is not available. It does not exist, was switched off, has not
+ been published, or is a copy whose source no longer allows re-sharing. Code
+ `feature_unavailable` means forks are not available in this environment (see
+ `GET /capabilities`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/logs/search:
- post:
- tags:
- - Logs
- summary: Search project logs
- description: |
- Search or filter logs for one resource type in the project. Set
- `resource.type` to `function`, `frontend`, or `database`. Add
- `resource.ids` to filter to one or more resources, and add
- `resource.deployments.ids` to read deployment logs instead of runtime
- logs for functions and frontends. Deployment logs are not supported for
- databases. Database logs are a SUPERAGENT feature; requests for
- `resource.type=database` from a HOBBY project owner return 403.
- Log history (runtime and deployment) is limited to the plan's retention
- window (HOBBY: 1 day, SUPERAGENT: 30 days); older time ranges are clamped to that
- window.
- operationId: searchProjectLogs
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/LogSearchRequest'
- responses:
- '200':
- description: Successful response
+ '409':
+ description: |
+ The share has a new release since the preview (code `release_changed`): fetch
+ the preview again and confirm the new release. Code `idempotency_key_reused`:
+ the `Idempotency-Key` was already used for a different request. Code
+ `request_in_progress`: the first request with this `Idempotency-Key` has made
+ its project but not yet queued the install; retry after `Retry-After`, and the
+ retry answers that project once it is settled. A project name you already use
+ is not a conflict: the project is created under that name with a short random
+ suffix added. Only when no free suffixed name is found after a few tries does
+ the request answer `409`.
+ headers:
+ Retry-After:
+ description: Seconds to wait before retrying (code `request_in_progress`). Absent otherwise.
+ schema:
+ type: integer
content:
application/json:
schema:
- $ref: '#/components/schemas/LogSearchResponse'
- '400':
- description: Bad request - invalid query parameter
+ $ref: '#/components/schemas/Error'
+ '422':
+ description: |
+ The release cannot be installed as it is, or `variables` names a variable the
+ release does not declare (code `variable_not_declared`). A variable left out,
+ or sent empty, is created empty. The message names the variables, never their
+ values. Code `variables_required` means the release declares variables Volcano
+ could not set up; ask the person who shared it to share it again.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
+ '429':
+ description: Too many forks (20 an hour) from this account; try again after `Retry-After`
+ headers:
+ Retry-After:
+ description: Seconds until the clock hour the limit counts in ends.
+ schema:
+ type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Forbidden - project ownership required
+ '451':
+ description: Volcano cannot serve requests from the visitor's location under US sanctions (a fork confirmed through the dashboard)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Project or resource not found
+ '500':
+ description: Failed to create the project from the deploy link
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/logs/stream:
- post:
+ '503':
+ description: |
+ Durable functions are paused (code `feature_paused`, with a `Retry-After`
+ header) and the release has a durable function. Code `service_unavailable`
+ means the dashboard proxy's own project is not being served right now. Code
+ `rate_limit_unavailable` means Volcano cannot count forks right now; retry
+ after `Retry-After`.
+ headers:
+ Retry-After:
+ description: Seconds until durable functions may be back (code `feature_paused`), or a short wait while forks cannot be counted (code `rate_limit_unavailable`). Absent otherwise.
+ schema:
+ type: integer
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/git-connection/production-branch:
+ put:
tags:
- - Logs
- summary: Stream project logs
+ - Projects
+ - Git Connections
+ summary: Set the branch a project deploys from
description: |
- Live-tail project logs as Server-Sent Events. The request body uses the
- resource selector plus `q`, `start_time`, and `limit`,
- including runtime logs and function/frontend deployment logs selected
- with `resource.deployments`. Deployment logs are not supported for
- databases. Database logs are a SUPERAGENT feature; `resource.type=database`
- from a HOBBY project owner returns 403. The `q` field uses the same
- syntax as search and activity requests. Do not send `cursor` or
- `end_time`; use `/logs/search` for range backfills.
- Explicit historical `start_time` values are limited to the plan's
- retention window (HOBBY: 1 day, SUPERAGENT: 30 days). Resume with
- `Last-Event-ID` or the `last_event_id` query parameter. The cursor is
- bound to the request body: the resource selector and every filter must
- match the original request when reconnecting, otherwise the request is
- rejected with `400`.
+ Changes only the production branch, leaving the repository binding
+ alone. PUT /projects/{id}/git-connection can also set it, but that is a
+ full rebind: it needs connection_id, installation_id and a repository
+ selector resent, and re-resolves the repository against GitHub for a
+ field that does not depend on it.
- This is a live tail, not a gap-free backfill. On connect or reconnect the
- server delivers at most `limit` of the most recent matching events from
- the cursor position and then follows new events; events older than that
- window are not replayed. Use `/logs/search` to backfill a time range.
- operationId: streamProjectLogs
+ The branch does not have to exist. It is validated as a Git branch name
+ and nothing more, so a project can be pointed at a branch that is about
+ to be pushed — the case a repository created empty depends on.
+
+ Setting the branch here marks it as the project's own choice, so a later
+ default-branch rename on GitHub no longer moves it, and the response
+ reports `production_branch_follows_default: false`. Projects that never
+ set one keep following the repository's default branch.
+
+ An empty string undoes that choice: the project deploys from the
+ repository's default branch again and follows later renames. Volcano
+ reads the default branch from GitHub through the project owner's
+ connection, and the response carries it with
+ `production_branch_follows_default: true`.
+ operationId: setProjectGitProductionBranch
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - name: Last-Event-ID
- in: header
- required: false
- schema:
- type: string
- description: Opaque stream cursor from the most recent SSE `id` field.
- - name: last_event_id
- in: query
- required: false
- schema:
- type: string
- description: Opaque stream cursor fallback when setting `Last-Event-ID` is not practical.
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/LogStreamRequest'
+ $ref: '#/components/schemas/SetProjectGitProductionBranchRequest'
responses:
'200':
- description: Server-Sent Events stream. `log` events contain a JSON `LogSearchEvent`; `warning` events contain a JSON object with an `error` field.
+ description: The project's repo connection, with the new branch
content:
- text/event-stream:
+ application/json:
schema:
- type: string
- examples:
- log:
- summary: Log event
- value: |
- : connected
-
- id: STREAM_CURSOR
- event: log
- data: {"id":"LOG_EVENT_ID","timestamp":"2024-01-01T12:00:00Z","level":"info","message":"User logged in","resource":{"type":"function","id":"550e8400-e29b-41d4-a716-446655440000","name":"login"},"region":"us-east-1"}
+ $ref: '#/components/schemas/ProjectGitConnection'
'400':
- description: Bad request - invalid selector, stream cursor, or unsupported stream field
+ description: |
+ Malformed request body, a production_branch that is not a valid
+ Git branch name, or an empty one for a repository with no commits
+ yet. Code `feature_unavailable` means this Volcano deployment has
+ no GitHub integration, so an empty production_branch cannot read
+ the default branch.
content:
application/json:
schema:
@@ -4977,41 +4940,58 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Forbidden - project ownership required
+ description: Project not owned by the caller
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Project or resource not found
+ description: |
+ Project not found, or it has no repository connected. The branch is
+ part of the connection, so there is nothing to set it on until one
+ exists.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: |
+ A Git source transition is pending, or an empty production_branch
+ could not read the default branch because the project owner's
+ GitHub connection needs reconnecting or lost access to the
+ repository
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '429':
+ description: GitHub rate limited reading the default branch for an empty production_branch. Try again shortly.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
- description: Internal server error - log streaming setup failed
+ description: Failed to set the production branch
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/functions/batch:
- post:
+ /projects/{id}/git-connection/root-directory:
+ put:
tags:
- - Functions
- summary: Deploy multiple functions in one request
+ - Projects
+ - Git Connections
+ summary: Set the directory a project builds from
description: |
- Upload multiple function source archives in one multipart request. Each archive should contain source files
- plus dependency manifests/lockfiles, not installed dependency directories. ZIP and tar.gz uploads are
- accepted and normalized to tar.gz before storage. The API enforces `SOURCE_ARCHIVE_SIZE_LIMIT_MB`
- for each uploaded and normalized source archive. The server records a shared
- deployment batch ID for the resulting function deployments. Each function deployment runs its own
- compile/publish workflow concurrently, and each publish build enforces `LAMBDA_TARGET_CONTAINER_SIZE_LIMIT_MB`
- for the final container image.
- One batch request can include up to 100 functions. Submit multiple batch requests for larger projects.
- If one function fails before its workflow starts, already-started function deployments are left
- running and the failed function is reported in the `failed` array. Failed new functions are deleted;
- failed updates are rolled back to their previous metadata/status where possible.
- operationId: createFunctionsBatch
+ Changes only the root directory, leaving the repository, the production
+ branch and `production_branch_follows_default` alone. Unlike PUT /projects/{id}/git-connection, this accepts a
+ project access token, so CI or an agent can move a project within its
+ repository without being able to change the repository.
+
+ The directory is a path relative to the repository root. An empty
+ string, `.` or `/` means the repository root. The response carries it in
+ the form a deploy reads it: `./apps/web/` comes back as `apps/web`.
+ operationId: setProjectGitRootDirectory
security:
- UserToken: []
- ProjectAccessToken: []
@@ -5020,323 +5000,447 @@ paths:
requestBody:
required: true
content:
- multipart/form-data:
+ application/json:
schema:
- type: object
- properties:
- functions:
- type: string
- description: |
- JSON array of functions with `name`, `runtime`, optional `handler`, and `file_field`. Each `file_field` must name a multipart file field containing that function's ZIP or tar.gz source bundle.
-
- Each entry may also declare `variable_scope` (`all` or `scoped`) and `variables` (an array of project variable names). Omitting them leaves the function's stored declaration unchanged. Volcano detects direct environment references in the uploaded source code and keeps them separate from the declared names: detected names are not written back to the declaration and do not appear in a config export. A scoped function receives its declared names plus the detected ones the project defines; a detected name the project does not define is ignored, since such a reference is often optional. Detection reads code only, so a name appearing solely in a comment or in an unrelated string is not a reference. Declare a name when the function reads it through a computed key, or when it must not deploy without the variable. The request is rejected with 400 before anything is deployed if a scoped function declares a variable the project does not define, or if the resulting environment exceeds 4096 bytes.
- code_0:
- type: string
- format: binary
- description: Function ZIP or tar.gz archive referenced by the first manifest entry's `file_field`; additional code_N file fields may be included. Each archive is subject to SOURCE_ARCHIVE_SIZE_LIMIT_MB.
- required:
- - functions
+ $ref: '#/components/schemas/SetProjectGitRootDirectoryRequest'
responses:
- '202':
- description: Batch deployment accepted
+ '200':
+ description: The project's repo connection, with the new root directory
content:
application/json:
schema:
- $ref: '#/components/schemas/BatchFunctionDeployResponse'
- '207':
- description: Batch deployment partially accepted; successful functions started deployment and failed functions were compensated where possible
+ $ref: '#/components/schemas/ProjectGitConnection'
+ '400':
+ description: |
+ Malformed request body, or a root_directory that is absolute or
+ leaves the repository
content:
application/json:
schema:
- $ref: '#/components/schemas/BatchFunctionDeployResponse'
- '400':
- description: Bad request
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Function limit exceeded for the project
+ description: Project not owned by the caller
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
+ '404':
description: |
- A name in the batch is held by a function of the other kind — a
- function cannot change kind — or the project's source is managed by
- Git, where deploys come from a push to the production branch.
+ Project not found, or it has no repository connected. The root
+ directory is part of the connection, so there is nothing to set it
+ on until one exists.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
+ '409':
description: |
- The owner's billing-cycle build-minutes allowance is spent. The
- error names the allowance and carries a link to the usage page.
+ A Git source transition is pending or complete, so the recorded
+ root cannot be changed
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: |
- Build usage could not be read, so the allowance could not be
- checked. The same request succeeds once it can be.
+ '500':
+ description: Failed to set the root directory
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/schedulers:
+ /projects/{id}/git-connection/owner-push:
get:
tags:
- - Functions
- summary: List every function scheduler in a project
+ - Projects
+ - Git Connections
+ summary: Check whether the project owner can push to the connected repository
description: |
- Project-scoped counterpart to `/projects/{id}/functions/{functionId}/schedulers`.
- Returns schedulers across all functions in the project, ordered by
- creation time descending, with standard page/limit pagination so
- clients don't have to fan out one request per function.
+ Answers whether the project owner's GitHub account can push to the
+ repository the project is connected to. Volcano makes the same check
+ before it writes to that repository for the project. The repository is
+ always the project's connected one; the route takes no repository.
- Schedulers of standard and durable functions are listed together, and
- each carries `function_kind`. Pass `function_kind` to list one kind
- only.
- operationId: listProjectSchedulers
+ When `can_push` is false, `reason` says why. The answer can be a few
+ seconds old: repeated checks within that time are answered without
+ asking GitHub again.
+
+ Checks that ask GitHub draw on an hourly budget for the project and
+ another for its owner, shared by all of the owner's projects. Over
+ either, the route answers `429` with `Retry-After`.
+ operationId: getProjectGitOwnerPush
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/Page'
- - $ref: '#/components/parameters/Limit'
- - $ref: '#/components/parameters/Cursor'
- - $ref: '#/components/parameters/EndingBefore'
- - $ref: '#/components/parameters/Offset'
- - $ref: '#/components/parameters/Search'
- - $ref: '#/components/parameters/FunctionKindFilter'
responses:
'200':
- description: Project schedulers
+ description: Whether the project owner can push to the connected repository
content:
application/json:
schema:
- $ref: '#/components/schemas/FunctionSchedulerListResponse'
- '400':
- description: Bad request - invalid pagination or filter
+ $ref: '#/components/schemas/ProjectGitOwnerPush'
+ '401':
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/functions/{functionId}/schedulers:
- get:
- tags:
- - Functions
- summary: List schedulers for a function
- operationId: listFunctionSchedulers
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/FunctionId'
- responses:
- '200':
- description: Function schedulers
+ '403':
+ description: Project not owned by the caller
content:
application/json:
schema:
- $ref: '#/components/schemas/FunctionSchedulerListResponse'
+ $ref: '#/components/schemas/Error'
'404':
- description: Function not found
+ description: |
+ Project not found, or has no repo connection. Code
+ `feature_unavailable` when this deployment has no Git provider
+ integration.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- post:
- tags:
- - Functions
- summary: Create a scheduler for a function
- description: Creates regional scheduled invocation jobs. Requested regions must be a subset of the function's deployed regions.
- operationId: createFunctionScheduler
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/FunctionId'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/CreateFunctionSchedulerRequest'
- responses:
- '201':
- description: Scheduler created
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/FunctionScheduler'
- '400':
+ '429':
description: |
- Invalid schedule, geofenced region, a scheduler of this name
- already exists on the function, or the function is not active.
+ The project, or its owner across their projects, used up the
+ hour's checks that ask GitHub. Try again after `Retry-After`.
+ headers:
+ Retry-After:
+ description: Seconds until the budget's hour ends.
+ schema:
+ type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: |
- Schedulers are not available on this plan, or the project already
- holds as many as the plan allows. The cap counts standard and
- durable function schedulers together.
+ '500':
+ description: Failed to check the project owner's access
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Function not found
+ '503':
+ description: |
+ The check could not be answered now: GitHub did not answer or is
+ rate limiting the owner's account, or Volcano could not read the
+ budget. Try again after `Retry-After`.
+ headers:
+ Retry-After:
+ description: Seconds to wait before checking again.
+ schema:
+ type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/functions/{functionId}/schedulers/{schedulerId}:
+ /projects/{id}/git-connection:
get:
tags:
- - Functions
- summary: Get a function scheduler
- operationId: getFunctionScheduler
+ - Projects
+ - Git Connections
+ summary: Get a project's repo connection
+ description: |
+ Returns the repository binding. `production_branch_follows_default`
+ tells a branch that tracks the repository's default from one the
+ project pinned: a client rebinding the same repository sends a pinned
+ branch back to keep it.
+ operationId: getProjectGitConnection
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/FunctionId'
- - $ref: '#/components/parameters/SchedulerId'
responses:
'200':
- description: Function scheduler
+ description: The project's current repo connection
content:
application/json:
schema:
- $ref: '#/components/schemas/FunctionScheduler'
+ $ref: '#/components/schemas/ProjectGitConnection'
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Project not owned by the caller
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'404':
- description: Function or scheduler not found
+ description: Project not found, or has no repo connection
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- patch:
+ '500':
+ description: Failed to get project git connection
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ put:
tags:
- - Functions
- summary: Update a function scheduler
- operationId: updateFunctionScheduler
+ - Projects
+ - Git Connections
+ summary: Connect or update a project's repo connection
+ description: |
+ Full replace, following Vercel's model: many projects may point at the
+ same repo, so this only binds the project — it never creates or
+ deletes git-provider state. Used for both the initial connect and
+ later edits (repo change, root directory, production branch).
+ Resolves the repository_id or repo_full_name selector against the repos
+ accessible through installation_id via connection_id's stored GitHub
+ user token, then persists repository metadata only from that validated
+ GitHub response.
+
+ Omitting production_branch follows the repository's default and
+ discards a pinned branch. To keep a pin when rebinding the same
+ repository, read the connection first and send production_branch back
+ when `production_branch_follows_default` is false. The response reports
+ the result in the same field.
+
+ Project access tokens are refused. Which repository a project deploys
+ from is a person's decision, made with a platform token or in the
+ dashboard. A project access token can still change the root directory
+ and production branch through PUT
+ /projects/{id}/git-connection/root-directory and PUT
+ /projects/{id}/git-connection/production-branch.
+
+ Connecting a repository to a project with none, while LavaFlow is on
+ and was turned on with no repository, makes it the one LavaFlow works
+ in, unless the LavaFlow settings' `fix_blocker` asks to turn it on
+ again after the link. Any later change of repository pauses LavaFlow until the owner
+ turns it on again; binding the repository LavaFlow works in again
+ resumes it with no new turn-on.
+ operationId: connectProjectGit
security:
- UserToken: []
- - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/FunctionId'
- - $ref: '#/components/parameters/SchedulerId'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/UpdateFunctionSchedulerRequest'
+ $ref: '#/components/schemas/ConnectProjectGitRequest'
responses:
'200':
- description: Scheduler updated
+ description: The project's repo connection
content:
application/json:
schema:
- $ref: '#/components/schemas/FunctionScheduler'
+ $ref: '#/components/schemas/ProjectGitConnection'
'400':
description: |
- Invalid schedule, geofenced region, or a scheduler of this name
- already exists on the function.
+ Malformed request body, no repository selector, selectors that
+ identify different repositories, a production_branch that is not a
+ valid Git branch name, no production_branch on a repository with no
+ default branch to follow (name one to connect a repository that has
+ no commits yet), or a production_branch other than the new
+ repository's default in a request that also changes repository
+ (a repository that reports no default branch accepts any branch).
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: |
+ Project not owned by the caller, the selected repository is not
+ accessible through installation_id, or the request used a project
+ access token or came through MCP. A full-scope token, and MCP, get
+ `project access tokens cannot change a project's repository; a
+ person changes it in the dashboard or with a platform token`, and a
+ read-only token gets `project access token is read-only`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Function or scheduler not found
+ description: Project or connection not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: |
+ A Git source transition is pending or complete, so the recorded
+ repository and root cannot be changed
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Failed to connect project git
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Git provider integration is not configured
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
tags:
- - Functions
- summary: Delete a function scheduler
- operationId: deleteFunctionScheduler
+ - Projects
+ - Git Connections
+ summary: Disconnect a project's repo connection
+ operationId: disconnectProjectGit
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/FunctionId'
- - $ref: '#/components/parameters/SchedulerId'
responses:
'204':
- description: Scheduler deleted
+ description: Connection removed
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Project not owned by the caller
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'404':
- description: Function or scheduler not found
+ description: Project not found, or has no repo connection
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/functions/{functionId}/deployments:
+ '409':
+ description: |
+ A Git source transition is pending or complete, so the recorded
+ repository cannot be disconnected
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Failed to disconnect project git
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/git-deploy-settings:
get:
tags:
- - Functions
- summary: List function deployments
- operationId: listFunctionDeployments
+ - Projects
+ - Git Connections
+ summary: Get a project's Git auto-deploy settings
+ operationId: getProjectGitDeploySettings
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/FunctionId'
- - $ref: '#/components/parameters/Page'
- - $ref: '#/components/parameters/Limit'
responses:
'200':
- description: Successful response
+ description: The project's current Git auto-deploy settings
content:
application/json:
schema:
- $ref: '#/components/schemas/PaginatedFunctionDeployments'
+ $ref: '#/components/schemas/ProjectGitDeploySettings'
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Project not owned by the caller
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'404':
- description: Function not found
+ description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/durable-functions:
- get:
+ '500':
+ description: Failed to get project git deploy settings
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ put:
tags:
- - Durable Functions
- summary: List all durable functions in a project
+ - Projects
+ - Git Connections
+ summary: Update a project's Git auto-deploy settings
description: |
- Standard functions never appear here, and durable functions never appear
- under `/projects/{id}/functions`. The two are separate collections.
- operationId: listDurableFunctions
+ Full replace of the project's Git auto-deploy settings: what a push to
+ the connected repo's production branch deploys.
+
+ Connecting a repository sets auto_deploy_enabled and deploy_functions
+ to true for a project that has never called this endpoint, so a push
+ deploys without any further setup. Once these settings have been saved
+ here they are the project's own: connecting, rebinding, disconnecting
+ and reconnecting all leave them untouched, including when they were
+ saved before any repository was connected. Frontend settings are off
+ until set here; the frontend need not exist when they are saved, since
+ frontend_name is resolved at deploy time.
+
+ apply_migrations is the exception to the full replace: omitting it
+ leaves the saved value unchanged. It is off until set here.
+ operationId: updateProjectGitDeploySettings
security:
- UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/Page'
- - $ref: '#/components/parameters/Limit'
- - $ref: '#/components/parameters/Search'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateProjectGitDeploySettingsRequest'
responses:
'200':
- description: Successful response
+ description: The project's updated Git auto-deploy settings
content:
application/json:
schema:
- $ref: '#/components/schemas/PaginatedDurableFunctions'
+ $ref: '#/components/schemas/ProjectGitDeploySettings'
'400':
- description: Bad request - invalid pagination parameters
+ description: |
+ Malformed request body, frontend_app_root without frontend_name, or
+ apply_migrations set to true where database migrations are not
+ available (code `feature_unavailable`)
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Project not owned by the caller
content:
application/json:
schema:
@@ -5347,1312 +5451,1498 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
- post:
+ '409':
+ description: |
+ A Git source transition is pending, or this change would remove
+ deploy coverage after Git has taken over
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Failed to update project git deploy settings
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/git-deployment-runs:
+ get:
tags:
- - Durable Functions
- summary: Create or update a durable function
+ - Projects
+ - Git Connections
+ summary: List a project's Git deployment runs
description: |
- Upload a durable function source bundle. Creates the function on the
- first call for a name and redeploys it on every call after that, the
- same create-or-update contract `POST /projects/{id}/functions` has.
+ Lists the deployment runs Git auto deploy recorded for the project,
+ newest push first. Each push to the production branch records one run,
+ which says whether the push deployed and, when it failed or was
+ skipped, why.
- Volcano builds and deploys asynchronously. A deployment that starts
- immediately returns `status: provisioning`, then transitions to `active`
- or `failed`; a deployment that has to wait for a running one is exposed
- through `pending_deployment_id`. Existing executions keep running
- against the runtime they started on.
+ A run that applied migrations names the migration run it started on
+ each database. Get one at
+ `GET /projects/{id}/databases/{databaseName}/migration-runs/{runId}`
+ for its files.
- The `durable` configuration is derived from the project's plan rather
- than supplied here, and is fixed once the function exists. A name
- already held by a standard function is rejected with 409: a function
- cannot change kind.
- operationId: createDurableFunction
+ Project access tokens can list runs, including read-only ones.
+ operationId: listGitDeploymentRuns
security:
- UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- requestBody:
- required: true
- content:
- multipart/form-data:
- schema:
- type: object
- required:
- - name
- - code
- - runtime
- properties:
- name:
- type: string
- description: DNS-safe function name (lowercase letters, numbers, hyphens; cannot start or end with hyphen)
- maxLength: 63
- pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$
- example: order-pipeline
- code:
- type: string
- format: binary
- description: ZIP or tar.gz archive containing function source code plus dependency manifests/lockfiles.
- runtime:
- type: string
- enum:
- - nodejs22.x
- - nodejs24.x
- - python3.13
- - python3.14
- description: |
- Runtime environment. Required. Durable execution needs the
- durable authoring API, which ships for these runtimes only;
- any other runtime is rejected with 400 and the response
- names the ones that work. Note that a durable Python
- function needs a newer runtime than a standard one defaults
- to. `GET /functions/runtimes` reports `durable_capable` per
- runtime.
- example: nodejs24.x
- handler:
- type: string
- description: The name of the function to invoke. Defaults to "handler" if not specified.
- default: handler
- example: handler
- visibility:
- allOf:
- - $ref: '#/components/schemas/FunctionVisibility'
- description: |
- Who may start an execution. Redeploying is the only way to
- change it, since the collection has no update endpoint; omit
- it to keep the current visibility, and a new function starts
- `private`.
-
- The standard collection's synchronous invocation fields —
- `invocation_mode`, `http_auth_mode`, `openapi_spec` —
- configure a request path no durable route serves, and are
- rejected with 400 rather than ignored.
- is_public:
- type: boolean
- deprecated: true
- description: |
- Deprecated alias for `visibility`: `true` means `public` and
- `false` means `authenticated`. Sending both with different
- meanings returns 400.
- variable_scope:
- type: string
- enum:
- - all
- - scoped
- x-enum-varnames:
- - CreateDurableFunctionMultipartBodyVariableScopeAll
- - CreateDurableFunctionMultipartBodyVariableScopeScoped
- description: |
- Which project variables this function receives. `all` (the default) gives it every project variable; `scoped` gives it only the variables it selects. Omitting this leaves an existing function's scope unchanged.
- variables:
- type: string
- description: |
- JSON-encoded array of project variable names this function requires, on top of the ones detected in its source. A declared name the project does not define is rejected with 400; a detected name it does not define is ignored. Only used when `variable_scope` is `scoped`. Omitting this leaves an existing function's declared names unchanged.
+ - $ref: '#/components/parameters/Limit'
+ - $ref: '#/components/parameters/IssueCursor'
+ - name: status
+ in: query
+ required: false
+ description: Return only runs in this status.
+ schema:
+ $ref: '#/components/schemas/GitDeploymentRunStatus'
+ - name: branch
+ in: query
+ required: false
+ description: Return only runs for pushes to this branch.
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 255
responses:
'200':
- description: Existing durable function updated; its deployment was started or queued
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DurableFunction'
- '201':
- description: Durable function created and deployment workflow started
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableFunction'
+ $ref: '#/components/schemas/PaginatedGitDeploymentRuns'
'400':
- description: |
- Bad request (invalid archive, unsupported runtime, invalid name, an
- unknown `visibility`, `visibility` and `is_public` disagree, or a
- project region that does not offer durable execution — a durable
- function deploys to every region of its project)
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '403':
- description: Durable function limit exceeded for the project
+ description: A filter or the cursor is invalid
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: |
- Name is held by a standard function, or a deletion is queued or
- running. The request is refused before the deploy starts, so
- nothing is deployed.
+ '401':
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Internal server error (function deployment failed)
+ '403':
+ description: Project not owned by the caller
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: |
- Durable deploys are paused platform-wide. The same request succeeds
- once they are re-enabled; executions already running are unaffected.
+ '404':
+ description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/durable-functions/{functionId}:
+ /projects/{id}/git-deployment-runs/{runId}:
get:
tags:
- - Durable Functions
- summary: Get durable function by ID or name
- operationId: getDurableFunction
+ - Projects
+ - Git Connections
+ summary: Get a Git deployment run
+ description: |
+ Returns one deployment run: the commit it deployed, its status, the
+ migration runs it started, and why it failed or was skipped.
+
+ Project access tokens can read runs, including read-only ones.
+ operationId: getGitDeploymentRun
security:
- UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableFunctionId'
+ - name: runId
+ in: path
+ required: true
+ description: Deployment run ID
+ schema:
+ type: string
+ format: uuid
responses:
'200':
description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableFunction'
- '404':
- description: Durable function not found
+ $ref: '#/components/schemas/GitDeploymentRun'
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Project not owned by the caller
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- delete:
- tags:
- - Durable Functions
- summary: Delete a durable function
- description: |
- Accepted for asynchronous teardown; the work continues after the
- response. The function's executions go with it: executions still in
- flight are stopped, and history stops being readable whatever
- `retention_days` had left.
-
- Stopping is asynchronous at the platform, and it does not interrupt a
- step already running -- that step runs to its next checkpoint. So a
- delete ends an execution rather than halting it mid-step; stop the
- execution yourself first if you need to observe it ending.
- operationId: deleteDurableFunction
- security:
- - UserToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableFunctionId'
- responses:
- '202':
- description: Deletion accepted and teardown started
'404':
- description: |
- Durable function not found. Also returned for an id that names a
- durable function in another project, so the response cannot be used
- to tell the two apart.
+ description: Project or run not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/durable-functions/{functionId}/deployments:
+ /projects/{id}/databases/{databaseName}/queries:
get:
tags:
- - Durable Functions
- summary: List durable function deployments
- operationId: listDurableFunctionDeployments
+ - Databases
+ summary: Get database queries
+ description: |
+ Returns the database's current top queries from pg_stat_statements
+ ranked by total execution time. Only data statements (SELECT, INSERT,
+ UPDATE, DELETE, MERGE) are listed; statements Volcano runs to operate
+ the database are left out.
+
+ **SUPERAGENT plan required.** This endpoint is only available to projects owned
+ by users on the SUPERAGENT billing plan.
+ operationId: getProjectDatabaseQueries
security:
- UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableFunctionId'
- - $ref: '#/components/parameters/Page'
- - $ref: '#/components/parameters/Limit'
+ - $ref: '#/components/parameters/DatabaseName'
+ - name: limit
+ in: query
+ description: Maximum number of queries to return.
+ schema:
+ type: integer
+ minimum: 1
+ maximum: 100
+ default: 10
responses:
'200':
- description: Successful response
+ description: Database query performance retrieved
content:
application/json:
schema:
- $ref: '#/components/schemas/PaginatedFunctionDeployments'
- '404':
- description: Durable function not found
+ $ref: '#/components/schemas/DatabaseQueryPerformanceResponse'
+ '400':
+ description: Bad request - invalid query parameters
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/durable-functions/{functionId}/schedulers:
- get:
- tags:
- - Durable Functions
- summary: List schedulers for a durable function
- description: |
- The durable collection's counterpart to
- `/projects/{id}/functions/{functionId}/schedulers`. A standard
- function's id is not accepted here, and a durable function's id is not
- accepted there.
- operationId: listDurableFunctionSchedulers
- security:
- - UserToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableFunctionId'
- responses:
- '200':
- description: Durable function schedulers
+ '401':
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
- $ref: '#/components/schemas/FunctionSchedulerListResponse'
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Access denied
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'404':
- description: Durable function not found
+ description: Project or database not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- post:
- tags:
- - Durable Functions
- summary: Create a scheduler for a durable function
- description: |
- Each tick starts an execution rather than invoking the function, under
- an execution name derived from the run, so a retried tick resolves to
- the execution it already started. Requested regions must be a subset of
- the function's deployed regions.
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /deployments:
+ get:
+ tags:
+ - Projects
+ summary: List deployments across a user's projects
+ description: |
+ Lists Function and Frontend deployment attempts across every project the
+ user owns, newest first. Pass `project_id` to narrow the feed to a single
+ project.
- A tick draws on the same durable allowances and concurrency cap a
- manual start does, and a tick that would exceed the cap fails that run.
- operationId: createDurableFunctionScheduler
+ Scope is project **ownership** (`projects.user_id`). `owner_id` names
+ whose deployments to return, not who started them — the actor is
+ `initiated_by_user_id`, which this endpoint does not filter on.
+
+ With a user token the scope is always the authenticated user: `owner_id`
+ may be omitted, or set to that same user, but naming anyone else is
+ refused with 403. Service callers on the management API must pass it,
+ since they have no authenticated user.
+
+ The owner is not checked for existence: an id with no projects returns an
+ empty page rather than `404`. Unlike `/users/{id}/usage`, this endpoint is
+ polled to detect an event, so a caller needs `404` to keep meaning "this
+ route is not served here" — which is how a consumer notices it is running
+ against an older release. A mistyped owner therefore reads as "nothing
+ deployed"; callers that need to tell those apart should verify the user
+ through `GET /users/{id}` first.
+
+ Ordering is selectable. The default is the feed order — most recent
+ attempt first. `completed_at.asc` orders by completion, oldest first, and
+ considers only attempts that finished; combined with `limit=1` and a
+ `status` filter it answers "when did this user first succeed" in one
+ bounded query.
+
+ Both pagination modes are supported, selected exactly as
+ `/projects/{id}/deployments` selects them: `cursor`/`ending_before` (or a
+ `limit` with no `page`) uses keyset pagination; otherwise `page`/`limit`
+ offset pagination. `page` with a cursor, and `cursor` with
+ `ending_before`, are rejected.
+
+ A cursor is bound to every filter *and* to `order`, so changing any of
+ them mid-pagination rejects the cursor rather than silently skipping or
+ repeating rows. The keyset position is `(created_at, id)` for
+ `created_at.desc` and `(completed_at, id)` for `completed_at.asc`.
+ operationId: listDeployments
security:
- UserToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableFunctionId'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/CreateFunctionSchedulerRequest'
+ - $ref: '#/components/parameters/Page'
+ - $ref: '#/components/parameters/Limit'
+ - $ref: '#/components/parameters/Cursor'
+ - $ref: '#/components/parameters/EndingBefore'
+ - $ref: '#/components/parameters/Offset'
+ - $ref: '#/components/parameters/DeploymentOwnerId'
+ - name: project_id
+ in: query
+ required: false
+ description: Restrict the feed to a single project owned by the user.
+ schema:
+ type: string
+ format: uuid
+ - name: created_after
+ in: query
+ required: false
+ description: Restrict results to attempts created at or after this timestamp.
+ schema:
+ type: string
+ format: date-time
+ - $ref: '#/components/parameters/DeploymentResourceType'
+ - $ref: '#/components/parameters/DeploymentStatus'
+ - $ref: '#/components/parameters/DeploymentOperation'
+ - $ref: '#/components/parameters/DeploymentOrder'
responses:
- '201':
- description: Scheduler created
+ '200':
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/FunctionScheduler'
+ $ref: '#/components/schemas/PaginatedProjectDeployments'
'400':
- description: |
- Invalid schedule, geofenced region, a scheduler of this name
- already exists on the function, or the function is not active.
+ description: Bad request - invalid filter or pagination
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: |
- Schedulers are not available on this plan, or the project already
- holds as many as the plan allows. The cap counts standard and
- durable function schedulers together.
+ description: Forbidden - owner_id names a different user
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Durable function not found
+ '500':
+ description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/durable-functions/{functionId}/schedulers/{schedulerId}:
+ /projects/{id}/deployments:
get:
tags:
- - Durable Functions
- summary: Get a durable function scheduler
- operationId: getDurableFunctionScheduler
+ - Projects
+ summary: List deployments in a project
+ description: |
+ Lists Function and Frontend deployment attempts across the project,
+ ordered most-recent first. Each item includes a normalized resource
+ reference so clients can render both resource types without extra
+ fetches.
+
+ Standard and durable function deployments both appear under
+ `resource.type: function`, and `resource.kind` tells them apart. Pass
+ `function_kind` to list one kind only; frontends are then excluded.
+ Combining `function_kind` with `resource_type=frontend` is rejected.
+ operationId: listProjectDeployments
security:
- UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableFunctionId'
- - $ref: '#/components/parameters/SchedulerId'
+ - $ref: '#/components/parameters/Page'
+ - $ref: '#/components/parameters/Limit'
+ - $ref: '#/components/parameters/Cursor'
+ - $ref: '#/components/parameters/EndingBefore'
+ - $ref: '#/components/parameters/Offset'
+ - $ref: '#/components/parameters/Search'
+ - name: created_after
+ in: query
+ required: false
+ description: Restrict results to attempts created at or after this timestamp.
+ schema:
+ type: string
+ format: date-time
+ - name: resource_type
+ in: query
+ required: false
+ description: |
+ Restrict the feed to a single resource type. Omit to return both
+ Function and Frontend deployments.
+ schema:
+ type: string
+ enum:
+ - function
+ - frontend
+ - $ref: '#/components/parameters/FunctionKindFilter'
responses:
'200':
- description: Durable function scheduler
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/FunctionScheduler'
- '404':
- description: Durable function or scheduler not found
+ $ref: '#/components/schemas/PaginatedProjectDeployments'
+ '400':
+ description: Bad request - invalid identifier or filter, or `function_kind` combined with `resource_type=frontend`
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- patch:
- tags:
- - Durable Functions
- summary: Update a durable function scheduler
- operationId: updateDurableFunctionScheduler
- security:
- - UserToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableFunctionId'
- - $ref: '#/components/parameters/SchedulerId'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/UpdateFunctionSchedulerRequest'
- responses:
- '200':
- description: Scheduler updated
+ '401':
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
- $ref: '#/components/schemas/FunctionScheduler'
- '400':
- description: |
- Invalid schedule, geofenced region, or a scheduler of this name
- already exists on the function.
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - project ownership required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Durable function or scheduler not found
+ '500':
+ description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- delete:
+ /projects/{id}/deployments/summary:
+ get:
tags:
- - Durable Functions
- summary: Delete a durable function scheduler
- operationId: deleteDurableFunctionScheduler
+ - Projects
+ summary: Summarize deployments in a project
+ description: |
+ Summarizes deployment attempts for one comparable resource pipeline.
+ Success rate uses conclusive outcomes only: active and deleted attempts
+ are successful; failed and degraded attempts are failures; in-progress
+ and superseded attempts are excluded. Median build duration includes
+ completed, non-superseded attempts with recorded build work,
+ including failed builds.
+
+ With `resource_type=function`, pass `function_kind` to summarize one
+ kind of function only. It is rejected with `resource_type=frontend`.
+ operationId: summarizeProjectDeployments
security:
- UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableFunctionId'
- - $ref: '#/components/parameters/SchedulerId'
+ - name: search
+ in: query
+ required: false
+ description: Restrict the summary to resource names containing this value.
+ schema:
+ type: string
+ - name: resource_type
+ in: query
+ required: true
+ description: Restrict the summary to one comparable deployment pipeline.
+ schema:
+ type: string
+ enum:
+ - function
+ - frontend
+ - $ref: '#/components/parameters/FunctionKindFilter'
+ - name: created_after
+ in: query
+ required: false
+ description: Restrict results to attempts created at or after this timestamp.
+ schema:
+ type: string
+ format: date-time
responses:
- '204':
- description: Scheduler deleted
- '404':
- description: Durable function or scheduler not found
+ '200':
+ description: Successful response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProjectDeploymentSummary'
+ '400':
+ description: Bad request - invalid identifier or filter, or `function_kind` combined with `resource_type=frontend`
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/durable-functions/{functionId}/executions:
- post:
- tags:
- - Durable Functions
- summary: Start a durable execution
- description: |
- Starts an execution and returns its handle. Never returns a result: an
- execution can outlive any request a client could hold open, so the
- result is read back from
- `GET /projects/{id}/durable-functions/{functionId}/executions/{executionId}`.
-
- The request body is the execution's input and must be valid JSON if
- present. An empty body starts the execution with no input.
-
- Send `X-Volcano-Execution-Name` to make the start idempotent: repeating a
- start with the same name returns the existing execution instead of
- beginning a second one.
-
- Each execution counts against the project's durable execution
- allowance, the operations it performs count against the durable
- operations allowance when it finishes, and the number of executions in
- flight at once is capped by the plan.
- operationId: startDurableExecution
- security:
- - UserToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableFunctionId'
- - name: X-Volcano-Execution-Name
- in: header
- required: false
- description: |
- Idempotency key for this execution. Generated when omitted. A repeat
- under a name that already names a running execution returns that
- execution and is not charged again.
-
- Letters, digits, `-`, `_` and `.`, up to 255 characters. Anything
- else is rejected with `400`.
- schema:
- type: string
- maxLength: 255
- pattern: ^[A-Za-z0-9._-]+$
- requestBody:
- required: false
- content:
- application/json:
- schema:
- description: Input passed to the function, up to 256 KiB.
- responses:
- '202':
- description: Execution accepted and started
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DurableExecution'
- '400':
- description: Payload is not valid JSON, or the execution name is invalid
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '404':
- description: Durable function not found
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '409':
- description: |
- Function is not deployed yet, or has no deployed region. Also
- returned when two starts under the same execution name raced and
- both released it, which is retryable as it stands.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '413':
- description: Payload exceeds the maximum execution input size
+ '401':
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
- description: |
- Too many executions already in flight for this project, or the
- account is out of one of its billing-cycle durable allowances:
- executions, operations, or compute. An owner-started execution is
- metered exactly like an application-started one.
+ '403':
+ description: Forbidden - project ownership required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: |
- Durable execution is not available in this environment, or the
- plan terms for the start could not be read. The first means the
- capability is paused or this deployment cannot serve it, so it is
- not one to retry in a loop; the second is transient.
+ '500':
+ description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
+ /projects/{id}/domains:
get:
tags:
- - Durable Functions
- summary: List a durable function's executions
+ - Frontends
+ summary: List all custom domains in a project
description: |
- Returns the platform's last observed status for each execution; listing
- does not poll each one. Fetch a single execution for its live state.
- operationId: listDurableExecutions
+ Project-scoped custom-domain list. Returns every active custom
+ domain across every frontend in the project (excludes soft-deleted
+ rows). Each item inlines the linked frontend's id and name so the
+ UI does not need a second fetch to render the "Linked to" column.
+ operationId: listProjectCustomDomains
security:
- UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableFunctionId'
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/Limit'
- - name: status
- in: query
- required: false
- description: Return only executions in this status.
- schema:
- $ref: '#/components/schemas/DurableExecutionStatus'
+ - $ref: '#/components/parameters/Cursor'
+ - $ref: '#/components/parameters/EndingBefore'
+ - $ref: '#/components/parameters/Offset'
+ - $ref: '#/components/parameters/Search'
responses:
'200':
description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/PaginatedDurableExecutions'
+ $ref: '#/components/schemas/PaginatedProjectCustomDomains'
'400':
- description: Unsupported status filter
+ description: Bad request - invalid identifier
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Durable function not found
+ '401':
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/durable-functions/{functionId}/executions/{executionId}:
- get:
- tags:
- - Durable Functions
- summary: Get a durable execution
- description: |
- Returns the execution's current state, including its `result` once it has
- succeeded. Poll this to wait for an execution to finish.
- operationId: getDurableExecution
- security:
- - UserToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableFunctionId'
- - $ref: '#/components/parameters/DurableExecutionId'
- responses:
- '200':
- description: Successful response
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DurableExecution'
- '404':
- description: Durable function or execution not found
+ '403':
+ description: Forbidden - project ownership required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: |
- Durable execution is not available in this environment. Either the
- capability is paused or this deployment cannot serve it, so the
- request is not one to retry in a loop.
+ '500':
+ description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/durable-functions/{functionId}/executions/{executionId}/operations:
+ /projects/{id}/functions:
get:
tags:
- - Durable Functions
- summary: List a durable execution's operations
+ - Functions
+ summary: List all functions in a project
description: |
- Returns the execution's trace: every operation it began — each step,
- wait, poll, child context, map item and parallel branch — with when it
- started and ended, how it ended, and each attempt of a retried step.
- `invocations` are the windows the function's code was actually running;
- the gaps between them are time the execution spent suspended, which is
- not charged.
-
- A finished execution's trace is final and `complete` is `true`. A
- running one is refreshed when it is read, and can be up to about ten
- seconds behind; `synced_at` says when it was last refreshed. Inputs,
- results and other payloads are never included.
-
- The list is not paginated: an execution is limited to 3,000
- operations, and a trace is read whole.
- operationId: listDurableExecutionOperations
+ Supports two mutually exclusive pagination modes. Offset mode uses `page`
+ and `limit` and returns `next` (URL). Cursor mode uses `cursor` and
+ `limit`, supports `search` (case-insensitive name match), and returns
+ `next_cursor`/`prev_cursor`. Sending both `page` and `cursor` (or `page`
+ and `search`) returns 400.
+ operationId: listFunctions
security:
- UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableFunctionId'
- - $ref: '#/components/parameters/DurableExecutionId'
+ - $ref: '#/components/parameters/Page'
+ - $ref: '#/components/parameters/Limit'
+ - $ref: '#/components/parameters/Cursor'
+ - $ref: '#/components/parameters/EndingBefore'
+ - $ref: '#/components/parameters/Offset'
+ - $ref: '#/components/parameters/Search'
responses:
'200':
description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableExecutionOperationList'
+ $ref: '#/components/schemas/PaginatedFunctions'
'404':
- description: Durable function or execution not found
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '500':
- description: The trace could not be read
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '503':
- description: |
- Durable execution is not available in this environment. Either the
- capability is paused or this deployment cannot serve it, so the
- request is not one to retry in a loop.
+ description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/durable-functions/{functionId}/executions/{executionId}/stop:
post:
tags:
- - Durable Functions
- summary: Stop a durable execution
+ - Functions
+ summary: Create or update function code
description: |
- Cancels a running execution. Its completed steps are not undone.
-
- The call is accepted rather than awaited: cancellation happens behind
- it, so the response reports the execution as it was read back and may
- still say `running`. Do not branch on that status — the execution
- settles into `stopped` shortly after, and polling
- `GET /projects/{id}/durable-functions/{functionId}/executions/{executionId}`
- is how you see it get there.
-
- Stopping an execution that already finished is not an error: the
- response carries the state it settled in.
- operationId: stopDurableExecution
- security:
- - UserToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableFunctionId'
- - $ref: '#/components/parameters/DurableExecutionId'
- responses:
- '200':
- description: |
- Stop accepted. The body is the execution as it was read back, which
- may still report `running`.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DurableExecution'
- '404':
- description: Durable function or execution not found
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '409':
- description: Execution has not started yet
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '503':
- description: |
- Durable execution is not available in this environment. Either the
- capability is paused or this deployment cannot serve it, so the
- request is not one to retry in a loop.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- /projects/{id}/durable-functions/{functionId}/executions/{executionId}/messages:
- post:
- tags:
- - Durable Functions
- summary: Send a message to a durable execution
- description: |
- Sends a named message to a running execution, as
- `POST /durable-functions/{functionId}/executions/{executionId}/messages`
- does for an application. The workflow receives it from
- `ctx.waitForMessage` with the same name; until then it is kept, and
- waits take messages oldest first.
-
- Project access tokens can send messages, but read-only ones cannot.
- A message never decides an approval.
- operationId: sendDurableMessage
+ Upload a function source bundle. Direct API clients may send the function code
+ as a ZIP or tar.gz archive via multipart/form-data. The API stores a normalized tar.gz
+ source archive.
+ Cloud deploys should include source files and dependency manifests/lockfiles, not installed
+ dependency directories. Volcano installs Node.js, Python, and Ruby dependencies during the
+ function compile build.
+ Source archive size is enforced by the API with `SOURCE_ARCHIVE_SIZE_LIMIT_MB`; the CLI
+ does not apply its own source archive size limit. After the final container image is
+ built, the publish build enforces `LAMBDA_TARGET_CONTAINER_SIZE_LIMIT_MB` before pushing.
+ Uploaded source archives cannot contain symlink entries. Safe symlinks created during
+ the cloud build are materialized before publish.
+ Volcano builds and deploys the function asynchronously after upload. A deployment that starts
+ immediately returns a Function resource with `status: provisioning`, then transitions to
+ `active` or `failed`. If another deployment is running, the response preserves the resource's
+ current status and exposes the queued deployment through `pending_deployment_id`.
+ Existing function traffic continues to use the last known-good runtime during an update. A failed
+ update keeps that runtime available and records the attempted deployment as failed.
+ Only one deployment runs for a given function. A newer request supersedes any queued request
+ and starts after the running deployment. Different functions and projects deploy concurrently.
+ If a function with the same name already exists in the project, this operation updates that
+ function's runtime, handler, and source bundle and returns `200 OK`.
+ Each project can contain up to 10,000 functions. Creating a new function over this cap returns 403.
+ operationId: createFunction
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableFunctionId'
- - $ref: '#/components/parameters/DurableExecutionId'
- - $ref: '#/components/parameters/DurableMessageIdempotencyKey'
requestBody:
required: true
content:
- application/json:
+ multipart/form-data:
schema:
- $ref: '#/components/schemas/SendDurableMessageRequest'
+ type: object
+ required:
+ - name
+ - code
+ - runtime
+ properties:
+ name:
+ type: string
+ description: DNS-safe function name (lowercase letters, numbers, hyphens; cannot start or end with hyphen)
+ maxLength: 63
+ pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$
+ example: my-api-function
+ code:
+ type: string
+ format: binary
+ description: ZIP or tar.gz archive containing function source code plus dependency manifests/lockfiles. The API enforces SOURCE_ARCHIVE_SIZE_LIMIT_MB and stores a normalized tar.gz source archive.
+ runtime:
+ type: string
+ enum:
+ - nodejs22.x
+ - nodejs24.x
+ - python3.10
+ - python3.11
+ - python3.12
+ - python3.13
+ - python3.14
+ - ruby3.3
+ - ruby3.4
+ - ruby4.0
+ description: |
+ Runtime environment. Required.
+ - Node.js: nodejs22.x, nodejs24.x
+ - Python: python3.10, python3.11, python3.12, python3.13, python3.14
+ - Ruby: ruby3.3, ruby3.4, ruby4.0
+
+ python3.10 is deprecated: it still deploys, and Volcano will remove it before 2027-08-31.
+ example: nodejs24.x
+ handler:
+ type: string
+ description: |
+ The name of the function to invoke. Defaults to "handler" if not specified.
+ Your code must export/define a function with this name:
+ - Node.js: exports.handler (in index.js, index.mjs or index.cjs, or in TypeScript in index.ts, index.mts or index.cts, which the build compiles without type-checking)
+ - Python: def handler() (in main.py)
+ - Ruby: def handler() (in main.rb)
+ default: handler
+ example: handler
+ visibility:
+ allOf:
+ - $ref: '#/components/schemas/FunctionVisibility'
+ description: |
+ Who can invoke the function. Omit it to keep the function's
+ current visibility; a new function starts `private`.
+ is_public:
+ type: boolean
+ deprecated: true
+ description: |
+ Deprecated alias for `visibility`: `true` means `public` and
+ `false` means `authenticated`. Sending both with different
+ meanings returns 400.
+ invocation_mode:
+ $ref: '#/components/schemas/FunctionInvocationMode'
+ http_auth_mode:
+ $ref: '#/components/schemas/FunctionHTTPAuthMode'
+ openapi_spec:
+ type: string
+ description: JSON-encoded OpenAPI 3.0 or 3.1 metadata for an HTTP-mode function.
+ variable_scope:
+ type: string
+ enum:
+ - all
+ - scoped
+ x-enum-varnames:
+ - CreateFunctionMultipartBodyVariableScopeAll
+ - CreateFunctionMultipartBodyVariableScopeScoped
+ description: |
+ Which project variables this function receives. `all` (the default) gives it only project variables marked `shared: true`; `scoped` gives it only the variables it selects. Omitting this leaves an existing function's scope unchanged.
+ variables:
+ type: string
+ description: |
+ JSON-encoded array of project variable names this function requires, on top of the ones detected in its source. A declared name the project does not define is rejected with 400; a detected name it does not define is ignored. Only used when `variable_scope` is `scoped`. Omitting this leaves an existing function's declared names unchanged.
+ commit:
+ type: string
+ description: |
+ JSON-encoded commit the uploaded source came from: `{"repository": "acme/app", "sha": "<40-character commit ID>", "dirty": false}`. `repository` is `owner/name` or a github.com remote URL (`https://github.com/acme/app.git`, `git@github.com:acme/app.git`, or `ssh://git@github.com/acme/app.git`); Volcano drops any credentials in the URL and records `owner/name`. `dirty` is `true` when the uploaded files differ from the commit. All three fields are required, and fields Volcano does not know are ignored. An empty value, `null`, or `""` reports no commit. A malformed commit, or a repository not on GitHub, returns 400 before anything is deployed. Volcano records a function's commit with `commit.verified: false`; a clean commit of the project's connected repository that its production branch holds gets `commit.verification: repository`.
responses:
'200':
- description: A message with this `Idempotency-Key` was already sent; it is returned
+ description: Existing function updated; its deployment was started or queued
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableMessage'
+ $ref: '#/components/schemas/Function'
'201':
- description: |
- Message sent. `status` is `delivered`, `delivering`, or `queued`,
- as on the application route.
+ description: Function created and deployment workflow started
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableMessage'
+ $ref: '#/components/schemas/Function'
'400':
- description: The name, data or idempotency key is invalid
+ description: |
+ Bad request (invalid file, too large, etc.), an unknown
+ `visibility`, `visibility` and `is_public` disagree, or a
+ malformed `commit`
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: The request used a `read_only` project access token
+ description: Function limit exceeded for the project
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Durable function or execution not found
+ '409':
+ description: |
+ Function deletion is queued or running, the name is already held
+ by a durable function — a function cannot change kind — or the
+ redeploy would take a function with Frontend Function routes out
+ of `public` or out of HTTP invocation mode. The request is refused
+ before the deploy starts, so nothing is deployed. The message
+ `project variables changed during the upload; retry` means
+ `NODE_PATH` was created or deleted while the upload was processed;
+ send the same request again.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
+ '429':
description: |
- The message cannot be sent. `code` is `execution_not_running` or
- `too_many_queued_messages`.
+ The owner's billing-cycle build-minutes allowance is spent. The
+ error names the allowance and carries a link to the usage page.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '413':
- description: The request body is larger than 72 KiB
+ '500':
+ description: Internal server error (function deployment failed)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
- description: Too many messages sent to this execution
+ '503':
+ description: |
+ Build usage could not be read, so the allowance could not be
+ checked. The same request succeeds once it can be.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
+ /projects/{id}/functions/{functionId}:
get:
tags:
- - Durable Functions
- summary: List a durable execution's messages
- description: |
- Lists the messages sent to and published by an execution, oldest
- first. Pass the last `seq` you read as `after` to read only what came
- next.
-
- Project access tokens can list messages, including read-only ones.
- operationId: listDurableMessages
+ - Functions
+ summary: Get function by ID
+ operationId: getFunction
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableFunctionId'
- - $ref: '#/components/parameters/DurableExecutionId'
- - $ref: '#/components/parameters/DurableMessageDirectionFilter'
- - $ref: '#/components/parameters/DurableMessageNameFilter'
- - $ref: '#/components/parameters/DurableMessageAfter'
- - $ref: '#/components/parameters/DurableMessageLimit'
+ - $ref: '#/components/parameters/FunctionId'
responses:
'200':
description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableMessageList'
- '400':
- description: A filter is invalid
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
+ $ref: '#/components/schemas/Function'
'404':
- description: Durable function or execution not found
+ description: Function not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/durable-functions/{functionId}/executions/{executionId}/message-waits:
- get:
+ patch:
tags:
- - Durable Functions
- summary: List a durable execution's open message waits
- description: |
- Lists the waits an execution has open in `ctx.waitForMessage`, oldest
- first, so you can see which message names it is waiting for.
-
- Project access tokens can list waits, including read-only ones.
- operationId: listDurableMessageWaits
+ - Functions
+ summary: Update function settings
+ operationId: updateFunction
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableFunctionId'
- - $ref: '#/components/parameters/DurableExecutionId'
+ - $ref: '#/components/parameters/FunctionId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateFunctionRequest'
+ examples:
+ makePublic:
+ summary: Let anon keys invoke the function
+ value:
+ visibility: public
+ allowSignedInUsers:
+ summary: Let signed-in users of the project invoke the function
+ value:
+ visibility: authenticated
+ makePrivate:
+ summary: Allow only service keys and schedulers (the default)
+ value:
+ visibility: private
responses:
'200':
- description: Successful response
+ description: Function updated
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableMessageWaitList'
- '404':
- description: Durable function or execution not found
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- /durable-messages/waits:
- post:
- tags:
- - Durable Functions
- summary: Wait for a message from inside a workflow
- description: |
- Registers a wait for a named message. The Volcano SDK calls this from
- `ctx.waitForMessage`; applications do not call it directly.
-
- `execution_ref` and `callback_id` are opaque values the SDK reads from
- the running workflow. Together they are the request's credential, so
- the operation takes no other authentication. When a message for the
- name is already queued, the wait takes the oldest one at once.
-
- Retrying is safe: a request for a wait that is already registered
- returns it with `200`.
- operationId: registerDurableMessageWait
- security: []
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/RegisterDurableMessageWaitRequest'
- responses:
- '200':
- description: The wait was already registered
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DurableMessageWaitRegistration'
- '201':
- description: Wait registered
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DurableMessageWaitRegistration'
- '400':
- description: The request body is invalid
+ $ref: '#/components/schemas/Function'
+ '400':
+ description: |
+ Invalid settings: an unknown `visibility`, `visibility` and
+ `is_public` disagree, or `http_auth_mode: none` on a function that
+ is not `public`
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: No running durable execution matches `execution_ref`
+ description: Function not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: |
- The wait cannot be registered now. `code` says why:
-
- - `callback_not_ready`: the workflow has not finished opening the
- wait yet. Retry with a short backoff; the SDK does.
- - `callback_closed`: the workflow is no longer waiting on it.
- - `callback_taken`: the callback is already registered as an
- approval or a messages session.
- - `execution_ended`: the execution has finished.
- - `too_many_message_waits`: the execution already has the maximum
- number of open waits.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '413':
- description: The request body is larger than 8 KiB
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '429':
- description: Too many requests from this execution
+ Function settings conflict with attached Frontend Function routes:
+ a routed function must stay `public` and in HTTP invocation mode.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: |
- The wait could not be confirmed with the workflow right now. Retry
- with backoff.
+ delete:
+ tags:
+ - Functions
+ summary: Delete a function
+ description: |
+ Schedules asynchronous function deletion. If another deployment is running, the function
+ preserves its current status and exposes the queued deletion through `pending_deployment_id`.
+ Its status changes to `deleting` when cleanup starts. After cleanup, it returns 404 and no
+ longer appears in function lists.
+ operationId: deleteFunction
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/FunctionId'
+ responses:
+ '202':
+ description: Function deletion started or queued
+ '404':
+ description: Function not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /durable-messages/sessions:
+ /functions/{functionId}/invoke:
post:
tags:
- - Durable Functions
- summary: Open a messages session from inside a workflow
+ - Functions
+ summary: Invoke a function
description: |
- Opens the session a workflow publishes messages with. The Volcano SDK
- calls this once per workflow context, on its first `ctx.publish`;
- applications do not call it directly.
+ Invoke a function. The function's `visibility` decides which credentials
+ may call it, and the function does not run for any other. A `private`
+ function answers every credential but a service key exactly as a
+ missing one, with 404, so its name and id cannot be discovered; an anon
+ key on an `authenticated` function gets 403. An SDK calling by name
+ resolves it first through `GET /functions/resolve`, which answers that
+ anon key with 404 instead.
- As for a wait, `execution_ref` and `callback_id` are the credential.
- The session's token is delivered to the workflow itself and never
- appears in a response.
+ **With Service Key** (admin/background operations, every visibility):
+ - Use for background jobs, webhooks, cron, admin operations
+ - Function receives payload only (no user context)
+ - Database queries bypass RLS (admin access)
- Retrying is safe: a request for a session that is already registered
- returns it with `200`.
- operationId: openDurableMessageSession
- security: []
+ **With Auth User Token** (user-facing, `authenticated` or `public` functions):
+ - Use for user-initiated actions
+ - Includes users from anonymous sign-ins
+ - Function receives payload + `__volcano_auth` context:
+ ```javascript
+ {
+ user_id: "uuid",
+ email: "user@example.com",
+ project_id: "uuid",
+ role: "authenticated" or "anonymous"
+ }
+ ```
+ - Database queries enforce RLS (user-scoped data)
+
+ **With Anon Key** (`public` functions only):
+ - Requires anon key permission: `functions.invoke`
+ - Function must have `visibility: public`
+ - Function receives payload only (no `__volcano_auth`)
+
+ **Reserved payload keys:** the top-level `__volcano_auth` and
+ `__volcano_http` keys are reserved. Volcano removes caller-supplied
+ values for both before the function runs; only an auth user token adds
+ a server-built `__volcano_auth`, and only HTTP-mode ingress sets
+ `__volcano_http: true`.
+
+ **Transport and CORS:**
+ - This operation is the authenticated direct RPC endpoint and always uses the
+ POST `{payload: ...}` contract, including for functions whose DNS ingress is
+ configured in HTTP mode.
+ - The geo-routed DNS ingress is the function's `invoke_url`. It is on a
+ different domain from this API, so it cannot be derived from the API host.
+ - RPC-mode DNS ingress accepts POST at `/`. HTTP-mode DNS ingress accepts GET,
+ HEAD, POST, PUT, PATCH, and DELETE at `/` and nested paths.
+ - Direct and RPC-mode CORS preflight advertises `POST, OPTIONS`. HTTP-mode DNS
+ preflight advertises `GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS`.
+ - `http_auth_mode: none` applies only to public HTTP-mode DNS ingress; this
+ direct operation always requires a Volcano credential.
+
+ **Durable functions are not invocable here.** A durable function's id
+ answers 404, whatever its visibility, because a synchronous call would
+ run it with no execution record, no idempotency and no concurrency
+ accounting. Start one with
+ `POST /durable-functions/{functionId}/executions`.
+ operationId: invokeFunction
+ security:
+ - AnonKey: []
+ - ServiceRoleKey: []
+ - AuthUserAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/FunctionId'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/OpenDurableMessageSessionRequest'
+ $ref: '#/components/schemas/FunctionInvocationRequest'
+ examples:
+ serviceCall:
+ summary: Admin/background operation (service key)
+ value:
+ payload:
+ action: process_batch
+ items:
+ - 1
+ - 2
+ - 3
+ userCall:
+ summary: User-initiated call (auth token)
+ value:
+ payload:
+ action: get_profile
+ anonCall:
+ summary: Public function call (anon key)
+ value:
+ payload:
+ action: ping_public_endpoint
responses:
'200':
- description: The session was already registered
- content:
- application/json:
+ description: Function response (passthrough from function runtime)
+ headers:
+ X-Volcano-Version:
+ description: Volcano API/runtime version that served this invocation (`` in production, `-` in non-production)
schema:
- $ref: '#/components/schemas/DurableMessageSessionRegistration'
- '201':
- description: Session opened
+ type: string
+ X-Volcano-Region:
+ description: Region the function ran in (for example `us-east-1`)
+ schema:
+ type: string
+ X-Volcano-Proxy-Ms:
+ description: Milliseconds Volcano spent preparing the invocation, counted from the request arriving until the function was dispatched. Present only when the function was invoked. Does not include function execution.
+ schema:
+ type: integer
+ minimum: 0
+ X-Volcano-Proxy-Handler-Ms:
+ description: The part of `X-Volcano-Proxy-Ms` spent in the invoke endpoint itself. Subtract it from `X-Volcano-Proxy-Ms` to see what authentication and request validation cost. Present only when the function was invoked.
+ schema:
+ type: integer
+ minimum: 0
+ X-Volcano-Compute-Ms:
+ description: Milliseconds spent running the function, from dispatch until it returned. Present only when the function was invoked. Does not include proxy preparation.
+ schema:
+ type: integer
+ minimum: 0
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableMessageSessionRegistration'
+ $ref: '#/components/schemas/FunctionInvocationResponse'
'400':
- description: The request body is invalid
+ description: Bad request - invalid payload or function in failed state
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: No running durable execution matches `execution_ref`
+ '401':
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
+ '403':
description: |
- The session cannot be opened now. `code` is `callback_not_ready`,
- `callback_closed`, `callback_taken` (the callback is already
- registered as an approval or a message wait), `execution_ended`,
- or `too_many_message_sessions`.
+ Forbidden - CORS blocked, missing `functions.invoke`, or an anon key
+ on an `authenticated` function
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '413':
- description: The request body is larger than 8 KiB
+ '404':
+ description: |
+ Function not found. Also returned for a `private` function to any
+ credential but a service key.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
- description: Too many requests from this execution
+ description: |
+ Rate limit exceeded (per-function or project-wide limit), or the
+ owning platform user's billing-cycle bandwidth allowance (aggregate ingress +
+ egress) was exceeded.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
description: |
- The session could not be confirmed with the workflow right now.
- Retry with backoff.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- /durable-messages/publish:
+ Function still provisioning or rate limiting service unavailable.
+ A freshly deployed (or updated) function may briefly report
+ `provisioning` and reject invocations until the background status
+ reconciler observes its deployment workflow completing and transitions
+ it to `active`. This is expected for a few seconds after deploy; clients
+ should retry.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ default:
+ description: Function response (passthrough; status code/body/headers come from the function)
+ headers:
+ X-Volcano-Version:
+ description: Volcano API/runtime version that served this invocation (`` in production, `-` in non-production)
+ schema:
+ type: string
+ X-Volcano-Region:
+ description: Region the function ran in (for example `us-east-1`)
+ schema:
+ type: string
+ X-Volcano-Proxy-Ms:
+ description: Milliseconds Volcano spent preparing the invocation, counted from the request arriving until the function was dispatched. Present only when the function was invoked. Does not include function execution.
+ schema:
+ type: integer
+ minimum: 0
+ X-Volcano-Proxy-Handler-Ms:
+ description: The part of `X-Volcano-Proxy-Ms` spent in the invoke endpoint itself. Subtract it from `X-Volcano-Proxy-Ms` to see what authentication and request validation cost. Present only when the function was invoked.
+ schema:
+ type: integer
+ minimum: 0
+ X-Volcano-Compute-Ms:
+ description: Milliseconds spent running the function, from dispatch until it returned. Present only when the function was invoked. Does not include proxy preparation.
+ schema:
+ type: integer
+ minimum: 0
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/FunctionInvocationResponse'
+ /durable-functions/{functionId}/executions:
post:
tags:
- Durable Functions
- summary: Publish a message from inside a workflow
+ summary: Start a durable execution from an application
description: |
- Publishes a named message from a running workflow. The Volcano SDK
- calls this from `ctx.publish`; applications do not call it directly.
+ Starts an execution of a durable function using an application
+ credential, and returns its handle.
- The message is stored, listed with the execution's messages, and
- delivered live to clients subscribed to the execution. Live delivery
- counts against the project's Realtime messages.
+ This is the durable counterpart of `POST /functions/{functionId}/invoke`,
+ and it is the endpoint an application calls. Like that one, it is not
+ project-scoped: an anon key, a service key and an auth user token each
+ carry their own project. The project-scoped collection under
+ `/projects/{id}/durable-functions/...` remains the owner's management
+ surface.
- The SDK sends an `Idempotency-Key` that a rerun of the publishing step
- repeats, so a step that runs again returns the first message with
- `200` and stores nothing new. That message is delivered live again,
- and counts again, because the first run may have stopped before
- subscribers got it. The SDKs deliver it to a subscriber once.
- operationId: publishDurableMessage
- security: []
+ **With a service key:** any durable function in the project.
+
+ **With an auth user token:** a durable function whose `visibility` is
+ `authenticated` or `public`.
+
+ **With an anon key:** requires the `functions.invoke` permission, and
+ the function must have `visibility: public`.
+
+ A `private` durable function answers every credential but a service key
+ exactly as a missing one, with 404.
+
+ The start returns a `client_token`. An anon key, a service key scoped
+ to a list without `*`, or a user who did not start the execution,
+ sends it as `X-Volcano-Client-Token` to read the execution, stop it,
+ and reach its messages. An anon key is shared by everyone who loads
+ the page, so the id alone never reaches an
+ execution. Listing executions takes the project owner's token or a
+ project access token.
+
+ Send `X-Volcano-Execution-Name` to make the start idempotent: repeating
+ a start with the same name returns the existing execution instead of
+ beginning a second one.
+
+ Each execution counts once against the project's durable execution
+ allowance, however many times the start is retried under the same
+ execution name, and the number in flight at once is capped by the plan.
+ The operations the execution performs are counted against the durable
+ operations allowance when it finishes.
+ operationId: startDurableExecutionFromApplication
+ security:
+ - AnonKey: []
+ - ServiceRoleKey: []
+ - AuthUserAccessToken: []
parameters:
- - name: X-Volcano-Durable-Session
+ - $ref: '#/components/parameters/DurableFunctionId'
+ - name: X-Volcano-Execution-Name
in: header
- required: true
- description: The session token the workflow received when its session opened.
+ required: false
+ description: |
+ Idempotency key for this execution. Generated when omitted. A repeat
+ under a name that already names a running execution returns that
+ execution and is not charged again.
+
+ Letters, digits, `-`, `_` and `.`, up to 255 characters. Anything
+ else is rejected with `400`.
schema:
type: string
- minLength: 1
- maxLength: 128
- - $ref: '#/components/parameters/DurableMessageIdempotencyKey'
+ maxLength: 255
+ pattern: ^[A-Za-z0-9._-]+$
requestBody:
- required: true
+ required: false
content:
application/json:
schema:
- $ref: '#/components/schemas/PublishDurableMessageRequest'
+ description: Input passed to the function, up to 256 KiB.
responses:
- '200':
- description: A message with this `Idempotency-Key` was already published; it is returned
+ '202':
+ description: Execution accepted and started
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableMessage'
- '201':
- description: Message published
+ $ref: '#/components/schemas/DurableExecution'
+ '400':
+ description: Payload is not valid JSON, or the execution name is invalid
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableMessage'
- '400':
- description: The session token header is missing, or the name, data or idempotency key is invalid
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: |
+ Missing or invalid credential. Also returned for a platform user
+ token, which is not an application credential; project owners start
+ executions through the project-scoped collection.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: The session token is not valid
+ '403':
+ description: |
+ The anon key lacks `functions.invoke` or the function is
+ `authenticated`, or the request's origin is refused by the project's
+ CORS policy.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: |
+ Durable function not found. Also returned for a standard function's
+ id, for a durable function in another project, and for a `private`
+ one to any credential but a service key, so the response cannot be
+ used to tell those apart.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: |
- The message cannot be published. `code` is
- `execution_not_running` or `too_many_published_messages`.
+ Function is not deployed yet, or has no deployed region. Also
+ returned when two starts under the same execution name raced and
+ both released it, which is retryable as it stands, and with `code`
+ `execution_name_held` when an unfinished start this caller may not
+ resume holds the execution name, which needs a name of its own.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'413':
- description: The request body is larger than 72 KiB
+ description: Payload is larger than 256 KiB
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /durable-callbacks:
- post:
+ '429':
+ description: |
+ The project has too many executions in flight for its plan, the
+ function invocation rate limit was exceeded, the project is over
+ its bandwidth cap, or the account is out of one of its
+ billing-cycle durable allowances: executions, operations, or
+ compute. Operations and compute are counted once an execution
+ finishes, so a refusal on either never interrupts an execution
+ already running — it declines the next start.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: |
+ Durable execution is not available in this environment, or the
+ plan terms for the start could not be read. The first means the
+ capability is paused or this deployment cannot serve it, so it is
+ not one to retry in a loop; the second is transient.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /durable-functions/{functionId}/executions/{executionId}:
+ get:
tags:
- Durable Functions
- summary: Get a callback token from inside a workflow
+ summary: Get a durable execution from an application
description: |
- Registers a waiting step and returns its callback token. The Volcano
- SDK calls this from `ctx.waitForCallback`; applications do not call it
- directly.
+ Returns the execution's current state with the credential that started
+ it, including its `result` once it has succeeded. Poll this to wait for
+ an execution to finish.
- `execution_ref` and `callback_id` are opaque values the SDK reads from
- the running workflow. Together they are the request's credential, so
- the operation takes no other authentication. The token works until
- the step's own timeout, and only for that step.
+ **With a service key:** any execution in the project when the key holds
+ `*`, the default. A key scoped to a list without `*` reaches an
+ execution whose `X-Volcano-Client-Token` the request carries, as an
+ anon key does; the start returns that token.
- Retrying is safe: a request for a step that is already registered
- returns the same token with `200`.
- operationId: registerDurableCallback
- security: []
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/RegisterDurableCallbackRequest'
+ **With an auth user token:** an execution the user started, or one
+ whose `X-Volcano-Client-Token` the request carries, of a durable
+ function whose `visibility` is `authenticated` or `public`.
+
+ **With an anon key:** an execution whose `X-Volcano-Client-Token` the
+ request carries, of a function with `visibility: public`.
+
+ Only a service key holding `*` reaches an execution that is still
+ `pending`. Any other execution answers `404`, as a missing one does.
+
+ The response is the one `GET
+ /projects/{id}/durable-functions/{functionId}/executions/{executionId}`
+ returns. It never carries `client_token`.
+ operationId: getDurableExecutionFromApplication
+ security:
+ - AnonKey: []
+ - ServiceRoleKey: []
+ - AuthUserAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/DurableFunctionId'
+ - $ref: '#/components/parameters/DurableExecutionId'
+ - $ref: '#/components/parameters/DurableClientToken'
responses:
'200':
- description: The step was already registered; its token is returned
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableCallbackRegistration'
- '201':
- description: Token issued
+ $ref: '#/components/schemas/DurableExecution'
+ '401':
+ description: Missing or invalid credential
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableCallbackRegistration'
- '400':
- description: The request body is invalid
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: |
+ The anon key lacks `functions.invoke`, the service key is scoped
+ without it, or the function is `authenticated` and the request
+ carries an anon key. Also returned when the request's origin is
+ refused by the project's CORS policy.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: No running durable execution matches `execution_ref`
+ description: |
+ Durable function or execution not found, or the credential cannot
+ reach the execution. A `private` function answers every credential
+ but a service key this way.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
+ '429':
description: |
- The token cannot be issued now. `code` says why:
-
- - `callback_not_ready`: the workflow has not finished opening the
- step yet. Retry with a short backoff; the SDK does.
- - `callback_closed`: the workflow is no longer waiting on it.
- - `callback_taken`: the step is already registered as an approval
- or a message wait.
- - `execution_ended`: the execution has finished.
- - `too_many_callback_tokens`: the execution already holds the
- maximum number of open tokens.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '413':
- description: The request body is larger than 8 KiB
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '429':
- description: Too many requests from this execution
+ The function's or the project's function rate limit, which reads
+ share with invocations and starts, or the project is over its
+ bandwidth cap.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
description: |
- The step could not be confirmed with the workflow right now. Retry
- with backoff.
+ Durable execution is not available in this environment, the plan
+ terms for the request could not be read, or reads of the
+ execution's state in its region are throttled. The first is not one
+ to retry in a loop; the others are transient, and a throttled read
+ carries `Retry-After`.
+ headers:
+ Retry-After:
+ description: |
+ Seconds to wait before reading again. Sent only when reads in
+ the execution's region are throttled.
+ schema:
+ type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /durable-callbacks/succeed:
+ /durable-functions/{functionId}/executions/{executionId}/stop:
post:
tags:
- Durable Functions
- summary: Complete a waiting step with a result
+ summary: Stop a durable execution from an application
description: |
- Resumes the workflow step waiting on the token with `result`. Call it
- from the system the workflow handed the token to.
+ Cancels a running execution with the credential that started it. Its
+ completed steps are not undone.
- The token is the only credential. A token takes one outcome: once it
- has succeeded or failed, every later request is refused with
- `409 callback_completed`, including a retry of the request that
- succeeded it.
- operationId: succeedDurableCallback
- security: []
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/SucceedDurableCallbackRequest'
+ Access follows the same rules as reading the execution.
+
+ The call is accepted rather than awaited: the response reports the
+ execution as it was read back and may still say `running`. Poll
+ `GET /durable-functions/{functionId}/executions/{executionId}` to see
+ it settle into `stopped`.
+
+ Stopping an execution that already finished is not an error: the
+ response carries the state it settled in.
+ operationId: stopDurableExecutionFromApplication
+ security:
+ - AnonKey: []
+ - ServiceRoleKey: []
+ - AuthUserAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/DurableFunctionId'
+ - $ref: '#/components/parameters/DurableExecutionId'
+ - $ref: '#/components/parameters/DurableClientToken'
responses:
'200':
- description: The workflow has the result
+ description: |
+ Stop accepted. The body is the execution as it was read back, which
+ may still report `running`.
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableCallbackOutcome'
- '202':
- description: |
- The result is recorded and on its way to the workflow, which takes
- longer than this request waits. Volcano finishes the delivery; do
- not send it again.
+ $ref: '#/components/schemas/DurableExecution'
+ '401':
+ description: Missing or invalid credential
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableCallbackOutcome'
- '400':
- description: The token is missing, or `result` is missing, null, not JSON, or larger than 64 KiB
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: |
+ The anon key lacks `functions.invoke`, the service key is scoped
+ without it, or the function is `authenticated` and the request
+ carries an anon key. Also returned when the request's origin is
+ refused by the project's CORS policy.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: |
- No callback has this token. `code` is `callback_not_found`.
+ Durable function or execution not found, or the credential cannot
+ reach the execution. A `private` function answers every credential
+ but a service key this way.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: |
- The token already has an outcome. `code` is `callback_completed`.
+ The execution has not started yet. Only a service key holding `*`
+ can reach an execution in that state.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '410':
+ '429':
description: |
- The workflow no longer waits on the token. `code` says why:
-
- - `callback_expired`: the step timed out, on its own timeout or
- its heartbeat timeout.
- - `execution_ended`: the execution finished or stopped.
+ The function's or the project's function rate limit, which stops
+ share with invocations and starts, or the project is over its
+ bandwidth cap.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '413':
- description: The request body is larger than 72 KiB
- content:
- application/json:
+ '503':
+ description: |
+ Durable execution is not available in this environment, the plan
+ terms for the request could not be read, or stops or reads of
+ executions in its region are throttled. The first is not one to
+ retry in a loop; the others are transient, and a throttle carries
+ `Retry-After`. A stop throttled while reading the execution back may
+ already have been sent; repeating it is safe, because a stop of an
+ execution that has ended answers the state it ended in.
+ headers:
+ Retry-After:
+ description: |
+ Seconds to wait before trying again. Sent only when stops or
+ reads of executions in the region are throttled.
schema:
- $ref: '#/components/schemas/Error'
- '429':
- description: Too many callback requests for the token or its project. Retry later.
+ type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /durable-callbacks/fail:
+ /durable-functions/{functionId}/executions/{executionId}/messages:
post:
tags:
- Durable Functions
- summary: Fail a waiting step
+ summary: Send a message to a durable execution from an application
description: |
- Resumes the workflow step waiting on the token by raising `error`. The
- SDKs raise it as `CallbackFailedError`, carrying its `type` and
- `message`.
+ Sends a named message to a running execution. The workflow receives it
+ from `ctx.waitForMessage` with the same name. A message sent before
+ anything waits for its name is kept, and each wait takes the oldest
+ one, so messages arrive in the order they were sent.
- The token is the only credential, and takes one outcome, as for
- succeeding it.
- operationId: failDurableCallback
- security: []
+ Messages never decide an approval: a workflow waiting in
+ `ctx.waitForApproval` is not resumed by one.
+
+ **With a service key:** any execution in the project when the key holds
+ `*`, the default. A key scoped to a list without `*`, such as
+ `["functions.invoke"]`, reaches an execution whose
+ `X-Volcano-Client-Token` the request carries, as an anon key does; the
+ start returns that token.
+
+ **With an auth user token:** an execution the user started, or one
+ whose `X-Volcano-Client-Token` the request carries, of a durable
+ function whose `visibility` is `authenticated` or `public`.
+
+ **With an anon key:** an execution whose `X-Volcano-Client-Token` the
+ request carries, of a function with `visibility: public`.
+
+ Any other execution answers `404`, as a missing one does.
+
+ Send `Idempotency-Key` to make a retry safe: a repeat with a key the
+ same sender has used on the execution returns the first message with
+ `200` and sends nothing.
+ operationId: sendDurableMessageFromApplication
+ security:
+ - AnonKey: []
+ - ServiceRoleKey: []
+ - AuthUserAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/DurableFunctionId'
+ - $ref: '#/components/parameters/DurableExecutionId'
+ - $ref: '#/components/parameters/DurableMessageIdempotencyKey'
+ - $ref: '#/components/parameters/DurableClientToken'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/FailDurableCallbackRequest'
+ $ref: '#/components/schemas/SendDurableMessageRequest'
responses:
'200':
- description: The workflow has the error
+ description: A message with this `Idempotency-Key` was already sent; it is returned
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableCallbackOutcome'
- '202':
+ $ref: '#/components/schemas/DurableMessage'
+ '201':
description: |
- The error is recorded and on its way to the workflow. Volcano
- finishes the delivery; do not send it again.
+ Message sent. `status` is `delivered` when a wait took it at once,
+ `delivering` when a wait took it and the handover is still being
+ confirmed, and `queued` when it is kept for the next wait.
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableCallbackOutcome'
+ $ref: '#/components/schemas/DurableMessage'
'400':
- description: The token is missing, or the error's `type` or `message` is invalid
+ description: The name, data or idempotency key is invalid
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
+ '401':
+ description: Missing or invalid credential
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
description: |
- No callback has this token. `code` is `callback_not_found`.
+ The anon key lacks `functions.invoke`, the service key is scoped
+ without it, or the function is `authenticated` and the request
+ carries an anon key. Also returned when the request's origin is
+ refused by the project's CORS policy.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
+ '404':
description: |
- The token already has an outcome. `code` is `callback_completed`.
+ Durable function or execution not found, or the credential cannot
+ reach the execution. A `private` function answers every credential
+ but a service key this way.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '410':
+ '409':
description: |
- The workflow no longer waits on the token. `code` is
- `callback_expired` or `execution_ended`.
+ The message cannot be sent. `code` says why:
+
+ - `execution_not_running`: the execution has finished.
+ - `too_many_queued_messages`: the execution already holds the
+ maximum number of messages nothing has taken.
content:
application/json:
schema:
@@ -6664,911 +6954,905 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'429':
- description: Too many callback requests for the token or its project. Retry later.
+ description: |
+ Too many messages sent to this execution, the function's or the
+ project's function rate limit, which sends share with invocations
+ and starts, or the project is over its bandwidth cap.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /durable-callbacks/heartbeat:
- post:
+ '503':
+ description: The plan terms for the request could not be read. Retry with backoff.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ get:
tags:
- Durable Functions
- summary: Keep a waiting step alive
+ summary: List a durable execution's messages from an application
description: |
- Tells the workflow step waiting on the token that the work is still
- going on, restarting its heartbeat timeout. A heartbeat never extends
- the step's own timeout, and a step without a heartbeat timeout needs
- none.
- operationId: heartbeatDurableCallback
- security: []
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/HeartbeatDurableCallbackRequest'
+ Lists the messages sent to and published by an execution, oldest
+ first. Pass the last `seq` you read as `after` to read only what came
+ next; that is how a client catches up after a live subscription
+ reconnects.
+
+ Access follows the same rules as sending.
+ operationId: listDurableMessagesFromApplication
+ security:
+ - AnonKey: []
+ - ServiceRoleKey: []
+ - AuthUserAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/DurableFunctionId'
+ - $ref: '#/components/parameters/DurableExecutionId'
+ - $ref: '#/components/parameters/DurableClientToken'
+ - $ref: '#/components/parameters/DurableMessageDirectionFilter'
+ - $ref: '#/components/parameters/DurableMessageNameFilter'
+ - $ref: '#/components/parameters/DurableMessageAfter'
+ - $ref: '#/components/parameters/DurableMessageLimit'
responses:
'200':
- description: The step is still waiting
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableCallbackOutcome'
+ $ref: '#/components/schemas/DurableMessageList'
'400':
- description: The token is missing
+ description: A filter is invalid
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: |
- No callback has this token. `code` is `callback_not_found`.
+ '401':
+ description: Missing or invalid credential
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
+ '403':
description: |
- The token already has an outcome. `code` is `callback_completed`.
+ The anon key lacks `functions.invoke`, the service key is scoped
+ without it, or the function is `authenticated` and the request
+ carries an anon key. Also returned when the request's origin is
+ refused by the project's CORS policy.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '410':
+ '404':
description: |
- The workflow no longer waits on the token. `code` is
- `callback_expired` or `execution_ended`.
+ Durable function or execution not found, or the credential cannot
+ reach the execution.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '413':
- description: The request body is larger than 8 KiB
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '429':
- description: Too many callback requests for the token or its project. Retry later.
+ '429':
+ description: |
+ The function's or the project's function rate limit, which lists
+ share with invocations and starts, or the project is over its
+ bandwidth cap.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
- description: The heartbeat could not reach the workflow right now. Retry with backoff.
+ description: The plan terms for the request could not be read. Retry with backoff.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /durable-approvals:
- post:
+ /functions/resolve:
+ get:
tags:
- - Durable Functions
- summary: Request an approval from inside a workflow
+ - Functions
+ summary: Resolve function name for invocation
description: |
- Registers an approval request for a running durable execution. The
- Volcano SDK calls this from `ctx.waitForApproval`; applications do not
- call it directly.
+ Resolves a DNS-safe function name to its function ID and invocation URL within the caller's project.
- `execution_ref` and `callback_id` are opaque values the SDK reads from
- the running workflow. Together they are the request's credential, so
- the operation takes no other authentication. The approval belongs to
- the project that owns the execution, and expires when the workflow's
- own approval timeout does.
+ SDKs use this endpoint internally to invoke by function name while routing by function ID.
+ Invoke the returned `invoke_url` as-is. It does not share a domain with the API, so a host
+ built from the API URL will not reach the function. In local development, and when the
+ deployment serves no public invocation domain, `invoke_url` is omitted and callers invoke
+ through `POST /functions/{functionId}/invoke`. A local function's own `invoke_url`, for
+ webhook testing, is on the function resource.
- Retrying is safe: a request for an approval that is already registered
- returns it with `200`.
- operationId: requestDurableApproval
- security: []
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/RequestDurableApprovalRequest'
+ **With Service Key**:
+ - Allowed
+
+ **With Auth User Token**:
+ - Allowed for `authenticated` and `public` functions
+ - A `private` function answers 404, exactly as a missing one
+
+ **With Anon Key**:
+ - Requires anon key permission: `functions.invoke`
+ - Function must have `visibility: public`; any other answers 404
+ operationId: resolveFunctionForInvocation
+ security:
+ - AnonKey: []
+ - ServiceRoleKey: []
+ - AuthUserAccessToken: []
+ parameters:
+ - name: name
+ in: query
+ required: true
+ schema:
+ type: string
+ maxLength: 63
+ pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$
+ description: DNS-safe function name (lowercase letters, numbers, hyphens; cannot start or end with hyphen)
+ example: my-function
responses:
'200':
- description: The approval was already registered
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DurableApprovalRegistration'
- '201':
- description: Approval registered
+ description: Function resolved successfully
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableApprovalRegistration'
+ $ref: '#/components/schemas/ResolveFunctionResponse'
'400':
- description: The request body is invalid
+ description: Bad request - missing or invalid function name
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: No running durable execution matches `execution_ref`
+ '401':
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
+ '403':
description: |
- The approval cannot be registered now. `code` says why:
-
- - `approval_not_ready`: the workflow has not finished opening the
- approval yet. Retry with a short backoff; the SDK does.
- - `approval_closed`: the workflow is no longer waiting on it.
- - `callback_taken`: the callback is already registered as a
- message wait or a messages session.
- - `execution_ended`: the execution has finished.
- - `too_many_pending_approvals`: the execution already has the
- maximum number of pending approvals.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '413':
- description: The request body is larger than 64 KiB
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '429':
- description: Too many approval requests from this execution or address
+ Forbidden - CORS blocked, or missing `functions.invoke` permission
+ for anon key
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
+ '404':
description: |
- The approval could not be confirmed with the workflow right now.
- Retry with backoff.
+ Function not found. Also returned for a `private` function with an
+ auth user token, and a non-public one with an anon key. A durable
+ function is never resolvable here: it is started through
+ `POST /durable-functions/{functionId}/executions`, not invoked.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/issues:
- get:
+ /projects/{id}/logs/activity:
+ post:
tags:
- - Issues
- summary: List issues
+ - Logs
+ summary: Get project log activity
description: |
- Lists the project's issues, most recently seen first. An issue groups
- the runtime errors one function or frontend raised with the same error
- type and stack, or the same message when there is no stack.
-
- Project access tokens can list issues, including read-only ones.
- operationId: listIssues
+ Retrieve bucketed log counts for one resource type in the project. Set
+ `resource.type` to `function`, `frontend`, or `database`. Add
+ `resource.ids` to filter to one or more resources, and add
+ `resource.deployments.ids` to count deployment logs instead of runtime
+ logs for functions and frontends. Deployment logs are not supported for
+ databases. Database logs are a SUPERAGENT feature; `resource.type=database`
+ from a HOBBY project owner returns 403. The activity window is limited
+ to the plan's retention window (HOBBY: 1 day, SUPERAGENT: 30 days); older start
+ times are clamped to that window. Buckets are aligned to UTC clock
+ intervals and count events in the half-open window
+ `[start_time, end_time)`.
+ operationId: getProjectLogActivity
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/Limit'
- - $ref: '#/components/parameters/IssueCursor'
- - name: status
- in: query
- required: false
- description: Return only issues in this status.
- schema:
- $ref: '#/components/schemas/IssueStatus'
- - name: resource_id
- in: query
- required: false
- description: Return only issues raised by this function or frontend.
- schema:
- type: string
- format: uuid
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/LogActivityRequest'
responses:
'200':
description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/PaginatedIssues'
+ $ref: '#/components/schemas/LogActivityResponse'
'400':
- description: A filter or the cursor is invalid
+ description: Bad request - invalid query parameter
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Project not found. Code `feature_unavailable` means issues are not available in this environment.
+ '401':
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/issues/{issueId}:
- get:
- tags:
- - Issues
- summary: Get an issue
- description: |
- Returns one issue: the resource that raised it, how often and when it
- was seen, and its status.
-
- Project access tokens can read issues, including read-only ones.
- operationId: getIssue
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/IssueId'
- responses:
- '200':
- description: Successful response
+ '403':
+ description: Forbidden - project ownership required
content:
application/json:
schema:
- $ref: '#/components/schemas/Issue'
+ $ref: '#/components/schemas/Error'
'404':
- description: Issue not found. Code `feature_unavailable` means issues are not available in this environment.
+ description: Project or resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- patch:
+ /projects/{id}/logs/search:
+ post:
tags:
- - Issues
- summary: Update an issue
+ - Logs
+ summary: Search project logs
description: |
- Sets an issue's status. A resolved issue that is seen again after it
- was resolved reopens, and `regressed_at` records when. An ignored issue
- stays ignored while it keeps being counted.
-
- Setting the status an issue already has is safe to repeat.
- operationId: updateIssue
+ Search or filter logs for one resource type in the project. Set
+ `resource.type` to `function`, `frontend`, or `database`. Add
+ `resource.ids` to filter to one or more resources, and add
+ `resource.deployments.ids` to read deployment logs instead of runtime
+ logs for functions and frontends. Deployment logs are not supported for
+ databases. Database logs are a SUPERAGENT feature; requests for
+ `resource.type=database` from a HOBBY project owner return 403.
+ Log history (runtime and deployment) is limited to the plan's retention
+ window (HOBBY: 1 day, SUPERAGENT: 30 days); older time ranges are clamped to that
+ window.
+ operationId: searchProjectLogs
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/IssueId'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/UpdateIssueRequest'
+ $ref: '#/components/schemas/LogSearchRequest'
responses:
'200':
- description: Updated
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/Issue'
+ $ref: '#/components/schemas/LogSearchResponse'
'400':
- description: The request body is invalid
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '404':
- description: Issue not found. Code `feature_unavailable` means issues are not available in this environment.
+ description: Bad request - invalid query parameter
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/autofix:
- get:
- tags:
- - Autofix
- summary: Get autofix settings
- description: |
- Returns whether Volcano diagnoses the project's issues with AI, how far
- a run may go, and which model it uses. A project that never saved
- settings returns the defaults, with autofix off.
-
- Your API key is never returned. `api_key_configured`,
- `api_key_provider`, and `api_key_last4` show whether one is set and
- which provider it belongs to.
-
- Where autofix is not available, saved settings stay readable. A project
- that never saved any answers `404` with code `feature_unavailable`.
- operationId: getAutofixSettings
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- responses:
- '200':
- description: Successful response
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/AutofixSettings'
- '404':
- description: Project not found. Code `feature_unavailable` means autofix is not available in this environment and the project never saved settings.
+ '401':
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '501':
- description: Autofix is not available in local mode.
+ '403':
+ description: Forbidden - project ownership required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: The owner's plan could not be resolved. Retry later.
+ '404':
+ description: Project or resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- put:
+ /projects/{id}/logs/stream:
+ post:
tags:
- - Autofix
- summary: Replace autofix settings
+ - Logs
+ summary: Stream project logs
description: |
- Replaces the project's autofix settings. Omitted fields take their
- defaults, except three: an omitted `provider` or `model` keeps its saved
- value, and an omitted `api_key` keeps the stored key. So
- `{"enabled": false}` turns autofix off and keeps the key.
-
- Project access tokens are refused. Autofix opens pull requests in the
- project's repository, so a person turns it on with a platform token or
- in the dashboard.
-
- Turning autofix on needs a plan that includes it. Settings that are
- already on stay stored after a downgrade, and saving them again is not
- refused, but no run starts until the plan includes autofix again. Other
- saves need no plan.
-
- Provider `anthropic` runs on your own API key. A key belongs to the
- provider it was saved with, and turning autofix on with a provider that
- runs on your own key needs one for it. Turning autofix off or switching
- providers keeps the stored key; only
- `DELETE /projects/{id}/autofix/api-key` removes it. Turning autofix on
- with provider `volcano` needs the `autofix.managed_models` capability;
- without it the request answers `400` with code `feature_unavailable`.
+ Live-tail project logs as Server-Sent Events. The request body uses the
+ resource selector plus `q`, `start_time`, and `limit`,
+ including runtime logs and function/frontend deployment logs selected
+ with `resource.deployments`. Deployment logs are not supported for
+ databases. Database logs are a SUPERAGENT feature; `resource.type=database`
+ from a HOBBY project owner returns 403. The `q` field uses the same
+ syntax as search and activity requests. Do not send `cursor` or
+ `end_time`; use `/logs/search` for range backfills.
+ Explicit historical `start_time` values are limited to the plan's
+ retention window (HOBBY: 1 day, SUPERAGENT: 30 days). Resume with
+ `Last-Event-ID` or the `last_event_id` query parameter. The cursor is
+ bound to the request body: the resource selector and every filter must
+ match the original request when reconnecting, otherwise the request is
+ rejected with `400`.
- Where autofix is not available, a project with saved settings can
- still change them with `enabled: false`. Turning autofix on answers
- `404` with code `feature_unavailable`.
- operationId: updateAutofixSettings
+ This is a live tail, not a gap-free backfill. On connect or reconnect the
+ server delivers at most `limit` of the most recent matching events from
+ the cursor position and then follows new events; events older than that
+ window are not replayed. Use `/logs/search` to backfill a time range.
+ operationId: streamProjectLogs
security:
- UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
+ - name: Last-Event-ID
+ in: header
+ required: false
+ schema:
+ type: string
+ description: Opaque stream cursor from the most recent SSE `id` field.
+ - name: last_event_id
+ in: query
+ required: false
+ schema:
+ type: string
+ description: Opaque stream cursor fallback when setting `Last-Event-ID` is not practical.
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/UpdateAutofixSettingsRequest'
+ $ref: '#/components/schemas/LogStreamRequest'
responses:
'200':
- description: Saved
+ description: Server-Sent Events stream. `log` events contain a JSON `LogSearchEvent`; `warning` events contain a JSON object with an `error` field.
content:
- application/json:
+ text/event-stream:
schema:
- $ref: '#/components/schemas/AutofixSettings'
+ type: string
+ examples:
+ log:
+ summary: Log event
+ value: |
+ : connected
+
+ id: STREAM_CURSOR
+ event: log
+ data: {"id":"LOG_EVENT_ID","timestamp":"2024-01-01T12:00:00Z","level":"info","message":"User logged in","resource":{"type":"function","id":"550e8400-e29b-41d4-a716-446655440000","name":"login"},"region":"us-east-1"}
'400':
- description: The request body is invalid, the key does not fit the provider, or turning autofix on with a provider that runs on your own key has no key for it. Code `feature_unavailable` means Volcano-managed models are not available in this environment.
+ description: Bad request - invalid selector, stream cursor, or unsupported stream field
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: The owner's plan does not include autofix, or the request used a project access token. Only a person changes autofix settings.
+ '401':
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Project not found. Code `feature_unavailable` means autofix is not available in this environment, which refuses turning it on and a project's first save.
+ '403':
+ description: Forbidden - project ownership required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '501':
- description: Autofix is not available in local mode.
+ '404':
+ description: Project or resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Turning autofix on needs the owner's plan, which could not be resolved. Nothing was saved. Retry later.
+ '500':
+ description: Internal server error - log streaming setup failed
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/autofix/api-key:
- delete:
+ /projects/{id}/functions/batch:
+ post:
tags:
- - Autofix
- summary: Delete the API key
+ - Functions
+ summary: Deploy multiple functions in one request
description: |
- Deletes the project's stored API key and returns the settings. Autofix
- on the key's provider runs on that key, so it turns off; on another
- provider it stays as it is. Deleting when no key is stored succeeds.
-
- Turning autofix off or switching providers never deletes the key, and
- neither does applying a project configuration. This works where
- autofix is not available, for a project that saved settings.
-
- Project access tokens are refused.
- operationId: deleteAutofixAPIKey
+ Upload multiple function source archives in one multipart request. Each archive should contain source files
+ plus dependency manifests/lockfiles, not installed dependency directories. ZIP and tar.gz uploads are
+ accepted and normalized to tar.gz before storage. The API enforces `SOURCE_ARCHIVE_SIZE_LIMIT_MB`
+ for each uploaded and normalized source archive. The server records a shared
+ deployment batch ID for the resulting function deployments. Each function deployment runs its own
+ compile/publish workflow concurrently, and each publish build enforces `LAMBDA_TARGET_CONTAINER_SIZE_LIMIT_MB`
+ for the final container image.
+ One batch request can include up to 100 functions. Submit multiple batch requests for larger projects.
+ If one function fails before its workflow starts, already-started function deployments are left
+ running and the failed function is reported in the `failed` array. Failed new functions are deleted;
+ failed updates are rolled back to their previous metadata/status where possible.
+ operationId: createFunctionsBatch
security:
- UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
+ requestBody:
+ required: true
+ content:
+ multipart/form-data:
+ schema:
+ type: object
+ properties:
+ functions:
+ type: string
+ description: |
+ JSON array of functions with `name`, `runtime`, optional `handler`, and `file_field`. Each `file_field` must name a multipart file field containing that function's ZIP or tar.gz source bundle.
+
+ Each entry may also declare `variable_scope` (`all` or `scoped`) and `variables` (an array of project variable names). Omitting them leaves the function's stored declaration unchanged. Volcano detects direct environment references in the uploaded source code and keeps them separate from the declared names: detected names are not written back to the declaration and do not appear in a config export. A scoped function receives its declared names plus the detected ones the project defines; a detected name the project does not define is ignored, since such a reference is often optional. Detection reads code only, so a name appearing solely in a comment or in an unrelated string is not a reference. Declare a name when the function reads it through a computed key, or when it must not deploy without the variable. The request is rejected with 400 before anything is deployed if a scoped function declares a variable the project does not define, or if the resulting environment exceeds 4096 bytes.
+
+ Each entry may also carry `commit`, the commit its source came from, as an object: `{"repository": "acme/app", "sha": "<40-character commit ID>", "dirty": false}`. It takes the same values as the `commit` field of a single function upload; `null` or `""` reports no commit. The request is rejected with 400 before anything is deployed if an entry's commit is malformed or names a repository not on GitHub.
+ code_0:
+ type: string
+ format: binary
+ description: Function ZIP or tar.gz archive referenced by the first manifest entry's `file_field`; additional code_N file fields may be included. Each archive is subject to SOURCE_ARCHIVE_SIZE_LIMIT_MB.
+ required:
+ - functions
responses:
- '200':
- description: Deleted
+ '202':
+ description: Batch deployment accepted
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/BatchFunctionDeployResponse'
+ '207':
+ description: Batch deployment partially accepted; successful functions started deployment and failed functions were compensated where possible
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/BatchFunctionDeployResponse'
+ '400':
+ description: Bad request
content:
application/json:
schema:
- $ref: '#/components/schemas/AutofixSettings'
+ $ref: '#/components/schemas/Error'
'403':
- description: The request used a project access token. Only a person deletes the key.
+ description: Function limit exceeded for the project
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Project not found. Code `feature_unavailable` means autofix is not available in this environment and the project never saved settings.
+ '409':
+ description: |
+ A name in the batch is held by a function of the other kind — a
+ function cannot change kind — or the project's source is managed by
+ Git, where deploys come from a push to the production branch. The
+ message `project variables changed during the upload; retry` means
+ `NODE_PATH` was created or deleted while the upload was processed;
+ nothing was deployed, so send the same request again.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '501':
- description: Autofix is not available in local mode.
+ '429':
+ description: |
+ The owner's billing-cycle build-minutes allowance is spent. The
+ error names the allowance and carries a link to the usage page.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/issues/{issueId}/autofix-runs:
- post:
+ '503':
+ description: |
+ Build usage could not be read, so the allowance could not be
+ checked. The same request succeeds once it can be.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/schedulers:
+ get:
tags:
- - Autofix
- summary: Diagnose an issue
+ - Functions
+ summary: List every function scheduler in a project
description: |
- Queues a run that diagnoses the issue with AI. The run reads the
- issue's runtime logs and, when a push to the project's connected
- repository built the deployment that was live when the issue was
- last seen, its source at that commit. Poll the run until its status is
- `succeeded`, `failed`, or `canceled`.
-
- Autofix must be on for the project. An issue has at most one queued or
- running run, a project runs one at a time, and a project starts at most
- 25 runs, manual and automatic, in any 24 hours.
+ Project-scoped counterpart to `/projects/{id}/functions/{functionId}/schedulers`.
+ Returns schedulers across all functions in the project, ordered by
+ creation time descending, with standard page/limit pagination so
+ clients don't have to fan out one request per function.
- Project access tokens are refused. A run spends model tokens on the
- project's provider, so a person starts it with a platform token or in
- the dashboard.
- operationId: startAutofixRun
+ Schedulers of standard and durable functions are listed together, and
+ each carries `function_kind`. Pass `function_kind` to list one kind
+ only.
+ operationId: listProjectSchedulers
security:
- UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/IssueId'
+ - $ref: '#/components/parameters/Page'
+ - $ref: '#/components/parameters/Limit'
+ - $ref: '#/components/parameters/Cursor'
+ - $ref: '#/components/parameters/EndingBefore'
+ - $ref: '#/components/parameters/Offset'
+ - $ref: '#/components/parameters/Search'
+ - $ref: '#/components/parameters/FunctionKindFilter'
responses:
- '202':
- description: Queued
+ '200':
+ description: Project schedulers
content:
application/json:
schema:
- $ref: '#/components/schemas/AutofixRun'
+ $ref: '#/components/schemas/FunctionSchedulerListResponse'
'400':
- description: Code `feature_unavailable` means the project's provider is `volcano` and Volcano-managed models are not available in this environment.
+ description: Bad request - invalid pagination or filter
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
+ /projects/{id}/notifications:
+ get:
+ tags:
+ - Notifications
+ summary: Get notification settings
+ description: |
+ Returns where the project's alerts go and when a failing scheduler is
+ announced. A project that never saved settings returns the defaults:
+ email to the project owner, no webhook, and an alert after 3 failed
+ runs in a row, followed by one when the scheduler recovers.
+
+ The webhook signing secret is never returned here; `secret_configured`
+ shows whether one is set. A read-only project access token is refused
+ with `403`, because the webhook URL can carry the receiver's token.
+ operationId: getNotificationSettings
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ responses:
+ '200':
+ description: Notification settings
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/NotificationSettings'
'403':
- description: The owner's plan does not include autofix, or the request used a project access token.
+ description: The request used a `read_only` project access token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Project or issue not found. Code `feature_unavailable` means autofix is not available in this environment.
+ description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: Autofix is off for the project, or the issue already has a queued or running run.
+ put:
+ tags:
+ - Notifications
+ summary: Update notification settings
+ description: |
+ Changes the project's notification settings. Omitted fields keep their
+ current values, so `{"email": {"enabled": false}}` only turns email off.
+
+ Alert emails go only to the project owner's verified account email
+ address. `email.recipients` may be empty or name that address; any
+ other list is refused with `400`, and so is any non-empty list while
+ the owner has no verified address. `email.status` in the response
+ says whether alerts are being emailed.
+
+ Setting `webhook.url` on a project without a webhook generates its
+ signing secret, returned in `webhook.secret` in this response only.
+ Changing the URL keeps the secret. An empty `webhook.url` removes the
+ webhook and its secret.
+
+ Outside local mode the webhook must be reachable on the public
+ internet; a URL naming a private or loopback address is refused, and
+ so is a delivery to a host name that resolves to one.
+ operationId: updateNotificationSettings
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateNotificationSettingsRequest'
+ responses:
+ '200':
+ description: Saved
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- '429':
- description: The project started its limit of runs in the last 24 hours.
+ $ref: '#/components/schemas/NotificationSettings'
+ '400':
+ description: The request body is invalid, for example a recipient other than the project owner's verified account email address.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '501':
- description: Autofix is not available in local mode.
+ '403':
+ description: The request used a `read_only` project access token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: The owner's plan could not be resolved. Retry later.
+ '404':
+ description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/autofix-runs:
- get:
+ /projects/{id}/notifications/webhook-secret:
+ post:
tags:
- - Autofix
- summary: List autofix runs
+ - Notifications
+ summary: Rotate the webhook signing secret
description: |
- Lists the project's autofix runs, newest first. Runs stay readable after
- autofix is turned off, and where autofix is not available.
-
- Project access tokens can list runs, including read-only ones.
- operationId: listAutofixRuns
+ Replaces the webhook signing secret and returns the settings with the
+ new one in `webhook.secret`, this once. Every delivery from now on is
+ signed with the new secret, including retries of earlier alerts.
+ operationId: rotateNotificationWebhookSecret
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/Limit'
- - $ref: '#/components/parameters/IssueCursor'
- - name: issue_id
- in: query
- required: false
- description: Return only runs for this issue.
- schema:
- type: string
- format: uuid
- - name: status
- in: query
- required: false
- description: Return only runs in this status.
- schema:
- $ref: '#/components/schemas/AutofixRunStatus'
responses:
'200':
- description: Successful response
+ description: Rotated
content:
application/json:
schema:
- $ref: '#/components/schemas/PaginatedAutofixRuns'
- '400':
- description: A filter or the cursor is invalid
+ $ref: '#/components/schemas/NotificationSettings'
+ '403':
+ description: The request used a `read_only` project access token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Project not found.
+ description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '501':
- description: Autofix is not available in local mode.
+ '409':
+ description: No webhook is configured. Set `webhook.url` first.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/autofix-runs/{runId}:
- get:
+ /projects/{id}/notifications/test:
+ post:
tags:
- - Autofix
- summary: Get an autofix run
+ - Notifications
+ summary: Send a test notification
description: |
- Returns one run: its status, the diagnosis once it succeeds, why it
- failed or was canceled, and the model tokens it used. Runs stay readable
- where autofix is not available.
-
- Project access tokens can read runs, including read-only ones.
- operationId: getAutofixRun
+ Sends a `notification.test` event on every channel that delivers
+ right away and reports how each delivery went. A webhook delivery is
+ signed like an alert. Enabled email is reported undelivered, without
+ sending, while the project owner has no verified account email
+ address. One test per project per minute.
+ operationId: sendTestNotification
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/AutofixRunId'
responses:
'200':
- description: Successful response
+ description: The test was attempted. Each delivery reports whether it arrived; a failed one is not retried.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/NotificationTestResult'
+ '403':
+ description: The request used a `read_only` project access token
content:
application/json:
schema:
- $ref: '#/components/schemas/AutofixRun'
+ $ref: '#/components/schemas/Error'
'404':
- description: Project or run not found.
+ description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '501':
- description: Autofix is not available in local mode.
+ '409':
+ description: No webhook is configured, and email is disabled or the project owner has no verified account email address, so there is nowhere to send.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/durable-approvals:
- get:
+ '429':
+ description: A test was sent less than a minute ago.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/functions/{functionId}/schedulers:
+ get:
tags:
- - Durable Functions
- summary: List durable approvals
- description: |
- Lists the approvals durable workflows in the project have requested,
- newest first. Pending approvals are the ones a workflow is waiting on;
- decided, expired, and cancelled ones are kept for a year.
-
- Project access tokens can list approvals, including read-only ones.
- operationId: listDurableApprovals
+ - Functions
+ summary: List schedulers for a function
+ operationId: listFunctionSchedulers
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/Page'
- - $ref: '#/components/parameters/Limit'
- - name: status
- in: query
- required: false
- description: Return only approvals in this status.
- schema:
- $ref: '#/components/schemas/DurableApprovalStatus'
- - $ref: '#/components/parameters/DurableApprovalFunctionFilter'
- - name: execution_id
- in: query
- required: false
- description: Return only approvals requested by this durable execution.
- schema:
- type: string
- format: uuid
- - name: from
- in: query
- required: false
- description: Return only approvals requested at or after this time.
- schema:
- type: string
- format: date-time
- - name: to
- in: query
- required: false
- description: Return only approvals requested before this time.
- schema:
- type: string
- format: date-time
+ - $ref: '#/components/parameters/FunctionId'
responses:
'200':
- description: Successful response
+ description: Function schedulers
content:
application/json:
schema:
- $ref: '#/components/schemas/PaginatedDurableApprovals'
- '400':
- description: A filter is invalid, or `from` is after `to`
+ $ref: '#/components/schemas/FunctionSchedulerListResponse'
+ '404':
+ description: Function not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/durable-approvals/stats:
- get:
+ post:
tags:
- - Durable Functions
- summary: Get durable approval statistics
- description: |
- Counts the project's approvals by outcome over a time window, overall,
- per workflow, and per day. The window defaults to the last 30 days and
- can cover up to a year. An approval is counted on the day it was
- requested.
-
- Project access tokens can read statistics, including read-only ones.
- operationId: getDurableApprovalStats
+ - Functions
+ summary: Create a scheduler for a function
+ description: Creates regional scheduled invocation jobs. Requested regions must be a subset of the function's deployed regions.
+ operationId: createFunctionScheduler
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableApprovalFunctionFilter'
- - name: from
- in: query
- required: false
- description: Start of the window. Defaults to 30 days before `to`.
- schema:
- type: string
- format: date-time
- - name: to
- in: query
- required: false
- description: End of the window. Defaults to now.
- schema:
- type: string
- format: date-time
+ - $ref: '#/components/parameters/FunctionId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateFunctionSchedulerRequest'
responses:
- '200':
- description: Successful response
+ '201':
+ description: Scheduler created
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableApprovalStats'
+ $ref: '#/components/schemas/FunctionScheduler'
'400':
- description: The window is invalid or longer than 366 days
+ description: |
+ Invalid schedule, geofenced region, a scheduler of this name
+ already exists on the function, or the function is not active.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/durable-approvals/{approvalId}:
+ '403':
+ description: |
+ Schedulers are not available on this plan, or the project already
+ holds as many as the plan allows. The cap counts standard and
+ durable function schedulers together.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Function not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/functions/{functionId}/schedulers/{schedulerId}:
get:
tags:
- - Durable Functions
- summary: Get a durable approval
- description: |
- Returns one approval: what the workflow asked, the durable function
- and execution that asked it, its deadline, and the decision once one
- is made.
-
- Project access tokens can read approvals, including read-only ones.
- operationId: getDurableApproval
+ - Functions
+ summary: Get a function scheduler
+ operationId: getFunctionScheduler
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableApprovalId'
+ - $ref: '#/components/parameters/FunctionId'
+ - $ref: '#/components/parameters/SchedulerId'
responses:
'200':
- description: Successful response
+ description: Function scheduler
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableApproval'
+ $ref: '#/components/schemas/FunctionScheduler'
'404':
- description: Approval not found
+ description: Function or scheduler not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/durable-approvals/{approvalId}/approve:
- post:
+ patch:
tags:
- - Durable Functions
- summary: Approve a durable approval
- description: |
- Approves a pending approval. The workflow resumes with the decision.
-
- Only a person can decide: use the dashboard or a platform token from
- `volcano login`. Project access tokens are refused with `403`.
-
- Approving an approval that is already approved returns it unchanged.
- If the workflow cannot be reached right away, the decision still
- stands and Volcano keeps delivering it.
- operationId: approveDurableApproval
+ - Functions
+ summary: Update a function scheduler
+ operationId: updateFunctionScheduler
security:
- UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableApprovalId'
+ - $ref: '#/components/parameters/FunctionId'
+ - $ref: '#/components/parameters/SchedulerId'
requestBody:
- required: false
+ required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableApprovalDecisionRequest'
+ $ref: '#/components/schemas/UpdateFunctionSchedulerRequest'
responses:
'200':
- description: Approved
+ description: Scheduler updated
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableApproval'
+ $ref: '#/components/schemas/FunctionScheduler'
'400':
- description: The request body is invalid
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '403':
- description: The credential is not a person's
+ description: |
+ Invalid schedule, geofenced region, or a scheduler of this name
+ already exists on the function.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Approval not found
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '409':
- description: |
- The approval was already denied, or has expired or been cancelled.
- `code` is `approval_decided`, `approval_expired`, or
- `approval_cancelled`.
+ description: Function or scheduler not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '413':
- description: The request body is larger than 16 KiB
+ delete:
+ tags:
+ - Functions
+ summary: Delete a function scheduler
+ operationId: deleteFunctionScheduler
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/FunctionId'
+ - $ref: '#/components/parameters/SchedulerId'
+ responses:
+ '204':
+ description: Scheduler deleted
+ '404':
+ description: Function or scheduler not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/durable-approvals/{approvalId}/deny:
- post:
+ /projects/{id}/functions/{functionId}/deployments:
+ get:
tags:
- - Durable Functions
- summary: Deny a durable approval
- description: |
- Denies a pending approval. The workflow resumes with the decision; a
- denial is a value the workflow branches on, not an error.
-
- Only a person can decide: use the dashboard or a platform token from
- `volcano login`. Project access tokens are refused with `403`.
-
- Denying an approval that is already denied returns it unchanged.
- If the workflow cannot be reached right away, the decision still
- stands and Volcano keeps delivering it.
- operationId: denyDurableApproval
+ - Functions
+ summary: List function deployments
+ operationId: listFunctionDeployments
security:
- UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DurableApprovalId'
- requestBody:
- required: false
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DurableApprovalDecisionRequest'
+ - $ref: '#/components/parameters/FunctionId'
+ - $ref: '#/components/parameters/Page'
+ - $ref: '#/components/parameters/Limit'
responses:
'200':
- description: Denied
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/DurableApproval'
- '400':
- description: The request body is invalid
+ $ref: '#/components/schemas/PaginatedFunctionDeployments'
+ '404':
+ description: Function not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: The credential is not a person's
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '404':
- description: Approval not found
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '409':
- description: |
- The approval was already approved, or has expired or been
- cancelled. `code` is `approval_decided`, `approval_expired`, or
- `approval_cancelled`.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '413':
- description: The request body is larger than 16 KiB
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- /projects/{id}/frontends:
+ /projects/{id}/durable-functions:
get:
tags:
- - Frontends
- summary: List all frontends in a project
+ - Durable Functions
+ summary: List all durable functions in a project
description: |
- Supports two mutually exclusive pagination modes. Offset mode uses `page`
- and `limit` and returns `next` (URL). Cursor mode uses `cursor` and
- `limit`, supports `search` (case-insensitive name match), and returns
- `next_cursor`. Sending both `page` and `cursor` (or `page` and `search`)
- returns 400.
- operationId: listFrontends
+ Standard functions never appear here, and durable functions never appear
+ under `/projects/{id}/functions`. The two are separate collections.
+ operationId: listDurableFunctions
security:
- UserToken: []
- ProjectAccessToken: []
@@ -7576,9 +7860,6 @@ paths:
- $ref: '#/components/parameters/ProjectId'
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/Limit'
- - $ref: '#/components/parameters/Cursor'
- - $ref: '#/components/parameters/EndingBefore'
- - $ref: '#/components/parameters/Offset'
- $ref: '#/components/parameters/Search'
responses:
'200':
@@ -7586,21 +7867,9 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/PaginatedFrontends'
+ $ref: '#/components/schemas/PaginatedDurableFunctions'
'400':
- description: Bad request - invalid project identifier
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '403':
- description: Forbidden - project ownership required
+ description: Bad request - invalid pagination parameters
content:
application/json:
schema:
@@ -7611,44 +7880,26 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Internal server error
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
post:
tags:
- - Frontends
- summary: Create a new frontend deployment
+ - Durable Functions
+ summary: Create or update a durable function
description: |
- Creates and deploys a frontend for the project.
- If a frontend with the same name already exists in the project, this operation updates that
- frontend using the uploaded archive and starts a new deployment. A deployment that starts
- immediately returns `status: provisioning`, then transitions to `active`, `degraded`, or
- `failed`. If another deployment is running, the response preserves the frontend's current status
- and exposes the queued deployment through `pending_deployment_id`.
- Existing frontend traffic continues to use an available runtime while the new deployment builds
- and provisions. Each deployment publishes its own static assets before the runtimes switch to its
- build, and the live build's assets keep serving until the new deployment is live, so a page loaded
- mid-deployment resolves its assets whichever build served it. A failed redeploy puts the runtimes
- back on the build they were running, leaves the frontend `active` on the previous deployment, and
- records the attempted deployment as failed. `degraded` means the runtime remains available but
- edge synchronization requires recovery; Volcano retries the edge step without rebuilding. Only one deployment may run for a
- given frontend, while independent frontends and projects can deploy concurrently.
- For monorepos, provide `app_root` as a relative path from the uploaded archive root
- to the Next.js app that should be built. Omit it for single-app archives.
- Supported frontend environments are Next.js 15.x and 16.x with Node.js
- 22.x or 24.x. The Node.js runtime is inferred from
- `package.json` `engines.node`; if omitted, Volcano uses Node.js 22.x.
- The selected Node.js family must also satisfy the installed Next.js package's
- `engines.node` constraint. Volcano tests Next 15.5.28 (`^18.18.0 || ^19.8.0 || >=20.0.0`) and Next 16.4.2 (`>=20.9.0`).
- Source archive size is enforced by the API with `SOURCE_ARCHIVE_SIZE_LIMIT_MB`; the CLI
- does not apply its own source archive size limit. After the final container images are
- built, the publish build enforces `LAMBDA_TARGET_CONTAINER_SIZE_LIMIT_MB` before pushing.
- This operation is limited by plan-based frontend deployment quotas (`FREE_FRONTEND_DEPLOYMENTS`, `PRO_FRONTEND_DEPLOYMENTS`).
- Each project can contain up to 10,000 frontends regardless of plan.
- operationId: createFrontend
+ Upload a durable function source bundle. Creates the function on the
+ first call for a name and redeploys it on every call after that, the
+ same create-or-update contract `POST /projects/{id}/functions` has.
+
+ Volcano builds and deploys asynchronously. A deployment that starts
+ immediately returns `status: provisioning`, then transitions to `active`
+ or `failed`; a deployment that has to wait for a running one is exposed
+ through `pending_deployment_id`. Existing executions keep running
+ against the runtime they started on.
+
+ The `durable` configuration is derived from the project's plan rather
+ than supplied here, and is fixed once the function exists. A name
+ already held by a standard function is rejected with 409: a function
+ cannot change kind.
+ operationId: createDurableFunction
security:
- UserToken: []
- ProjectAccessToken: []
@@ -7662,2327 +7913,2730 @@ paths:
type: object
required:
- name
- - archive
+ - code
+ - runtime
properties:
name:
type: string
+ description: DNS-safe function name (lowercase letters, numbers, hyphens; cannot start or end with hyphen)
maxLength: 63
pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$
- description: DNS-safe frontend name
- framework:
+ example: order-pipeline
+ code:
+ type: string
+ format: binary
+ description: ZIP or tar.gz archive containing function source code plus dependency manifests/lockfiles.
+ runtime:
type: string
enum:
- - nextjs
- default: nextjs
- description: Next.js frontend. Supported Next.js majors are 15.x and 16.x.
- app_root:
+ - nodejs22.x
+ - nodejs24.x
+ - python3.13
+ - python3.14
+ description: |
+ Runtime environment. Required. Durable execution needs the
+ durable authoring API, which ships for these runtimes only;
+ any other runtime is rejected with 400 and the response
+ names the ones that work. Note that a durable Python
+ function needs a newer runtime than a standard one defaults
+ to. `GET /functions/runtimes` reports `durable_capable` per
+ runtime.
+ example: nodejs24.x
+ handler:
type: string
- maxLength: 1024
- description: Optional relative POSIX path from the uploaded archive root to the Next.js app to build, for example `apps/web`.
- example: apps/web
+ description: The name of the function to invoke. Defaults to "handler" if not specified.
+ default: handler
+ example: handler
+ visibility:
+ allOf:
+ - $ref: '#/components/schemas/FunctionVisibility'
+ description: |
+ Who may start an execution. Redeploying is the only way to
+ change it, since the collection has no update endpoint; omit
+ it to keep the current visibility, and a new function starts
+ `private`.
+
+ The standard collection's synchronous invocation fields —
+ `invocation_mode`, `http_auth_mode`, `openapi_spec` —
+ configure a request path no durable route serves, and are
+ rejected with 400 rather than ignored.
+ is_public:
+ type: boolean
+ deprecated: true
+ description: |
+ Deprecated alias for `visibility`: `true` means `public` and
+ `false` means `authenticated`. Sending both with different
+ meanings returns 400.
variable_scope:
type: string
enum:
- all
- scoped
- description: Variable selection for this deployment. New frontends default to `scoped`; omitting this field for an existing frontend preserves its current selection.
+ x-enum-varnames:
+ - CreateDurableFunctionMultipartBodyVariableScopeAll
+ - CreateDurableFunctionMultipartBodyVariableScopeScoped
+ description: |
+ Which project variables this function receives. `all` (the default) gives it every project variable; `scoped` gives it only the variables it selects. Omitting this leaves an existing function's scope unchanged.
variables:
- type: array
- items:
- type: string
- pattern: ^[A-Za-z_][A-Za-z0-9_]*$
- description: Project variable names selected when `variable_scope` is `scoped`. Submit each name as a repeated multipart field.
- archive:
type: string
- format: binary
- description: ZIP or tar.gz archive of the frontend project directory or monorepo workspace root. The API enforces SOURCE_ARCHIVE_SIZE_LIMIT_MB and stores a normalized tar.gz archive.
+ description: |
+ JSON-encoded array of project variable names this function requires, on top of the ones detected in its source. A declared name the project does not define is rejected with 400; a detected name it does not define is ignored. Only used when `variable_scope` is `scoped`. Omitting this leaves an existing function's declared names unchanged.
+ commit:
+ type: string
+ description: |
+ JSON-encoded commit the uploaded source came from: `{"repository": "acme/app", "sha": "<40-character commit ID>", "dirty": false}`. `repository` is `owner/name` or a github.com remote URL (`https://github.com/acme/app.git`, `git@github.com:acme/app.git`, or `ssh://git@github.com/acme/app.git`); Volcano drops any credentials in the URL and records `owner/name`. `dirty` is `true` when the uploaded files differ from the commit. All three fields are required, and fields Volcano does not know are ignored. An empty value, `null`, or `""` reports no commit. A malformed commit, or a repository not on GitHub, returns 400 before anything is deployed. Volcano records a function's commit with `commit.verified: false`; a clean commit of the project's connected repository that its production branch holds gets `commit.verification: repository`.
responses:
'200':
- description: Existing frontend updated; its deployment was started or queued
+ description: Existing durable function updated; its deployment was started or queued
content:
application/json:
schema:
- $ref: '#/components/schemas/Frontend'
+ $ref: '#/components/schemas/DurableFunction'
'201':
- description: Frontend created and deployment workflow started
+ description: Durable function created and deployment workflow started
content:
application/json:
schema:
- $ref: '#/components/schemas/Frontend'
+ $ref: '#/components/schemas/DurableFunction'
'400':
- description: Bad request
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
+ description: |
+ Bad request (invalid archive, unsupported runtime, invalid name, an
+ unknown `visibility`, `visibility` and `is_public` disagree, a
+ malformed `commit`, or a project region that does not offer durable
+ execution — a durable
+ function deploys to every region of its project)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Frontend deployment limit exceeded for the current plan or project hard cap
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '404':
- description: Project not found
+ description: Durable function limit exceeded for the project
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
- description: Conflict - frontend deletion is queued or running
+ description: |
+ Name is held by a standard function, or a deletion is queued or
+ running. The request is refused before the deploy starts, so
+ nothing is deployed. The message `project variables changed during
+ the upload; retry` means `NODE_PATH` was created or deleted while
+ the upload was processed; send the same request again.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
- description: Internal server error
+ description: Internal server error (function deployment failed)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
- description: Service unavailable - frontend workflow or archive limit configuration missing
+ description: |
+ Durable deploys are paused platform-wide. The same request succeeds
+ once they are re-enabled; executions already running are unaffected.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/frontends/{frontendId}:
+ /projects/{id}/durable-functions/{functionId}:
get:
tags:
- - Frontends
- summary: Get frontend details
- operationId: getFrontend
+ - Durable Functions
+ summary: Get durable function by ID or name
+ operationId: getDurableFunction
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/FrontendId'
+ - $ref: '#/components/parameters/DurableFunctionId'
responses:
'200':
description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/Frontend'
- '400':
- description: Bad request - invalid identifier
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '403':
- description: Forbidden - project ownership required
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
+ $ref: '#/components/schemas/DurableFunction'
'404':
- description: Frontend not found
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '500':
- description: Internal server error
+ description: Durable function not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
tags:
- - Frontends
- summary: Delete a frontend
+ - Durable Functions
+ summary: Delete a durable function
description: |
- Schedules asynchronous frontend deletion. If another deployment is running, the frontend
- preserves its current status and exposes the queued deletion through `pending_deployment_id`.
- Its status changes to `deleting` when cleanup starts. After cleanup, it returns 404 and no
- longer appears in frontend lists.
- operationId: deleteFrontend
+ Accepted for asynchronous teardown; the work continues after the
+ response. The function's executions go with it: executions still in
+ flight are stopped, and history stops being readable whatever
+ `retention_days` had left.
+
+ Stopping is asynchronous at the platform, and it does not interrupt a
+ step already running -- that step runs to its next checkpoint. So a
+ delete ends an execution rather than halting it mid-step; stop the
+ execution yourself first if you need to observe it ending.
+ operationId: deleteDurableFunction
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/FrontendId'
+ - $ref: '#/components/parameters/DurableFunctionId'
responses:
'202':
- description: Frontend deletion started or queued
- '400':
- description: Bad request - invalid identifier
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
+ description: Deletion accepted and teardown started
+ '404':
+ description: |
+ Durable function not found. Also returned for an id that names a
+ durable function in another project, so the response cannot be used
+ to tell the two apart.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Forbidden - project ownership required
+ /projects/{id}/durable-functions/{functionId}/deployments:
+ get:
+ tags:
+ - Durable Functions
+ summary: List durable function deployments
+ operationId: listDurableFunctionDeployments
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DurableFunctionId'
+ - $ref: '#/components/parameters/Page'
+ - $ref: '#/components/parameters/Limit'
+ responses:
+ '200':
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
+ $ref: '#/components/schemas/PaginatedFunctionDeployments'
'404':
- description: Frontend not found
+ description: Durable function not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Internal server error
+ /projects/{id}/durable-functions/{functionId}/schedulers:
+ get:
+ tags:
+ - Durable Functions
+ summary: List schedulers for a durable function
+ description: |
+ The durable collection's counterpart to
+ `/projects/{id}/functions/{functionId}/schedulers`. A standard
+ function's id is not accepted here, and a durable function's id is not
+ accepted there.
+ operationId: listDurableFunctionSchedulers
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DurableFunctionId'
+ responses:
+ '200':
+ description: Durable function schedulers
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- '503':
- description: Service unavailable - frontend workflow configuration missing
+ $ref: '#/components/schemas/FunctionSchedulerListResponse'
+ '404':
+ description: Durable function not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/frontends/{frontendId}/redeploy:
post:
tags:
- - Frontends
- summary: Redeploy frontend using latest uploaded artifact
+ - Durable Functions
+ summary: Create a scheduler for a durable function
description: |
- Starts a new frontend workflow using the latest stored artifact. A deployment that starts
- immediately returns `status: provisioning`, then transitions to `active`, `degraded`, or
- `failed`. An overlapping deployment preserves the frontend's current status, is exposed through
- `pending_deployment_id`, and supersedes any older queued deployment. The previous runtime and its
- published static assets remain available during provisioning, and a failed redeploy restores the
- regional runtimes to that build and keeps it serving while the attempted deployment is recorded as
- failed.
- operationId: redeployFrontend
+ Each tick starts an execution rather than invoking the function, under
+ an execution name derived from the run, so a retried tick resolves to
+ the execution it already started. Requested regions must be a subset of
+ the function's deployed regions.
+
+ A tick draws on the same durable allowances and concurrency cap a
+ manual start does, and a tick that would exceed the cap fails that run.
+ operationId: createDurableFunctionScheduler
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/FrontendId'
+ - $ref: '#/components/parameters/DurableFunctionId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateFunctionSchedulerRequest'
responses:
- '200':
- description: Frontend redeploy started or queued
+ '201':
+ description: Scheduler created
content:
application/json:
schema:
- $ref: '#/components/schemas/Frontend'
+ $ref: '#/components/schemas/FunctionScheduler'
'400':
- description: Bad request - invalid identifier
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
+ description: |
+ Invalid schedule, geofenced region, a scheduler of this name
+ already exists on the function, or the function is not active.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Forbidden - project ownership required
+ description: |
+ Schedulers are not available on this plan, or the project already
+ holds as many as the plan allows. The cap counts standard and
+ durable function schedulers together.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Frontend not found
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '409':
- description: Conflict - frontend deletion is queued or running
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '500':
- description: Internal server error
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '503':
- description: Service unavailable - frontend workflow configuration missing
+ description: Durable function not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/frontends/{frontendId}/domain:
+ /projects/{id}/durable-functions/{functionId}/schedulers/{schedulerId}:
get:
tags:
- - Frontends
- summary: Get frontend custom domain status
- operationId: getFrontendCustomDomain
+ - Durable Functions
+ summary: Get a durable function scheduler
+ operationId: getDurableFunctionScheduler
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/FrontendId'
+ - $ref: '#/components/parameters/DurableFunctionId'
+ - $ref: '#/components/parameters/SchedulerId'
responses:
'200':
- description: |
- Frontend custom domain status, or null when the frontend has no
- custom domain configured (the common empty state).
- content:
- application/json:
- schema:
- nullable: true
- allOf:
- - $ref: '#/components/schemas/FrontendCustomDomainResponse'
- '400':
- description: Bad request - invalid identifier
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '403':
- description: Forbidden - project ownership required
+ description: Durable function scheduler
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
+ $ref: '#/components/schemas/FunctionScheduler'
'404':
- description: Frontend not found
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '500':
- description: Internal server error
+ description: Durable function or scheduler not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- post:
+ patch:
tags:
- - Frontends
- summary: Configure frontend custom domain
- description: |
- Configures one custom domain for a frontend.
- The default Volcano-generated frontend URL remains active.
- Wildcard Volcano frontend TLS remains valid and isolated from custom-domain certificate changes.
- The account must own the hostname: it must have verified the hostname or a domain above it (see `POST /user/domains`). A certificate does not prove ownership.
- When the account owns no domain covering the hostname, Volcano asks for a TXT record at `_volcano.`, such as `_volcano.example.com`. Publishing it verifies the whole domain, so later subdomains need no record. A managed TLS request reserves the hostname and returns that record in `verification_records`; the reservation expires after 72 hours unless the record is published. A BYOC request gets `409` with `code: ownership_verification_required` and the record in `required_record`; publish it and send the same request again.
- Managed TLS then returns the CNAME that authorizes certificate issuance and renewal.
- To move an active BYOC domain to managed TLS without downtime, send `tls.mode: managed` for the same hostname. The response is `200` with the CNAME to publish; the uploaded certificate keeps serving until Volcano issues the managed one, and `serving_certificate` changes from `uploaded` to `managed`.
- To move an active managed domain to BYOC without downtime, send `tls.mode: byoc` with the certificate for the same hostname. The response is `200`; the uploaded certificate replaces the managed one at once, and Volcano stops renewing the managed certificate.
- An unverified reservation does not block an account that proves ownership. When another account holds one, a request gets `409` with `code: ownership_verification_required` and the caller's own `required_record`; after publishing it, the same request takes over the reservation. When another account verified the domain, the same `409` names the record that moves the domain to the caller once the other account's record is no longer published. A hostname below a domain another account owns otherwise returns `409` without `code`.
- operationId: createFrontendCustomDomain
+ - Durable Functions
+ summary: Update a durable function scheduler
+ operationId: updateDurableFunctionScheduler
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/FrontendId'
+ - $ref: '#/components/parameters/DurableFunctionId'
+ - $ref: '#/components/parameters/SchedulerId'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/CreateFrontendCustomDomainRequest'
+ $ref: '#/components/schemas/UpdateFunctionSchedulerRequest'
responses:
'200':
- description: 'Custom domain already configured with the same hostname. A request with the other TLS mode for the frontend''s active domain switches it in place. To managed TLS, the uploaded certificate keeps serving, with `serving_certificate: uploaded`, until Volcano issues the managed certificate. To BYOC, the uploaded certificate replaces the managed one at once.'
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/FrontendCustomDomainResponse'
- '201':
- description: Custom domain provisioning started
+ description: Scheduler updated
content:
application/json:
schema:
- $ref: '#/components/schemas/FrontendCustomDomainResponse'
+ $ref: '#/components/schemas/FunctionScheduler'
'400':
- description: Bad request - invalid domain
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '403':
- description: Forbidden - the plan does not include custom domains, or a managed TLS request would exceed the account's managed TLS certificate limit
+ description: |
+ Invalid schedule, geofenced region, or a scheduler of this name
+ already exists on the function.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Frontend not found
+ description: Durable function or scheduler not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: 'Conflict - ownership not verified, custom domain owned or reserved by another account, already in use, still detaching, or frontend already has a custom domain. While a removed domain detaches and Volcano releases it (about a minute for BYOC, a few minutes for managed TLS), adding its hostname to any frontend, or any domain to its frontend, returns `code: custom_domain_releasing` and a `Retry-After` header; send the same request again after that many seconds. A release that will not finish within a few minutes returns the conflict without `code`.'
- headers:
- Retry-After:
- description: Seconds to wait before sending the same request again. Sent only with code `custom_domain_releasing`.
- schema:
- type: integer
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/FrontendCustomDomainConflictError'
- '500':
- description: Internal server error
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '503':
- description: Service unavailable - custom domain provisioning is temporarily unavailable
+ delete:
+ tags:
+ - Durable Functions
+ summary: Delete a durable function scheduler
+ operationId: deleteDurableFunctionScheduler
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DurableFunctionId'
+ - $ref: '#/components/parameters/SchedulerId'
+ responses:
+ '204':
+ description: Scheduler deleted
+ '404':
+ description: Durable function or scheduler not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- delete:
+ /projects/{id}/durable-functions/{functionId}/executions:
+ post:
tags:
- - Frontends
- summary: Delete frontend custom domain
- operationId: deleteFrontendCustomDomain
+ - Durable Functions
+ summary: Start a durable execution
+ description: |
+ Starts an execution and returns its handle. Never returns a result: an
+ execution can outlive any request a client could hold open, so the
+ result is read back from
+ `GET /projects/{id}/durable-functions/{functionId}/executions/{executionId}`.
+
+ The request body is the execution's input and must be valid JSON if
+ present. An empty body starts the execution with no input.
+
+ Send `X-Volcano-Execution-Name` to make the start idempotent: repeating a
+ start with the same name returns the existing execution instead of
+ beginning a second one.
+
+ Each execution counts against the project's durable execution
+ allowance, the operations it performs count against the durable
+ operations allowance when it finishes, and the number of executions in
+ flight at once is capped by the plan.
+ operationId: startDurableExecution
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/FrontendId'
+ - $ref: '#/components/parameters/DurableFunctionId'
+ - name: X-Volcano-Execution-Name
+ in: header
+ required: false
+ description: |
+ Idempotency key for this execution. Generated when omitted. A repeat
+ under a name that already names a running execution returns that
+ execution and is not charged again.
+
+ Letters, digits, `-`, `_` and `.`, up to 255 characters. Anything
+ else is rejected with `400`.
+ schema:
+ type: string
+ maxLength: 255
+ pattern: ^[A-Za-z0-9._-]+$
+ requestBody:
+ required: false
+ content:
+ application/json:
+ schema:
+ description: Input passed to the function, up to 256 KiB.
responses:
- '204':
- description: Custom domain detach scheduled
+ '202':
+ description: Execution accepted and started
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DurableExecution'
'400':
- description: Bad request - invalid identifier
+ description: Payload is not valid JSON, or the execution name is invalid
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
+ '404':
+ description: Durable function not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Forbidden - project ownership required
+ '409':
+ description: |
+ Function is not deployed yet, or has no deployed region. Also
+ returned when two starts under the same execution name raced and
+ both released it, which is retryable as it stands.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Frontend or custom domain not found
+ '413':
+ description: Payload exceeds the maximum execution input size
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: The custom domain switched TLS mode while the request ran. Send it again.
+ '429':
+ description: |
+ Too many executions already in flight for this project, or the
+ account is out of one of its billing-cycle durable allowances:
+ executions, operations, or compute. An owner-started execution is
+ metered exactly like an application-started one.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Internal server error
+ '503':
+ description: |
+ Durable execution is not available in this environment, or the
+ plan terms for the start could not be read. The first means the
+ capability is paused or this deployment cannot serve it, so it is
+ not one to retry in a loop; the second is transient.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/frontends/{frontendId}/deployments:
get:
tags:
- - Frontends
- summary: List frontend deployments
- operationId: listFrontendDeployments
+ - Durable Functions
+ summary: List a durable function's executions
+ description: |
+ Returns the platform's last observed status for each execution; listing
+ does not poll each one. Fetch a single execution for its live state.
+ operationId: listDurableExecutions
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/FrontendId'
+ - $ref: '#/components/parameters/DurableFunctionId'
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/Limit'
+ - name: status
+ in: query
+ required: false
+ description: Return only executions in this status.
+ schema:
+ $ref: '#/components/schemas/DurableExecutionStatus'
responses:
'200':
description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/PaginatedFrontendDeployments'
+ $ref: '#/components/schemas/PaginatedDurableExecutions'
'400':
- description: Bad request - invalid identifier
+ description: Unsupported status filter
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
+ '404':
+ description: Durable function not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Forbidden - project ownership required
+ /projects/{id}/durable-functions/{functionId}/executions/{executionId}:
+ get:
+ tags:
+ - Durable Functions
+ summary: Get a durable execution
+ description: |
+ Returns the execution's current state, including its `result` once it has
+ succeeded. Poll this to wait for an execution to finish.
+ operationId: getDurableExecution
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DurableFunctionId'
+ - $ref: '#/components/parameters/DurableExecutionId'
+ responses:
+ '200':
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
+ $ref: '#/components/schemas/DurableExecution'
'404':
- description: Frontend not found
+ description: Durable function or execution not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Internal server error
+ '503':
+ description: |
+ Durable execution is not available in this environment, or reads of
+ the execution's state in its region are throttled. The first means
+ the capability is paused or this deployment cannot serve it, so the
+ request is not one to retry in a loop. A throttled read is transient
+ and carries `Retry-After`.
+ headers:
+ Retry-After:
+ description: |
+ Seconds to wait before reading again. Sent only when reads in
+ the execution's region are throttled.
+ schema:
+ type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/frontends/{frontendId}/usage:
+ /projects/{id}/durable-functions/{functionId}/executions/{executionId}/operations:
get:
tags:
- - Frontends
- summary: Per-day request and error counts for a single frontend
+ - Durable Functions
+ summary: List a durable execution's operations
description: |
- Returns a zero-filled daily series of request counts and 5xx
- error counts for one frontend, oldest first. Each entry is one
- UTC day; missing days (no traffic recorded) come back as
- `requests: 0, errors: 0` so the response always has exactly
- `days` entries.
+ Returns the execution's trace: every operation it began — each step,
+ wait, poll, child context, map item and parallel branch — with when it
+ started and ended, how it ended, and each attempt of a retried step.
+ `invocations` are the windows the function's code was actually running;
+ the gaps between them are time the execution spent suspended, which is
+ not charged.
- Backs the Monitoring section on the frontend detail page in
- the Volcano dashboard. `days` defaults to 30 and is capped at 90 to keep
- the (frontend_id, day) index scan bounded.
- operationId: getFrontendUsageHistory
+ A finished execution's trace is final and `complete` is `true`. A
+ running one is refreshed when it is read, and can be up to about ten
+ seconds behind; `synced_at` says when it was last refreshed. Inputs,
+ results and other payloads are never included.
+
+ The list is not paginated: an execution is limited to 3,000
+ operations, and a trace is read whole.
+ operationId: listDurableExecutionOperations
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/FrontendId'
- - name: days
- in: query
- description: Number of trailing days to return (1–90, default 30).
- required: false
- schema:
- type: integer
- minimum: 1
- maximum: 90
- default: 30
+ - $ref: '#/components/parameters/DurableFunctionId'
+ - $ref: '#/components/parameters/DurableExecutionId'
responses:
'200':
description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/FrontendUsageHistoryResponse'
- '400':
- description: Bad request - invalid identifier
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '403':
- description: Forbidden - project ownership required
+ $ref: '#/components/schemas/DurableExecutionOperationList'
+ '404':
+ description: Durable function or execution not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Frontend not found
+ '500':
+ description: The trace could not be read
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Internal server error
+ '503':
+ description: |
+ Durable execution is not available in this environment. Either the
+ capability is paused or this deployment cannot serve it, so the
+ request is not one to retry in a loop.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/frontends/{frontendId}/function-routes:
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/FrontendId'
- get:
+ /projects/{id}/durable-functions/{functionId}/executions/{executionId}/stop:
+ post:
tags:
- - Frontends
- summary: List a Frontend's Function routes
- operationId: listFrontendFunctionRoutes
+ - Durable Functions
+ summary: Stop a durable execution
+ description: |
+ Cancels a running execution. Its completed steps are not undone.
+
+ The call is accepted rather than awaited: cancellation happens behind
+ it, so the response reports the execution as it was read back and may
+ still say `running`. Do not branch on that status — the execution
+ settles into `stopped` shortly after, and polling
+ `GET /projects/{id}/durable-functions/{functionId}/executions/{executionId}`
+ is how you see it get there.
+
+ Stopping an execution that already finished is not an error: the
+ response carries the state it settled in.
+ operationId: stopDurableExecution
security:
- UserToken: []
- ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DurableFunctionId'
+ - $ref: '#/components/parameters/DurableExecutionId'
responses:
'200':
- description: Function routes ordered from most to least specific
+ description: |
+ Stop accepted. The body is the execution as it was read back, which
+ may still report `running`.
content:
application/json:
schema:
- $ref: '#/components/schemas/FrontendFunctionRouteList'
- '401':
- description: Unauthorized
+ $ref: '#/components/schemas/DurableExecution'
+ '404':
+ description: Durable function or execution not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Project not owned by the caller
+ '409':
+ description: Execution has not started yet
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Failed to list Function routes
+ '503':
+ description: |
+ Durable execution is not available in this environment, or stops or
+ reads of executions in its region are throttled. The first means the
+ capability is paused or this deployment cannot serve it, so the
+ request is not one to retry in a loop. A throttle is transient and
+ carries `Retry-After`. A stop throttled while reading the execution
+ back may already have been sent; repeating it is safe, because a
+ stop of an execution that has ended answers the state it ended in.
+ headers:
+ Retry-After:
+ description: |
+ Seconds to wait before trying again. Sent only when stops or
+ reads of executions in the region are throttled.
+ schema:
+ type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
+ /projects/{id}/durable-functions/{functionId}/executions/{executionId}/messages:
post:
tags:
- - Frontends
- summary: Route a Frontend path to an HTTP Function
- operationId: createFrontendFunctionRoute
+ - Durable Functions
+ summary: Send a message to a durable execution
description: |
- The Frontend and Function must belong to this Project. The Function must be a standard
- Function with `visibility: public` and HTTP invocation mode, because requests through the
- route carry no credential: Volcano does not check a token sent to a route path or add
- `__volcano_auth`, so the Function authenticates its callers itself. A Function cannot leave `public`
- while a route targets it. The route applies to every hostname that resolves to the
- Frontend, including generated, custom-domain, preview, and local hostnames.
+ Sends a named message to a running execution, as
+ `POST /durable-functions/{functionId}/executions/{executionId}/messages`
+ does for an application. The workflow receives it from
+ `ctx.waitForMessage` with the same name; until then it is kept, and
+ waits take messages oldest first.
+
+ Project access tokens can send messages, but read-only ones cannot.
+ A message never decides an approval.
+ operationId: sendDurableMessage
security:
- UserToken: []
- ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DurableFunctionId'
+ - $ref: '#/components/parameters/DurableExecutionId'
+ - $ref: '#/components/parameters/DurableMessageIdempotencyKey'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/CreateFrontendFunctionRouteRequest'
+ $ref: '#/components/schemas/SendDurableMessageRequest'
responses:
- '201':
- description: Function route created
+ '200':
+ description: A message with this `Idempotency-Key` was already sent; it is returned
content:
application/json:
schema:
- $ref: '#/components/schemas/FrontendFunctionRoute'
- '400':
- description: Invalid path or non-HTTP Function
+ $ref: '#/components/schemas/DurableMessage'
+ '201':
+ description: |
+ Message sent. `status` is `delivered`, `delivering`, or `queued`,
+ as on the application route.
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized
+ $ref: '#/components/schemas/DurableMessage'
+ '400':
+ description: The name, data or idempotency key is invalid
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Project not owned by the caller
+ description: The request used a `read_only` project access token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Frontend or Function not found in the Project
+ description: Durable function or execution not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
- description: Path is already routed, the Frontend has reached its 64-route limit, or the Function is not public
+ description: |
+ The message cannot be sent. `code` is `execution_not_running` or
+ `too_many_queued_messages`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Failed to create Function route
+ '413':
+ description: The request body is larger than 72 KiB
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/frontends/{frontendId}/function-routes/{routeId}:
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/FrontendId'
- - $ref: '#/components/parameters/FrontendFunctionRouteId'
- put:
+ '429':
+ description: Too many messages sent to this execution
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ get:
tags:
- - Frontends
- summary: Replace a Frontend Function route
- description: 'Replaces the route''s target, path, and prefix handling. The new target must meet the same rules as on create, including `visibility: public`.'
- operationId: updateFrontendFunctionRoute
+ - Durable Functions
+ summary: List a durable execution's messages
+ description: |
+ Lists the messages sent to and published by an execution, oldest
+ first. Pass the last `seq` you read as `after` to read only what came
+ next.
+
+ Project access tokens can list messages, including read-only ones.
+ operationId: listDurableMessages
security:
- UserToken: []
- ProjectAccessToken: []
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/CreateFrontendFunctionRouteRequest'
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DurableFunctionId'
+ - $ref: '#/components/parameters/DurableExecutionId'
+ - $ref: '#/components/parameters/DurableMessageDirectionFilter'
+ - $ref: '#/components/parameters/DurableMessageNameFilter'
+ - $ref: '#/components/parameters/DurableMessageAfter'
+ - $ref: '#/components/parameters/DurableMessageLimit'
responses:
'200':
- description: Function route replaced
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/FrontendFunctionRoute'
+ $ref: '#/components/schemas/DurableMessageList'
'400':
- description: Invalid path or non-HTTP Function
+ description: A filter is invalid
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized
+ '404':
+ description: Durable function or execution not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Project not owned by the caller
+ /projects/{id}/durable-functions/{functionId}/executions/{executionId}/message-waits:
+ get:
+ tags:
+ - Durable Functions
+ summary: List a durable execution's open message waits
+ description: |
+ Lists the waits an execution has open in `ctx.waitForMessage`, oldest
+ first, so you can see which message names it is waiting for.
+
+ Project access tokens can list waits, including read-only ones.
+ operationId: listDurableMessageWaits
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DurableFunctionId'
+ - $ref: '#/components/parameters/DurableExecutionId'
+ responses:
+ '200':
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
+ $ref: '#/components/schemas/DurableMessageWaitList'
'404':
- description: Function route, Frontend, or Function not found
+ description: Durable function or execution not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: Path is already routed, the Frontend has reached its 64-route limit, or the Function is not public
+ /durable-messages/waits:
+ post:
+ tags:
+ - Durable Functions
+ summary: Wait for a message from inside a workflow
+ description: |
+ Registers a wait for a named message. The Volcano SDK calls this from
+ `ctx.waitForMessage`; applications do not call it directly.
+
+ `execution_ref` and `callback_id` are opaque values the SDK reads from
+ the running workflow. Together they are the request's credential, so
+ the operation takes no other authentication. When a message for the
+ name is already queued, the wait takes the oldest one at once.
+
+ Retrying is safe: a request for a wait that is already registered
+ returns it with `200`.
+ operationId: registerDurableMessageWait
+ security: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/RegisterDurableMessageWaitRequest'
+ responses:
+ '200':
+ description: The wait was already registered
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- '500':
- description: Failed to replace Function route
+ $ref: '#/components/schemas/DurableMessageWaitRegistration'
+ '201':
+ description: Wait registered
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- delete:
- tags:
- - Frontends
- summary: Delete a Frontend Function route
- operationId: deleteFrontendFunctionRoute
- security:
- - UserToken: []
- - ProjectAccessToken: []
- responses:
- '204':
- description: Function route deleted
- '401':
- description: Unauthorized
+ $ref: '#/components/schemas/DurableMessageWaitRegistration'
+ '400':
+ description: The request body is invalid
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Project not owned by the caller
+ '404':
+ description: No running durable execution matches `execution_ref`
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Function route not found on the Frontend
+ '409':
+ description: |
+ The wait cannot be registered now. `code` says why:
+
+ - `callback_not_ready`: the workflow has not finished opening the
+ wait yet. Retry with a short backoff; the SDK does.
+ - `callback_closed`: the workflow is no longer waiting on it.
+ - `callback_taken`: the callback is already registered as an
+ approval or a messages session.
+ - `execution_ended`: the execution has finished.
+ - `too_many_message_waits`: the execution already has the maximum
+ number of open waits.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Failed to delete Function route
+ '413':
+ description: The request body is larger than 8 KiB
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/variable-environments:
- get:
- tags:
- - Variable Environments
- summary: List variable Environments
- operationId: listVariableEnvironments
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- responses:
- '200':
- description: Variable Environments, with Global first and custom Environments ordered by name
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/VariableEnvironmentList'
- '401':
- description: Unauthorized
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '403':
- description: Project not owned by the caller
+ '429':
+ description: Too many requests from this execution
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Failed to list variable Environments
+ '503':
+ description: |
+ The wait could not be confirmed with the workflow right now. Retry
+ with backoff.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
+ /durable-messages/sessions:
post:
tags:
- - Variable Environments
- summary: Create a variable Environment
- operationId: createVariableEnvironment
- description: Creates a custom variable Environment. Global is reserved and already exists. A Project may have at most 100 custom Environments.
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
+ - Durable Functions
+ summary: Open a messages session from inside a workflow
+ description: |
+ Opens the session a workflow publishes messages with. The Volcano SDK
+ calls this once per workflow context, on its first `ctx.publish`;
+ applications do not call it directly.
+
+ As for a wait, `execution_ref` and `callback_id` are the credential.
+ The session's token is delivered to the workflow itself and never
+ appears in a response.
+
+ Retrying is safe: a request for a session that is already registered
+ returns it with `200`.
+ operationId: openDurableMessageSession
+ security: []
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/CreateVariableEnvironmentRequest'
+ $ref: '#/components/schemas/OpenDurableMessageSessionRequest'
responses:
+ '200':
+ description: The session was already registered
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DurableMessageSessionRegistration'
'201':
- description: Variable Environment created
+ description: Session opened
content:
application/json:
schema:
- $ref: '#/components/schemas/VariableEnvironment'
+ $ref: '#/components/schemas/DurableMessageSessionRegistration'
'400':
- description: |
- Invalid name, or the reserved Global name. Schema-invalid names
- return the generic invalid-request error; a reserved name returns
- `invalid_variable_environment`.
+ description: The request body is invalid
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized
+ '404':
+ description: No running durable execution matches `execution_ref`
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Project not owned by the caller
+ '409':
+ description: |
+ The session cannot be opened now. `code` is `callback_not_ready`,
+ `callback_closed`, `callback_taken` (the callback is already
+ registered as an approval or a message wait), `execution_ended`,
+ or `too_many_message_sessions`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Project no longer exists
+ '413':
+ description: The request body is larger than 8 KiB
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: |
- A case-insensitive name conflict or the 100-custom-Environment
- limit has been reached, or the Project is being deleted. Tell them
- apart with `code`, which is `variable_environment_conflict`,
- `variable_environment_limit_reached`, or `project_deleting`.
+ '429':
+ description: Too many requests from this execution
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Failed to create the variable Environment
+ '503':
+ description: |
+ The session could not be confirmed with the workflow right now.
+ Retry with backoff.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/variable-environments/{environmentId}:
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/VariableEnvironmentId'
- get:
+ /durable-messages/publish:
+ post:
tags:
- - Variable Environments
- summary: Get a variable Environment
- operationId: getVariableEnvironment
- security:
- - UserToken: []
- - ProjectAccessToken: []
+ - Durable Functions
+ summary: Publish a message from inside a workflow
+ description: |
+ Publishes a named message from a running workflow. The Volcano SDK
+ calls this from `ctx.publish`; applications do not call it directly.
+
+ The message is stored, listed with the execution's messages, and
+ delivered live to clients subscribed to the execution. Live delivery
+ counts against the project's Realtime messages.
+
+ The SDK sends an `Idempotency-Key` that a rerun of the publishing step
+ repeats, so a step that runs again returns the first message with
+ `200` and stores nothing new. That message is delivered live again,
+ and counts again, because the first run may have stopped before
+ subscribers got it. The SDKs deliver it to a subscriber once.
+ operationId: publishDurableMessage
+ security: []
+ parameters:
+ - name: X-Volcano-Durable-Session
+ in: header
+ required: true
+ description: The session token the workflow received when its session opened.
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 128
+ - $ref: '#/components/parameters/DurableMessageIdempotencyKey'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PublishDurableMessageRequest'
responses:
'200':
- description: Variable Environment details
+ description: A message with this `Idempotency-Key` was already published; it is returned
content:
application/json:
schema:
- $ref: '#/components/schemas/VariableEnvironment'
- '401':
- description: Unauthorized
+ $ref: '#/components/schemas/DurableMessage'
+ '201':
+ description: Message published
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DurableMessage'
+ '400':
+ description: The session token header is missing, or the name, data or idempotency key is invalid
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Project not owned by the caller
+ '401':
+ description: The session token is not valid
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Variable Environment not found in this Project
+ '409':
+ description: |
+ The message cannot be published. `code` is
+ `execution_not_running` or `too_many_published_messages`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Failed to get the variable Environment
+ '413':
+ description: The request body is larger than 72 KiB
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- patch:
+ /durable-callbacks:
+ post:
tags:
- - Variable Environments
- summary: Rename a variable Environment
- operationId: renameVariableEnvironment
- description: Renames a custom Environment without changing its stable ID. Global cannot be renamed.
- security:
- - UserToken: []
- - ProjectAccessToken: []
+ - Durable Functions
+ summary: Get a callback token from inside a workflow
+ description: |
+ Registers a waiting step and returns its callback token. The Volcano
+ SDK calls this from `ctx.waitForCallback`; applications do not call it
+ directly.
+
+ `execution_ref` and `callback_id` are opaque values the SDK reads from
+ the running workflow. Together they are the request's credential, so
+ the operation takes no other authentication. The token works until
+ the step's own timeout, and only for that step.
+
+ Retrying is safe: a request for a step that is already registered
+ returns the same token with `200` while the step still waits. Once
+ the token is answered, or the step times out or ends, a retry answers
+ `409` with `callback_closed`.
+ operationId: registerDurableCallback
+ security: []
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/RenameVariableEnvironmentRequest'
+ $ref: '#/components/schemas/RegisterDurableCallbackRequest'
responses:
'200':
- description: Variable Environment renamed
+ description: The step was already registered; its token is returned
content:
application/json:
schema:
- $ref: '#/components/schemas/VariableEnvironment'
+ $ref: '#/components/schemas/DurableCallbackRegistration'
+ '201':
+ description: Token issued
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DurableCallbackRegistration'
'400':
- description: |
- Invalid name, or the reserved Global name. Schema-invalid names
- return the generic invalid-request error; a reserved name returns
- `invalid_variable_environment`.
+ description: The request body is invalid
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized
+ '404':
+ description: No running durable execution matches `execution_ref`
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Project not owned by the caller
+ '409':
+ description: |
+ The token cannot be issued now. `code` says why:
+
+ - `callback_not_ready`: the workflow has not finished opening the
+ step yet. Retry with a short backoff; the SDK does.
+ - `callback_closed`: the workflow is no longer waiting on it.
+ - `callback_taken`: the step is already registered as an approval
+ or a message wait.
+ - `execution_ended`: the execution has finished.
+ - `too_many_callback_tokens`: the execution already holds the
+ maximum number of open tokens.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Variable Environment not found in this Project
+ '413':
+ description: The request body is larger than 8 KiB
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: |
- A case-insensitive name conflict, an attempt to rename Global, or
- a Project being deleted. Tell them apart with `code`, which is
- `variable_environment_conflict`,
- `variable_environment_immutable`, or `project_deleting`.
+ '429':
+ description: Too many requests from this execution
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Failed to rename the variable Environment
+ '503':
+ description: |
+ The step could not be confirmed with the workflow right now. Retry
+ with backoff.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- delete:
+ /durable-callbacks/succeed:
+ post:
tags:
- - Variable Environments
- summary: Delete a variable Environment
- operationId: deleteVariableEnvironment
- description: Deletes a custom Environment. Global cannot be deleted.
- security:
- - UserToken: []
- - ProjectAccessToken: []
+ - Durable Functions
+ summary: Complete a waiting step with a result
+ description: |
+ Resumes the workflow step waiting on the token with `result`. Call it
+ from the system the workflow handed the token to.
+
+ The token is the only credential. A token takes one outcome: once it
+ has succeeded or failed, every later request is refused with
+ `409 callback_completed`, including a retry of the request that
+ succeeded it.
+ operationId: succeedDurableCallback
+ security: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SucceedDurableCallbackRequest'
responses:
- '204':
- description: Variable Environment deleted
- '401':
- description: Unauthorized
+ '200':
+ description: The workflow has the result
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- '403':
- description: Project not owned by the caller
+ $ref: '#/components/schemas/DurableCallbackOutcome'
+ '202':
+ description: |
+ The result is recorded and on its way to the workflow, which takes
+ longer than this request waits. Volcano finishes the delivery; do
+ not send it again.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DurableCallbackOutcome'
+ '400':
+ description: The token is missing or malformed, or `result` is missing, null, not JSON, or larger than 64 KiB
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Variable Environment not found in this Project
+ description: |
+ No callback has this token. `code` is `callback_not_found`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: |
- Global is protected, or the Project is being deleted. Tell them
- apart with `code`, which is `variable_environment_immutable` or
- `project_deleting`.
+ The token already has an outcome. `code` is `callback_completed`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Failed to delete the variable Environment
+ '410':
+ description: |
+ The workflow no longer waits on the token. `code` says why:
+
+ - `callback_expired`: the step timed out, on its own timeout or
+ its heartbeat timeout.
+ - `execution_ended`: the execution finished or stopped.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/variables:
- get:
- tags:
- - Variables
- summary: List all variables for a project
- description: |
- Returns project-level environment variables used by deployed functions and frontends.
- operationId: listVariables
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/Page'
- - $ref: '#/components/parameters/Limit'
- - $ref: '#/components/parameters/Cursor'
- - $ref: '#/components/parameters/EndingBefore'
- - $ref: '#/components/parameters/Offset'
- - $ref: '#/components/parameters/Search'
- responses:
- '200':
- description: Successful response
+ '413':
+ description: The request body is larger than 72 KiB
content:
application/json:
schema:
- $ref: '#/components/schemas/PaginatedVariables'
- '404':
- description: Project not found
+ $ref: '#/components/schemas/Error'
+ '429':
+ description: Too many callback requests for the token or its project. Retry later.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
+ /durable-callbacks/fail:
post:
tags:
- - Variables
- summary: Create or update a variable
+ - Durable Functions
+ summary: Fail a waiting step
description: |
- Creates a project-level environment variable and triggers asynchronous propagation
- to deployed functions and frontends in the project's configured regions.
- operationId: createVariable
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
+ Resumes the workflow step waiting on the token by raising `error`. The
+ SDKs raise it as `CallbackFailedError`, carrying its `type` and
+ `message`.
+
+ The token is the only credential, and takes one outcome, as for
+ succeeding it.
+ operationId: failDurableCallback
+ security: []
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/CreateVariableRequest'
+ $ref: '#/components/schemas/FailDurableCallbackRequest'
responses:
- '201':
- description: Variable created
+ '200':
+ description: The workflow has the error
content:
application/json:
schema:
- $ref: '#/components/schemas/Variable'
+ $ref: '#/components/schemas/DurableCallbackOutcome'
+ '202':
+ description: |
+ The error is recorded and on its way to the workflow. Volcano
+ finishes the delivery; do not send it again.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DurableCallbackOutcome'
'400':
- description: Bad request
+ description: The token is missing or malformed, or the error's `type` or `message` is invalid
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Private variable membership writes are disabled during rollout
+ '404':
+ description: |
+ No callback has this token. `code` is `callback_not_found`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/databases:
- get:
- tags:
- - Databases
- summary: List all databases for a project
- description: |
- Supports two mutually exclusive pagination modes. Offset mode uses `page`
- and `limit`. Cursor mode uses `cursor` and `limit`, supports `search`
- (case-insensitive name match), and returns `next_cursor`/`prev_cursor`.
- The optional `status` filter applies in both modes and is bound to the
- cursor. Sending both `page` and `cursor` (or `page` and `search`) returns 400.
- operationId: listDatabases
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/Page'
- - $ref: '#/components/parameters/Limit'
- - $ref: '#/components/parameters/Cursor'
- - $ref: '#/components/parameters/EndingBefore'
- - $ref: '#/components/parameters/Offset'
- - $ref: '#/components/parameters/Search'
- - name: status
- in: query
- required: false
- schema:
- type: string
- enum:
- - provisioning
- - active
- - restoring
- - failed
- - deleting
- description: Return only the databases in this status.
- responses:
- '200':
- description: Successful response
+ '409':
+ description: |
+ The token already has an outcome. `code` is `callback_completed`.
content:
application/json:
schema:
- $ref: '#/components/schemas/PaginatedDatabases'
+ $ref: '#/components/schemas/Error'
+ '410':
+ description: |
+ The workflow no longer waits on the token. `code` is
+ `callback_expired` or `execution_ended`.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '413':
+ description: The request body is larger than 200 KiB
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '429':
+ description: Too many callback requests for the token or its project. Retry later.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /durable-callbacks/heartbeat:
post:
tags:
- - Databases
- summary: Create a new PostgreSQL database
+ - Durable Functions
+ summary: Keep a waiting step alive
description: |
- Creates a PostgreSQL database in the project.
- Each project can hold 1 database on HOBBY and up to 10,000 on SUPERAGENT.
- Requests over the plan's cap return 403.
- operationId: createDatabase
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
+ Tells the workflow step waiting on the token that the work is still
+ going on, restarting its heartbeat timeout. A heartbeat never extends
+ the step's own timeout, and a step without a heartbeat timeout needs
+ none.
+ operationId: heartbeatDurableCallback
+ security: []
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/CreateDatabaseRequest'
+ $ref: '#/components/schemas/HeartbeatDurableCallbackRequest'
responses:
- '201':
- description: Database created (provisioning)
+ '200':
+ description: The step is still waiting
content:
application/json:
schema:
- $ref: '#/components/schemas/Database'
- '403':
- description: Database limit exceeded for the project
+ $ref: '#/components/schemas/DurableCallbackOutcome'
+ '400':
+ description: The token is missing or malformed
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/databases/{databaseName}:
- get:
- tags:
- - Databases
- summary: Get database details
- operationId: getDatabase
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
- responses:
- '200':
- description: Successful response
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Database'
- delete:
- tags:
- - Databases
- summary: Delete a database
- description: |
- Deletes a database and the instance backing it. When the instance is
- removed synchronously the database row is deleted and the response is
- `204`. If the instance cannot be deleted right away, the database row
- is retained (status `deleting`) and its teardown is handed to the
- background reconciler, which retries the deletion and removes the row
- once the instance is gone; in that case the response is `202`. The database row is
- never dropped while its instance still exists, so an instance is
- never orphaned without a record to retry from.
- operationId: deleteDatabase
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
- responses:
- '202':
- description: |
- Deletion accepted and in progress. The backing instance could not be
- removed synchronously, so the database is marked `deleting` and torn
- down asynchronously by the reconciler.
- content:
- application/json:
- schema:
- type: object
- properties:
- status:
- type: string
- example: deleting
- message:
- type: string
- example: database deletion in progress
- '204':
- description: Database deleted (backing instance removed synchronously)
- '404':
- description: Project or database not found
+ '404':
+ description: |
+ No callback has this token. `code` is `callback_not_found`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: |
- A restore is running on the database. Deleting it while a worker is
- replacing its data would race that worker, so wait for the restore
- to finish.
+ The token already has an outcome. `code` is `callback_completed`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
+ '410':
description: |
- Volcano could not check whether a restore is running, and will not
- delete a database that might be mid-restore. Retry.
+ The workflow no longer waits on the token. `code` is
+ `callback_expired` or `execution_ended`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/databases/{databaseName}/branches:
- get:
- tags:
- - Database Branches
- summary: List a database's branches
- description: |
- Returns every branch of the database, including those still provisioning
- and those that failed, since each still holds a name.
-
- Connection strings are omitted. Fetch a single branch to get its
- connection string.
- operationId: listDatabaseBranches
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
- responses:
- '200':
- description: Successful response
+ '413':
+ description: The request body is larger than 8 KiB
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseBranchList'
- '404':
- description: Project or database not found
+ $ref: '#/components/schemas/Error'
+ '429':
+ description: Too many callback requests for the token or its project. Retry later.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
- description: Branching is temporarily unavailable
+ description: The heartbeat could not reach the workflow right now. Retry with backoff.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
+ /durable-approvals:
post:
tags:
- - Database Branches
- summary: Create a branch of a database
+ - Durable Functions
+ summary: Request an approval from inside a workflow
description: |
- Forks the database into a new branch. The branch starts as an exact copy
- of the parent's data and diverges from there.
+ Registers an approval request for a running durable execution. The
+ Volcano SDK calls this from `ctx.waitForApproval`; applications do not
+ call it directly.
- Provisioning is asynchronous: the response is `202` with the branch in
- `provisioning` and no connection string. Poll the branch until it reports
- `active`, at which point it carries its own connection string.
+ `execution_ref` and `callback_id` are opaque values the SDK reads from
+ the running workflow. Together they are the request's credential, so
+ the operation takes no other authentication. The approval belongs to
+ the project that owns the execution, and expires when the workflow's
+ own approval timeout does.
- Retrying a create with a name that already exists returns `409` rather
- than a second branch, so a retried request cannot silently consume two
- slots of the branch allowance.
- operationId: createDatabaseBranch
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
+ Retrying is safe: a request for an approval that is already registered
+ returns it with `200`.
+ operationId: requestDurableApproval
+ security: []
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/CreateDatabaseBranchRequest'
+ $ref: '#/components/schemas/RequestDurableApprovalRequest'
responses:
- '202':
- description: Branch accepted and provisioning
+ '200':
+ description: The approval was already registered
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseBranch'
- '400':
- description: Invalid branch name or lifetime
+ $ref: '#/components/schemas/DurableApprovalRegistration'
+ '201':
+ description: Approval registered
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- '403':
- description: |
- The database has reached its branch allowance, or the owner's plan
- does not include branching.
+ $ref: '#/components/schemas/DurableApprovalRegistration'
+ '400':
+ description: The request body is invalid
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Project or database not found
+ description: No running durable execution matches `execution_ref`
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: |
- A branch of that name already exists on this database, or the
- database cannot be branched right now because it is still
- provisioning, being restored, failed, or being deleted.
+ The approval cannot be registered now. `code` says why:
+
+ - `approval_not_ready`: the workflow has not finished opening the
+ approval yet. Retry with a short backoff; the SDK does.
+ - `approval_closed`: the workflow is no longer waiting on it.
+ - `callback_taken`: the callback is already registered as a
+ message wait or a messages session.
+ - `execution_ended`: the execution has finished.
+ - `too_many_pending_approvals`: the execution already has the
+ maximum number of pending approvals.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '413':
+ description: The request body is larger than 64 KiB
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '429':
+ description: Too many approval requests from this execution or address
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
- description: Branching is temporarily unavailable
+ description: |
+ The approval could not be confirmed with the workflow right now.
+ Retry with backoff.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/databases/{databaseName}/branches/{branchName}:
+ /projects/{id}/capabilities:
get:
tags:
- - Database Branches
- summary: Get a branch
+ - Projects
+ summary: List a project's capabilities
description: |
- Returns the branch, including its connection string once it is `active`.
- Poll this after creating a branch to learn when it is connectable.
- operationId: getDatabaseBranch
+ Lists which product capabilities accept new work for this project. It
+ has the same entries as `GET /capabilities`, and answers each one as it
+ does, except for capabilities a project can have when another can't:
+
+ | ID | Available for this project when |
+ | --- | --- |
+ | `lavaflow` | LavaFlow is released, offered to the project's owner, and included in the owner's plan |
+ | `lavaflow.merge` | `lavaflow` is, and LavaFlow's merging is released in this environment |
+ | `lavaflow.lineage` | `lavaflow` is, and fix lineage is released in this environment |
+ | `lavaflow.code_quality` | `lavaflow` is, Code Quality is released in this environment, and the owner's plan allows Code Quality findings; with an allowance of 0 it is `unavailable` with `code` `plan_required` |
+ | `lavaflow.slack` | `lavaflow` is, the Volcano Slack app is set up in this environment, and Slack reports have launched in it |
+
+ Where `lavaflow` isn't available, a project with LavaFlow settings or
+ runs lists it `read_only`: its LavaFlow reads answer, and its owner can
+ turn LavaFlow off. A project without them lists it `unavailable`, with
+ `code` `plan_required` when the owner's plan leaves LavaFlow out.
+
+ Check it to decide what to offer for a project, instead of calling a
+ route to see whether it fails. Project access tokens can read it,
+ including read-only ones.
+ operationId: listProjectCapabilities
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
- - $ref: '#/components/parameters/BranchName'
responses:
'200':
- description: Successful response
+ description: Capabilities for this project
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseBranch'
- '404':
- description: Project, database, or branch not found
+ $ref: '#/components/schemas/CapabilityList'
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Branching is temporarily unavailable
+ '404':
+ description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- patch:
+ /lavaflow/settings:
+ get:
tags:
- - Database Branches
- summary: Extend a branch's lifetime
+ - LavaFlow
+ summary: Get LavaFlow settings
description: |
- Replaces the branch's lifetime and restarts the countdown from now, so a
- branch you are still working on is not swept mid-session. The new
- duration is remembered, so a later reset re-arms the same lifetime.
- operationId: updateDatabaseBranch
+ Returns whether LavaFlow works on the project's issues, how far it goes
+ on its own, and its saved context and instructions, which runs do not
+ use yet. A project
+ that never saved settings returns the defaults, with LavaFlow off.
+ LavaFlow sends this project's logs and source code to an AI service
+ that Volcano operates.
+
+ `can_update` says whether the caller can save the settings: only the
+ project's owner can, with a platform token. Project access tokens can
+ read the settings, including read-only ones.
+ operationId: getLavaflowSettings
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
- - $ref: '#/components/parameters/BranchName'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/UpdateDatabaseBranchRequest'
+ - $ref: '#/components/parameters/ProjectIdQuery'
responses:
'200':
- description: Lifetime updated
+ description: The project's LavaFlow settings
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseBranch'
+ $ref: '#/components/schemas/LavaflowSettings'
'400':
- description: Requested lifetime is outside the allowed range
+ description: '`project_id` is missing or not a UUID.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Project, database, or branch not found
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: The branch is being deleted
+ '403':
+ description: Code `plan_required` means the owner's plan does not include LavaFlow and the project has no LavaFlow records. Without a code, the owner's plan could not be read; retry later.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Branching is temporarily unavailable
+ '404':
+ description: Not found. A project the caller can't read answers exactly like one that doesn't exist, and so does one being deleted. Code `feature_unavailable` means LavaFlow is not available for this project and it has no LavaFlow records.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- delete:
+ put:
tags:
- - Database Branches
- summary: Delete a branch
+ - LavaFlow
+ summary: Update LavaFlow settings (deprecated)
+ deprecated: true
description: |
- Marks the branch for teardown and returns immediately. The branch stops
- accepting connections at once; its fork and its row are removed by a
- background job, so a provider outage cannot leave the call hanging or the
- branch half-deleted.
+ Deprecated: use `PATCH /lavaflow/settings`, which takes the same body.
+ This operation keeps working, and refuses every project access token
+ before it reads the body.
- Deleting a branch that is still provisioning is allowed and stops the
- build, and repeating the call while teardown is in progress is accepted
- again. Once the branch is gone the call returns `404`.
- operationId: deleteDatabaseBranch
+ Changes the fields the request names for the project `project_id`
+ names; an omitted field keeps its saved value, or its default when
+ nothing is saved. `{"project_id": "…", "enabled": true}` turns LavaFlow
+ on for every function, frontend and durable function in the project,
+ and records the repository the project points at as the one LavaFlow
+ works in. A request carrying `"enabled": true` is a turn-on, even while
+ LavaFlow is on. When the project points at no repository at a turn-on,
+ the first repository it connects afterwards is recorded. A request
+ that omits `enabled` never changes which repository is recorded.
+ LavaFlow sends this project's logs
+ and source code to an AI service that Volcano operates.
+
+ Turning LavaFlow on, from off, also starts runs for up to 5 open issues
+ with `exception: true` and an `event_count` of at least 2, last seen in
+ the past 7 days, most recently seen first, leaving out any issue
+ LavaFlow already ran; runs LavaFlow queued on its own and hasn't
+ started count toward the 5. They start like any run LavaFlow starts on
+ its own, one at a time per project. Only the owner's save with a
+ `volcano login` token whose sign-in is live, or a platform token that
+ expires, starts them; any other save turns LavaFlow on without them. A save while LavaFlow is on starts none, and neither
+ does LavaFlow becoming available to the project.
+
+ Only the project's owner can save, with a platform token, while their
+ account is active. A full-scope project access token, its save that
+ turns skill learning off included, or a request made through MCP,
+ gets `403` with code `person_required`; a token sends that save with
+ `PATCH`. A read-only project access token is refused as read-only
+ first, without a code, and so is the owner of a read-only account.
+
+ `autonomy: merge` needs the project's `lavaflow.merge` capability.
+ Without it, a save that sets `autonomy` to `merge`, or changes
+ `merge_policy`, answers `400` with code `feature_unavailable`. A save
+ that sends the saved values again passes this check, though it can
+ still need the owner's check below, and a project at `merge` can
+ still change to another autonomy. The save doesn't read the
+ repository's branch rules: LavaFlow merges only into a base branch
+ that requires at least one status check, and holds every fix with
+ `no_required_checks` on any other.
+
+ Changing `autonomy` to `merge` lets LavaFlow merge with no one else
+ looking. So does turning `enabled` on while `autonomy` stays `merge`,
+ and changing `merge_policy`, `custom_context` or `system_prompt`, to
+ any value, while `autonomy` is, or becomes, `merge`. Under settings
+ saved with automatic runs off before this API, the runs LavaFlow
+ starts on its own stop at a draft pull request. Sending `enabled:
+ true` or `autonomy: merge` again, while LavaFlow is on and `autonomy`
+ is `merge`, lets them merge, so it needs the same check. Turning
+ `allow_ungated_workflows` on lets LavaFlow open a fix
+ where a workflow could run it with the repository's secrets before a
+ person approves it. Turning `skill_learning` up, from `off` to
+ `review` or `auto` or from `review` to `auto`, lets what LavaFlow
+ learns steer later runs with less review. Only the owner can make
+ these changes, with a
+ credential of their own that expires: a `volcano
+ login` token whose sign-in is live, or a platform token with an
+ expiry. The owner's GitHub account must also be able to push to the
+ project's repository. A project access token, MCP, a platform token
+ that never expires, a sign-in that ended, an owner who can't push, and
+ a project with no repository get `403` with code `person_required`,
+ and nothing is saved. Turning LavaFlow or `allow_ungated_workflows`
+ off, and turning `skill_learning` down or off, needs no check.
+ Nothing is saved either when the push check can't be answered (`429`
+ or `503`, with `Retry-After`). When the project points at another
+ repository, reaches its repository through another Volcano GitHub App
+ installation, or points at none, `autonomy` changes from `merge` to
+ `open_pr`; pointing back doesn't change it back. Reconnecting after a
+ reinstall of the App counts as another installation.
+
+ Turning LavaFlow on needs a plan that includes it (`403`, code
+ `plan_required`). LavaFlow is available where the project's
+ `lavaflow` capability is, which includes the owner's plan. Where it is
+ not, a project with LavaFlow records can still turn LavaFlow, Code
+ Quality or skill learning off, or several of them: a save that sends
+ `enabled: false`, `code_quality: {enabled: false}`,
+ `skill_learning: off` or several of them, and otherwise only
+ `allow_ungated_workflows: false` sent with `enabled` or
+ `skill_learning`. Any other save,
+ and any save for a project without records, answers `404` with code
+ `feature_unavailable` while LavaFlow is not offered to the project, and
+ `403` with code `plan_required` when it is but the owner's plan does
+ not include it.
+ operationId: updateLavaflowSettings
security:
- UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
- - $ref: '#/components/parameters/BranchName'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/LavaflowSettingsUpdate'
responses:
- '202':
- description: Deletion accepted and in progress
+ '200':
+ description: Saved
content:
application/json:
schema:
- type: object
- properties:
- status:
- type: string
- example: deleting
- message:
- type: string
- example: branch deletion in progress
- required:
- - status
- - message
- '404':
- description: Project, database, or branch not found
+ $ref: '#/components/schemas/LavaflowSettings'
+ '400':
+ description: 'The body is invalid: `project_id` missing or not a UUID, no field to change, an unknown field or autonomy, a `human_review_paths` pattern that is not relative to the repository root or holds a NUL character, or `custom_context` or `system_prompt` over 4000 characters. Code `feature_unavailable` means the save sets `autonomy: merge` or changes `merge_policy` without the project''s `lavaflow.merge` capability, or turns `skill_learning` up without the project''s `lavaflow.skills` capability.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Branching is temporarily unavailable
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/databases/{databaseName}/branches/{branchName}/reset:
- post:
- tags:
- - Database Branches
- summary: Reset a branch to its parent's current state
- description: |
- Discards everything written on the branch and re-forks it from the
- parent as it is now.
-
- Returns immediately with the branch in `provisioning`. The rewind runs in
- the background; poll the branch until it reports `active` before
- connecting again.
-
- The branch keeps its name and its connection string, so anything holding
- that string keeps working once it is active again, and its lifetime is
- re-armed to the duration it was created with. The branch does not serve
- connections for the duration of the reset.
- operationId: resetDatabaseBranch
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
- - $ref: '#/components/parameters/BranchName'
- responses:
- '202':
- description: Branch reset accepted; the branch is provisioning
+ '403':
+ description: 'Code `person_required` means a full-scope project access token or MCP made the request, or the save turns on a setting only the project''s owner may turn on, and the owner did not make it with a credential of their own that expires: a `volcano login` token whose sign-in is live, or a platform token with an expiry, never a project access token or a platform token that never expires. Those settings are `code_quality`, `allow_ungated_workflows`, `autonomy: merge`, `enabled` turned on while `autonomy` stays `merge`, a change to `merge_policy`, `custom_context` or `system_prompt` while `autonomy` is or becomes `merge`, `enabled: true` or `autonomy: merge` sent again under settings saved with automatic runs off before this API, which lets the runs LavaFlow starts on its own merge, and `skill_learning` turned up from `off` or from `review`. It also means the owner''s GitHub account can''t push to the project''s repository, or the project has none. Code `plan_required` means the owner''s plan does not include LavaFlow. Without a code: a read-only project access token made the request, the owner''s account is read-only, or the owner''s plan could not be read and nothing was saved; retry later.'
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseBranch'
+ $ref: '#/components/schemas/Error'
'404':
- description: Project, database, or branch not found
+ description: Not found. A project the caller can't read answers exactly like one that doesn't exist, and so does one being deleted. Code `feature_unavailable` means LavaFlow is not available for this project and the save does more than turn LavaFlow, Code Quality or skill learning off on a project with LavaFlow records.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
+ description: Another save, or a change of the project's repository, changed the settings while this save checked them, and kept changing them when it tried again. Nothing was saved. Send the request again.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '413':
+ description: Request body exceeds 131,072 bytes
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '429':
description: |
- The branch is not active, a reset is already in progress, the parent
- database is being restored, or the parent was restored within the
- last 24 hours — a reset re-forks from the parent, and the provider
- holds a child's reset shut for that long afterwards.
+ The save turns on `code_quality`, `allow_ungated_workflows` or
+ `autonomy: merge`, turns `enabled` on under `merge`, changes
+ `merge_policy`, `custom_context` or `system_prompt` under `merge`,
+ lets the runs LavaFlow starts on its own merge again, or turns
+ `skill_learning` up, and the project, or its owner across their
+ projects, used up the hour's checks of the owner's GitHub push access.
+ Nothing was saved. Try again after `Retry-After`.
+ headers:
+ Retry-After:
+ description: Seconds until the budget's hour ends.
+ schema:
+ type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
- description: Branching is temporarily unavailable
+ description: |
+ The save turns on `code_quality`, `allow_ungated_workflows` or
+ `autonomy: merge`, turns `enabled` on under `merge`, changes
+ `merge_policy`, `custom_context` or `system_prompt` under `merge`,
+ lets the runs LavaFlow starts on its own merge again, or turns
+ `skill_learning` up, and the owner's GitHub push access could not be
+ checked now.
+ Nothing was saved. Try again after `Retry-After`.
+ headers:
+ Retry-After:
+ description: Seconds to wait before saving again.
+ schema:
+ type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/databases/{databaseName}/branches/{branchName}/reset-password:
- post:
+ patch:
tags:
- - Database Branches
- summary: Rotate a branch's password
- description: |
- Issues a new password for the branch and invalidates the previous
- connection string. Existing connections are not interrupted; new ones
- must use the returned string. Proxies pick the rotation up within a few
- seconds, so the previous password can still open new connections until
- then.
+ - LavaFlow
+ summary: Update LavaFlow settings
+ description: |
+ Changes the fields the request names for the project `project_id`
+ names; an omitted field keeps its saved value, or its default when
+ nothing is saved. `{"project_id": "…", "enabled": true}` turns LavaFlow
+ on for every function, frontend and durable function in the project,
+ and records the repository the project points at as the one LavaFlow
+ works in. A request carrying `"enabled": true` is a turn-on, even while
+ LavaFlow is on. When the project points at no repository at a turn-on,
+ the first repository it connects afterwards is recorded. A request
+ that omits `enabled` never changes which repository is recorded.
+ LavaFlow sends this project's logs and source code to an AI service
+ that Volcano operates.
- The parent database's credentials are untouched.
- operationId: resetDatabaseBranchPassword
+ Turning LavaFlow on, from off, also starts runs for up to 5 open issues
+ with `exception: true` and an `event_count` of at least 2, last seen in
+ the past 7 days, most recently seen first, leaving out any issue
+ LavaFlow already ran; runs LavaFlow queued on its own and hasn't
+ started count toward the 5. They start like any run LavaFlow starts on
+ its own, one at a time per project. Only the owner's save with a
+ `volcano login` token whose sign-in is live, or a platform token that
+ expires, starts them; any other save turns LavaFlow on without them. A save while LavaFlow is on starts none, and neither
+ does LavaFlow becoming available to the project.
+
+ Only the project's owner can save, with a platform token, while their
+ account is active. A full-scope project access token can only turn
+ settings off: a body with `project_id` and one or both of
+ `"code_quality": {"enabled": false}` and `"skill_learning": "off"`,
+ each field spelled exactly and sent once, and nothing else. Any other
+ body from a project access token, including one that turns a setting
+ on, adds a field, sends `null`, or names a field the schema doesn't
+ have, gets `403` with code `person_required`, as does a request made
+ through MCP. A read-only project access token is refused as read-only
+ first, without a code,
+ and so is the owner of a read-only account.
+
+ `code_quality.enabled: true` turns on LavaFlow Code Quality, which
+ reviews the lines each production deploy of a frontend changes and
+ turns what it confirms into issues and pull requests. Function deploys
+ ask for no scan yet. It needs the project's `lavaflow.code_quality`
+ capability: while Code Quality isn't released here the save answers
+ `400` with code `feature_unavailable`, and while the owner's plan
+ allows no Code Quality findings it answers `403` with code
+ `plan_required`. Only the owner can turn it on, with the check below.
+ Turning it off always works, and drops the deploys waiting to be
+ scanned.
+
+ `autonomy: merge` needs the project's `lavaflow.merge` capability.
+ Without it, a save that sets `autonomy` to `merge`, or changes
+ `merge_policy`, answers `400` with code `feature_unavailable`. A save
+ that sends the saved values again passes this check, though it can
+ still need the owner's check below, and a project at `merge` can
+ still change to another autonomy. The save doesn't read the
+ repository's branch rules: LavaFlow merges only into a base branch
+ that requires at least one status check, and holds every fix with
+ `no_required_checks` on any other.
+
+ Changing `autonomy` to `merge` lets LavaFlow merge with no one else
+ looking. So does turning `enabled` on while `autonomy` stays `merge`,
+ and changing `merge_policy`, `custom_context` or `system_prompt`, to
+ any value, while `autonomy` is, or becomes, `merge`. Under settings
+ saved with automatic runs off before this API, the runs LavaFlow
+ starts on its own stop at a draft pull request. Sending `enabled:
+ true` or `autonomy: merge` again, while LavaFlow is on and `autonomy`
+ is `merge`, lets them merge, so it needs the same check. Turning
+ `allow_ungated_workflows` on lets LavaFlow open a fix
+ where a workflow could run it with the repository's secrets before a
+ person approves it. Turning `code_quality` on starts work on every
+ frontend production deploy with no incident behind it, and turning
+ `skill_learning` up, from `off` to `review` or `auto` or from `review`
+ to `auto`, lets what LavaFlow learns steer later runs with less
+ review. Only the owner can make these changes, with a credential of
+ their own that expires: a `volcano login` token
+ whose sign-in is live, or a platform token with an expiry. The owner's
+ GitHub account must also be able to push to the project's repository.
+ A project access token, MCP, a platform token that never expires, a
+ sign-in that ended, an owner who can't push, and a project with no
+ repository get `403` with code `person_required`, and nothing is
+ saved. Turning LavaFlow, `allow_ungated_workflows` or `code_quality`
+ off, and turning `skill_learning` down or off, needs no check.
+ Nothing is saved either when the push check can't be answered (`429`
+ or `503`, with `Retry-After`). When the project points at another
+ repository, reaches its repository through another Volcano GitHub App
+ installation, or points at none, `autonomy` changes from `merge` to
+ `open_pr`; pointing back doesn't change it back. Reconnecting after a
+ reinstall of the App counts as another installation.
+
+ Turning LavaFlow on needs a plan that includes it (`403`, code
+ `plan_required`). LavaFlow is available where the project's
+ `lavaflow` capability is, which includes the owner's plan. Where it is
+ not, a project with LavaFlow records can still turn LavaFlow, Code
+ Quality or skill learning off, or several of them: a save that sends
+ `enabled: false`, `code_quality: {enabled: false}`,
+ `skill_learning: off` or several of them, and otherwise only
+ `allow_ungated_workflows: false` sent with `enabled` or
+ `skill_learning`. Any other save,
+ and any save for a project without records, answers `404` with code
+ `feature_unavailable` while LavaFlow is not offered to the project, and
+ `403` with code `plan_required` when it is but the owner's plan does
+ not include it.
+ operationId: patchLavaflowSettings
security:
- UserToken: []
- ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
- - $ref: '#/components/parameters/BranchName'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/LavaflowSettingsUpdate'
responses:
'200':
- description: Password rotated
+ description: Saved
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseBranch'
+ $ref: '#/components/schemas/LavaflowSettings'
+ '400':
+ description: 'The body is invalid: `project_id` missing or not a UUID, no field to change, an unknown field or autonomy, a `human_review_paths` pattern that is not relative to the repository root or holds a NUL character, or `custom_context` or `system_prompt` over 4000 characters. Code `feature_unavailable` means the save sets `autonomy: merge` or changes `merge_policy` without the project''s `lavaflow.merge` capability, turns `code_quality` on while Code Quality isn''t released, or turns `skill_learning` up without the project''s `lavaflow.skills` capability.'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: 'Code `person_required` means a full-scope project access token made any save but turning Code Quality or skill learning off, MCP made the request, or the save turns on a setting only the project''s owner may turn on, and the owner did not make it with a credential of their own that expires: a `volcano login` token whose sign-in is live, or a platform token with an expiry, never a project access token or a platform token that never expires. Those settings are `code_quality`, `allow_ungated_workflows`, `autonomy: merge`, `enabled` turned on while `autonomy` stays `merge`, a change to `merge_policy`, `custom_context` or `system_prompt` while `autonomy` is or becomes `merge`, `enabled: true` or `autonomy: merge` sent again under settings saved with automatic runs off before this API, which lets the runs LavaFlow starts on its own merge, and `skill_learning` turned up from `off` or from `review`. It also means the owner''s GitHub account can''t push to the project''s repository, or the project has none. Code `plan_required` means the owner''s plan does not include LavaFlow, or allows no Code Quality findings for a save that turns `code_quality` on. Without a code: a read-only project access token made the request, the owner''s account is read-only, or the owner''s plan could not be read and nothing was saved; retry later.'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'404':
- description: Project, database, or branch not found
+ description: Not found. A project the caller can't read answers exactly like one that doesn't exist, and so does one being deleted. Code `feature_unavailable` means LavaFlow is not available for this project and the save does more than turn LavaFlow, Code Quality or skill learning off on a project with LavaFlow records.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
- description: The branch is not active
+ description: Another save, or a change of the project's repository, changed the settings while this save checked them, and kept changing them when it tried again. Nothing was saved. Send the request again.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '413':
+ description: Request body exceeds 131,072 bytes
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '429':
+ description: |
+ The save turns on `code_quality`, `allow_ungated_workflows` or
+ `autonomy: merge`, turns `enabled` on under `merge`, changes
+ `merge_policy`, `custom_context` or `system_prompt` under `merge`,
+ lets the runs LavaFlow starts on its own merge again, or turns
+ `skill_learning` up, and the project, or its owner across their
+ projects, used up the hour's checks of the owner's GitHub push access.
+ Nothing was saved. Try again after `Retry-After`.
+ headers:
+ Retry-After:
+ description: Seconds until the budget's hour ends.
+ schema:
+ type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
- description: Branching is temporarily unavailable
+ description: |
+ The save turns on `code_quality`, `allow_ungated_workflows` or
+ `autonomy: merge`, turns `enabled` on under `merge`, changes
+ `merge_policy`, `custom_context` or `system_prompt` under `merge`,
+ lets the runs LavaFlow starts on its own merge again, or turns
+ `skill_learning` up, and the owner's GitHub push access could not be
+ checked now.
+ Nothing was saved. Try again after `Retry-After`.
+ headers:
+ Retry-After:
+ description: Seconds to wait before saving again.
+ schema:
+ type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/databases/{databaseName}/backups:
+ /lavaflow/connector-bindings:
get:
tags:
- - Database Backups
- summary: List a database's backups
+ - LavaFlow
+ summary: List the project's connector bindings
description: |
- Returns every backup of the database, newest first, together with the
- window a point-in-time restore may target.
-
- Both backups you took and backups the schedule produced are listed;
- `source` tells them apart. Only manual backups count against the plan's
- backup allowance.
- operationId: listDatabaseBackups
+ Lists where problems are reported to LavaFlow from for the project,
+ such as Slack channels. In a bound Slack channel, someone whose Slack
+ identity is connected to the project owner's account can mention the
+ Volcano app to report a problem. Project access tokens can read the
+ list, including read-only ones, and so can MCP, as
+ `get_lavaflow_connector_bindings`. The list answers whether or not the
+ project's `lavaflow.slack` capability is available.
+ operationId: listLavaflowConnectorBindings
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
+ - $ref: '#/components/parameters/ProjectIdQuery'
responses:
'200':
- description: Successful response
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DatabaseBackupList'
- '403':
- description: Backups require SUPERAGENT
+ description: The project's connector bindings
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- '404':
- description: Project or database not found
+ $ref: '#/components/schemas/LavaflowConnectorBindingsResponse'
+ '400':
+ description: '`project_id` is missing or not a UUID.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: |
- The database has no storage project yet, so there is nothing to
- list. A database reports this while it is still provisioning.
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Backups are temporarily unavailable
+ '404':
+ description: Not found. A project the caller can't read answers exactly like one that doesn't exist, and so does one being deleted.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
tags:
- - Database Backups
- summary: Back up a database
- description: |
- Captures the database as it is now. The backup is available immediately;
- its `size_bytes` appears once the storage provider has costed it.
+ - LavaFlow
+ summary: Bind a connector to the project
+ description: |
+ Binds a place in a connector to the project, so problems reported
+ there reach LavaFlow for it, and answers `201`. For a `slack`
+ connector the place is a channel. Binding a channel that is already
+ bound answers `200` with that binding, and makes the current owner the
+ one who bound it, so a retry is safe. One of the Slack identities the
+ caller's sign-in session signed in as must belong to the connector's
+ workspace and be a member of the channel, so on an account several
+ people share, each binds only channels they are in. The channel must
+ be one the picker (`GET /user/slack/channels`) lists: one the Volcano
+ app is in, and not archived, a Slack Connect channel, or shared
+ across an organization.
- Backups are rate-limited to one per minute per database, and capped by
- the owner's plan.
- operationId: createDatabaseBackup
+ Only the project's owner can bind, with a platform token. A project
+ access token, or a request made through MCP, gets `403` with code
+ `person_required`. Binding a Slack channel needs the project's
+ `lavaflow.slack` capability: where it is unavailable, this answers
+ `404` with code `feature_unavailable`, or `403` with code
+ `plan_required` when the owner's plan does not include LavaFlow.
+ operationId: createLavaflowConnectorBinding
security:
- UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/CreateDatabaseBackupRequest'
+ $ref: '#/components/schemas/LavaflowConnectorBindingCreate'
responses:
+ '200':
+ description: The channel was already bound for the project
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/LavaflowConnectorBinding'
'201':
- description: Backup created
+ description: The connector is bound
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseBackup'
+ $ref: '#/components/schemas/LavaflowConnectorBinding'
'400':
- description: Invalid backup name
+ description: 'The body is invalid, the connector is not one the caller can use, the caller''s sign-in session signed in as no Slack identity in its workspace, the channel cannot report problems (it is archived, a Slack Connect channel, or shared across an organization), or the Volcano app is not in the channel yet: invite it, then bind again.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: |
- The database has reached its backup allowance, or the owner's plan
- does not include backups, which are available only on SUPERAGENT.
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Project or database not found
+ '403':
+ description: Code `person_required` means a project access token or MCP made the request. Code `plan_required` means the owner's plan does not include LavaFlow. Without a code, the owner's account is read-only, or the owner's plan could not be read; retry later.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: |
- A backup of that name already exists, the database is not active, a
- restore is running on it, or a backup was taken too recently.
+ '404':
+ description: Not found. A project the caller can't read answers exactly like one that doesn't exist, and so does a channel that no Slack identity the caller's sign-in session signed in as is a member of, and a private channel the Volcano app is not in, which the app cannot see. Code `feature_unavailable` means the project's `lavaflow.slack` capability is unavailable.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Backups are temporarily unavailable
+ '502':
+ description: Slack did not answer whether the owner is a member of the channel; try again
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/databases/{databaseName}/backups/{backupName}:
- get:
+ /lavaflow/connector-bindings/{binding_id}:
+ delete:
tags:
- - Database Backups
- summary: Get a backup
- description: Returns one backup of the database.
- operationId: getDatabaseBackup
+ - LavaFlow
+ summary: Remove a connector binding
+ description: |
+ Stops a bound place, such as a Slack channel, reporting problems for
+ its project. Reports from it still queued are canceled at their next
+ check. The binding's own project authorizes the request. Only the
+ project's owner can remove one, with a platform token. A project
+ access token or MCP gets `403` with code `person_required` for a
+ binding of its own project, and `404` for another project's, as for an
+ unknown one. Removing works whether or not the project's
+ `lavaflow.slack` capability is available.
+ operationId: deleteLavaflowConnectorBinding
security:
- UserToken: []
- - ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
- - $ref: '#/components/parameters/BackupName'
+ - name: binding_id
+ in: path
+ required: true
+ description: The binding's ID, from listing the project's connector bindings
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/ItemProjectIdQuery'
responses:
- '200':
- description: Successful response
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DatabaseBackup'
- '403':
- description: Backups require SUPERAGENT
+ '204':
+ description: The place no longer reports for the project
+ '400':
+ description: '`project_id` is given, and it or the binding ID is not a UUID.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Project, database, or backup not found
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: |
- The database has no storage project yet, so it holds no backups. A
- database reports this while it is still provisioning.
+ '403':
+ description: Code `person_required` means a project access token or MCP made the request. Without a code, the owner's account is read-only.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Backups are temporarily unavailable
+ '404':
+ description: No such binding. A binding of a project the caller can't read, or of another project than a given `project_id`, answers exactly like one that doesn't exist. Without `project_id`, so does a binding ID that is not a UUID.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- delete:
+ /lavaflow/scans:
+ get:
tags:
- - Database Backups
- summary: Delete a backup
+ - LavaFlow
+ summary: List LavaFlow Code Quality scans
description: |
- Deletes the backup and frees its storage. Scheduled backups can be
- deleted too. A backup that is already gone reports `404`, so a name
- that never existed and a name that no longer does read the same.
- Refused with `409` while the database is being restored.
- operationId: deleteDatabaseBackup
+ Pages the project's Code Quality scans, newest first. The first page
+ starts with the project's waiting scan, if it has one: the deploys
+ that went live since the last scan, with `status: waiting` and the
+ bound it waits at in `waiting_reason`. A bound never drops a deploy:
+ the waiting scan covers every commit since the last one when it
+ starts.
+
+ Each scan shows the commits it compared, the resources whose deploys
+ it covers, what it did with what it found, and the findings whose
+ runs were billed. Scans stay readable while LavaFlow or Code Quality
+ is off. Project access tokens can read them, including read-only
+ ones.
+ operationId: listLavaflowScans
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
- - $ref: '#/components/parameters/BackupName'
+ - $ref: '#/components/parameters/ProjectIdQuery'
+ - $ref: '#/components/parameters/LavaflowScanLimit'
+ - $ref: '#/components/parameters/LavaflowRunCursor'
responses:
'200':
- description: Backup deleted
+ description: A page of scans
content:
application/json:
schema:
- type: object
- properties:
- status:
- type: string
- example: deleted
- message:
- type: string
- example: backup deleted
- required:
- - status
- - message
- '403':
- description: Backups require SUPERAGENT
+ $ref: '#/components/schemas/PaginatedLavaflowScans'
+ '400':
+ description: '`project_id` is missing or not a UUID, or the cursor or limit is invalid.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Project, database, or backup not found
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: |
- The database is being restored. A restore is pinned to a backup it
- may not have restored yet, so deleting one is refused until the
- restore finishes.
+ '403':
+ description: Code `plan_required` means the owner's plan does not include LavaFlow and the project has no LavaFlow records. Without a code, the owner's plan could not be read; retry later.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Backups are temporarily unavailable
+ '404':
+ description: Not found. A project the caller can't read answers exactly like one that doesn't exist, and so does one being deleted. Code `feature_unavailable` means LavaFlow is not available for this project and it has no LavaFlow records.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/databases/{databaseName}/backup-schedule:
+ /lavaflow/stats:
get:
tags:
- - Database Backups
- summary: Get the automated backup schedule
+ - LavaFlow
+ summary: Get LavaFlow stats
description: |
- Returns the database's backup schedule. An empty list means no scheduled
- backups.
- operationId: getDatabaseBackupSchedule
+ Counts the issues LavaFlow took on and the pull requests it opened per
+ UTC day, oldest first, with every day in the window present. Merges
+ never count. The window ends today, which is partial. The totals equal
+ the sum of `days` and of the per-resource counts from
+ `GET /lavaflow/resources` for the same project, `days` and `category`.
+
+ `category` counts only runs in that category. These counts are issues
+ taken on and pull requests opened, while `GET /lavaflow/runs` counts
+ runs, so the two need not match.
+ operationId: getLavaflowStats
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
+ - $ref: '#/components/parameters/ProjectIdQuery'
+ - $ref: '#/components/parameters/LavaflowDays'
+ - $ref: '#/components/parameters/LavaflowCategoryFilter'
responses:
'200':
- description: Successful response
+ description: The project's LavaFlow activity per day
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseBackupSchedule'
- '403':
- description: Backups require SUPERAGENT
+ $ref: '#/components/schemas/LavaflowStats'
+ '400':
+ description: '`project_id` is missing or not a UUID, `days` is outside 1 to 90, or `category` is not a category.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Project or database not found
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: |
- The database has no storage project yet, so it has no schedule. A
- database reports this while it is still provisioning.
+ '403':
+ description: Code `plan_required` means the owner's plan does not include LavaFlow and the project has no LavaFlow records. Without a code, the owner's plan could not be read; retry later.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Backups are temporarily unavailable
+ '404':
+ description: Not found. A project the caller can't read answers exactly like one that doesn't exist, and so does one being deleted. Code `feature_unavailable` means LavaFlow is not available for this project and it has no LavaFlow records.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- put:
+ /lavaflow/resources:
+ get:
tags:
- - Database Backups
- summary: Replace the automated backup schedule
+ - LavaFlow
+ summary: List LavaFlow's resources
description: |
- Replaces the schedule wholesale. Send an empty `entries` list to stop
- scheduled backups.
+ Lists every function, durable function and frontend in the project with
+ LavaFlow's activity in the window, zeros included, sorted by name. A
+ removed resource is listed when it has activity in the window (in that
+ category, with `category` set), so the counts add up to
+ `GET /lavaflow/stats`.
- Scheduled backups do not count against the plan's backup allowance, but
- their retention is clamped to the plan's.
- operationId: updateDatabaseBackupSchedule
+ `anomaly.flagged` is true when the last 24 hours have at least 3
+ issues opened for the resource and at least 3 times its daily average
+ over the 29 days before, counting that average as at least 1.
+
+ `category` counts, and flags anomalies from, only runs in that
+ category; every current resource is still listed, and
+ `last_analyzed_at` counts every run.
+ operationId: listLavaflowResources
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DatabaseBackupSchedule'
+ - $ref: '#/components/parameters/ProjectIdQuery'
+ - $ref: '#/components/parameters/LavaflowDays'
+ - $ref: '#/components/parameters/LavaflowCategoryFilter'
responses:
'200':
- description: Schedule replaced
+ description: The project's resources with LavaFlow's activity
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseBackupSchedule'
+ $ref: '#/components/schemas/LavaflowResourceList'
'400':
- description: |
- The schedule names a recurrence that cannot fire: a weekly or
- monthly one with no `day`, or a `day` outside its frequency's range
- (1-7 for weekly, 1-28 for monthly). The response says which.
+ description: '`project_id` is missing or not a UUID, `days` is outside 1 to 90, or `category` is not a category.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Backups require SUPERAGENT
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '404':
- description: Project or database not found
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: |
- The database is not active, or a restore is running on it — a restore
- moves the data to a new branch, and the provider keeps the schedule
- per branch.
+ '403':
+ description: Code `plan_required` means the owner's plan does not include LavaFlow and the project has no LavaFlow records. Without a code, the owner's plan could not be read; retry later.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Backups are temporarily unavailable
+ '404':
+ description: Not found. A project the caller can't read answers exactly like one that doesn't exist, and so does one being deleted. Code `feature_unavailable` means LavaFlow is not available for this project and it has no LavaFlow records.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/databases/{databaseName}/restores:
+ /lavaflow/runs:
get:
tags:
- - Database Backups
- summary: List a database's restores
+ - LavaFlow
+ summary: List LavaFlow runs
description: |
- Returns the database's restore history, newest first, capped at the 50
- most recent. There is no pagination: a database that has been restored
- more than 50 times keeps the older records but does not return them.
- operationId: listDatabaseRestores
+ Pages the project's LavaFlow runs, newest first unless `order` says
+ otherwise. A page carries bounded display text, including the saved
+ proposed fix's optional `fix_summary`; read a run for its diagnosis,
+ log lines and diff. Each run names its category, the resources it
+ involves and its issue. A confirmed Code Quality finding can supply
+ `issue.severity`, and a recorded pull request can supply `branch`.
+ Unknown or withheld optional fields are omitted.
+
+ Every filter narrows the list, and filters combine. `include=counts`
+ adds `counts`, computed from the same filters: ask for them on the
+ first page, since they don't depend on the cursor. Keep the filters
+ and `order` while paging.
+ operationId: listLavaflowRuns
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
+ - $ref: '#/components/parameters/ProjectIdQuery'
+ - $ref: '#/components/parameters/LavaflowRunLimit'
+ - $ref: '#/components/parameters/LavaflowRunCursor'
+ - $ref: '#/components/parameters/LavaflowRunStatusFilter'
+ - $ref: '#/components/parameters/LavaflowResourceIdFilter'
+ - $ref: '#/components/parameters/LavaflowCategoryFilter'
+ - $ref: '#/components/parameters/LavaflowInvolvedResourceFilter'
+ - $ref: '#/components/parameters/LavaflowIssueIdFilter'
+ - $ref: '#/components/parameters/LavaflowPullRequestStateFilter'
+ - $ref: '#/components/parameters/LavaflowRunDays'
+ - $ref: '#/components/parameters/LavaflowRunOrder'
+ - $ref: '#/components/parameters/LavaflowRunInclude'
responses:
'200':
- description: Successful response
+ description: A page of runs
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseRestoreList'
- '403':
- description: Backups require SUPERAGENT
+ $ref: '#/components/schemas/PaginatedLavaflowRuns'
+ '400':
+ description: '`project_id` is missing or not a UUID, a filter, `order`, `days`, `include` or `limit` is invalid, or the cursor is invalid or was issued for another `order`.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Project or database not found
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Backups are temporarily unavailable
+ '403':
+ description: Code `plan_required` means the owner's plan does not include LavaFlow and the project has no LavaFlow records. Without a code, the owner's plan could not be read; retry later.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Not found. A project the caller can't read answers exactly like one that doesn't exist, and so does one being deleted. An `issue_id` from another project answers `issue not found`, as an unknown one does. Code `feature_unavailable` means LavaFlow is not available for this project and it has no LavaFlow records.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
tags:
- - Database Backups
- summary: Restore a database
+ - LavaFlow
+ summary: Start a LavaFlow run
description: |
- Replaces the database's data, either with a named backup or with its
- state at a point in time. This is destructive: everything written after
- that point is discarded.
+ Starts a run on one of the project's issues. LavaFlow starts runs on
+ its own only for issues with `exception: true`, and only while it is
+ on. Start one here for any other issue, or for one recorded before
+ LavaFlow was turned on. The run follows the project's settings, as
+ one LavaFlow starts on its own does, and answers `202` while it is
+ `queued`; read it with `GET /lavaflow/runs/{run_id}`.
- Asynchronous: the response is `202` with the restore `pending` and the
- database `restoring`. The database does not accept connections until the
- restore reports `completed`; its connection string is unchanged
- throughout, so nothing holding it needs updating.
+ Only the project's owner can start a run, as a person, while their
+ account is active: with a platform token that expires, or `volcano
+ login`. A platform token that never expires, a `volcano login` token
+ whose sign-in ended, a full-scope project access token, and a request
+ made through MCP get `403` with code `person_required`; a read-only
+ project access token is refused as read-only first, without a code,
+ and so is the owner of a read-only account.
- Restores are in place. There is no way to restore into a second
- database, and a database's branches are never restored — they keep
- serving their own data, but resetting a branch from its parent is
- refused by the storage provider for up to 24 hours afterwards.
- operationId: createDatabaseRestore
+ Every start counts toward the run limits: 5 runs per issue and 200 per
+ project in any 24 hours. An issue has one run in progress at a time,
+ so sending the request again while the first run is in progress
+ answers `409` with code `lavaflow_run_in_progress`.
+
+ A run on a Code Quality issue is a Code Quality run. It starts only
+ while Code Quality is available to the project, as
+ `lavaflow.code_quality` in `GET /capabilities` reports, and on for it.
+ operationId: createLavaflowRun
security:
- UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/CreateDatabaseRestoreRequest'
+ $ref: '#/components/schemas/LavaflowRunCreate'
responses:
'202':
- description: Restore accepted and in progress
+ description: The run, queued
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseRestore'
+ $ref: '#/components/schemas/LavaflowRun'
'400':
- description: |
- Neither or both restore targets were named, or the requested time is
- outside the available window.
+ description: 'The body is invalid: `project_id` or `issue_id` missing or not a UUID, or an unknown field. Code `feature_unavailable` means the issue is a Code Quality issue and Code Quality is not available.'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: |
- The owner's plan does not include backups or point-in-time restore.
- Both are available only on SUPERAGENT.
+ description: 'Code `person_required` means the request didn''t come from the owner''s live person credential: a platform token that never expires, a `volcano login` token whose sign-in ended, a full-scope project access token, or MCP made it. Start a run with a platform token that expires, or `volcano login`. Code `plan_required` means the owner''s plan does not include LavaFlow, or, for a Code Quality issue, Code Quality. Without a code: a read-only project access token made the request, the owner''s account is read-only or inactive, or the owner''s plan could not be read; retry later.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Project, database, or backup not found
+ description: Not found. A project the caller can't read answers exactly like one that doesn't exist, and so does one being deleted. Code `issue_not_found` means the project has no issue `issue_id`; an issue of another project answers the same. Code `feature_unavailable` means LavaFlow is not available for this project.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
- description: |
- A restore is already in progress, the database is not active,
- another database operation is still running, or the database is
- holding as many pre-restore branches as it may.
+ description: The run did not start. Code `lavaflow_disabled` means LavaFlow is off for the project, or, for a Code Quality issue, Code Quality is; turn it on. Code `repository_required` means LavaFlow was turned on for a repository the project no longer links, and `repository_changed` that the project links another repository than LavaFlow was turned on for; turn LavaFlow on again. Code `lavaflow_run_in_progress` means the issue has a run in progress.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Backups are temporarily unavailable
+ '413':
+ description: Request body exceeds 4,096 bytes
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/databases/{databaseName}/restores/{restoreId}:
+ '429':
+ description: A run limit is reached. Code `issue_run_limit_reached` means the issue started 5 runs in the last 24 hours, and `project_run_limit_reached` that the project started 200. Try again after `Retry-After`.
+ headers:
+ Retry-After:
+ description: Seconds until the limit has room for the run.
+ schema:
+ type: integer
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /lavaflow/runs/{run_id}:
get:
tags:
- - Database Backups
- summary: Get a restore
+ - LavaFlow
+ summary: Get a LavaFlow run
description: |
- Returns the restore. Poll this after starting one; the database is
- connectable again once it reports `completed`.
- operationId: getDatabaseRestore
+ Returns a run, with its diagnosis, the log lines it cites, its diff,
+ its review, including the findings the review left open and what it
+ asks a person to decide, and whether the repository's own checks
+ passed when LavaFlow ran them on the fix, with the commands they ran.
+ The run's project authorizes the read, so `project_id` is optional.
+ The text holds the project's logs and source code, so this endpoint
+ takes the same access as the project's log endpoints.
+
+ A run held because the repository's workflows could run its fix with
+ the repository's secrets before a person approves it
+ (`pull_request_skipped: ungated_workflows`) lists every such job in
+ `held_workflows`, beside the fix's `diff` and `diff_sha256`.
+ operationId: getLavaflowRun
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
- - $ref: '#/components/parameters/RestoreId'
+ - $ref: '#/components/parameters/LavaflowRunId'
+ - $ref: '#/components/parameters/ItemProjectIdQuery'
responses:
'200':
- description: Successful response
+ description: The run
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseRestore'
- '403':
- description: Backups require SUPERAGENT
+ $ref: '#/components/schemas/LavaflowRun'
+ '400':
+ description: '`project_id` is given and not a UUID.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Project, database, or restore not found
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Backups are temporarily unavailable
+ '403':
+ description: Code `plan_required` means the owner's plan does not include LavaFlow and the project has no LavaFlow records. Without a code, the owner's plan could not be read; retry later.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/databases/{databaseName}/reset-password:
+ '404':
+ description: Not found. A run of a project the caller can't read, or of a project being deleted, answers exactly like one that doesn't exist, and so does a run of another project than a given `project_id`. Code `feature_unavailable` means LavaFlow is not available for the project and it has no LavaFlow records.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /lavaflow/held-fix-opens:
post:
tags:
- - Databases
- summary: Reset database password
- description: |
- Rotates the Volcano-managed PostgreSQL password used by clients when connecting
- through pgproxy. This does not rotate or expose the internal owner password.
- The returned password and connection string are the only client credentials that
- will authenticate through pgproxy after reset.
+ - LavaFlow
+ summary: Open a held LavaFlow fix
+ description: |
+ Opens the pull request for a fix LavaFlow held because the
+ repository's workflows could run it with the repository's secrets
+ before a person approves it (`pull_request_skipped:
+ ungated_workflows`). Read the run first: send its `id` as `run_id`,
+ with the `diff_sha256` and `held_workflows.jobs_sha256` it served, to
+ say you read that diff and that list of jobs. LavaFlow opens the fix it
+ saved, exactly as reviewed, past those jobs only. It writes no new
+ fix.
- Existing connections are not interrupted; new ones must use the returned
- string. Proxies pick the rotation up within a few seconds, so the previous
- password can still open new connections until then.
- operationId: resetDatabasePassword
+ Right before it queues the run, LavaFlow serves the diff again and
+ reads the workflows again. A diff served differently since you read
+ it, or a job list or a commit the workflows were read at that changed,
+ answers `409` with code `run_changed`; read the run again, which lists
+ what LavaFlow found. The response is the run, `202` while it is
+ `queued`. LavaFlow reads the workflows again before it opens the pull
+ request, and once more as it pushes the fix: a job you didn't read, a
+ new commit on a branch the workflows were read on, even one that
+ changes no job, or a production branch other than the one you read
+ them on holds the fix again with a new list.
+
+ Opening a fix lets its pull request open, nothing more. LavaFlow
+ starts no CI on it and never merges it, as for every fix opened past
+ ungated workflows; a person pushes to the branch or merges it. The
+ pull request's description names who opened it and lists the jobs.
+ One exception: when LavaFlow's read before the pull request opens
+ finds no job that runs the fix before a person approves it, because
+ the workflows were gated since you read them, the fix opens as any
+ other fix and follows the project's merge settings. A run whose
+ `held_workflows` lists no job opens the same way.
+
+ Only the project's owner can open a fix, as a person, while their
+ account is active: with a `volcano login` token
+ whose sign-in is live, or a platform token that expires. Their GitHub
+ account must be able to push to the project's repository. A project
+ access token, a request made through MCP, a platform token that never
+ expires, and a sign-in that ended get `403` with code
+ `person_required`. Opening a fix uses one of the run's attempts: the
+ attempt that opens it is one of the run's, so a run held again on its
+ last attempt can't be opened again. It starts no new run and counts
+ toward no run limit.
+ operationId: createLavaflowHeldFixOpen
security:
- UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/LavaflowHeldFixOpen'
responses:
- '200':
- description: Password reset successful
+ '202':
+ description: The run, queued to open its fix
content:
application/json:
schema:
- type: object
- properties:
- message:
- type: string
- role_name:
- type: string
- description: Volcano-managed per-database client login (also the pgproxy routing username)
- example: volcano_client_11111111-1111-1111-1111-111111111111
- new_password:
- type: string
- description: New Volcano-managed client password. Always starts with `vpg_`.
- connection_string:
- type: string
- description: Updated pgproxy connection string using Volcano-managed credentials.
+ $ref: '#/components/schemas/LavaflowRun'
'400':
- description: Database is not active
+ description: 'The body is invalid: `project_id` or `run_id` missing or not a UUID, `diff_sha256` or `jobs_sha256` missing or not 64 lowercase hex characters, or an unknown field.'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: 'Code `person_required` means the request didn''t come from the owner''s live person credential: a full-scope project access token, MCP, a platform token that never expires, or a `volcano login` token whose sign-in ended made it, or the owner''s GitHub account can''t push to the project''s repository, or the project has none. Open the fix with a platform token that expires, or `volcano login`. Code `plan_required` means the owner''s plan does not include LavaFlow. Without a code: a read-only project access token made the request, the owner''s account is read-only or inactive, or the owner''s plan could not be read; retry later.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Database not found
+ description: Not found. A project the caller can't read answers exactly like one that doesn't exist, and so does one being deleted. A run of another project than `project_id` answers as one that doesn't exist. Code `feature_unavailable` means LavaFlow is not available for this project.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
- description: |
- A restore is running on the database. A restore replaces the
- credentials as it finishes, so wait for it and rotate afterwards.
+ description: 'Nothing was queued. Code `run_not_held` means the run holds no fix you can open: it was not held for ungated workflows, its pull request opened or is queued to, its diff is cut short or withholds a file, or LavaFlow could not list every job that held it (`held_workflows` is `null`). Code `run_changed` means the diff or the jobs are not the ones you named: read the run again. Code `run_attempts_exhausted` means the run used all its retries, so LavaFlow can''t open its fix any more; apply the fix yourself from the run''s `diff`, and where the diff is cut short or withholds a file, from its `diagnosis`. Code `lavaflow_disabled` means LavaFlow is off for the project; turn it on. Code `repository_required` means LavaFlow was turned on for a repository the project no longer links, `repository_changed` that the project links another repository than LavaFlow was turned on for, or than the fix was written for, and `repository_unreadable` that LavaFlow can no longer read the repository''s workflows. Code `lavaflow_run_in_progress` means another run of the issue is in progress.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: |
- Volcano could not check whether a restore is running, and will not
- rotate a credential a restore might be about to replace. Retry.
+ '413':
+ description: Request body exceeds 4,096 bytes
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/databases/{databaseName}/type:
- patch:
- tags:
- - Databases
- summary: Update database size
- description: |
- Change the size tier of a database. This may briefly interrupt active connections.
-
- **Available sizes:**
- - `volcano-db-xs`: Up to ~1GB RAM - Development, small apps
- - `volcano-db-s`: Up to ~4GB RAM - Production-ready, light traffic
- - `volcano-db-m`: Up to ~8GB RAM - Medium traffic applications
- - `volcano-db-l`: Up to ~16GB RAM - High traffic, larger datasets
- - `volcano-db-xl`: Up to ~32GB RAM - Heavy workloads
- - `volcano-db-2xl`: Up to ~64GB RAM - Enterprise-scale
- operationId: updateDatabaseType
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/UpdateDatabaseTypeRequest'
- responses:
- '200':
- description: Database type updated
- content:
- application/json:
+ '429':
+ description: The project, or its owner across their projects, used up the hour's checks of the owner's GitHub push access. Nothing was queued. Try again after `Retry-After`.
+ headers:
+ Retry-After:
+ description: Seconds until the budget's hour ends.
schema:
- $ref: '#/components/schemas/Database'
- '400':
- description: Invalid database type
- '404':
- description: Database not found
- '409':
- description: |
- The database is not active — being provisioned, deleted, or
- restored. Compute can only be changed while it is active.
+ type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
- description: |
- Volcano could not check whether a restore is running, and will not
- reconfigure compute a restore might be moving. Retry.
+ description: GitHub didn't answer the owner's push check or the read of the workflows. Nothing was queued. Try again after `Retry-After`.
+ headers:
+ Retry-After:
+ description: Seconds to wait before trying again.
+ schema:
+ type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/databases/{databaseName}/stats:
+ /lavaflow/skills:
get:
tags:
- - Databases
- summary: Get database consumption metrics
+ - LavaFlow
+ summary: List LavaFlow skills
description: |
- Retrieve consumption metrics including storage, compute time, and data transfer.
- Metrics are aggregated at the project level. Defaults to last 24 hours.
+ Lists the project's skills, newest first: short, cited notes on how
+ the project wants something done, with each one's active version,
+ counts and source. A project skill belongs to its project and never
+ leaves it. Filter by `status`. The list holds at most 350 skills, so
+ it has no pages.
- **Note:** Advanced metrics require an upgraded plan.
- operationId: getDatabaseStats
+ LavaFlow doesn't yet learn skills from corrections to its fixes or
+ load them into runs; both come in a later release.
+
+ Project access tokens can list skills, including read-only ones.
+ Skills stay readable while the project's `lavaflow.skills` capability
+ is unavailable.
+ operationId: listLavaflowSkills
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/DatabaseName'
- - name: from
- in: query
- required: false
- schema:
- type: string
- format: date-time
- description: Start time in RFC3339 format (e.g., "2024-01-01T00:00:00Z"). Defaults to 24 hours ago.
- - name: to
- in: query
- required: false
- schema:
- type: string
- format: date-time
- description: End time in RFC3339 format (e.g., "2024-01-02T00:00:00Z"). Defaults to now.
- - name: granularity
- in: query
- required: false
- schema:
- type: string
- enum:
- - hourly
- - daily
- - monthly
- default: hourly
- description: Level of detail for metrics aggregation
+ - $ref: '#/components/parameters/ProjectIdQuery'
+ - $ref: '#/components/parameters/LavaflowSkillStatusFilter'
responses:
'200':
- description: Successful response
+ description: The project's skills
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseStats'
+ $ref: '#/components/schemas/LavaflowSkillList'
'400':
- description: Invalid parameters
+ description: '`project_id` is missing or not a UUID, or `status` is unknown.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Database not found
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Database metrics not available or requires upgraded plan
+ '403':
+ description: Code `plan_required` means the owner's plan does not include LavaFlow and the project has no LavaFlow records. Without a code, the owner's plan could not be read; retry later.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /databases/{databaseName}/query/ping:
- post:
+ '404':
+ description: Not found. A project the caller can't read answers exactly like one that doesn't exist, and so does one being deleted. Code `feature_unavailable` means LavaFlow is not available for this project and it has no LavaFlow records.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /lavaflow/skills/{skill_id}:
+ get:
tags:
- - Database Queries
- summary: Database connectivity probe (REST API)
+ - LavaFlow
+ summary: Get a LavaFlow skill
description: |
- Connectivity probe that runs a fixed `SELECT 1` through pgproxy, using the
- same authentication, status/bandwidth gating, and metering as the other
- `/query/*` endpoints.
-
- Unlike those endpoints, ping takes **no request body** and performs **no
- table-name validation**, so it works on any database — including a freshly
- provisioned, empty one. It is a real committed round-trip through pgproxy,
- so a `200` means the database is reachable and queryable. Used by the
- dashboard's database connection test.
- operationId: queryDatabasePing
+ Returns one of a project's skills with its active version. The skill's
+ project authorizes the read, so `project_id` is optional. Project
+ access tokens can read skills, including read-only ones.
+ operationId: getLavaflowSkill
security:
- - AuthUserAccessToken: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/DatabaseName'
+ - $ref: '#/components/parameters/LavaflowSkillId'
+ - $ref: '#/components/parameters/ItemProjectIdQuery'
responses:
'200':
- description: Database is reachable
- headers:
- X-Volcano-Proxy-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyMs'
- X-Volcano-Proxy-Handler-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
- X-Volcano-Compute-Ms:
- $ref: '#/components/headers/DatabaseQueryComputeMs'
+ description: The skill
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseQueryResult'
- example:
- data:
- - ?column?: 1
- count: 1
+ $ref: '#/components/schemas/LavaflowSkill'
+ '400':
+ description: '`project_id` is given and not a UUID.'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'401':
description: Not authenticated
content:
@@ -9990,77 +10644,79 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Access denied
+ description: Code `plan_required` means the owner's plan does not include LavaFlow and the project has no LavaFlow records. Without a code, the owner's plan could not be read; retry later.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Database not found
+ description: Not found. A skill of a project the caller can't read, or of a project being deleted, answers exactly like one that doesn't exist, and so does a skill of another project than a given `project_id`. Code `feature_unavailable` means LavaFlow is not available for the project and it has no LavaFlow records.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
- $ref: '#/components/responses/DatabaseQueryCapExceeded'
- /databases/{databaseName}/query/select:
- post:
+ patch:
tags:
- - Database Queries
- summary: Query database with SELECT (REST API)
- description: |
- Query your database using a simple REST API - no SQL required!
-
- **Authentication:** Requires auth user access token (from signup/signin)
+ - LavaFlow
+ summary: Change a LavaFlow skill
+ description: |
+ Changes only the fields you send: a skill's `description`, `body` or
+ `applies_to`, or its `status`: `active` activates a proposed skill or
+ restores a retired one, and `retired` retires it. `applies_to` merges
+ member by member: an omitted member keeps its value, and a list you
+ send replaces it, so `[]` clears it. Citations can't be changed.
+ A skill is a standing instruction to LavaFlow, so only the project's
+ owner changes one, signed in as a person: with a
+ `volcano login` token whose sign-in is live, or a platform token with
+ an expiry. A change other than retiring also needs the owner's GitHub
+ account to be able to push to the project's repository. A project
+ access token, MCP, a platform token that never expires, a sign-in
+ that ended, an owner who can't push, and a project with no repository
+ get `403` with code `person_required`, and nothing is saved. Retiring
+ needs no repository. Nothing is saved either when the push check
+ can't be answered (`429` or `503`, with `Retry-After`).
- **Row-Level Security:** Automatically enforced - you see only data you have access to
+ A project keeps its 200 most recently retired skills: retiring
+ another deletes the oldest retired skill and its versions.
- **Use Cases:**
- - Query from browser/mobile apps
- - Simple data retrieval
- - Filtered searches with sorting and pagination
+ Every change but retiring passes the skill check. Only a change to
+ the text adds a version; activating or restoring doesn't. Text that
+ holds a credential, a project secret value, an email address, a link
+ or a host name, an invisible or control character, a CI-skip
+ directive, or an instruction to skip or weaken tests, CI or
+ LavaFlow's rules answers `400` with code `skill_refused` and the
+ `rules` it failed; nothing is saved, and the text is not kept. When
+ the check can't run, the change answers `503` with code
+ `scan_unavailable` and `Retry-After`.
- **Note:** For complex queries (JOINs, CTEs), use functions with direct SQL
- operationId: queryDatabaseSelect
+ Retiring works while the project's `lavaflow.skills` capability is
+ unavailable. Any other change answers `400` with code
+ `feature_unavailable` then.
+ operationId: updateLavaflowSkill
security:
- - AuthUserAccessToken: []
+ - UserToken: []
parameters:
- - $ref: '#/components/parameters/DatabaseName'
+ - $ref: '#/components/parameters/LavaflowSkillId'
+ - $ref: '#/components/parameters/ItemProjectIdQuery'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseSelectRequest'
+ $ref: '#/components/schemas/LavaflowSkillUpdate'
responses:
'200':
- description: Query successful
- headers:
- X-Volcano-Proxy-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyMs'
- X-Volcano-Proxy-Handler-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
- X-Volcano-Compute-Ms:
- $ref: '#/components/headers/DatabaseQueryComputeMs'
+ description: Saved
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseQueryResult'
- example:
- data:
- - id: uuid-123
- title: My Post
- content: Post content
- status: published
- views: 150
- created_at: '2026-01-13T10:00:00Z'
- count: 1
+ $ref: '#/components/schemas/LavaflowSkill'
'400':
- description: Invalid query
+ description: 'The body is invalid: no field to change, an unknown field, or a field past its size. Code `skill_refused` means the check refused the text, and `rules` names why. Code `feature_unavailable` means the change does more than retire the skill while the project''s `lavaflow.skills` capability is unavailable.'
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
+ $ref: '#/components/schemas/LavaflowSkillError'
'401':
description: Not authenticated
content:
@@ -10068,142 +10724,75 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Access denied
+ description: 'Code `person_required` means the change was not made by the project''s owner signed in as a person: a full-scope project access token, MCP, a platform token that never expires, or a `volcano login` token whose sign-in ended made it. For a change other than retiring, it also means the owner''s GitHub account can''t push to the project''s repository, or the project has none. Without a code: a read-only project access token made it, the owner''s account is read-only, or the owner''s plan could not be read; retry later.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Database not found
+ description: Not found, as the read answers. Code `feature_unavailable` means LavaFlow is not available for the project and it has no LavaFlow records.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
- $ref: '#/components/responses/DatabaseQueryCapExceeded'
- /databases/{databaseName}/query/insert:
- post:
- tags:
- - Database Queries
- summary: Insert data into database (REST API)
- description: |
- Insert new rows into your database using REST API.
-
- **Authentication:** Requires auth user access token
-
- **Auto-set user_id:** If your table has a trigger using `auth.uid()`,
- user_id will be automatically set to the authenticated user
-
- **Security:** Row-Level Security policies are enforced
- operationId: queryDatabaseInsert
- security:
- - AuthUserAccessToken: []
- parameters:
- - $ref: '#/components/parameters/DatabaseName'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DatabaseInsertRequest'
- responses:
- '200':
- description: Insert successful
- headers:
- X-Volcano-Proxy-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyMs'
- X-Volcano-Proxy-Handler-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
- X-Volcano-Compute-Ms:
- $ref: '#/components/headers/DatabaseQueryComputeMs'
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DatabaseQueryResult'
- example:
- data:
- - id: uuid-123
- title: My New Post
- content: This is the content
- status: draft
- user_id: user-uuid
- created_at: '2026-01-13T10:00:00Z'
- count: 1
- '400':
- description: Invalid request
+ '409':
+ description: 'Code `skill_limit_reached` means the change would take the project past a cap: 100 active or 50 proposed skills, or 1 MiB of skill text across every version the project keeps. Without a code, another change to the skill landed first, or the project now points at another repository than the push check admitted; read the skill and send the change again.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Not authenticated
+ '413':
+ description: Request body exceeds 65,536 bytes
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Access denied
+ '429':
+ description: The project made more than 10 skill changes in the last minute, its changes used the day's 200 checks, or the owner's GitHub push access was checked too often. Nothing was saved. Try again after `Retry-After`.
+ headers:
+ Retry-After:
+ description: Seconds to wait before changing a skill again.
+ schema:
+ type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Database not found
+ '503':
+ description: Code `scan_unavailable` means the check could not run. Without a code, the owner's GitHub push access could not be checked. Either way nothing was saved. Try again after `Retry-After`.
+ headers:
+ Retry-After:
+ description: Seconds to wait before changing the skill again.
+ schema:
+ type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
- $ref: '#/components/responses/DatabaseQueryCapExceeded'
- /databases/{databaseName}/query/update:
- post:
+ delete:
tags:
- - Database Queries
- summary: Update data in database (REST API)
+ - LavaFlow
+ summary: Delete a LavaFlow skill
description: |
- Update existing rows in your database using REST API.
-
- **Security:** Row-Level Security ensures you can only update data you have access to
-
- **Safety:** Requires at least one filter to prevent accidental mass updates. A
- request with no `filters` is rejected with `400` (mirrors delete). This matters
- for service-key queries, which run with full access and bypass RLS.
-
- **Note:** If RLS blocks the update, an empty result is returned (not an error)
- operationId: queryDatabaseUpdate
+ Deletes a skill and every version of its text. A record that it
+ existed stays, without its text. Only the project's owner deletes a
+ skill, signed in as a person: with a `volcano
+ login` token whose sign-in is live, or a platform token with an
+ expiry. A project access token, MCP, a platform token that never
+ expires, and a sign-in that ended get `403` with code
+ `person_required`. Deleting needs no repository, and works while the
+ project's `lavaflow.skills` capability is unavailable.
+ operationId: deleteLavaflowSkill
security:
- - AuthUserAccessToken: []
+ - UserToken: []
parameters:
- - $ref: '#/components/parameters/DatabaseName'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DatabaseUpdateRequest'
+ - $ref: '#/components/parameters/LavaflowSkillId'
+ - $ref: '#/components/parameters/ItemProjectIdQuery'
responses:
- '200':
- description: Update successful
- headers:
- X-Volcano-Proxy-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyMs'
- X-Volcano-Proxy-Handler-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
- X-Volcano-Compute-Ms:
- $ref: '#/components/headers/DatabaseQueryComputeMs'
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DatabaseQueryResult'
- example:
- data:
- - id: post-uuid
- title: Updated Title
- status: published
- updated_at: '2026-01-13T10:05:00Z'
- count: 1
+ '204':
+ description: Deleted
'400':
- description: Invalid request
+ description: '`project_id` is given and not a UUID.'
content:
application/json:
schema:
@@ -10215,64 +10804,53 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Access denied
+ description: 'Code `person_required` means the project''s owner, signed in as a person, did not make the request: a full-scope project access token, MCP, a platform token that never expires, or a `volcano login` token whose sign-in ended made it. Without a code: a read-only project access token made it, the owner''s account is read-only, or the owner''s plan could not be read; retry later.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Database not found
+ description: Not found, as the read answers. Code `feature_unavailable` means LavaFlow is not available for the project and it has no LavaFlow records.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
- $ref: '#/components/responses/DatabaseQueryCapExceeded'
- /databases/{databaseName}/query/delete:
- post:
+ description: The project made more than 10 skill changes in the last minute. Nothing was deleted. Try again after `Retry-After`.
+ headers:
+ Retry-After:
+ description: Seconds to wait before changing a skill again.
+ schema:
+ type: integer
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /lavaflow/skill-versions:
+ get:
tags:
- - Database Queries
- summary: Delete data from database (REST API)
+ - LavaFlow
+ summary: List a LavaFlow skill's versions
description: |
- Delete rows from your database using REST API.
-
- **Safety:** Requires at least one filter to prevent accidental mass deletions
-
- **Security:** Row-Level Security ensures you can only delete data you have access to
-
- **Note:** If RLS blocks the delete, an empty result is returned (not an error)
- operationId: queryDatabaseDelete
+ Lists a skill's versions, newest first, each with its text, source and
+ content hash. A skill keeps its 20 newest versions and its active one.
+ Project access tokens can list them, including read-only ones.
+ operationId: listLavaflowSkillVersions
security:
- - AuthUserAccessToken: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/DatabaseName'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DatabaseDeleteRequest'
+ - $ref: '#/components/parameters/ProjectIdQuery'
+ - $ref: '#/components/parameters/LavaflowSkillIdQuery'
responses:
'200':
- description: Delete successful
- headers:
- X-Volcano-Proxy-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyMs'
- X-Volcano-Proxy-Handler-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
- X-Volcano-Compute-Ms:
- $ref: '#/components/headers/DatabaseQueryComputeMs'
+ description: The skill's versions
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseQueryResult'
- example:
- data:
- - id: post-uuid
- title: Deleted Post
- count: 1
+ $ref: '#/components/schemas/LavaflowSkillVersionList'
'400':
- description: Invalid request or missing filters
+ description: '`project_id` or `skill_id` is missing or not a UUID.'
content:
application/json:
schema:
@@ -10284,62 +10862,49 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Access denied
+ description: Code `plan_required` means the owner's plan does not include LavaFlow and the project has no LavaFlow records. Without a code, the owner's plan could not be read; retry later.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Database not found
+ description: Not found. A project the caller can't read answers exactly like one that doesn't exist, and a skill of another project answers like an unknown one. Code `feature_unavailable` means LavaFlow is not available for this project and it has no LavaFlow records.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
- $ref: '#/components/responses/DatabaseQueryCapExceeded'
- /databases/{databaseName}/branches/{branchName}/query/ping:
- post:
+ /lavaflow/global-skills:
+ get:
tags:
- - Database Queries
- summary: Database connectivity probe (REST API)
+ - LavaFlow
+ summary: List Volcano's global skills
description: |
- Connectivity probe that runs a fixed `SELECT 1` through pgproxy, using the
- same authentication, status/bandwidth gating, and metering as the other
- `/query/*` endpoints.
-
- Unlike those endpoints, ping takes **no request body** and performs **no
- table-name validation**, so it works on any database — including a freshly
- provisioned, empty one. It is a real committed round-trip through pgproxy,
- so a `200` means the database is reachable and queryable. Used by the
- dashboard's database connection test.
+ Lists the skills Volcano wrote for every project. Volcano writes and
+ reviews each one, and none holds customer content. They belong to no
+ project, so items carry `scope` and no `project_id`; `project_id`
+ authorizes the caller. While the project's `lavaflow.skills`
+ capability is unavailable, the list is empty.
- **Branch-targeted.** Runs against the named branch instead of the parent
- database, using the branch's own credentials. The branch must be `active`
- and unexpired. Nothing about this request can reach the parent's data.
- operationId: queryDatabaseBranchPing
+ Project access tokens can list them, including read-only ones.
+ operationId: listLavaflowGlobalSkills
security:
- - AuthUserAccessToken: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/DatabaseName'
- - $ref: '#/components/parameters/BranchName'
+ - $ref: '#/components/parameters/ProjectIdQuery'
responses:
'200':
- description: Database is reachable
- headers:
- X-Volcano-Proxy-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyMs'
- X-Volcano-Proxy-Handler-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
- X-Volcano-Compute-Ms:
- $ref: '#/components/headers/DatabaseQueryComputeMs'
+ description: Volcano's global skills
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseQueryResult'
- example:
- data:
- - ?column?: 1
- count: 1
+ $ref: '#/components/schemas/LavaflowGlobalSkillList'
+ '400':
+ description: '`project_id` is missing or not a UUID.'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'401':
description: Not authenticated
content:
@@ -10347,1762 +10912,1606 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Access denied
+ description: Code `plan_required` means the owner's plan does not include LavaFlow and the project has no LavaFlow records. Without a code, the owner's plan could not be read; retry later.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Database or branch not found
+ description: Not found. A project the caller can't read answers exactly like one that doesn't exist, and so does one being deleted. Code `feature_unavailable` means LavaFlow is not available for this project and it has no LavaFlow records.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
- $ref: '#/components/responses/DatabaseQueryCapExceeded'
- '503':
- $ref: '#/components/responses/DatabaseBranchQueryUnavailable'
- /databases/{databaseName}/branches/{branchName}/query/select:
- post:
+ /projects/{id}/issues:
+ get:
tags:
- - Database Queries
- summary: Query database with SELECT (REST API)
+ - Issues
+ summary: List issues
description: |
- Query your database using a simple REST API - no SQL required!
-
- **Authentication:** Requires auth user access token (from signup/signin)
-
- **Row-Level Security:** Automatically enforced - you see only data you have access to
-
- **Use Cases:**
- - Query from browser/mobile apps
- - Simple data retrieval
- - Filtered searches with sorting and pagination
-
- **Note:** For complex queries (JOINs, CTEs), use a function with direct SQL
+ Lists the project's issues, most recently seen first. An issue groups
+ the runtime errors one function or frontend raised with the same error
+ type and stack, or the same message when there is no stack.
- **Branch-targeted.** Runs against the named branch instead of the parent
- database, using the branch's own credentials. The branch must be `active`
- and unexpired. Nothing about this request can reach the parent's data.
- operationId: queryDatabaseBranchSelect
+ Project access tokens can list issues, including read-only ones.
+ operationId: listIssues
security:
- - AuthUserAccessToken: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/DatabaseName'
- - $ref: '#/components/parameters/BranchName'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DatabaseSelectRequest'
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/Limit'
+ - $ref: '#/components/parameters/IssueCursor'
+ - name: status
+ in: query
+ required: false
+ description: Return only issues in this status.
+ schema:
+ $ref: '#/components/schemas/IssueStatus'
+ - name: resource_id
+ in: query
+ required: false
+ description: Return only issues raised by this function or frontend.
+ schema:
+ type: string
+ format: uuid
responses:
'200':
- description: Query successful
- headers:
- X-Volcano-Proxy-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyMs'
- X-Volcano-Proxy-Handler-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
- X-Volcano-Compute-Ms:
- $ref: '#/components/headers/DatabaseQueryComputeMs'
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseQueryResult'
- example:
- data:
- - id: uuid-123
- title: My Post
- content: Post content
- status: published
- views: 150
- created_at: '2026-01-13T10:00:00Z'
- count: 1
+ $ref: '#/components/schemas/PaginatedIssues'
'400':
- description: Invalid query
+ description: A filter or the cursor is invalid
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Not authenticated
+ '404':
+ description: Project not found. Code `feature_unavailable` means issues are not available in this environment.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Access denied
+ /projects/{id}/issues/{issueId}:
+ get:
+ tags:
+ - Issues
+ summary: Get an issue
+ description: |
+ Returns one issue: the resource that raised it, how often and when it
+ was seen, and its status.
+
+ Project access tokens can read issues, including read-only ones.
+ operationId: getIssue
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/IssueId'
+ responses:
+ '200':
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
+ $ref: '#/components/schemas/Issue'
'404':
- description: Database or branch not found
+ description: Issue not found. Code `feature_unavailable` means issues are not available in this environment.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
- $ref: '#/components/responses/DatabaseQueryCapExceeded'
- '503':
- $ref: '#/components/responses/DatabaseBranchQueryUnavailable'
- /databases/{databaseName}/branches/{branchName}/query/insert:
- post:
+ patch:
tags:
- - Database Queries
- summary: Insert data into database (REST API)
+ - Issues
+ summary: Update an issue
description: |
- Insert new rows into your database using REST API.
-
- **Authentication:** Requires auth user access token
-
- **Auto-set user_id:** If your table has a trigger using `auth.uid()`,
- user_id will be automatically set to the authenticated user
-
- **Security:** Row-Level Security policies are enforced
+ Sets an issue's status. A resolved issue that is seen again after it
+ was resolved reopens, and `regressed_at` records when. An ignored issue
+ stays ignored while it keeps being counted.
- **Branch-targeted.** Runs against the named branch instead of the parent
- database, using the branch's own credentials. The branch must be `active`
- and unexpired. Nothing about this request can reach the parent's data.
- operationId: queryDatabaseBranchInsert
+ Setting the status an issue already has is safe to repeat.
+ operationId: updateIssue
security:
- - AuthUserAccessToken: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/DatabaseName'
- - $ref: '#/components/parameters/BranchName'
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/IssueId'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseInsertRequest'
+ $ref: '#/components/schemas/UpdateIssueRequest'
responses:
'200':
- description: Insert successful
- headers:
- X-Volcano-Proxy-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyMs'
- X-Volcano-Proxy-Handler-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
- X-Volcano-Compute-Ms:
- $ref: '#/components/headers/DatabaseQueryComputeMs'
+ description: Updated
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseQueryResult'
- example:
- data:
- - id: uuid-123
- title: My New Post
- content: This is the content
- status: draft
- user_id: user-uuid
- created_at: '2026-01-13T10:00:00Z'
- count: 1
+ $ref: '#/components/schemas/Issue'
'400':
- description: Invalid request
+ description: The request body is invalid
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Not authenticated
+ '404':
+ description: Issue not found. Code `feature_unavailable` means issues are not available in this environment.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Access denied
+ /projects/{id}/durable-approvals:
+ get:
+ tags:
+ - Durable Functions
+ summary: List durable approvals
+ description: |
+ Lists the approvals durable workflows in the project have requested,
+ newest first. Pending approvals are the ones a workflow is waiting on;
+ decided, expired, and cancelled ones are kept for a year.
+
+ Project access tokens can list approvals, including read-only ones.
+ operationId: listDurableApprovals
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/Page'
+ - $ref: '#/components/parameters/Limit'
+ - name: status
+ in: query
+ required: false
+ description: Return only approvals in this status.
+ schema:
+ $ref: '#/components/schemas/DurableApprovalStatus'
+ - $ref: '#/components/parameters/DurableApprovalFunctionFilter'
+ - name: execution_id
+ in: query
+ required: false
+ description: Return only approvals requested by this durable execution.
+ schema:
+ type: string
+ format: uuid
+ - name: from
+ in: query
+ required: false
+ description: Return only approvals requested at or after this time.
+ schema:
+ type: string
+ format: date-time
+ - name: to
+ in: query
+ required: false
+ description: Return only approvals requested before this time.
+ schema:
+ type: string
+ format: date-time
+ responses:
+ '200':
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- '404':
- description: Database or branch not found
+ $ref: '#/components/schemas/PaginatedDurableApprovals'
+ '400':
+ description: A filter is invalid, or `from` is after `to`
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
- $ref: '#/components/responses/DatabaseQueryCapExceeded'
- '503':
- $ref: '#/components/responses/DatabaseBranchQueryUnavailable'
- /databases/{databaseName}/branches/{branchName}/query/update:
- post:
+ /projects/{id}/durable-approvals/stats:
+ get:
tags:
- - Database Queries
- summary: Update data in database (REST API)
+ - Durable Functions
+ summary: Get durable approval statistics
description: |
- Update existing rows in your database using REST API.
-
- **Security:** Row-Level Security ensures you can only update data you have access to
-
- **Safety:** Requires at least one filter to prevent accidental mass updates. A
- request with no `filters` is rejected with `400` (mirrors delete). This matters
- for service-key queries, which run with full access and bypass RLS.
-
- **Note:** If RLS blocks the update, an empty result is returned (not an error)
+ Counts the project's approvals by outcome over a time window, overall,
+ per workflow, and per day. The window defaults to the last 30 days and
+ can cover up to a year. An approval is counted on the day it was
+ requested.
- **Branch-targeted.** Runs against the named branch instead of the parent
- database, using the branch's own credentials. The branch must be `active`
- and unexpired. Nothing about this request can reach the parent's data.
- operationId: queryDatabaseBranchUpdate
+ Project access tokens can read statistics, including read-only ones.
+ operationId: getDurableApprovalStats
security:
- - AuthUserAccessToken: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/DatabaseName'
- - $ref: '#/components/parameters/BranchName'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DatabaseUpdateRequest'
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DurableApprovalFunctionFilter'
+ - name: from
+ in: query
+ required: false
+ description: Start of the window. Defaults to 30 days before `to`.
+ schema:
+ type: string
+ format: date-time
+ - name: to
+ in: query
+ required: false
+ description: End of the window. Defaults to now.
+ schema:
+ type: string
+ format: date-time
responses:
'200':
- description: Update successful
- headers:
- X-Volcano-Proxy-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyMs'
- X-Volcano-Proxy-Handler-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
- X-Volcano-Compute-Ms:
- $ref: '#/components/headers/DatabaseQueryComputeMs'
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseQueryResult'
- example:
- data:
- - id: post-uuid
- title: Updated Title
- status: published
- updated_at: '2026-01-13T10:05:00Z'
- count: 1
+ $ref: '#/components/schemas/DurableApprovalStats'
'400':
- description: Invalid request
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '401':
- description: Not authenticated
+ description: The window is invalid or longer than 366 days
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Access denied
+ /projects/{id}/durable-approvals/{approvalId}:
+ get:
+ tags:
+ - Durable Functions
+ summary: Get a durable approval
+ description: |
+ Returns one approval: what the workflow asked, the durable function
+ and execution that asked it, its deadline, and the decision once one
+ is made.
+
+ Project access tokens can read approvals, including read-only ones.
+ operationId: getDurableApproval
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DurableApprovalId'
+ responses:
+ '200':
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
+ $ref: '#/components/schemas/DurableApproval'
'404':
- description: Database or branch not found
+ description: Approval not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
- $ref: '#/components/responses/DatabaseQueryCapExceeded'
- '503':
- $ref: '#/components/responses/DatabaseBranchQueryUnavailable'
- /databases/{databaseName}/branches/{branchName}/query/delete:
+ /projects/{id}/durable-approvals/{approvalId}/approve:
post:
tags:
- - Database Queries
- summary: Delete data from database (REST API)
+ - Durable Functions
+ summary: Approve a durable approval
description: |
- Delete rows from your database using REST API.
-
- **Safety:** Requires at least one filter to prevent accidental mass deletions
-
- **Security:** Row-Level Security ensures you can only delete data you have access to
+ Approves a pending approval. The workflow resumes with the decision.
- **Note:** If RLS blocks the delete, an empty result is returned (not an error)
+ Only a person can decide: use the dashboard or a platform token from
+ `volcano login`. Project access tokens are refused with `403`.
- **Branch-targeted.** Runs against the named branch instead of the parent
- database, using the branch's own credentials. The branch must be `active`
- and unexpired. Nothing about this request can reach the parent's data.
- operationId: queryDatabaseBranchDelete
+ Approving an approval that is already approved returns it unchanged.
+ If the workflow cannot be reached right away, the decision still
+ stands and Volcano keeps delivering it.
+ operationId: approveDurableApproval
security:
- - AuthUserAccessToken: []
+ - UserToken: []
parameters:
- - $ref: '#/components/parameters/DatabaseName'
- - $ref: '#/components/parameters/BranchName'
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DurableApprovalId'
requestBody:
- required: true
+ required: false
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseDeleteRequest'
+ $ref: '#/components/schemas/DurableApprovalDecisionRequest'
responses:
'200':
- description: Delete successful
- headers:
- X-Volcano-Proxy-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyMs'
- X-Volcano-Proxy-Handler-Ms:
- $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
- X-Volcano-Compute-Ms:
- $ref: '#/components/headers/DatabaseQueryComputeMs'
+ description: Approved
content:
application/json:
schema:
- $ref: '#/components/schemas/DatabaseQueryResult'
- example:
- data:
- - id: post-uuid
- title: Deleted Post
- count: 1
+ $ref: '#/components/schemas/DurableApproval'
'400':
- description: Invalid request or missing filters
+ description: The request body is invalid
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Not authenticated
+ '403':
+ description: The credential is not a person's
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Access denied
+ '404':
+ description: Approval not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Database or branch not found
+ '409':
+ description: |
+ The approval was already denied, or has expired or been cancelled.
+ `code` is `approval_decided`, `approval_expired`, or
+ `approval_cancelled`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
- $ref: '#/components/responses/DatabaseQueryCapExceeded'
- '503':
- $ref: '#/components/responses/DatabaseBranchQueryUnavailable'
- /databases/regions:
- get:
- tags:
- - Databases
- summary: List platform-supported regions for database provisioning
- operationId: listDatabaseRegions
- description: |
- Returns the regions enabled for database provisioning in this platform environment.
- These are the same regions offered for function deployment, and the only values
- the `region` field of a database accepts.
- This is a public endpoint that doesn't require authentication.
- responses:
- '200':
- description: List of platform-supported regions
+ '413':
+ description: The request body is larger than 16 KiB
content:
application/json:
schema:
- type: array
- items:
- type: object
- properties:
- id:
- type: string
- example: us-east-1
- description: Region identifier for API usage
- name:
- type: string
- example: US East (N. Virginia)
- description: Human-readable region location
- /databases/postgres-versions:
- get:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/durable-approvals/{approvalId}/deny:
+ post:
tags:
- - Databases
- summary: List available PostgreSQL versions
- operationId: listPostgresVersions
+ - Durable Functions
+ summary: Deny a durable approval
description: |
- Returns the PostgreSQL major versions a database can be created on,
- newest first. Local mode lists only the version its server runs.
- This is a public endpoint that doesn't require authentication.
+ Denies a pending approval. The workflow resumes with the decision; a
+ denial is a value the workflow branches on, not an error.
+
+ Only a person can decide: use the dashboard or a platform token from
+ `volcano login`. Project access tokens are refused with `403`.
+
+ Denying an approval that is already denied returns it unchanged.
+ If the workflow cannot be reached right away, the decision still
+ stands and Volcano keeps delivering it.
+ operationId: denyDurableApproval
+ security:
+ - UserToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DurableApprovalId'
+ requestBody:
+ required: false
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DurableApprovalDecisionRequest'
responses:
'200':
- description: List of available PostgreSQL versions
+ description: Denied
content:
application/json:
schema:
- type: array
- items:
- type: object
- properties:
- version:
- type: string
- example: '18'
- description: PostgreSQL major version number
- name:
- type: string
- example: PostgreSQL 18
- description: Human-readable version name
- default:
- type: boolean
- description: True on the version to preselect for a new database; absent on the others
- recommended:
- type: boolean
- description: True on the version recommended for new databases; absent on the others
- deprecated:
- type: boolean
- description: Whether this version is deprecated (approaching EOL)
- /functions/runtimes:
- get:
- tags:
- - Functions
- summary: List supported function runtimes
- operationId: listFunctionRuntimes
- security: []
- description: |
- Returns the public function runtime catalog: every runtime a deploy accepts, its display
- label for runtime pickers, language defaults, durable capability, and local source packaging
- metadata for deployments.
- This is a public endpoint that doesn't require authentication.
- responses:
- '200':
- description: Supported function runtimes
+ $ref: '#/components/schemas/DurableApproval'
+ '400':
+ description: The request body is invalid
content:
application/json:
schema:
- $ref: '#/components/schemas/FunctionRuntimesResponse'
- /functions/regions:
- get:
- tags:
- - Functions
- summary: List available regions for function deployment
- operationId: listFunctionRegions
- security: []
- description: |
- Returns the configured regions where functions can be deployed, each annotated
- with a human-readable label and country flag emoji for use in UI pickers.
- This is a public endpoint that doesn't require authentication.
- responses:
- '200':
- description: Available function deployment regions
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: The credential is not a person's
content:
application/json:
schema:
- type: array
- items:
- $ref: '#/components/schemas/FunctionRegion'
- /projects/{id}/variables/{name}:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Approval not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: |
+ The approval was already approved, or has expired or been
+ cancelled. `code` is `approval_decided`, `approval_expired`, or
+ `approval_cancelled`.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '413':
+ description: The request body is larger than 16 KiB
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/frontends:
get:
tags:
- - Variables
- summary: Get variable by name
+ - Frontends
+ summary: List all frontends in a project
description: |
- Returns a project-level environment variable used by deployed functions and frontends.
- operationId: getVariable
+ Supports two mutually exclusive pagination modes. Offset mode uses `page`
+ and `limit` and returns `next` (URL). Cursor mode uses `cursor` and
+ `limit`, supports `search` (case-insensitive name match), and returns
+ `next_cursor`. Sending both `page` and `cursor` (or `page` and `search`)
+ returns 400.
+ operationId: listFrontends
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/VariableName'
+ - $ref: '#/components/parameters/Page'
+ - $ref: '#/components/parameters/Limit'
+ - $ref: '#/components/parameters/Cursor'
+ - $ref: '#/components/parameters/EndingBefore'
+ - $ref: '#/components/parameters/Offset'
+ - $ref: '#/components/parameters/Search'
responses:
'200':
description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/Variable'
- '404':
- description: Variable not found
+ $ref: '#/components/schemas/PaginatedFrontends'
+ '400':
+ description: Bad request - invalid project identifier
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- put:
- tags:
- - Variables
- summary: Update a variable
- description: |
- Updates a project-level environment variable and triggers asynchronous propagation
- to deployed functions and frontends in the project's configured regions.
- operationId: updateVariable
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/VariableName'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/UpdateVariableRequest'
- responses:
- '200':
- description: Variable updated
+ '401':
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
- $ref: '#/components/schemas/Variable'
- '400':
- description: Invalid or reserved variable name
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - project ownership required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Variable not found
+ description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Private variable membership writes are disabled during rollout
+ '500':
+ description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- delete:
+ post:
tags:
- - Variables
- summary: Delete a variable
+ - Frontends
+ summary: Create a new frontend deployment
description: |
- Deletes a project-level environment variable and triggers asynchronous propagation
- of the removal to deployed functions and frontends in the project's configured regions.
- operationId: deleteVariable
+ Creates and deploys a frontend for the project.
+ If a frontend with the same name already exists in the project, this operation updates that
+ frontend using the uploaded archive and starts a new deployment. A deployment that starts
+ immediately returns `status: provisioning`, then transitions to `active`, `degraded`, or
+ `failed`. If another deployment is running, the response preserves the frontend's current status
+ and exposes the queued deployment through `pending_deployment_id`.
+ Existing frontend traffic continues to use an available runtime while the new deployment builds
+ and provisions. Each deployment publishes its own static assets before the runtimes switch to its
+ build, and the live build's assets keep serving until the new deployment is live, so a page loaded
+ mid-deployment resolves its assets whichever build served it. A failed redeploy puts the runtimes
+ back on the build they were running, leaves the frontend `active` on the previous deployment, and
+ records the attempted deployment as failed. `degraded` means the runtime remains available but
+ edge synchronization requires recovery; Volcano retries the edge step without rebuilding. Only one deployment may run for a
+ given frontend, while independent frontends and projects can deploy concurrently.
+ For monorepos, provide `app_root` as a relative path from the uploaded archive root
+ to the Next.js app that should be built. Omit it for single-app archives.
+ Supported frontend environments are Next.js 15.x and 16.x with Node.js
+ 22.x or 24.x. The Node.js runtime is inferred from
+ `package.json` `engines.node`; if omitted, Volcano uses Node.js 22.x.
+ The selected Node.js family must also satisfy the installed Next.js package's
+ `engines.node` constraint. Volcano tests Next 15.5.29 (`^18.18.0 || ^19.8.0 || >=20.0.0`) and Next 16.4.5 (`>=20.9.0`).
+ Source archive size is enforced by the API with `SOURCE_ARCHIVE_SIZE_LIMIT_MB`; the CLI
+ does not apply its own source archive size limit. After the final container images are
+ built, the publish build enforces `LAMBDA_TARGET_CONTAINER_SIZE_LIMIT_MB` before pushing.
+ Plans do not limit how many frontends a project has; usage allowances apply across all of a user's frontends.
+ Each project can contain up to 10,000 frontends regardless of plan.
+ operationId: createFrontend
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/VariableName'
+ requestBody:
+ required: true
+ content:
+ multipart/form-data:
+ schema:
+ type: object
+ required:
+ - name
+ - archive
+ properties:
+ name:
+ type: string
+ maxLength: 63
+ pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$
+ description: DNS-safe frontend name
+ framework:
+ type: string
+ enum:
+ - nextjs
+ default: nextjs
+ description: Next.js frontend. Supported Next.js majors are 15.x and 16.x.
+ app_root:
+ type: string
+ maxLength: 1024
+ description: Optional relative POSIX path from the uploaded archive root to the Next.js app to build, for example `apps/web`.
+ example: apps/web
+ variable_scope:
+ type: string
+ enum:
+ - all
+ - scoped
+ description: Variable selection for this deployment. New frontends default to `scoped`; omitting this field for an existing frontend preserves its current selection.
+ variables:
+ type: array
+ items:
+ type: string
+ pattern: ^[A-Za-z_][A-Za-z0-9_]*$
+ description: Project variable names selected when `variable_scope` is `scoped`. Submit each name as a repeated multipart field.
+ archive:
+ type: string
+ format: binary
+ description: ZIP or tar.gz archive of the frontend project directory or monorepo workspace root. The API enforces SOURCE_ARCHIVE_SIZE_LIMIT_MB and stores a normalized tar.gz archive.
+ commit:
+ type: string
+ description: |
+ JSON-encoded commit the uploaded source came from: `{"repository": "acme/app", "sha": "<40-character commit ID>", "dirty": false, "root": "apps/web"}`. `repository` is `owner/name` or a github.com remote URL (`https://github.com/acme/app.git`, `git@github.com:acme/app.git`, or `ssh://git@github.com/acme/app.git`); Volcano drops any credentials in the URL and records `owner/name`. `dirty` is `true` when the uploaded files differ from the commit. `root` is the uploaded directory's path from the repository root, `""` for the root itself. `repository`, `sha`, and `dirty` are required, and fields Volcano does not know are ignored. An empty value, `null`, or `""` reports no commit. A malformed commit, or a repository not on GitHub, returns 400 before anything is deployed. Volcano checks the commit against the project's connected repository and each uploaded file against the commit's file at `root`, and returns the result in the deployment's `commit.verified`; an uploaded file in the project's root directory that the commit does not hold sets `commit.dirty`, and one outside it leaves the commit unverified. A commit it cannot verify is still recorded and never fails the deploy.
responses:
- '204':
- description: Variable deleted
+ '200':
+ description: Existing frontend updated; its deployment was started or queued
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Frontend'
+ '201':
+ description: Frontend created and deployment workflow started
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Frontend'
+ '400':
+ description: Bad request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Project frontend hard cap exceeded
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'404':
- description: Variable not found
+ description: Project not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/password-policy:
+ '409':
+ description: 'Conflict. `code: frontend_served_by_candidate` - a promoted Candidate serves the existing frontend; roll back to the frontend''s own runtime before deploying it. Without a code, the frontend''s deletion is queued or running.'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Service unavailable - frontend workflow or archive limit configuration missing
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/frontends/{frontendId}:
get:
tags:
- - Authentication
- summary: Get the effective password policy
- description: |
- Returns the backend-enforced password bounds and compromised-password
- screening status for the project identified by the anon key. A valid
- anon key is required, but no route-specific auth permission is needed.
- operationId: authGetPasswordPolicy
+ - Frontends
+ summary: Get frontend details
+ operationId: getFrontend
security:
- - AnonKey: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/AuthProxyAuthorization'
- - $ref: '#/components/parameters/AuthProxyClientIP'
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/FrontendId'
responses:
'200':
- description: Effective password policy
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/AuthPasswordPolicy'
+ $ref: '#/components/schemas/Frontend'
+ '400':
+ description: Bad request - invalid identifier
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'401':
- description: Invalid, missing, or revoked anon key; or invalid auth proxy metadata
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - project ownership required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Project or auth configuration not found
+ description: Frontend not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/signup:
- post:
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ delete:
tags:
- - Authentication
- summary: Sign up a new auth user
+ - Frontends
+ summary: Delete a frontend
description: |
- Create a new end-user account. The project is determined from the anon key.
- Requires project-specific anon key in Authorization header.
-
- **Session-less**: signup never issues a session. On success it returns a
- uniform acknowledgement (`AuthSignupResponse`) with no tokens; the client
- obtains a session with a subsequent `POST /auth/signin`. If email confirmation
- is enabled for the project, a confirmation email is sent and
- `confirmation_required` is `true`.
-
- **Anti-enumeration**: a signup for an already-registered email returns the
- exact same `201` response as a fresh signup — it never returns `409` — so the
- response cannot be used to discover which emails are registered.
- operationId: authSignup
+ Schedules asynchronous frontend deletion. If another deployment is running, the frontend
+ preserves its current status and exposes the queued deletion through `pending_deployment_id`.
+ Its status changes to `deleting` when cleanup starts. After cleanup, it returns 404 and no
+ longer appears in frontend lists.
+ operationId: deleteFrontend
security:
- - AnonKey: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/AuthProxyAuthorization'
- - $ref: '#/components/parameters/AuthProxyClientIP'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- type: object
- required:
- - email
- - password
- properties:
- email:
- type: string
- format: email
- password:
- type: string
- description: |
- Password validated after NFC normalization against the
- policy returned by GET /auth/password-policy.
- user_metadata:
- type: object
- additionalProperties: true
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/FrontendId'
responses:
- '201':
- description: |
- Signup acknowledged (session-less). Returned identically for a new
- account and for an already-registered email (anti-enumeration).
+ '202':
+ description: Frontend deletion started or queued
+ '400':
+ description: Bad request - invalid identifier
content:
application/json:
schema:
- $ref: '#/components/schemas/AuthSignupResponse'
- '400':
- description: Invalid input (bad email/password format)
+ $ref: '#/components/schemas/Error'
'401':
- description: |
- Unauthorized - Invalid, tampered, revoked, or wrong-project anon key.
- Also returned for invalid, repeated, or under-scoped auth proxy metadata
- (`invalid auth proxy metadata`).
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'403':
- description: |
- Forbidden - Signups disabled, anon key lacks signup permission, or the
- email domain is not in `allowed_email_domains`. The internal
- `anonymous.volcano.internal` domain is reserved for anonymous
- accounts and is refused whatever the project allows.
- '429':
- description: Rate limit exceeded
- '503':
- description: Compromised-password screening is temporarily unavailable
+ description: Forbidden - project ownership required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/signin:
+ '404':
+ description: Frontend not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: Another Frontend's route mounts this Frontend. Remove those routes first; the error names the mounting Frontends.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Service unavailable - frontend workflow configuration missing
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/frontends/{frontendId}/redeploy:
post:
tags:
- - Authentication
- summary: Sign in an auth user
+ - Frontends
+ summary: Redeploy frontend using latest uploaded artifact
description: |
- Authenticate with email and password. Requires an anon key.
-
- Set `session_mode` to `cookie` to request HttpOnly refresh-token
- storage. Cookie mode is honored only for an exact, credentialed CORS
- origin on the same schemeful site as this API. Otherwise the response
- retains the refresh token in its body. A frontend on its default
- Volcano URL is cross-site with this API and so always gets the body
- token.
- operationId: authSignin
+ Starts a new frontend workflow using the latest stored artifact. A deployment that starts
+ immediately returns `status: provisioning`, then transitions to `active`, `degraded`, or
+ `failed`. An overlapping deployment preserves the frontend's current status, is exposed through
+ `pending_deployment_id`, and supersedes any older queued deployment. The previous runtime and its
+ published static assets remain available during provisioning, and a failed redeploy restores the
+ regional runtimes to that build and keeps it serving while the attempted deployment is recorded as
+ failed.
+ operationId: redeployFrontend
security:
- - AnonKey: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/AuthProxyAuthorization'
- - $ref: '#/components/parameters/AuthProxyClientIP'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- type: object
- required:
- - email
- - password
- properties:
- email:
- type: string
- password:
- type: string
- session_mode:
- type: string
- enum:
- - cookie
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/FrontendId'
responses:
'200':
- description: Signin successful
+ description: Frontend redeploy started or queued
content:
application/json:
schema:
- $ref: '#/components/schemas/AuthTokenResponse'
+ $ref: '#/components/schemas/Frontend'
'400':
- description: Invalid input (missing email/password)
- '401':
- description: |
- Unauthorized - Invalid credentials, invalid/tampered/revoked anon key,
- or account banned/deleted; or invalid auth proxy metadata
- '403':
- description: |
- Forbidden - Anon key lacks signin permission, or the email domain is
- not in `allowed_email_domains` while `allowed_email_domains_mode` is
- `signup_and_signin`. The domain is taken from the account's canonical
- email (its primary identity), which is not necessarily the address in
- the request.
- '429':
- description: Rate limit exceeded
- /auth/refresh:
- post:
- tags:
- - Authentication
- summary: Refresh access token
- description: |
- Get a new access token using a refresh token. Requires an anon key.
-
- Send `refresh_token` in the body for the default flow. An eligible
- cookie-mode browser request may instead send `session_mode: cookie`
- with an empty token or omit the request body; the API reads and resets
- the project's HttpOnly cookie and omits `refresh_token` from the
- response.
- operationId: authRefresh
- security:
- - AnonKey: []
- parameters:
- - $ref: '#/components/parameters/AuthProxyAuthorization'
- - $ref: '#/components/parameters/AuthProxyClientIP'
- requestBody:
- required: false
- content:
- application/json:
- schema:
- type: object
- properties:
- refresh_token:
- type: string
- session_mode:
- type: string
- enum:
- - cookie
- responses:
- '200':
- description: Token refreshed
+ description: Bad request - invalid identifier
content:
application/json:
schema:
- $ref: '#/components/schemas/AuthTokenResponse'
+ $ref: '#/components/schemas/Error'
'401':
- description: Invalid or expired refresh token; or invalid auth proxy metadata
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: |
- The account's email domain is not in `allowed_email_domains` while
- `allowed_email_domains_mode` is `signup_and_signin`, so the session
- cannot be extended
+ description: Forbidden - project ownership required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
- description: Rate limit exceeded
+ '404':
+ description: Frontend not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/logout:
- post:
- tags:
- - Authentication
- summary: Logout (revoke refresh token)
- description: |
- Invalidate a refresh token. Requires an anon key.
-
- Send `refresh_token` for the default flow. An eligible cookie-mode
- browser request may instead send `session_mode: cookie` with an empty
- token; logout remains idempotent when the cookie is missing or expired.
- operationId: authLogout
- security:
- - AnonKey: []
- parameters:
- - $ref: '#/components/parameters/AuthProxyAuthorization'
- - $ref: '#/components/parameters/AuthProxyClientIP'
- requestBody:
- required: false
- content:
- application/json:
- schema:
- type: object
- properties:
- refresh_token:
- type: string
- session_mode:
- type: string
- enum:
- - cookie
- responses:
- '204':
- description: Logged out successfully
- '401':
- description: Missing, invalid, or revoked anon key; or invalid, repeated, or under-scoped auth proxy metadata
+ '409':
+ description: 'Conflict. `code: frontend_served_by_candidate` - a promoted Candidate serves the frontend; roll back to the frontend''s own runtime before redeploying it. Without a code, the frontend''s deletion is queued or running.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/forgot-password:
- post:
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Service unavailable - frontend workflow configuration missing
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/frontends/{frontendId}/domain:
+ get:
tags:
- - Authentication
- summary: Request password reset
+ - Frontends
+ summary: Get frontend custom domain status
description: |
- Generates recovery token and stores it (email sending pending).
- Returns generic message to prevent email enumeration.
- Project is identified via the anon key.
- operationId: authForgotPassword
+ Deprecated: use `GET /projects/{id}/frontends/{frontendId}/domains`.
+ Returns the frontend's oldest domain that serves it rather than redirecting.
+ deprecated: true
+ operationId: getFrontendCustomDomain
security:
- - AnonKey: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/AuthProxyAuthorization'
- - $ref: '#/components/parameters/AuthProxyClientIP'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- type: object
- required:
- - email
- properties:
- email:
- type: string
- format: email
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/FrontendId'
responses:
'200':
- description: Generic success message (doesn't reveal if email exists)
+ description: |
+ Frontend custom domain status, or null when the frontend has no
+ custom domain configured (the common empty state).
content:
application/json:
schema:
- type: object
- properties:
- message:
- type: string
- example: If the email exists, a password reset link has been sent
+ nullable: true
+ allOf:
+ - $ref: '#/components/schemas/FrontendCustomDomainResponse'
+ '400':
+ description: Bad request - invalid identifier
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'401':
- description: Missing, invalid, or revoked anon key; or invalid, repeated, or under-scoped auth proxy metadata
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Password reset is disabled for this project
+ description: Forbidden - project ownership required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
- description: Rate limit exceeded (10 requests per hour per IP)
+ '404':
+ description: Frontend not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/reset-password:
post:
tags:
- - Authentication
- summary: Reset password with recovery token
+ - Frontends
+ summary: Configure frontend custom domain
+ deprecated: true
description: |
- Reset password using recovery token from forgot-password.
- Revokes all existing sessions for security.
- operationId: authResetPassword
- security:
- - AnonKey: []
- parameters:
- - $ref: '#/components/parameters/AuthProxyAuthorization'
- - $ref: '#/components/parameters/AuthProxyClientIP'
+ Deprecated: use `POST /projects/{id}/frontends/{frontendId}/domains`, which adds a domain beside the frontend's others.
+ Configures one custom domain for a frontend. When the frontend already has a domain, a request for another hostname returns `409`.
+ The default Volcano-generated frontend URL remains active.
+ Wildcard Volcano frontend TLS remains valid and isolated from custom-domain certificate changes.
+ The account must own the hostname: it must have verified the hostname or a domain above it (see `POST /user/domains`). A certificate does not prove ownership.
+ When the account owns no domain covering the hostname, Volcano asks for a TXT record at `_volcano.`, such as `_volcano.example.com`. Publishing it verifies the whole domain, so later subdomains need no record. A managed TLS request reserves the hostname and returns that record in `verification_records`; the reservation expires after 72 hours unless the record is published. A BYOC request gets `409` with `code: ownership_verification_required` and the record in `required_record`; publish it and send the same request again.
+ Managed TLS then returns the CNAME that authorizes certificate issuance and renewal.
+ To move an active BYOC domain to managed TLS without downtime, send `tls.mode: managed` for the same hostname. The response is `200` with the CNAME to publish; the uploaded certificate keeps serving until Volcano issues the managed one, and `serving_certificate` changes from `uploaded` to `managed`.
+ To move an active managed domain to BYOC without downtime, send `tls.mode: byoc` with the certificate for the same hostname. The response is `200`; the uploaded certificate replaces the managed one at once, and Volcano stops renewing the managed certificate.
+ An unverified reservation does not block an account that proves ownership. When another account holds one, a request gets `409` with `code: ownership_verification_required` and the caller's own `required_record`; after publishing it, the same request takes over the reservation. When another account verified the domain, the same `409` names the record that moves the domain to the caller once the other account's record is no longer published. A hostname below a domain another account owns otherwise returns `409` without `code`.
+ operationId: createFrontendCustomDomain
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/FrontendId'
requestBody:
required: true
content:
application/json:
schema:
- type: object
- required:
- - token
- - new_password
- properties:
- token:
- type: string
- description: Recovery token from forgot-password
- new_password:
- type: string
- description: |
- Password validated after NFC normalization against the
- policy returned by GET /auth/password-policy.
+ $ref: '#/components/schemas/CreateFrontendCustomDomainRequest'
responses:
'200':
- description: Password reset successful
+ description: 'Custom domain already configured with the same hostname. A request with the other TLS mode for the frontend''s active domain switches it in place. To managed TLS, the uploaded certificate keeps serving, with `serving_certificate: uploaded`, until Volcano issues the managed certificate. To BYOC, the uploaded certificate replaces the managed one at once.'
content:
application/json:
schema:
- type: object
- properties:
- message:
- type: string
+ $ref: '#/components/schemas/FrontendCustomDomainResponse'
+ '201':
+ description: Custom domain provisioning started
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/FrontendCustomDomainResponse'
'400':
- description: Password doesn't meet requirements
+ description: Bad request - invalid domain
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'401':
- description: Invalid or expired token; or invalid auth proxy metadata
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - the plan does not include custom domains, the frontend has as many custom domains as the plan allows, or a managed TLS request would exceed the account's managed TLS certificate limit
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Frontend not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: 'Conflict - ownership not verified, custom domain owned or reserved by another account, already in use, still detaching, or frontend already has a custom domain. While a removed domain detaches and Volcano releases it (about a minute for BYOC, a few minutes for managed TLS), adding its hostname to any frontend, or any domain to its frontend, returns `code: custom_domain_releasing` and a `Retry-After` header; send the same request again after that many seconds. A release that will not finish within a few minutes returns the conflict without `code`.'
+ headers:
+ Retry-After:
+ description: Seconds to wait before sending the same request again. Sent only with code `custom_domain_releasing`.
+ schema:
+ type: integer
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/FrontendCustomDomainConflictError'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'503':
- description: Compromised-password screening is temporarily unavailable
+ description: Service unavailable - custom domain provisioning is temporarily unavailable
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/confirm:
- post:
+ delete:
tags:
- - Authentication
- summary: Confirm email address
+ - Frontends
+ summary: Delete frontend custom domain
description: |
- Confirm email address using token sent via email.
- Required if require_email_confirmation is enabled.
- operationId: authConfirmEmail
+ Deprecated: use `DELETE /projects/{id}/frontends/{frontendId}/domains/{domain}`.
+ Deletes the frontend's custom domain. A frontend with several domains
+ returns `409`; name the one to delete on the collection route.
+ deprecated: true
+ operationId: deleteFrontendCustomDomain
security:
- - AnonKey: []
- requestBody:
- required: true
- content:
- application/json:
- schema:
- type: object
- required:
- - token
- properties:
- token:
- type: string
- description: Confirmation token from email
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/FrontendId'
responses:
- '200':
- description: Email confirmed or already confirmed
+ '204':
+ description: Custom domain detach scheduled
+ '400':
+ description: Bad request - invalid identifier
content:
application/json:
schema:
- type: object
- properties:
- message:
- type: string
- enum:
- - Email confirmed successfully
- - Email already confirmed
- examples:
- confirmed:
- summary: Fresh confirmation
- value:
- message: Email confirmed successfully
- alreadyConfirmed:
- summary: Token belongs to already-confirmed user
- value:
- message: Email already confirmed
- '400':
- description: Missing confirmation token in request body
+ $ref: '#/components/schemas/Error'
'401':
- description: Invalid or expired token
- /auth/resend-confirmation:
- post:
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - project ownership required
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Frontend or custom domain not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: The custom domain switched TLS mode while the request ran, so send it again, another domain of the frontend redirects to it, or the frontend has several domains.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/frontends/{frontendId}/domains:
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/FrontendId'
+ get:
tags:
- - Authentication
- summary: Resend confirmation email
+ - Frontends
+ summary: List a frontend's custom domains
description: |
- Resend email confirmation link.
- Returns generic message to prevent email enumeration.
- No email is sent when the account does not exist or is already confirmed.
- If the account exists and is unconfirmed, a new token is generated and
- any previous confirmation token is invalidated.
- operationId: authResendConfirmation
+ Lists the frontend's custom domains, oldest first. Each domain either
+ serves the frontend or, with `redirect` set, redirects every request to
+ another domain of the frontend.
+ operationId: listFrontendDomains
security:
- - AnonKey: []
- requestBody:
- required: true
- content:
- application/json:
- schema:
- type: object
- required:
- - email
- properties:
- email:
- type: string
- format: email
+ - UserToken: []
+ - ProjectAccessToken: []
responses:
'200':
- description: Generic success message
+ description: The frontend's custom domains
content:
application/json:
schema:
- type: object
- properties:
- message:
- type: string
- '429':
- description: Rate limit exceeded
+ $ref: '#/components/schemas/FrontendCustomDomainList'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Project not owned by the caller
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Frontend not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Failed to list custom domains
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/signup-anonymous:
post:
tags:
- - Authentication
- summary: Create anonymous user
- description: |
- Create guest user without email/password.
+ - Frontends
+ summary: Add a custom domain to a frontend
+ description: |
+ Adds a custom domain beside the frontend's others, up to the plan's
+ custom domains per frontend. The domain serves the frontend, or, with
+ `redirect`, redirects every request to `redirect.to`, another active
+ domain of the same frontend that serves it, keeping the path and query
+ string.
+ A redirecting domain still needs TLS, so it takes `tls` like any other.
- User metadata (like display_name) can be included and will appear in realtime presence events.
- Requires enable_anonymous_signins to be true.
- operationId: authSignupAnonymous
+ Ownership, verification records, TLS mode switches, and the `409` codes
+ work as on `POST /projects/{id}/frontends/{frontendId}/domain`. A
+ request for a hostname the frontend already has returns it with `200`,
+ or switches its TLS mode in place. When the request's redirect differs
+ from the domain's, it returns `409`; change a redirect with `PATCH`.
+ operationId: createFrontendDomain
security:
- - AnonKey: []
- parameters:
- - $ref: '#/components/parameters/AuthProxyAuthorization'
- - $ref: '#/components/parameters/AuthProxyClientIP'
+ - UserToken: []
+ - ProjectAccessToken: []
requestBody:
- description: Optional user metadata
+ required: true
content:
application/json:
schema:
- type: object
- properties:
- user_metadata:
- type: object
- additionalProperties: true
- description: Custom user metadata (e.g., display_name, avatar_url)
- example:
- display_name: Alice
- avatar_url: https://example.com/alice.jpg
+ $ref: '#/components/schemas/CreateFrontendDomainRequest'
responses:
- '201':
- description: Anonymous user created
+ '200':
+ description: The frontend already has this hostname, or its TLS mode was switched in place
content:
application/json:
schema:
- $ref: '#/components/schemas/AuthTokenResponse'
- '401':
- description: Missing, invalid, or revoked anon key; or invalid, repeated, or under-scoped auth proxy metadata
+ $ref: '#/components/schemas/FrontendCustomDomainResponse'
+ '201':
+ description: Custom domain provisioning started
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/FrontendCustomDomainResponse'
+ '400':
+ description: Invalid domain, TLS, or redirect, such as a redirect to a hostname the frontend does not serve or that is not active yet
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Anonymous signins disabled
- /auth/user/convert-anonymous:
- post:
+ description: The plan does not include custom domains, the frontend has as many as the plan allows, or a managed TLS request would exceed the managed TLS certificate limit
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Frontend not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: 'Ownership not verified, the hostname is owned, reserved, or used elsewhere, the frontend already has the hostname with a different redirect, or a removed domain is still releasing it (`code: custom_domain_releasing` with `Retry-After`).'
+ headers:
+ Retry-After:
+ description: Seconds to wait before sending the same request again. Sent only with code `custom_domain_releasing`.
+ schema:
+ type: integer
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/FrontendCustomDomainConflictError'
+ '500':
+ description: Failed to add the custom domain
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Custom domain provisioning is temporarily unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/frontends/{frontendId}/domains/{domain}:
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/FrontendId'
+ - $ref: '#/components/parameters/FrontendCustomDomainHostname'
+ get:
tags:
- - Authentication
- summary: Convert anonymous user to authenticated
- description: |
- Add email and password to anonymous user.
- Requires auth user access token.
- If require_email_confirmation is enabled for the project, the converted
- user remains unconfirmed until /auth/confirm succeeds. When email
- sending is enabled, a confirmation email is sent during conversion.
- operationId: authConvertAnonymous
+ - Frontends
+ summary: Get a frontend custom domain
+ operationId: getFrontendDomain
security:
- - AuthUserAccessToken: []
- requestBody:
- required: true
- content:
- application/json:
- schema:
- type: object
- required:
- - email
- - password
- properties:
- email:
- type: string
- format: email
- password:
- type: string
- description: |
- Password validated after NFC normalization against the
- policy returned by GET /auth/password-policy.
- user_metadata:
- type: object
- additionalProperties: true
+ - UserToken: []
+ - ProjectAccessToken: []
responses:
'200':
- description: User converted successfully
+ description: The custom domain
content:
application/json:
schema:
- type: object
- properties:
- user:
- $ref: '#/components/schemas/AuthUser'
- '400':
- description: Not an anonymous user
+ $ref: '#/components/schemas/FrontendCustomDomainResponse'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'403':
- description: |
- The chosen email domain is not in `allowed_email_domains`
- '409':
- description: Email already in use
- '503':
- description: Compromised-password screening is temporarily unavailable
+ description: Project not owned by the caller
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/user/change-email:
- post:
+ '404':
+ description: Frontend or custom domain not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Failed to get the custom domain
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ patch:
tags:
- - Authentication
- summary: Request email change
+ - Frontends
+ summary: Set or clear a custom domain's redirect
description: |
- Request to change user's email address.
- Sends confirmation token to new email address.
- operationId: authRequestEmailChange
+ `{"redirect": {"to": "www.example.com", "status": 308}}` makes the
+ domain redirect to another active domain of the frontend that serves it.
+ `{"redirect": null}` makes it serve the frontend again. A domain other
+ domains redirect to cannot become a redirect itself. `status` defaults
+ to `308`. Proxies apply the change within seconds.
+ operationId: updateFrontendDomain
security:
- - AuthUserAccessToken: []
+ - UserToken: []
+ - ProjectAccessToken: []
requestBody:
required: true
content:
application/json:
schema:
- type: object
- required:
- - new_email
- properties:
- new_email:
- type: string
- format: email
+ $ref: '#/components/schemas/UpdateFrontendCustomDomainRequest'
responses:
'200':
- description: Confirmation email sent
+ description: The updated custom domain
content:
application/json:
schema:
- type: object
- properties:
- message:
- type: string
- new_email:
- type: string
+ $ref: '#/components/schemas/FrontendCustomDomainResponse'
'400':
- description: Invalid email format or same as current email
+ description: 'Invalid redirect: the target is this domain, is not an active domain of the frontend, or redirects itself'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
- description: Not authenticated
+ description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: |
- The requested email domain is not in `allowed_email_domains`
+ description: Project not owned by the caller
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: 'Frontend or custom domain not found, or the domain is being removed (`domain_status: detaching`)'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
- description: Email already in use
+ description: Other domains of the frontend redirect to this one; the message names them
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
- description: Rate limit exceeded (10 requests per hour per IP)
+ '500':
+ description: Failed to update the custom domain
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/user/confirm-email-change:
- post:
+ delete:
tags:
- - Authentication
- summary: Confirm email change
- description: Confirm email change with token sent to new address
- operationId: authConfirmEmailChange
+ - Frontends
+ summary: Remove a custom domain from a frontend
+ description: |
+ Detaches the domain. A domain other domains redirect to cannot be
+ removed until those redirects are removed or retargeted.
+ operationId: deleteFrontendDomain
security:
- - AuthUserAccessToken: []
- requestBody:
- required: true
- content:
- application/json:
- schema:
- type: object
- required:
- - email_change_token
- properties:
- email_change_token:
- type: string
+ - UserToken: []
+ - ProjectAccessToken: []
responses:
- '200':
- description: Email changed successfully
+ '204':
+ description: Custom domain detach scheduled
+ '401':
+ description: Unauthorized
content:
application/json:
schema:
- type: object
- properties:
- message:
- type: string
- user:
- $ref: '#/components/schemas/AuthUser'
- '400':
- description: Invalid or expired token, or no pending email change
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Project not owned by the caller
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Not authenticated
+ '404':
+ description: Frontend or custom domain not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: |
- The pending email domain is no longer in `allowed_email_domains`.
- Re-checked here because the allowlist can narrow between the request
- and the confirmation.
+ '409':
+ description: Other domains of the frontend redirect to this one, and the message names them, or the domain switched TLS mode while the request ran
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: Email is now in use by another user
+ '500':
+ description: Failed to remove the custom domain
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/user/cancel-email-change:
- delete:
+ /projects/{id}/frontends/{frontendId}/deployments:
+ get:
tags:
- - Authentication
- summary: Cancel pending email change
- operationId: authCancelEmailChange
+ - Frontends
+ summary: List frontend deployments
+ operationId: listFrontendDeployments
security:
- - AuthUserAccessToken: []
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/FrontendId'
+ - $ref: '#/components/parameters/Page'
+ - $ref: '#/components/parameters/Limit'
responses:
'200':
- description: Email change cancelled
+ description: Successful response
content:
application/json:
schema:
- type: object
- properties:
- message:
- type: string
+ $ref: '#/components/schemas/PaginatedFrontendDeployments'
+ '400':
+ description: Bad request - invalid identifier
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'401':
- description: Not authenticated
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/user/sessions:
- get:
- tags:
- - Authentication
- summary: Get current user's sessions
- description: |
- Returns paginated sessions for the currently authenticated user.
- Each session includes device info, IP addresses, and activity timestamps.
- The current session is marked with `is_current: true`.
-
- **Ordering and pagination.** Without `sort`, results are ordered by most
- recent activity and paged with `page`/`limit`, returning the
- `sessions`/`total`/`page`/`limit`/`total_pages` body below. This is the
- legacy default and is preserved for existing clients.
-
- Send `sort=created_at` to opt into the standard list contract: results are
- ordered by session start (newest first) and may be paged either with
- `page`/`limit` or by cursor with `cursor`/`ending_before` plus a bounded
- `offset` past the cursor anchor. Cursor responses use the shared
- `data` envelope with `next_cursor`/`prev_cursor`.
-
- Unlike other list endpoints, sending `limit` without `page` does **not**
- select cursor mode here; `sort=created_at` is the only opt-in. Cursor
- pagination is rejected with 400 for the activity order, because
- `last_activity_at` changes whenever a session refreshes its token: a row
- that crosses the cursor anchor between two requests would be skipped and
- never shown. The `status=expired` filter is also offset-only because a
- session can expire above the cursor anchor during a walk. Sending that
- filter in cursor mode, `page` with `cursor` or `ending_before`, or both
- cursor directions returns 400.
- operationId: authGetMySessions
- security:
- - AuthUserAccessToken: []
- parameters:
- - name: page
- in: query
- description: Page number (1-indexed)
- schema:
- type: integer
- minimum: 1
- default: 1
- - name: limit
- in: query
- description: Number of sessions per page (max 100)
- schema:
- type: integer
- minimum: 1
- maximum: 100
- default: 20
- - name: sort
- in: query
- description: |
- Sort key. `last_activity` (default) orders by most recent activity and
- supports offset pagination only. `created_at` orders by session start
- and supports both offset and cursor pagination.
- schema:
- type: string
- enum:
- - last_activity
- - created_at
- default: last_activity
- - name: status
- in: query
- description: |
- Filter by whether the session can still be refreshed. Omit for every
- stored session, including expired ones. `expired` is not supported
- with cursor pagination.
- schema:
- type: string
- enum:
- - active
- - expired
- - name: cursor
- in: query
- description: |
- Opaque keyset cursor from a previous response's `next_cursor`. Requires
- `sort=created_at`; mutually exclusive with `page` and `ending_before`.
- schema:
- type: string
- - name: ending_before
- in: query
- description: |
- Opaque keyset cursor from a previous response's `prev_cursor`, paging
- backward. Requires `sort=created_at`; mutually exclusive with `page`
- and `cursor`.
- schema:
- type: string
- - name: offset
- in: query
- description: |
- Bounded number of rows to skip past the cursor anchor (the hybrid
- jump, maximum 100000). Ignored unless `cursor` or `ending_before` is
- supplied.
- schema:
- type: integer
- minimum: 0
- maximum: 100000
- responses:
- '200':
- description: Paginated list of user sessions
+ '403':
+ description: Forbidden - project ownership required
content:
application/json:
schema:
- type: object
- properties:
- sessions:
- type: array
- items:
- $ref: '#/components/schemas/AuthSession'
- total:
- type: integer
- description: Total number of sessions
- page:
- type: integer
- description: Current page number
- limit:
- type: integer
- description: Number of sessions per page
- total_pages:
- type: integer
- description: Total number of pages
- data:
- type: array
- description: Sessions for this page (cursor pagination only)
- items:
- $ref: '#/components/schemas/AuthSession'
- has_more:
- type: boolean
- description: Whether a further page exists (cursor pagination only)
- next_cursor:
- type: string
- description: Opaque cursor for the next page (cursor pagination only)
- prev_cursor:
- type: string
- description: Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`.
- '400':
- description: Invalid or conflicting pagination parameters
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Frontend not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Not authenticated
+ '500':
+ description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- delete:
+ post:
tags:
- - Authentication
- summary: Sign out from all other devices
+ - Frontends
+ summary: Deploy an existing build to a frontend
description: |
- Deletes all sessions except the current one.
- Use this to log out from all other devices while keeping the current session active.
- operationId: authDeleteAllMySessions
+ Deploys the build of another frontend's deployment in the same project to this frontend, without
+ compiling it again. Use it to serve one build from several frontends, such as one per region or
+ brand. This frontend gets its own copy of the source archive and the build, so later changes to the
+ source frontend do not reach it, and a later redeploy of this frontend compiles that copied source.
+
+ The build-time variables this frontend would build with must equal those the source build read,
+ compared by name and value. Volcano records a keyed digest of each value, unique to the build, and
+ never stores the values. A mismatch returns `409` with `code: build_variables_differ` and the differing
+ names in `error`. The source deployment must be `active` or `degraded`, and both frontends must use
+ the same framework and app root.
+
+ Admission is the redeploy's: the deployment starts with `status: provisioning`, or, while another
+ deployment is in progress, is exposed through `pending_deployment_id` and supersedes any older
+ queued deployment. Nothing is compiled: the deployment's build minutes cover publishing the build
+ alone. The checks run again when a queued deployment starts. A refusal then fails the deployment
+ without a retry, its `error_message` starting with the refusal's code.
+ operationId: createFrontendDeployment
security:
- - AuthUserAccessToken: []
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/FrontendId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateFrontendDeploymentRequest'
responses:
- '204':
- description: All other sessions deleted
- '401':
- description: Not authenticated
+ '200':
+ description: Deployment started or queued
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Frontend'
+ '400':
+ description: 'Bad request - invalid identifier or body, or `code: source_deployment_same_frontend` when the source deployment belongs to this frontend; redeploy the frontend instead.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/user/sessions/{sessionId}:
- delete:
- tags:
- - Authentication
- summary: Sign out from specific device
- description: |
- Deletes a specific session, logging out that device.
- You can get session IDs from the list sessions endpoint.
- operationId: authDeleteMySession
- security:
- - AuthUserAccessToken: []
- parameters:
- - name: sessionId
- in: path
- required: true
- description: The session ID to delete
- schema:
- type: string
- format: uuid
- responses:
- '204':
- description: Session deleted
'401':
- description: Not authenticated
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Session not found
+ '403':
+ description: Forbidden - project ownership required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/user:
- get:
- tags:
- - Authentication
- summary: Get current user profile
- description: Returns authenticated user's profile. Requires access token.
- operationId: authGetUser
- security:
- - AuthUserAccessToken: []
- responses:
- '200':
- description: User profile
+ '404':
+ description: 'Frontend not found, or `code: source_deployment_not_found` when the source deployment is not in this project.'
content:
application/json:
schema:
- type: object
- properties:
- user:
- $ref: '#/components/schemas/AuthUser'
- '401':
- description: Not authenticated - access token missing or invalid
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: 'Conflict. `code: build_variables_differ` names the build-time variables whose values differ. `code: source_deployment_not_active` refuses a deployment that is not `active` or `degraded`. `code: source_deployment_is_preview` refuses a preview''s deployment; deploy from a frontend''s own deployment. `code: source_served_by_candidate` refuses a deployment of a frontend a promoted Candidate serves, since that frontend does not serve its own build; roll the source frontend back to its own build first. `code: source_build_unavailable` refuses a deployment made before Volcano kept builds, or whose build is no longer kept; redeploy the source frontend once and deploy from that deployment. `code: frontend_incompatible` refuses a different framework or app root. `code: frontend_served_by_candidate` refuses a frontend a promoted Candidate serves; roll back to the frontend''s own runtime first. Without a code, the frontend''s deletion is queued or running, or the project''s source is managed by Git, where deploys come from a push to the production branch.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- put:
- tags:
- - Authentication
- summary: Update user profile
- description: Update password or metadata. Requires access token.
- operationId: authUpdateUser
- security:
- - AuthUserAccessToken: []
- requestBody:
- content:
- application/json:
- schema:
- type: object
- properties:
- password:
- type: string
- description: |
- Password validated after NFC normalization against the
- policy returned by GET /auth/password-policy.
- user_metadata:
- type: object
- additionalProperties: true
- description: |
- Metadata keys to merge into the current user metadata.
- Omitted keys remain unchanged; set a key to null to remove it.
- Merging is shallow; nested objects replace the stored value for that top-level key.
- responses:
- '200':
- description: Profile updated
+ '429':
+ description: Monthly build-minutes allowance exceeded
content:
application/json:
schema:
- type: object
- properties:
- user:
- $ref: '#/components/schemas/AuthUser'
- '400':
- description: Bad request - invalid password or metadata format
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Not authenticated - access token missing or invalid
+ '501':
+ description: '`code: build_reuse_unavailable` - this server cannot deploy an existing build. Local mode answers this; deploy the frontend from source instead.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
- description: Compromised-password screening is temporarily unavailable
+ description: Service unavailable - frontend workflow configuration missing, or the build-minutes check is temporarily unavailable; retry later.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/user/identities:
+ /projects/{id}/frontends/{frontendId}/candidates:
get:
tags:
- - Authentication
- summary: List the current user's identities
+ - Frontends
+ summary: List a frontend's Candidates
description: |
- Returns every real email identity the account owns. An account can own
- multiple identities (for example a password identity plus one or more
- OAuth identities on different emails). Anonymous accounts have no real
- identity and return an empty list.
- operationId: authListIdentities
+ Returns the frontend's Candidates, oldest first, each with its latest deployment. A frontend
+ has at most 20 live Candidates. Reading never depends on the `frontends.candidates` capability.
+ operationId: listFrontendCandidates
security:
- - AuthUserAccessToken: []
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/FrontendId'
responses:
'200':
- description: List of identities
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/AuthIdentitiesResponse'
- '401':
- description: Not authenticated
+ description: The frontend's Candidates
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- /auth/user/identities/{identityId}:
- delete:
- tags:
- - Authentication
- summary: Unlink an identity from the current user
- description: |
- Removes a non-primary identity and its attached sign-in methods. Refused
- when the identity is the account's primary, its only identity, or when
- removing it would leave the account with no way to sign in.
- operationId: authUnlinkIdentity
- security:
- - AuthUserAccessToken: []
- parameters:
- - name: identityId
- in: path
- required: true
- description: The identity ID to unlink
- schema:
- type: string
- format: uuid
- responses:
- '204':
- description: Identity unlinked
+ $ref: '#/components/schemas/FrontendCandidateList'
'400':
- description: Identity cannot be unlinked (primary, last, or would remove last sign-in method), or the identity id is malformed
+ description: Bad request - invalid identifier
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
- description: Not authenticated
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Identity not found
+ '403':
+ description: Forbidden - project ownership required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/user/methods:
- get:
- tags:
- - Authentication
- summary: List the current user's sign-in methods
- description: |
- Returns a flat list of every sign-in method the account owns (password,
- each OAuth provider, and any active anonymous method), with the primary
- method flagged. Password stubs and converted anonymous methods are excluded.
- operationId: authListMethods
- security:
- - AuthUserAccessToken: []
- responses:
- '200':
- description: List of sign-in methods
+ '404':
+ description: Frontend not found
content:
application/json:
schema:
- $ref: '#/components/schemas/AuthMethodsResponse'
- '401':
- description: Not authenticated
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/user/methods/{methodId}/promote:
post:
tags:
- - Authentication
- summary: Set a method as the account's primary
- description: |
- Promotes the given method to the account's primary sign-in method. The
- account's canonical email is re-derived from the promoted method's identity.
- Refused for password stubs and converted anonymous methods, and for an
- identity whose domain is outside the project's `allowed_email_domains`.
- operationId: authPromoteMethod
+ - Frontends
+ summary: Create a frontend Candidate
+ description: |
+ Builds a copy of the frontend from the uploaded archive, with the frontend's own variable
+ selection, and deploys it to one region: the first region the frontend deploys to, or the
+ project's first region by name if it has not deployed yet. The Candidate is served at its own
+ URL, so it can be checked without changing what the frontend serves. The URL is reachable by
+ anyone who holds it and is not indexed; a Candidate is never public and does not claim to be
+ private. The response is `202` while the first deployment runs; read the Candidate for its
+ `status` and `url`.
+
+ Creating a Candidate is available while the `frontends.candidates` capability is. While it is
+ not, this operation, redeploying, promoting and rolling back to a Candidate answer `404` with
+ code `feature_unavailable`; reading and deleting existing Candidates, and rolling back to the
+ frontend's own runtime, keep working.
+
+ A Candidate builds like any deploy and spends the project's build minutes. A frontend has at
+ most 20 live Candidates, and each name is unique within the frontend. Without `ttl_seconds` a
+ Candidate is kept until it is deleted.
+ operationId: createFrontendCandidate
security:
- - AuthUserAccessToken: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - name: methodId
- in: path
- required: true
- description: The method ID to promote
- schema:
- type: string
- format: uuid
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/FrontendId'
+ requestBody:
+ required: true
+ content:
+ multipart/form-data:
+ schema:
+ type: object
+ required:
+ - name
+ - archive
+ properties:
+ name:
+ type: string
+ minLength: 1
+ maxLength: 128
+ description: Names the Candidate within the frontend. Cannot be `production`.
+ ttl_seconds:
+ type: integer
+ minimum: 1
+ maximum: 2592000
+ description: Deletes the Candidate this many seconds after it is created, at most 30 days. Omit to keep it until deleted.
+ archive:
+ type: string
+ format: binary
+ description: ZIP or tar.gz archive of the frontend project, as for creating a frontend. The API enforces SOURCE_ARCHIVE_SIZE_LIMIT_MB.
responses:
- '200':
- description: The promoted method
+ '202':
+ description: Candidate created; its first deployment is running
content:
application/json:
schema:
- $ref: '#/components/schemas/AuthMethodSummary'
+ $ref: '#/components/schemas/FrontendCandidate'
'400':
- description: This method cannot be set as primary (password stub, converted anonymous method, or unverified email), or the method id is malformed
+ description: Bad request - invalid name, expiry, identifier or archive, a variable the frontend declares has no value, or the resolved variables are too large
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
- description: Not authenticated
+ description: Unauthorized - invalid or missing token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: The promoted identity's email domain is not in the project's allowed_email_domains
+ description: Forbidden - project ownership required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Method not found
+ description: Frontend not found, or the `frontends.candidates` capability is unavailable (code `feature_unavailable`)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/auth/insights:
+ '409':
+ description: 'Conflict. `code: candidate_name_taken` - the name is taken. `code: candidate_limit_reached` - the frontend has the maximum Candidates. `code: configuration_changed` - the frontend''s configuration changed during the deploy; retry. `code: frontend_deleting` or `code: project_deleting` - the frontend or project is being deleted.'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '413':
+ description: The request body is larger than the archive limit, SOURCE_ARCHIVE_SIZE_LIMIT_MB
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '429':
+ description: Too many requests - the project's build minutes for the billing cycle are used up
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Service unavailable - frontend deployments are not configured
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/frontends/{frontendId}/candidates/{candidateId}:
get:
tags:
- - Auth Admin
- summary: Get auth user insights
- description: |
- Returns current and deleted auth-user totals, rolling 24-hour and 30-day
- active users, and zero-filled daily activity and account-retention counts
- for an inclusive UTC date range. Weeks start on Monday.
- The existing deletions series counts accounts by deletion date; net_growth
- remains signups minus deletions and is not affected by bans.
- The banned_users, deleted_users, and available_users fields describe the
- current state of users registered in each bucket. Banned users exclude
- deleted users and expired bans. Available users are signups minus
- banned_users minus deleted_users. Unban and expiry restore availability in
- the original signup bucket. These current-state cohorts can change after
- the requested dates have passed, without rewriting activity counts.
- Sign-in counts remain grouped by session creation date. Deleted users
- contribute to active counts until their last activity leaves the rolling
- window. Token refreshes affect active users but not the sign-in series.
- Signup history is backfilled from accounts present when collection was
- deployed. Accounts hard-deleted before deletion-history collection cannot
- be recovered. Current bans require no separate event-history collection.
- operationId: getAuthInsights
+ - Frontends
+ summary: Get a frontend Candidate
+ operationId: getFrontendCandidate
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - name: from
- in: query
- description: Inclusive UTC start date. Defaults to 29 days before `to`.
- schema:
- type: string
- format: date
- - name: to
- in: query
- description: Inclusive UTC end date. Defaults to today.
- schema:
- type: string
- format: date
- - name: interval
- in: query
- description: Chart bucket size. Defaults to `day`.
- schema:
- $ref: '#/components/schemas/AuthInsightsInterval'
+ - $ref: '#/components/parameters/FrontendId'
+ - $ref: '#/components/parameters/FrontendCandidateId'
responses:
'200':
- description: Auth insights retrieved
+ description: The Candidate with its latest deployment
content:
application/json:
schema:
- $ref: '#/components/schemas/AuthInsightsResponse'
- example:
- project_id: 4f165080-a931-4e03-b3bd-41c45c3f0058
- observed_at: '2026-07-20T18:00:00Z'
- window:
- from: '2026-06-21'
- to: '2026-07-20'
- interval: day
- summary:
- total_users: 1234
- deleted_users: 42
- active_users_1d: 83
- active_users_30d: 418
- series:
- - bucket_start: '2026-07-20'
- signups: 12
- signins: 97
- deletions: 3
- banned_users: 2
- deleted_users: 3
- available_users: 7
- net_growth: 9
- is_partial: true
+ $ref: '#/components/schemas/FrontendCandidate'
'400':
- description: Invalid date range or interval
+ description: Bad request - invalid identifier
content:
application/json:
schema:
@@ -12114,13 +12523,13 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Access denied
+ description: Forbidden - project ownership required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Project not found
+ description: Frontend or Candidate not found
content:
application/json:
schema:
@@ -12131,793 +12540,728 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/auth/users:
- get:
+ delete:
tags:
- - Auth Admin
- summary: List all auth users (admin)
- description: List auth users in project. Requires platform token.
- operationId: listAuthUsers
+ - Frontends
+ summary: Delete a frontend Candidate
+ description: |
+ Starts deleting the Candidate: its regional runtime, images, edge state and stored source are
+ removed once any running deployment finishes. Asking again for a Candidate that is already being
+ deleted is the same request. The Candidate answers `404` once it is gone.
+
+ A Candidate the frontend serves cannot be deleted: roll back first. A Candidate the frontend only
+ keeps as the runtime a rollback returns to can be deleted, and doing so gives up that rollback;
+ rolling back to the frontend's own runtime stays possible.
+ operationId: deleteFrontendCandidate
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/Page'
- - $ref: '#/components/parameters/Limit'
- - $ref: '#/components/parameters/Cursor'
- - $ref: '#/components/parameters/EndingBefore'
- - $ref: '#/components/parameters/Offset'
- - $ref: '#/components/parameters/Search'
- - name: status
- in: query
- required: false
- description: Filter by effective status. `banned` returns only currently-banned users; an expired temporary ban lists as `active`.
- schema:
- type: string
- enum:
- - active
- - banned
+ - $ref: '#/components/parameters/FrontendId'
+ - $ref: '#/components/parameters/FrontendCandidateId'
responses:
- '200':
- description: Successful response
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/PaginatedAuthUsers'
+ '202':
+ description: Deletion started
'400':
- description: Invalid status or pagination parameters
+ description: Bad request - invalid identifier
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/auth/users/{userId}:
- get:
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - project ownership required
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Frontend or Candidate not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: '`code: candidate_in_use` - the frontend serves this Candidate.'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/frontends/{frontendId}/candidates/{candidateId}/deployments:
+ post:
tags:
- - Auth Admin
- summary: Get specific auth user (admin)
- operationId: getAuthUser
+ - Frontends
+ summary: Deploy a new archive to a frontend Candidate
+ description: |
+ Builds the uploaded archive with the frontend's own variable selection and deploys it to the
+ Candidate. The Candidate keeps serving its previous deployment until this one succeeds, and a
+ failed deployment leaves it on the previous one. A Candidate takes one deployment at a time.
+ While the `frontends.candidates` capability is unavailable, it answers `404` with code
+ `feature_unavailable`.
+ operationId: redeployFrontendCandidate
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - name: userId
- in: path
- required: true
- schema:
- type: string
- format: uuid
+ - $ref: '#/components/parameters/FrontendId'
+ - $ref: '#/components/parameters/FrontendCandidateId'
+ requestBody:
+ required: true
+ content:
+ multipart/form-data:
+ schema:
+ type: object
+ required:
+ - archive
+ properties:
+ archive:
+ type: string
+ format: binary
+ description: ZIP or tar.gz archive of the frontend project, as for creating a frontend.
responses:
- '200':
- description: Auth user details
+ '202':
+ description: The deployment is running
content:
application/json:
schema:
- $ref: '#/components/schemas/AuthUser'
- delete:
+ $ref: '#/components/schemas/FrontendCandidateDeployment'
+ '400':
+ description: Bad request - invalid identifier or archive, a variable the frontend declares has no value, or the resolved variables are too large
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - project ownership required
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Frontend or Candidate not found, or the `frontends.candidates` capability is unavailable (code `feature_unavailable`)
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: 'Conflict. `code: deployment_in_progress` - a deployment is already running; retry once it finishes. `code: candidate_not_deployable` - the Candidate is being deleted or is not ready to deploy to. `code: candidate_in_use` - the frontend serves it or keeps it for a rollback. `code: configuration_changed` - the frontend''s configuration changed during the deploy; retry. `code: frontend_deleting` or `code: project_deleting` - the frontend or project is being deleted.'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '413':
+ description: The request body is larger than the archive limit, SOURCE_ARCHIVE_SIZE_LIMIT_MB
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '429':
+ description: Too many requests - the project's build minutes for the billing cycle are used up
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Service unavailable - frontend deployments are not configured
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/frontends/{frontendId}/serving:
+ get:
tags:
- - Auth Admin
- summary: Delete auth user (admin)
- description: Soft-deletes user and revokes all sessions
- operationId: deleteAuthUser
+ - Frontends
+ summary: Get what a frontend serves
+ description: |
+ Reports whether the frontend serves its own runtime or a promoted Candidate's, and the
+ revision a promotion or rollback must name.
+ operationId: getFrontendServing
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - name: userId
- in: path
- required: true
- schema:
- type: string
- format: uuid
+ - $ref: '#/components/parameters/FrontendId'
responses:
- '204':
- description: User deleted
- /projects/{id}/auth/users/{userId}/sessions:
- get:
+ '200':
+ description: What the frontend serves
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/FrontendServing'
+ '400':
+ description: Bad request - invalid identifier
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - project ownership required
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Frontend not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/frontends/{frontendId}/serving/rollback:
+ post:
tags:
- - Auth Admin
- summary: List user sessions
+ - Frontends
+ summary: Roll a frontend back to the runtime it served before
description: |
- List paginated sessions for a specific auth user.
- Returns session details including device info, IP address, and activity timestamps.
+ Returns the frontend's traffic to the runtime it served before the last activation, or to its
+ own runtime with `to_production`. A rollback is a new activation, so what it leaves becomes the
+ runtime a further rollback returns to, and it can itself be undone. It names the revision the
+ caller read; a competing activation makes it fail with `409`.
- Ordering and pagination match `GET /auth/user/sessions`: the default is
- activity order with `page`/`limit` and the legacy `sessions` body, and
- `sort=created_at` opts into the standard cursor/offset hybrid with the
- shared `data` envelope. Cursor pagination is only available for
- `sort=created_at`, because the activity timestamp changes under paging.
- The `status=expired` filter is offset-only because sessions can expire
- above a cursor anchor during a walk.
- operationId: listUserSessions
+ Rolling back to a Candidate promotes it again and is refused with `409` when promoting it would
+ be. Rolling back to the frontend's own runtime is not.
+ operationId: rollbackFrontendServing
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - name: userId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- - name: page
- in: query
- description: Page number (1-indexed)
- schema:
- type: integer
- minimum: 1
- default: 1
- - name: limit
- in: query
- description: Number of sessions per page (max 100)
- schema:
- type: integer
- minimum: 1
- maximum: 100
- default: 20
- - name: sort
- in: query
- description: |
- Sort key. `last_activity` (default) orders by most recent activity and
- supports offset pagination only. `created_at` orders by session start
- and supports both offset and cursor pagination.
- schema:
- type: string
- enum:
- - last_activity
- - created_at
- default: last_activity
- - name: status
- in: query
- description: |
- Filter by whether the session can still be refreshed. Omit for every
- stored session, including expired ones. `expired` is not supported
- with cursor pagination.
- schema:
- type: string
- enum:
- - active
- - expired
- - name: cursor
- in: query
- description: |
- Opaque keyset cursor from a previous response's `next_cursor`. Requires
- `sort=created_at`; mutually exclusive with `page` and `ending_before`.
- schema:
- type: string
- - name: ending_before
- in: query
- description: |
- Opaque keyset cursor from a previous response's `prev_cursor`, paging
- backward. Requires `sort=created_at`; mutually exclusive with `page`
- and `cursor`.
- schema:
- type: string
- - name: offset
- in: query
- description: |
- Bounded number of rows to skip past the cursor anchor (the hybrid
- jump, maximum 100000). Ignored unless `cursor` or `ending_before` is
- supplied.
- schema:
- type: integer
- minimum: 0
- maximum: 100000
+ - $ref: '#/components/parameters/FrontendId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties: false
+ required:
+ - expected_revision
+ properties:
+ expected_revision:
+ type: integer
+ format: int64
+ minimum: 0
+ to_production:
+ type: boolean
+ default: false
+ description: Return to the frontend's own runtime whatever it served before.
responses:
'200':
- description: Paginated list of user sessions
+ description: The frontend serves the runtime it was rolled back to
content:
application/json:
schema:
- type: object
- properties:
- sessions:
- type: array
- items:
- $ref: '#/components/schemas/AuthSession'
- total:
- type: integer
- description: Total number of sessions
- page:
- type: integer
- description: Current page number
- limit:
- type: integer
- description: Number of sessions per page
- total_pages:
- type: integer
- description: Total number of pages
- data:
- type: array
- description: Sessions for this page (cursor pagination only)
- items:
- $ref: '#/components/schemas/AuthSession'
- has_more:
- type: boolean
- description: Whether a further page exists (cursor pagination only)
- next_cursor:
- type: string
- description: Opaque cursor for the next page (cursor pagination only)
- prev_cursor:
- type: string
- description: Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`.
+ $ref: '#/components/schemas/FrontendServing'
'400':
- description: Invalid or conflicting pagination parameters
+ description: Bad request - invalid identifier or body
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - project ownership required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: User not found
- delete:
- tags:
- - Auth Admin
- summary: Delete all user sessions
- description: |
- Revokes all sessions for a user, forcing them to re-authenticate on all devices.
- Use this to log out a user from everywhere.
- operationId: deleteAllUserSessions
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - name: userId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '204':
- description: All sessions deleted
- '404':
- description: User not found
- /projects/{id}/auth/users/{userId}/sessions/{sessionId}:
- delete:
- tags:
- - Auth Admin
- summary: Delete specific session
- description: |
- Revokes a specific session for a user.
- Use this to log out a user from a single device.
- operationId: deleteUserSession
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - name: userId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- - name: sessionId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '204':
- description: Session deleted
- '404':
- description: Session or user not found
- /projects/{id}/auth/users/{userId}/ban:
+ description: Frontend not found, or `feature_unavailable` when the release gate is off and the rollback would make a candidate serve again
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: 'Conflict. `code: stale_revision` - the revision is stale; read `serving` again. `code: nothing_to_roll_back` - there is no earlier runtime to return to. `code: rollback_unavailable` - the runtime to roll back to is gone. `code: configuration_changed` - the Candidate to roll back to was built with a different configuration. `code: deployment_in_progress` - a deployment of the Candidate or of the frontend itself is still running; retry once it finishes. `code: source_managed_by_git` - the project''s repository is the source of truth; roll back to the frontend''s own runtime.'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '413':
+ description: The request body is larger than 4 KiB
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/frontends/{frontendId}/candidates/{candidateId}/promote:
post:
tags:
- - Auth Admin
- summary: Ban a user
+ - Frontends
+ summary: Promote a frontend Candidate
description: |
- Bans a user temporarily or permanently. Banned users cannot sign in
- and all their active sessions are immediately revoked.
- Omitting banned_until clears any previous expiry. Deleted accounts cannot be banned.
+ Makes the Candidate what the frontend serves. Nothing is rebuilt or copied: the frontend's
+ traffic is routed to the Candidate's runtime, its own custom domains and metering are
+ unchanged, and what it served becomes the runtime a rollback returns to.
- - Omit `banned_until` for a permanent ban
- - Provide `banned_until` ISO timestamp for a temporary ban
- operationId: banAuthUser
+ The Candidate must be ready and serving an active deployment, and that deployment must have
+ been built with the variables the frontend selects now. A Candidate that serves stops expiring and cannot be deleted. While one
+ serves, deploying the frontend itself answers `409`; roll back to the frontend's own runtime
+ first. Promotion names the revision the caller read from `serving`; a competing activation
+ makes it fail with `409`. Once the project's repository is the source of truth, promotion
+ is refused with `409`, as a direct deploy is, and so is rolling back to a Candidate; rolling
+ back to the frontend's own runtime is not. While the `frontends.candidates` capability is
+ unavailable, promotion and rolling back to a Candidate answer `404` with code
+ `feature_unavailable`; rolling back to the frontend's own runtime does not.
+ operationId: promoteFrontendCandidate
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - name: userId
- in: path
- required: true
- schema:
- type: string
- format: uuid
+ - $ref: '#/components/parameters/FrontendId'
+ - $ref: '#/components/parameters/FrontendCandidateId'
requestBody:
+ required: true
content:
application/json:
schema:
type: object
+ additionalProperties: false
+ required:
+ - expected_revision
properties:
- banned_until:
- type: string
- format: date-time
- description: When the ban expires (omit for permanent ban)
- example: '2026-12-31T23:59:59Z'
+ expected_revision:
+ type: integer
+ format: int64
+ minimum: 0
responses:
'200':
- description: User banned successfully
+ description: The frontend serves the Candidate
content:
application/json:
schema:
- $ref: '#/components/schemas/BanUserResponse'
+ $ref: '#/components/schemas/FrontendServing'
+ '400':
+ description: Bad request - invalid identifier or body
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - project ownership required
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'404':
- description: User not found
+ description: Frontend or Candidate not found, or the `frontends.candidates` capability is unavailable (code `feature_unavailable`)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
- description: Deleted accounts cannot be banned or restored
+ description: 'Conflict. `code: stale_revision` - the revision is stale; read `serving` again. `code: candidate_not_ready` - the Candidate is not ready. `code: configuration_changed` - it was built with a different configuration; redeploy it. `code: already_serving` - it already serves. `code: deployment_in_progress` - a deployment of the Candidate or of the frontend itself is still running; retry once it finishes. `code: source_managed_by_git` - the project''s repository is the source of truth. `code: frontend_not_deployed` - the frontend has no deployment of its own to roll back to; deploy it first.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/auth/users/{userId}/unban:
- post:
+ '413':
+ description: The request body is larger than 4 KiB
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/frontends/{frontendId}/usage:
+ get:
tags:
- - Auth Admin
- summary: Unban a user
+ - Frontends
+ summary: Per-day request and error counts for a single frontend
description: |
- Removes a ban from a user, restoring their ability to sign in.
- The user's status is set back to 'active'. Deleted accounts cannot be restored.
- operationId: unbanAuthUser
+ Returns a zero-filled daily series of request counts and 5xx
+ error counts for one frontend, oldest first. Each entry is one
+ UTC day; missing days (no traffic recorded) come back as
+ `requests: 0, errors: 0` so the response always has exactly
+ `days` entries.
+
+ Backs the Monitoring section on the frontend detail page in
+ the Volcano dashboard. `days` defaults to 30 and is capped at 90 to keep
+ the (frontend_id, day) index scan bounded.
+ operationId: getFrontendUsageHistory
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - name: userId
- in: path
- required: true
+ - $ref: '#/components/parameters/FrontendId'
+ - name: days
+ in: query
+ description: Number of trailing days to return (1–90, default 30).
+ required: false
schema:
- type: string
- format: uuid
+ type: integer
+ minimum: 1
+ maximum: 90
+ default: 30
responses:
'200':
- description: User unbanned successfully
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/UnbanUserResponse'
+ $ref: '#/components/schemas/FrontendUsageHistoryResponse'
+ '400':
+ description: Bad request - invalid identifier
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - project ownership required
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'404':
- description: User not found
+ description: Frontend not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: Deleted accounts cannot be banned or restored
+ '500':
+ description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/email-templates:
+ /projects/{id}/frontends/{frontendId}/function-routes:
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/FrontendId'
get:
tags:
- - Auth Configuration
- summary: List email templates
- description: Returns all custom email templates for this project.
- operationId: listEmailTemplates
+ - Frontends
+ summary: List a Frontend's Function routes
+ operationId: listFrontendFunctionRoutes
security:
- UserToken: []
- ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
responses:
'200':
- description: Email templates list
+ description: Function routes ordered from most to least specific
content:
application/json:
schema:
- type: object
- properties:
- data:
- type: array
- items:
- $ref: '#/components/schemas/EmailTemplate'
+ $ref: '#/components/schemas/FrontendFunctionRouteList'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Project not owned by the caller
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Failed to list Function routes
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
post:
tags:
- - Auth Configuration
- summary: Create email template
+ - Frontends
+ summary: Route a Frontend path to an HTTP Function
+ operationId: createFrontendFunctionRoute
description: |
- Creates a custom email template for the project. Custom email templates
- are a SUPERAGENT feature: requests from a HOBBY project owner are
- rejected with 403, and HOBBY projects always send the built-in default
- templates regardless of any previously saved custom rows.
- Every project is created with one template per type, so customizing one
- is usually a PUT; creating a type the project already has returns 409.
- Valid template types: welcome, confirmation, password_reset, password_changed
- operationId: createEmailTemplate
+ The Frontend and Function must belong to this Project. The Function must be a standard
+ Function with `visibility: public` and HTTP invocation mode, because requests through the
+ route carry no credential: Volcano does not check a token sent to a route path or add
+ `__volcano_auth`, so the Function authenticates its callers itself. A Function cannot leave `public`
+ while a route targets it. The route applies to every hostname that resolves to the
+ Frontend, including generated, custom-domain, preview, and local hostnames.
security:
- UserToken: []
- ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/CreateEmailTemplateRequest'
+ $ref: '#/components/schemas/CreateFrontendFunctionRouteRequest'
responses:
'201':
- description: Template created
+ description: Function route created
content:
application/json:
schema:
- $ref: '#/components/schemas/EmailTemplate'
+ $ref: '#/components/schemas/FrontendFunctionRoute'
'400':
- description: Invalid template type
+ description: Invalid path or non-HTTP Function
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Custom email templates require the SUPERAGENT plan
+ description: Project not owned by the caller
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Frontend or Function not found in the Project
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
- description: The project already has a template of this type
+ description: Path is already routed, the Frontend has reached its 64-route limit, or the Function is not public
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/email-templates/{type}:
- get:
- tags:
- - Auth Configuration
- summary: Get email template
- operationId: getEmailTemplate
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - name: type
- in: path
- required: true
- schema:
- type: string
- enum:
- - welcome
- - confirmation
- - password_reset
- - password_changed
- responses:
- '200':
- description: Email template
+ '500':
+ description: Failed to create Function route
content:
application/json:
schema:
- $ref: '#/components/schemas/EmailTemplate'
- '404':
- description: Template not found
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/frontends/{frontendId}/function-routes/{routeId}:
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/FrontendId'
+ - $ref: '#/components/parameters/FrontendFunctionRouteId'
put:
tags:
- - Auth Configuration
- summary: Update email template
- description: |
- Updates a custom email template. Custom email templates are a SUPERAGENT
- feature: requests from a HOBBY project owner are rejected with 403
- (including after a downgrade), so a HOBBY project cannot modify
- templates and always sends the built-in defaults.
- operationId: updateEmailTemplate
+ - Frontends
+ summary: Replace a Frontend Function route
+ description: 'Replaces the route''s target, path, and prefix handling. The new target must meet the same rules as on create, including `visibility: public`.'
+ operationId: updateFrontendFunctionRoute
security:
- UserToken: []
- ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - name: type
- in: path
- required: true
- schema:
- type: string
- enum:
- - welcome
- - confirmation
- - password_reset
- - password_changed
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/UpdateEmailTemplateRequest'
+ $ref: '#/components/schemas/CreateFrontendFunctionRouteRequest'
responses:
'200':
- description: Template updated
+ description: Function route replaced
content:
application/json:
schema:
- $ref: '#/components/schemas/EmailTemplate'
+ $ref: '#/components/schemas/FrontendFunctionRoute'
+ '400':
+ description: Invalid path or non-HTTP Function
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'403':
- description: Custom email templates require the SUPERAGENT plan
+ description: Project not owned by the caller
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Template not found
+ description: Function route, Frontend, or Function not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: Path is already routed, the Frontend has reached its 64-route limit, or the Function is not public
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Failed to replace Function route
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
delete:
tags:
- - Auth Configuration
- summary: Delete email template
- description: |
- Deletes a custom template, reverting to the default. Custom email
- templates are a SUPERAGENT feature: requests from a HOBBY project owner
- are rejected with 403.
- operationId: deleteEmailTemplate
+ - Frontends
+ summary: Delete a Frontend Function route
+ operationId: deleteFrontendFunctionRoute
security:
- UserToken: []
- ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - name: type
- in: path
- required: true
- schema:
- type: string
- enum:
- - welcome
- - confirmation
- - password_reset
- - password_changed
responses:
'204':
- description: Template deleted
+ description: Function route deleted
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'403':
- description: Custom email templates require the SUPERAGENT plan
+ description: Project not owned by the caller
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Template not found
- /email-templates/defaults:
- get:
- tags:
- - Auth Configuration
- summary: Get default email templates
- description: Returns the default email templates used when no custom template is configured.
- operationId: getDefaultEmailTemplates
- responses:
- '200':
- description: Default templates
+ description: Function route not found on the Frontend
content:
application/json:
schema:
- type: object
- properties:
- data:
- type: array
- items:
- $ref: '#/components/schemas/EmailTemplate'
- /email-templates/defaults/{type}:
- get:
- tags:
- - Auth Configuration
- summary: Get default email template by type
- operationId: getDefaultEmailTemplate
- parameters:
- - name: type
- in: path
- required: true
- schema:
- type: string
- enum:
- - welcome
- - confirmation
- - password_reset
- - password_changed
- responses:
- '200':
- description: Default template
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Failed to delete Function route
content:
application/json:
schema:
- $ref: '#/components/schemas/EmailTemplate'
- '404':
- description: Template type not found
- /projects/{id}/auth/config:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/frontends/{frontendId}/frontend-routes:
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/FrontendId'
get:
tags:
- - Auth Configuration
- summary: Get auth configuration
- operationId: getAuthConfig
+ - Frontends
+ summary: List a Frontend's Frontend routes
+ operationId: listFrontendRoutes
security:
- UserToken: []
- ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
responses:
'200':
- description: Auth configuration
+ description: Frontend routes ordered from most to least specific
content:
application/json:
schema:
- $ref: '#/components/schemas/AuthConfig'
- put:
- tags:
- - Auth Configuration
- summary: Update auth configuration
- description: |
- Updates the project's auth configuration. Only the fields present in
- the body are changed.
- operationId: updateAuthConfig
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- requestBody:
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/UpdateAuthConfigRequest'
- responses:
- '200':
- description: Configuration updated
+ $ref: '#/components/schemas/FrontendRouteList'
+ '401':
+ description: Unauthorized
content:
application/json:
schema:
- $ref: '#/components/schemas/AuthConfig'
+ $ref: '#/components/schemas/Error'
'403':
- description: |
- The update would turn on, widen, or otherwise edit the email domain
- allowlist (`allowed_email_domains`, `allowed_email_domains_mode`)
- for a project that is not on the SUPERAGENT plan. A HOBBY project keeps
- whatever allowlist it already has — parked, enforcing nothing until
- it upgrades — and may still remove it, so a downgrade never leaves a
- project locked out of its own signups.
+ description: Project not owned by the caller
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/auth/config/test-email:
- post:
- tags:
- - Auth Configuration
- summary: Send a test email using the project's saved SMTP config
- description: |
- Sends a diagnostic email to `to_email` using the project's
- persisted `auth_config` SMTP credentials. If `html_body` or
- `text_body` is supplied, the override path is taken: those
- values (plus optional `subject`) are rendered through
- html/text templates against the project's `Data` and
- used as the body — used by the template editor's "Send Test"
- affordance to preview an unsaved template. With both bodies
- omitted, a hardcoded diagnostic message is sent and any
- `subject` field is ignored. Sending `subject` alone (no
- bodies) is rejected with 400 to avoid a silently-dropped
- subject or a blank message. Also rejects with 400 if
- `email_enabled=false`, `smtp_host` is empty, or the saved
- `smtp_password` can't be read and must be set again.
- operationId: testEmailConfig
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/TestEmailRequest'
- responses:
- '200':
- description: Test email sent
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/TestEmailResponse'
- '400':
- description: Invalid request or email delivery not configured
- '401':
- description: Unauthorized
- '403':
- description: Forbidden
- '404':
- description: Project not found
- '502':
- description: Template render failure or SMTP delivery failed
- /projects/{id}/auth/hosted-pages/{pageType}:
- get:
- tags:
- - Auth Configuration
- summary: Get hosted auth page
- description: |
- Returns the saved HTML/CSS for the page type, or `page: null` when the
- project has not customized it yet. Always returns `defaults` (the theme
- shell to seed an editor with, which is valid input to the update endpoint)
- and `runtime` (the script the rendered page runs, plus a preview harness).
- operationId: getAuthHostedPage
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - name: pageType
- in: path
- required: true
- schema:
- $ref: '#/components/schemas/HostedAuthPageType'
- responses:
- '200':
- description: Hosted page loaded
+ '500':
+ description: Failed to list Frontend routes
content:
application/json:
schema:
- $ref: '#/components/schemas/AuthHostedPageResponse'
- put:
+ $ref: '#/components/schemas/Error'
+ post:
tags:
- - Auth Configuration
- summary: Update hosted auth page
- description: |
- Saves the current HTML/CSS for this page type.
- Security validation rejects script tags, javascript: URLs, inline event handlers, iframe/object/embed/meta/link tags in HTML,
- and closing style/head tags in CSS.
- operationId: updateAuthHostedPage
+ - Frontends
+ summary: Mount another Frontend at a path
+ operationId: createFrontendRoute
+ description: |
+ Serves `path_prefix` and everything under it on this Frontend's hostnames from another
+ Frontend in the same Project. The path is forwarded unchanged, so the mounted Frontend must
+ serve its pages under the prefix (page directories or a matching `basePath`). Its root
+ `/_next/static` files and `/_next/image` requests are sent to it too. A Frontend may be
+ mounted at several prefixes. Function and Frontend routes share one path namespace and the
+ 64-route limit; the most specific prefix wins. A mounted Frontend's own routes do not apply
+ to requests it receives through a route. The route applies to every hostname that resolves
+ to this Frontend, including generated, custom-domain, and local hostnames. While the mounted
+ Frontend has no active deployment, its paths answer 502, as its own hostname does.
security:
- UserToken: []
- ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - name: pageType
- in: path
- required: true
- schema:
- $ref: '#/components/schemas/HostedAuthPageType'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/UpdateAuthHostedPageRequest'
+ $ref: '#/components/schemas/CreateFrontendRouteRequest'
responses:
- '200':
- description: Hosted page updated
+ '201':
+ description: Frontend route created
content:
application/json:
schema:
- $ref: '#/components/schemas/AuthHostedPageResponse'
+ $ref: '#/components/schemas/FrontendRoute'
'400':
- description: Invalid input or unsafe markup
- '401':
- description: Unauthorized
- '403':
- description: Forbidden
- '404':
- description: Project not found
- /projects/{id}/auth/pages/appearance:
- get:
- tags:
- - Auth Configuration
- summary: Get managed auth page appearance
- operationId: getAuthPageAppearance
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- responses:
- '200':
- description: Saved appearance and effective plan state
+ description: Invalid path, or the Frontend would mount itself
content:
application/json:
schema:
- $ref: '#/components/schemas/AuthPageAppearanceResponse'
+ $ref: '#/components/schemas/Error'
'401':
description: Unauthorized
content:
@@ -12925,49 +13269,58 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Access denied
+ description: Project not owned by the caller
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Project not found
+ description: Frontend or mounted Frontend not found in the Project, or, with code `feature_unavailable`, Frontend routes are not available in this environment (see `GET /capabilities`)
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: Path is already routed, the Frontend has reached its 64-route limit, or this Frontend or the mounted Frontend is being deleted
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
- description: Appearance could not be read
+ description: Failed to create Frontend route
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/auth/pages/theme:
+ /projects/{id}/frontends/{frontendId}/frontend-routes/{routeId}:
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/FrontendId'
+ - $ref: '#/components/parameters/FrontendRouteId'
put:
tags:
- - Auth Configuration
- summary: Save the managed auth page theme
- operationId: updateAuthPageTheme
+ - Frontends
+ summary: Replace a Frontend route
+ description: Replaces the route's mounted Frontend and path. The new values must meet the same rules as on create.
+ operationId: updateFrontendRoute
security:
- UserToken: []
- ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/UpdateAuthPageThemeRequest'
+ $ref: '#/components/schemas/CreateFrontendRouteRequest'
responses:
'200':
- description: Theme saved
+ description: Frontend route replaced
content:
application/json:
schema:
- $ref: '#/components/schemas/UpdateAuthPageThemeRequest'
+ $ref: '#/components/schemas/FrontendRoute'
'400':
- description: Invalid or unreadable theme
+ description: Invalid path, or the Frontend would mount itself
content:
application/json:
schema:
@@ -12979,36 +13332,40 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Plan does not permit customisation
+ description: Project not owned by the caller
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Project not found
+ description: Frontend route, Frontend, or mounted Frontend not found, or, with code `feature_unavailable`, Frontend routes are not available in this environment (see `GET /capabilities`)
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: Path is already routed, or this Frontend or the mounted Frontend is being deleted
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
- description: Theme could not be saved
+ description: Failed to replace Frontend route
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
tags:
- - Auth Configuration
- summary: Clear the managed auth page theme
- operationId: deleteAuthPageTheme
+ - Frontends
+ summary: Delete a Frontend route
+ operationId: deleteFrontendRoute
security:
- UserToken: []
- ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
responses:
'204':
- description: Theme cleared
+ description: Frontend route deleted
'401':
description: Unauthorized
content:
@@ -13016,58 +13373,41 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Plan does not permit customisation
+ description: Project not owned by the caller
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Project not found
+ description: Frontend route not found on the Frontend
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
- description: Theme could not be cleared
+ description: Failed to delete Frontend route
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/auth/pages/{pageType}/layout:
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - name: pageType
- in: path
- required: true
- schema:
- $ref: '#/components/schemas/HostedAuthPageType'
- put:
+ /projects/{id}/variable-environments:
+ get:
tags:
- - Auth Configuration
- summary: Save one managed auth page layout
- operationId: updateAuthPageLayout
+ - Variable Environments
+ summary: List variable Environments
+ operationId: listVariableEnvironments
security:
- UserToken: []
- ProjectAccessToken: []
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/UpdateAuthPageLayoutRequest'
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
responses:
'200':
- description: Layout saved
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/UpdateAuthPageLayoutRequest'
- '400':
- description: Invalid page type or layout
+ description: Variable Environments, with Global first and custom Environments ordered by name
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
+ $ref: '#/components/schemas/VariableEnvironmentList'
'401':
description: Unauthorized
content:
@@ -13075,38 +13415,48 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Plan does not permit customisation
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '404':
- description: Project not found
+ description: Project not owned by the caller
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
- description: Layout could not be saved
+ description: Failed to list variable Environments
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- delete:
+ post:
tags:
- - Auth Configuration
- summary: Clear one managed auth page layout
- operationId: deleteAuthPageLayout
+ - Variable Environments
+ summary: Create a variable Environment
+ operationId: createVariableEnvironment
+ description: Creates a custom variable Environment. Global is reserved and already exists. A Project may have at most 100 custom Environments.
security:
- UserToken: []
- ProjectAccessToken: []
- responses:
- '204':
- description: Layout cleared
- '400':
- description: Invalid page type
- content:
- application/json:
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateVariableEnvironmentRequest'
+ responses:
+ '201':
+ description: Variable Environment created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/VariableEnvironment'
+ '400':
+ description: |
+ Invalid name, or the reserved Global name. Schema-invalid names
+ return the generic invalid-request error; a reserved name returns
+ `invalid_variable_environment`.
+ content:
+ application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
@@ -13116,98 +13466,103 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Plan does not permit customisation
+ description: Project not owned by the caller
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Project not found
+ description: Project no longer exists
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: |
+ A case-insensitive name conflict or the 100-custom-Environment
+ limit has been reached, or the Project is being deleted. Tell them
+ apart with `code`, which is `variable_environment_conflict`,
+ `variable_environment_limit_reached`, or `project_deleting`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
- description: Layout could not be cleared
+ description: Failed to create the variable Environment
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/auth/pages/{pageType}/preview:
+ /projects/{id}/variable-environments/{environmentId}:
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/VariableEnvironmentId'
get:
tags:
- - Auth Configuration
- summary: Render a short-lived managed auth page preview
- description: |
- Public HTML endpoint for a preview URL returned by the POST operation.
- The signed ticket contains the unsaved appearance, expires shortly, and
- runs the production page runtime against mocked authentication responses.
- operationId: renderAuthPagePreview
- security: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - name: pageType
- in: path
- required: true
- schema:
- $ref: '#/components/schemas/HostedAuthPageType'
- - name: ticket
- in: query
- required: true
- schema:
- type: string
- minLength: 1
- maxLength: 4096
- description: Short-lived signed preview ticket returned by the POST operation.
+ - Variable Environments
+ summary: Get a variable Environment
+ operationId: getVariableEnvironment
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
responses:
'200':
- description: Rendered preview document
+ description: Variable Environment details
content:
- text/html:
+ application/json:
schema:
- type: string
+ $ref: '#/components/schemas/VariableEnvironment'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Project not owned by the caller
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'404':
- description: Ticket is invalid or expired, its path does not match, or managed authentication is disabled
+ description: Variable Environment not found in this Project
content:
- text/plain:
+ application/json:
schema:
- type: string
+ $ref: '#/components/schemas/Error'
'500':
- description: Preview could not be rendered
+ description: Failed to get the variable Environment
content:
- text/plain:
+ application/json:
schema:
- type: string
- post:
+ $ref: '#/components/schemas/Error'
+ patch:
tags:
- - Auth Configuration
- summary: Preview an unsaved managed auth page appearance
- operationId: previewAuthPage
+ - Variable Environments
+ summary: Rename a variable Environment
+ operationId: renameVariableEnvironment
+ description: Renames a custom Environment without changing its stable ID. Global cannot be renamed.
security:
- UserToken: []
- ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - name: pageType
- in: path
- required: true
- schema:
- $ref: '#/components/schemas/HostedAuthPageType'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/PreviewAuthPageRequest'
+ $ref: '#/components/schemas/RenameVariableEnvironmentRequest'
responses:
'200':
- description: Short-lived URL for the rendered preview document
+ description: Variable Environment renamed
content:
application/json:
schema:
- $ref: '#/components/schemas/PreviewAuthPageResponse'
+ $ref: '#/components/schemas/VariableEnvironment'
'400':
- description: Invalid page type or draft
+ description: |
+ Invalid name, or the reserved Global name. Schema-invalid names
+ return the generic invalid-request error; a reserved name returns
+ `invalid_variable_environment`.
content:
application/json:
schema:
@@ -13219,3394 +13574,3243 @@ paths:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Access denied
+ description: Project not owned by the caller
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Project not found or managed authentication is disabled
+ description: Variable Environment not found in this Project
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: |
+ A case-insensitive name conflict, an attempt to rename Global, or
+ a Project being deleted. Tell them apart with `code`, which is
+ `variable_environment_conflict`,
+ `variable_environment_immutable`, or `project_deleting`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
- description: Preview could not be rendered
+ description: Failed to rename the variable Environment
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/auth/hosted/{pageType}:
+ delete:
+ tags:
+ - Variable Environments
+ summary: Delete a variable Environment
+ operationId: deleteVariableEnvironment
+ description: Deletes a custom Environment. Global cannot be deleted.
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ responses:
+ '204':
+ description: Variable Environment deleted
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Project not owned by the caller
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Variable Environment not found in this Project
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: |
+ Global is protected, or the Project is being deleted. Tell them
+ apart with `code`, which is `variable_environment_immutable` or
+ `project_deleting`.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Failed to delete the variable Environment
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/variables:
get:
tags:
- - Auth Configuration
- summary: Render a managed auth page
+ - Variables
+ summary: List all variables for a project
description: |
- Public HTML endpoint for signup, forgot-password, device approval,
- verify-email, and reset-password pages. Login uses the path without a
- page type.
- Requires `Accept: text/html`.
- Returns 404 when managed hosted pages are disabled for the project.
- security: []
- operationId: renderManagedAuthPage
+ Returns project-level environment variables used by deployed functions and frontends.
+ operationId: listVariables
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - name: pageType
- in: path
- required: true
- schema:
- $ref: '#/components/schemas/HostedRenderablePageType'
+ - $ref: '#/components/parameters/Page'
+ - $ref: '#/components/parameters/Limit'
+ - $ref: '#/components/parameters/Cursor'
+ - $ref: '#/components/parameters/EndingBefore'
+ - $ref: '#/components/parameters/Offset'
+ - $ref: '#/components/parameters/Search'
responses:
'200':
- description: Hosted auth page HTML
+ description: Successful response
content:
- text/html:
+ application/json:
schema:
- type: string
- '400':
- description: Invalid project id or unsupported Accept header
+ $ref: '#/components/schemas/PaginatedVariables'
'404':
- description: Managed pages disabled or page type not found
- /projects/{id}/auth/hosted:
- get:
+ description: Project not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ post:
tags:
- - Auth Configuration
- summary: Render default managed auth page
+ - Variables
+ summary: Create or update a variable
description: |
- Public HTML endpoint for the managed login page.
- Requires `Accept: text/html`.
- security: []
- operationId: renderDefaultManagedAuthPage
+ Creates a project-level environment variable and triggers asynchronous propagation
+ to deployed functions and frontends in the project's configured regions.
+ operationId: createVariable
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - name: action
- in: query
- required: false
- schema:
- type: string
- enum:
- - login
- - signup
- - forgot-password
- - device
- description: |
- Optional deep-link action for the unified hosted page. Ignored when a
- custom login page is configured. `action=device` renders the device
- authorization approval UI inline (no redirect to any external app);
- it signs the user in and calls `POST /auth/device/verify`.
- - name: user_code
- in: query
- required: false
- schema:
- type: string
- description: Device user code (from `POST /auth/device/authorize`) used with `action=device`.
- - name: anon_key
- in: query
- required: false
- schema:
- type: string
- description: Project anon key used by built-in managed auth flows (required for login/signup/device actions).
- - name: state
- in: query
- required: false
- schema:
- type: string
- description: |
- Opaque one-time nonce generated by the client SDK before redirecting
- here. On successful login/signup it is echoed back in the post-auth
- redirect fragment as `state`, so the SDK can bind the returned session
- to the flow it initiated (login-CSRF / session-fixation defense). The
- SDK rejects a returned session whose `state` does not match.
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateVariableRequest'
responses:
- '200':
- description: Hosted auth page HTML
+ '201':
+ description: Variable created
content:
- text/html:
+ application/json:
schema:
- type: string
+ $ref: '#/components/schemas/Variable'
'400':
- description: Invalid project id or unsupported Accept header
- '404':
- description: Managed pages disabled
- /projects/{id}/auth/hosted/login/options:
+ description: Bad request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Private variable membership writes are disabled during rollout
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/databases:
get:
tags:
- - Auth Configuration
- summary: Get hosted login runtime options
+ - Databases
+ summary: List all databases for a project
description: |
- Returns runtime options for the built-in managed login flow.
- Requires `anon_key` query parameter.
- Rate limited per project and client IP. Excess requests return `429` and `Retry-After`.
- security: []
- operationId: getHostedLoginOptions
+ Supports two mutually exclusive pagination modes. Offset mode uses `page`
+ and `limit`. Cursor mode uses `cursor` and `limit`, supports `search`
+ (case-insensitive name match), and returns `next_cursor`/`prev_cursor`.
+ The optional `status` filter applies in both modes and is bound to the
+ cursor. Sending both `page` and `cursor` (or `page` and `search`) returns 400.
+ operationId: listDatabases
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - name: anon_key
+ - $ref: '#/components/parameters/Page'
+ - $ref: '#/components/parameters/Limit'
+ - $ref: '#/components/parameters/Cursor'
+ - $ref: '#/components/parameters/EndingBefore'
+ - $ref: '#/components/parameters/Offset'
+ - $ref: '#/components/parameters/Search'
+ - name: status
in: query
- required: true
+ required: false
schema:
type: string
+ enum:
+ - provisioning
+ - active
+ - restoring
+ - failed
+ - deleting
+ description: Return only the databases in this status.
responses:
'200':
- description: Hosted login options returned
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/HostedLoginOptionsResponse'
- '401':
- description: Invalid or missing anon key
- '404':
- description: Managed pages disabled
- '429':
- description: Rate limit exceeded
- /projects/{id}/auth/hosted/login/check-email:
+ $ref: '#/components/schemas/PaginatedDatabases'
post:
tags:
- - Auth Configuration
- summary: Check whether email exists for hosted login flow
+ - Databases
+ summary: Create a new PostgreSQL database
description: |
- Used by the built-in managed login page to branch UI between signin and signup.
- Requires anon key in Authorization header.
- Rate limited per project and client IP. Excess requests return `429` and `Retry-After`.
- security: []
- operationId: hostedLoginCheckEmail
+ Creates a PostgreSQL database in the project.
+ Each project can hold 1 database on HOBBY and up to 10,000 on SUPERAGENT.
+ Requests over the plan's cap return 403.
+ operationId: createDatabase
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - name: Authorization
- in: header
- required: true
- schema:
- type: string
- description: Bearer anon key (`Bearer `)
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/HostedLoginEmailCheckRequest'
+ $ref: '#/components/schemas/CreateDatabaseRequest'
responses:
- '200':
- description: Email existence evaluated
+ '201':
+ description: Database created (provisioning)
content:
application/json:
schema:
- $ref: '#/components/schemas/HostedLoginEmailCheckResponse'
- '401':
- description: Invalid or missing anon key
- '429':
- description: Rate limit exceeded
- /projects/{id}/auth/methods:
+ $ref: '#/components/schemas/Database'
+ '403':
+ description: Database limit exceeded for the project
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/databases/{databaseName}:
get:
tags:
- - Auth Configuration
- summary: Get all authentication methods
- description: |
- Returns all configured authentication methods for this project,
- including email/password, anonymous, device authorization, and OAuth providers.
- operationId: getAuthMethods
+ - Databases
+ summary: Get database details
+ operationId: getDatabase
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DatabaseName'
responses:
'200':
- description: Authentication methods configuration
+ description: Successful response
content:
application/json:
schema:
- type: object
- properties:
- email_password:
- type: object
- properties:
- enabled:
- type: boolean
- method:
- type: string
- name:
- type: string
- anonymous:
- type: object
- properties:
- enabled:
- type: boolean
- method:
- type: string
- name:
- type: string
- oauth_providers:
- type: array
- items:
- type: object
- properties:
- enabled:
- type: boolean
- method:
- type: string
- provider:
- type: string
- name:
- type: string
- redirect_url:
- type: string
- scopes:
- type: array
- items:
- type: string
- available_methods:
- type: array
- items:
- type: string
- example:
- - email_password
- - oauth_google
- - oauth_github
- put:
+ $ref: '#/components/schemas/Database'
+ delete:
tags:
- - Auth Configuration
- summary: Configure authentication methods (unified)
+ - Databases
+ summary: Delete a database
description: |
- Configure all authentication methods in a single request.
- At least one method must remain enabled.
- operationId: configureAuthMethods
+ Deletes a database and the instance backing it. When the instance is
+ removed synchronously the database row is deleted and the response is
+ `204`. If the instance cannot be deleted right away, the database row
+ is retained (status `deleting`) and its teardown is handed to the
+ background reconciler, which retries the deletion and removes the row
+ once the instance is gone; in that case the response is `202`. The database row is
+ never dropped while its instance still exists, so an instance is
+ never orphaned without a record to retry from.
+ operationId: deleteDatabase
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- requestBody:
- content:
- application/json:
- schema:
- type: object
- properties:
- enable_email_password:
- type: boolean
- enable_anonymous:
- type: boolean
- oauth_providers:
- type: array
- items:
- type: object
- properties:
- provider:
- type: string
- enabled:
- type: boolean
+ - $ref: '#/components/parameters/DatabaseName'
responses:
- '200':
- description: Methods configured
- '400':
- description: At least one method must be enabled
- /projects/{id}/oauth/configs:
- get:
- tags:
- - OAuth Configuration
- summary: List OAuth configurations
- description: List all OAuth provider configurations for this project
- operationId: listOAuthConfigs
+ '202':
+ description: |
+ Deletion accepted and in progress. The backing instance could not be
+ removed synchronously, so the database is marked `deleting` and torn
+ down asynchronously by the reconciler.
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ example: deleting
+ message:
+ type: string
+ example: database deletion in progress
+ '204':
+ description: Database deleted (backing instance removed synchronously)
+ '404':
+ description: Project or database not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: |
+ A restore is running on the database. Deleting it while a worker is
+ replacing its data would race that worker, so wait for the restore
+ to finish.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: |
+ Volcano could not check whether a restore is running, and will not
+ delete a database that might be mid-restore. Retry.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/databases/{databaseName}/branches:
+ get:
+ tags:
+ - Database Branches
+ summary: List a database's branches
+ description: |
+ Returns every branch of the database, including those still provisioning
+ and those that failed, since each still holds a name.
+
+ Connection strings are omitted. Fetch a single branch to get its
+ connection string.
+ operationId: listDatabaseBranches
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DatabaseName'
responses:
'200':
- description: List of OAuth configurations
+ description: Successful response
content:
application/json:
schema:
- type: object
- properties:
- configs:
- type: array
- items:
- $ref: '#/components/schemas/OAuthConfig'
+ $ref: '#/components/schemas/DatabaseBranchList'
+ '404':
+ description: Project or database not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Branching is temporarily unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
post:
tags:
- - OAuth Configuration
- summary: Create OAuth configuration
- description: Configure OAuth provider (Google, GitHub, Microsoft, Apple, Device)
- operationId: createOAuthConfig
+ - Database Branches
+ summary: Create a branch of a database
+ description: |
+ Forks the database into a new branch. The branch starts as an exact copy
+ of the parent's data and diverges from there.
+
+ Provisioning is asynchronous: the response is `202` with the branch in
+ `provisioning` and no connection string. Poll the branch until it reports
+ `active`, at which point it carries its own connection string.
+
+ Retrying a create with a name that already exists returns `409` rather
+ than a second branch, so a retried request cannot silently consume two
+ slots of the branch allowance.
+ operationId: createDatabaseBranch
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DatabaseName'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/CreateOAuthConfigRequest'
+ $ref: '#/components/schemas/CreateDatabaseBranchRequest'
responses:
- '201':
- description: OAuth config created
+ '202':
+ description: Branch accepted and provisioning
content:
application/json:
schema:
- $ref: '#/components/schemas/OAuthConfig'
+ $ref: '#/components/schemas/DatabaseBranch'
+ '400':
+ description: Invalid branch name or lifetime
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: |
+ The database has reached its branch allowance, or the owner's plan
+ does not include branching.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Project or database not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'409':
- description: Provider already configured
- /projects/{id}/oauth/configs/{provider}:
+ description: |
+ A branch of that name already exists on this database, or the
+ database cannot be branched right now because it is still
+ provisioning, being restored, failed, or being deleted.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Branching is temporarily unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/databases/{databaseName}/branches/{branchName}:
get:
tags:
- - OAuth Configuration
- summary: Get OAuth configuration
- operationId: getOAuthConfig
+ - Database Branches
+ summary: Get a branch
+ description: |
+ Returns the branch, including its connection string once it is `active`.
+ Poll this after creating a branch to learn when it is connectable.
+ operationId: getDatabaseBranch
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - name: provider
- in: path
- required: true
- schema:
- type: string
- enum:
- - google
- - github
- - microsoft
- - apple
- - device
- - name: client_id
- in: query
- required: false
- schema:
- type: string
- description: Required when `provider=device` to select a specific device client.
+ - $ref: '#/components/parameters/DatabaseName'
+ - $ref: '#/components/parameters/BranchName'
responses:
'200':
- description: OAuth configuration
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/OAuthConfig'
- put:
+ $ref: '#/components/schemas/DatabaseBranch'
+ '404':
+ description: Project, database, or branch not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Branching is temporarily unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ patch:
tags:
- - OAuth Configuration
- summary: Update OAuth configuration
- operationId: updateOAuthConfig
+ - Database Branches
+ summary: Extend a branch's lifetime
+ description: |
+ Replaces the branch's lifetime and restarts the countdown from now, so a
+ branch you are still working on is not swept mid-session. The new
+ duration is remembered, so a later reset re-arms the same lifetime.
+ operationId: updateDatabaseBranch
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - name: provider
- in: path
- required: true
- schema:
- type: string
- enum:
- - google
- - github
- - microsoft
- - apple
- - device
- - name: client_id
- in: query
- required: false
- schema:
- type: string
- description: Required when `provider=device` to select a specific device client.
+ - $ref: '#/components/parameters/DatabaseName'
+ - $ref: '#/components/parameters/BranchName'
requestBody:
+ required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/UpdateOAuthConfigRequest'
+ $ref: '#/components/schemas/UpdateDatabaseBranchRequest'
responses:
'200':
- description: OAuth config updated
+ description: Lifetime updated
content:
application/json:
schema:
- $ref: '#/components/schemas/OAuthConfig'
+ $ref: '#/components/schemas/DatabaseBranch'
+ '400':
+ description: Requested lifetime is outside the allowed range
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Project, database, or branch not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: The branch is being deleted
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Branching is temporarily unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
delete:
tags:
- - OAuth Configuration
- summary: Delete OAuth configuration
- operationId: deleteOAuthConfig
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - name: provider
- in: path
- required: true
- schema:
- type: string
- enum:
- - google
- - github
- - microsoft
- - apple
- - device
- - name: client_id
- in: query
- required: false
- schema:
- type: string
- description: Required when `provider=device` to select a specific device client.
- responses:
- '204':
- description: OAuth config deleted
- /projects/{id}/oauth/providers:
- get:
- tags:
- - OAuth Configuration
- summary: List available OAuth providers
- description: Get list of supported OAuth providers and their default scopes
- operationId: listAvailableOAuthProviders
+ - Database Branches
+ summary: Delete a branch
+ description: |
+ Marks the branch for teardown and returns immediately. The branch stops
+ accepting connections at once; its fork and its row are removed by a
+ background job, so a provider outage cannot leave the call hanging or the
+ branch half-deleted.
+
+ Deleting a branch that is still provisioning is allowed and stops the
+ build, and repeating the call while teardown is in progress is accepted
+ again. Once the branch is gone the call returns `404`.
+ operationId: deleteDatabaseBranch
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DatabaseName'
+ - $ref: '#/components/parameters/BranchName'
responses:
- '200':
- description: Available providers
+ '202':
+ description: Deletion accepted and in progress
content:
application/json:
schema:
type: object
properties:
- providers:
- type: array
- items:
- type: object
- properties:
- id:
- type: string
- name:
- type: string
- default_scopes:
- type: array
- items:
- type: string
- /auth/oauth/{provider}/authorize:
- get:
- tags:
- - OAuth Authentication
- summary: Start OAuth authorization
- description: |
- Redirects user to OAuth provider for authorization.
- Handles CSRF protection with state parameter.
- Project is identified via the anon_key query parameter.
- operationId: authOAuthAuthorize
- parameters:
- - name: provider
- in: path
- required: true
- schema:
- type: string
- enum:
- - google
- - github
- - microsoft
- - apple
- - name: anon_key
- in: query
- required: true
- schema:
- type: string
- description: Project anon key (required - identifies the project)
- - name: redirect_url
- in: query
- schema:
- type: string
- description: |
- URL to redirect to after the OAuth flow (optional). Must exactly
- match an entry in the project's `allowed_redirect_urls`, including
- its query string, or be the project's own managed hosted-auth page
- URL.
- - name: client_state
- in: query
- schema:
- type: string
- maxLength: 255
- description: |
- Optional application nonce. It is stored with the server-generated
- provider state and echoed to redirect_url as `state`.
- - name: response_mode
- in: query
- schema:
- type: string
- enum:
- - code
- description: |
- Set to `code` to receive a short-lived authorization code at
- redirect_url, then use POST /auth/oauth/exchange to obtain the
- session. `redirect_url` is required in this mode. When omitted, the
- established session-fragment response is retained for compatibility
- with existing clients.
- responses:
- '307':
- description: Redirect to OAuth provider
- '400':
- description: |
- OAuth provider is disabled for this project, or `redirect_url` is
- not registered in `allowed_redirect_urls`
+ status:
+ type: string
+ example: deleting
+ message:
+ type: string
+ example: branch deletion in progress
+ required:
+ - status
+ - message
'404':
- description: OAuth provider not configured
- /auth/oauth/{provider}/callback:
- get:
- tags:
- - OAuth Authentication
- summary: OAuth callback handler
- description: |
- Handles OAuth provider callback with authorization code.
- Exchanges code for tokens and creates/signs in user.
- operationId: authOAuthCallback
- parameters:
- - name: provider
- in: path
- required: true
- schema:
- type: string
- enum:
- - google
- - github
- - microsoft
- - apple
- - name: code
- in: query
- required: true
- schema:
- type: string
- - name: state
- in: query
- required: true
- schema:
- type: string
- - name: error
- in: query
- schema:
- type: string
- responses:
- '200':
- description: Existing user signed in (when redirect_url was omitted)
+ description: Project, database, or branch not found
content:
application/json:
schema:
- $ref: '#/components/schemas/AuthTokenResponse'
- '201':
- description: New user created and signed in (when redirect_url was omitted)
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Branching is temporarily unavailable
content:
application/json:
schema:
- $ref: '#/components/schemas/AuthTokenResponse'
- '303':
- description: |
- Redirect to the exact registered redirect_url. Flows that requested
- response_mode=code receive a short-lived, single-use `code` and
- optional application `state`; compatibility flows receive the
- established session fragment.
- '400':
- description: |
- Missing/invalid code or state, the state parameter expired, or the
- flow's stored redirect_url is no longer registered in
- allowed_redirect_urls (re-checked at callback time)
- '403':
- description: |
- The provider's email domain is not in `allowed_email_domains`. Creating
- an account is refused under `signup` and `signup_and_signin`; signing in
- an already-linked account is refused under `signup_and_signin`.
- '409':
- description: Email already exists (requires linking)
- /auth/oauth/exchange:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/databases/{databaseName}/branches/{branchName}/reset:
post:
tags:
- - OAuth Authentication
- summary: Exchange OAuth authorization code
+ - Database Branches
+ summary: Reset a branch to its parent's current state
description: |
- Atomically consumes a short-lived callback code and returns the user's
- session. The request must use the same project anon key and exact
- redirect_url that initiated the flow.
- operationId: authOAuthExchange
+ Discards everything written on the branch and re-forks it from the
+ parent as it is now.
+
+ Returns immediately with the branch in `provisioning`. The rewind runs in
+ the background; poll the branch until it reports `active` before
+ connecting again.
+
+ The branch keeps its name and its connection string, so anything holding
+ that string keeps working once it is active again, and its lifetime is
+ re-armed to the duration it was created with. The branch does not serve
+ connections for the duration of the reset.
+ operationId: resetDatabaseBranch
security:
- - AnonKey: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/AuthProxyAuthorization'
- - $ref: '#/components/parameters/AuthProxyClientIP'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- type: object
- required:
- - code
- - redirect_url
- properties:
- code:
- type: string
- redirect_url:
- type: string
- format: uri
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DatabaseName'
+ - $ref: '#/components/parameters/BranchName'
responses:
- '200':
- description: Authorization code consumed and session created
+ '202':
+ description: Branch reset accepted; the branch is provisioning
content:
application/json:
schema:
- $ref: '#/components/schemas/AuthTokenResponse'
- '400':
- description: Invalid, expired, consumed, or redirect-mismatched code
- '401':
- description: Missing or invalid project anon key; or invalid auth proxy metadata
- '403':
+ $ref: '#/components/schemas/DatabaseBranch'
+ '404':
+ description: Project, database, or branch not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
description: |
- Email confirmation is now required, or the account's email domain is not
- in `allowed_email_domains` while `allowed_email_domains_mode` is
- `signup_and_signin`. Both are re-checked here because the code outlives
- the callback that issued it.
- '429':
- description: Too many exchange attempts from this client
- /auth/device/authorize:
- post:
- tags:
- - OAuth Authentication
- summary: Start RFC8628 device authorization
- description: |
- Starts OAuth 2.0 Device Authorization Grant (RFC 8628).
- Returns `device_code` for the CLI and `user_code` for browser verification.
-
- By default the returned `verification_uri` / `verification_uri_complete`
- point at the project's managed device-approval page served by this API
- (`/projects/{projectId}/auth/hosted?action=device&user_code=...&anon_key=...`),
- which requires managed auth enabled and a default anon key for the
- project.
-
- Projects can override this by setting `device_verification_url` on the
- auth config (`PATCH /auth/config`). When set, that URL is returned as-is
- with the `user_code` appended (no `action=device` hint and no embedded
- anon key — the page brings its own), so a CLI's `login` command surfaces
- the project's own RFC 8628 approval page. With a custom URL, device login
- does **not** require managed auth to be enabled; the custom page's origin
- must be in the project's auth CORS allowlist to call
- `POST /auth/device/verify`. Either way the verification page must
- authenticate the end user and call `POST /auth/device/verify` with the
- `user_code`. See the device-auth guide for both approaches.
- operationId: authDeviceAuthorize
- requestBody:
- required: true
- content:
- application/json:
- schema:
- type: object
- required:
- - client_id
- properties:
- client_id:
- type: string
- description: Enabled `device` OAuth client ID for the target project
- responses:
- '200':
- description: Device authorization started
+ The branch is not active, a reset is already in progress, the parent
+ database is being restored, or the parent was restored within the
+ last 24 hours — a reset re-forks from the parent, and the provider
+ holds a child's reset shut for that long afterwards.
content:
application/json:
schema:
- $ref: '#/components/schemas/DeviceAuthorizationResponse'
- '400':
- description: Invalid request or unauthorized client
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Branching is temporarily unavailable
content:
application/json:
schema:
- $ref: '#/components/schemas/OAuthErrorResponse'
- /auth/device/token:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/databases/{databaseName}/branches/{branchName}/reset-password:
post:
tags:
- - OAuth Authentication
- summary: Poll device token endpoint
+ - Database Branches
+ summary: Rotate a branch's password
description: |
- RFC8628 token polling endpoint.
- Returns OAuth errors such as `authorization_pending`, `slow_down`, `access_denied`, and `expired_token`.
- operationId: authDeviceToken
- requestBody:
- required: true
- content:
- application/json:
- schema:
- type: object
- required:
- - grant_type
- - device_code
- - client_id
- properties:
- grant_type:
- type: string
- enum:
- - urn:ietf:params:oauth:grant-type:device_code
- device_code:
- type: string
- client_id:
- type: string
+ Issues a new password for the branch and invalidates the previous
+ connection string. Existing connections are not interrupted; new ones
+ must use the returned string. Proxies pick the rotation up within a few
+ seconds, so the previous password can still open new connections until
+ then.
+
+ The parent database's credentials are untouched.
+ operationId: resetDatabaseBranchPassword
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DatabaseName'
+ - $ref: '#/components/parameters/BranchName'
responses:
'200':
- description: Device flow completed, auth-user session minted
+ description: Password rotated
content:
application/json:
schema:
- $ref: '#/components/schemas/AuthTokenResponse'
- '400':
- description: Polling state/error response
+ $ref: '#/components/schemas/DatabaseBranch'
+ '404':
+ description: Project, database, or branch not found
content:
application/json:
schema:
- $ref: '#/components/schemas/OAuthErrorResponse'
- '403':
- description: |
- `access_denied` - the approving account's email domain is not in
- `allowed_email_domains` while `allowed_email_domains_mode` is
- `signup_and_signin`. Re-checked here because approval and redemption
- are separate requests.
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: The branch is not active
content:
application/json:
schema:
- $ref: '#/components/schemas/OAuthErrorResponse'
- /auth/device/verify:
- post:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Branching is temporarily unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/databases/{databaseName}/backups:
+ get:
tags:
- - OAuth Authentication
- summary: Approve or deny a device code
+ - Database Backups
+ summary: List a database's backups
description: |
- Browser-side endpoint for authenticated auth-users to approve (`approve`) or deny (`deny`) a `user_code`.
+ Returns every backup of the database, newest first, together with the
+ window a point-in-time restore may target.
- Called by the verification page after the end user signs in. The grant is
- scoped to the project the auth-user token belongs to: approving a
- `user_code` issued for a different project returns `403`. This endpoint
- does not require managed auth to be enabled, so a custom verification page
- (hosted anywhere) can drive approval — it just needs an authenticated
- project auth-user access token and, for cross-origin browser calls, the
- page origin allowed in the project's auth CORS settings.
- operationId: authDeviceVerify
+ Backups you took, backups the schedule produced, and backups taken
+ before migrations are all listed; `source` tells them apart. Only manual
+ backups count against the plan's backup allowance.
+ operationId: listDatabaseBackups
security:
- - AuthUserAccessToken: []
- requestBody:
- required: true
- content:
- application/json:
- schema:
- type: object
- required:
- - user_code
- properties:
- user_code:
- type: string
- action:
- type: string
- enum:
- - approve
- - deny
- default: approve
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DatabaseName'
responses:
'200':
- description: Verification action accepted
+ description: Successful response
content:
application/json:
schema:
- type: object
- properties:
- success:
- type: boolean
- status:
- type: string
- '401':
- description: Not authenticated
+ $ref: '#/components/schemas/DatabaseBackupList'
+ '403':
+ description: Backups require SUPERAGENT
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Project or database not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: |
+ The database has no storage project yet, so there is nothing to
+ list. A database reports this while it is still provisioning.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Backups are temporarily unavailable
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/platform/exchange:
post:
tags:
- - OAuth Authentication
- summary: Exchange auth-user device session for platform token
+ - Database Backups
+ summary: Back up a database
description: |
- Exchanges a verified auth-user device-flow session into a platform token for CLI usage.
- The target platform user is derived from authenticated auth-user mapping; client cannot select another user.
- operationId: authPlatformExchange
+ Captures the database as it is now. The backup is available immediately;
+ its `size_bytes` appears once the storage provider has costed it.
+
+ Backups are rate-limited to one per minute per database, and capped by
+ the owner's plan.
+ operationId: createDatabaseBackup
security:
- - AuthUserAccessToken: []
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DatabaseName'
requestBody:
required: true
content:
application/json:
schema:
- type: object
- required:
- - client_id
- properties:
- client_id:
- type: string
+ $ref: '#/components/schemas/CreateDatabaseBackupRequest'
responses:
- '200':
- description: Platform token minted
+ '201':
+ description: Backup created
content:
application/json:
schema:
- $ref: '#/components/schemas/PlatformExchangeResponse'
+ $ref: '#/components/schemas/DatabaseBackup'
+ '400':
+ description: Invalid backup name, or one with a reserved prefix
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'403':
description: |
- Exchange not allowed for this session/client/project, or the
- account's email domain is not in `allowed_email_domains` while
- `allowed_email_domains_mode` is `signup_and_signin`. The domain is
- re-checked here because the minted platform token outlives the
- session it is exchanged from.
+ The database has reached its backup allowance, or the owner's plan
+ does not include backups, which are available only on SUPERAGENT.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/oauth/providers:
- get:
- tags:
- - OAuth Authentication
- summary: List user's linked providers
- description: Get list of OAuth providers linked to current user
- operationId: authListOAuthProviders
- security:
- - AuthUserAccessToken: []
- responses:
- '200':
- description: Linked providers
+ '404':
+ description: Project or database not found
content:
application/json:
schema:
- type: object
- properties:
- providers:
- type: array
- items:
- type: object
- properties:
- provider:
- type: string
- linked_at:
- type: string
- format: date-time
- updated_at:
- type: string
- format: date-time
- '401':
- description: Not authenticated
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: |
+ A backup of that name already exists, the database is not active, a
+ restore is running on it, or a backup was taken too recently.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/oauth/{provider}/link:
- post:
+ '503':
+ description: Backups are temporarily unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/databases/{databaseName}/backups/{backupName}:
+ get:
tags:
- - OAuth Authentication
- summary: Link OAuth provider to current user
- description: |
- Generates authorization URL to link OAuth provider to existing account.
- User must be authenticated.
- operationId: authLinkOAuthProvider
+ - Database Backups
+ summary: Get a backup
+ description: Returns one backup of the database.
+ operationId: getDatabaseBackup
security:
- - AuthUserAccessToken: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - name: provider
- in: path
- required: true
- schema:
- type: string
- enum:
- - google
- - github
- - microsoft
- - apple
- - name: redirect_url
- in: query
- schema:
- type: string
- description: |
- URL to redirect to after linking completes (optional). Same
- allowed_redirect_urls requirement as GET /auth/oauth/{provider}/authorize.
- - name: client_state
- in: query
- schema:
- type: string
- maxLength: 255
- description: |
- Optional application nonce echoed to redirect_url as `state`.
- - name: response_mode
- in: query
- schema:
- type: string
- enum:
- - code
- description: |
- Set to `code` to receive a short-lived authorization code at
- redirect_url. `redirect_url` is required in this mode. When
- omitted, the established session-fragment response is retained for
- compatibility with existing clients.
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DatabaseName'
+ - $ref: '#/components/parameters/BackupName'
responses:
'200':
- description: Authorization URL generated
- content:
- application/json:
- schema:
- type: object
- properties:
- authorization_url:
- type: string
- '400':
- description: redirect_url is not registered in allowed_redirect_urls
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- '401':
- description: Not authenticated
+ $ref: '#/components/schemas/DatabaseBackup'
+ '403':
+ description: Backups require SUPERAGENT
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: OAuth provider not configured
+ description: Project, database, or backup not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
- description: Provider already linked
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- /auth/oauth/{provider}/unlink:
- delete:
- tags:
- - OAuth Authentication
- summary: Unlink OAuth provider
- description: |
- Remove OAuth provider from user's account.
- Cannot unlink if it's the only authentication method.
- operationId: authUnlinkOAuthProvider
- security:
- - AuthUserAccessToken: []
- parameters:
- - name: provider
- in: path
- required: true
- schema:
- type: string
- enum:
- - google
- - github
- - microsoft
- - apple
- responses:
- '204':
- description: Provider unlinked
- '400':
- description: Cannot unlink last authentication method
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '401':
- description: Not authenticated
+ description: |
+ The database has no storage project yet, so it holds no backups. A
+ database reports this while it is still provisioning.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Provider not linked
+ '503':
+ description: Backups are temporarily unavailable
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/oauth/{provider}/refresh-token:
- post:
+ delete:
tags:
- - OAuth Authentication
- summary: Refresh OAuth provider token
+ - Database Backups
+ summary: Delete a backup
description: |
- Refresh the access token for an OAuth provider using its refresh token.
- Allows calling provider APIs on user's behalf (e.g., Google Drive, GitHub repos).
- operationId: refreshOAuthProviderToken
+ Deletes the backup and frees its storage. Scheduled backups can be
+ deleted too. A backup that is already gone reports `404`, so a name
+ that never existed and a name that no longer does read the same.
+ Refused with `409` while the database is being restored.
+ operationId: deleteDatabaseBackup
security:
- - AuthUserAccessToken: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - name: provider
- in: path
- required: true
- schema:
- type: string
- enum:
- - google
- - github
- - microsoft
- - apple
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DatabaseName'
+ - $ref: '#/components/parameters/BackupName'
responses:
'200':
- description: Token refreshed successfully
+ description: Backup deleted
content:
application/json:
schema:
type: object
properties:
- message:
+ status:
type: string
- provider:
+ example: deleted
+ message:
type: string
- expires_in:
- type: integer
- '400':
- description: No refresh token available or refresh failed
+ example: backup deleted
+ required:
+ - status
+ - message
+ '403':
+ description: Backups require SUPERAGENT
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Not authenticated
+ '404':
+ description: Project, database, or backup not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Provider not linked
+ '409':
+ description: |
+ The database is being restored. A restore is pinned to a backup it
+ may not have restored yet, so deleting one is refused until the
+ restore finishes.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/oauth/{provider}/token:
+ '503':
+ description: Backups are temporarily unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/databases/{databaseName}/backup-schedule:
get:
tags:
- - OAuth Authentication
- summary: Get current provider access token
+ - Database Backups
+ summary: Get the automated backup schedule
description: |
- Get valid access token for OAuth provider.
- Automatically refreshes if expired.
- operationId: getOAuthProviderToken
+ Returns the database's backup schedule. An empty list means no scheduled
+ backups.
+ operationId: getDatabaseBackupSchedule
security:
- - AuthUserAccessToken: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - name: provider
- in: path
- required: true
- schema:
- type: string
- enum:
- - google
- - github
- - microsoft
- - apple
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DatabaseName'
responses:
'200':
- description: Current access token
+ description: Successful response
content:
application/json:
schema:
- type: object
- properties:
- message:
- type: string
- provider:
- type: string
- expires_in:
- type: integer
- '401':
- description: Not authenticated
+ $ref: '#/components/schemas/DatabaseBackupSchedule'
+ '403':
+ description: Backups require SUPERAGENT
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Provider not linked
+ description: Project or database not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /auth/oauth/{provider}/call-api:
- post:
- tags:
- - OAuth Authentication
- summary: Call OAuth provider API
- description: |
- Make an authenticated request to an OAuth provider's API on behalf of the user.
- The user's stored access token is automatically used and refreshed if needed.
-
- The request is always sent to the provider's fixed API base URL joined with
- the caller-supplied `endpoint`. `endpoint` must be a relative path beginning
- with `/` (optionally with a query string); it cannot change the target host.
- Absolute URLs, protocol-relative `//host` values, or userinfo (`@host`) are
- rejected with `400` so the request can never be redirected to another host.
-
- Examples of `endpoint`:
- - Google userinfo: `/oauth2/v1/userinfo`
- - GitHub repositories: `/user/repos`
- - Microsoft Graph profile: `/me`
+ '409':
+ description: |
+ The database has no storage project yet, so it has no schedule. A
+ database reports this while it is still provisioning.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Backups are temporarily unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ put:
+ tags:
+ - Database Backups
+ summary: Replace the automated backup schedule
+ description: |
+ Replaces the schedule wholesale. Send an empty `entries` list to stop
+ scheduled backups.
- The response wraps the provider's raw JSON value with request metadata.
- An empty provider body is represented as `data: null`; the envelope
- preserves the provider's HTTP status in `status_code`, including errors.
- Provider response bodies are limited to 8 MiB after decompression.
- Transport failures, invalid JSON (including invalid UTF-8), and oversized
- bodies return `502`. Provider redirects to another origin are blocked and
- return `400`.
- operationId: callOAuthProviderAPI
+ Scheduled backups do not count against the plan's backup allowance, but
+ their retention is clamped to the plan's.
+ operationId: updateDatabaseBackupSchedule
security:
- - AuthUserAccessToken: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - name: provider
- in: path
- required: true
- schema:
- type: string
- enum:
- - google
- - github
- - microsoft
- - apple
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DatabaseName'
requestBody:
required: true
content:
application/json:
schema:
- type: object
- required:
- - endpoint
- properties:
- endpoint:
- type: string
- description: |
- Relative path on the provider's API, beginning with `/`. It is
- joined with the provider's fixed base URL; it must not contain a
- scheme, host, userinfo, or a leading `//`.
- example: /user/repos
- method:
- type: string
- enum:
- - GET
- - POST
- default: GET
- description: HTTP method to use
- body:
- type: object
- additionalProperties: true
- description: Request body for POST requests
+ $ref: '#/components/schemas/DatabaseBackupSchedule'
responses:
'200':
- description: Provider API response
+ description: Schedule replaced
content:
application/json:
schema:
- type: object
- description: OAuth provider API response envelope
- required:
- - provider
- - endpoint
- - status_code
- - data
- properties:
- provider:
- type: string
- enum:
- - google
- - github
- - microsoft
- - apple
- endpoint:
- type: string
- status_code:
- type: integer
- minimum: 100
- maximum: 599
- data:
- description: Raw provider JSON value, or null when the provider returns no body
- nullable: true
+ $ref: '#/components/schemas/DatabaseBackupSchedule'
'400':
description: |
- Invalid request (for example: missing `endpoint`, an `endpoint` that is
- not a relative path, or an unsupported HTTP method), or a provider
- redirect to another origin.
+ The schedule names a recurrence that cannot fire: a weekly or
+ monthly one with no `day`, or a `day` outside its frequency's range
+ (1-7 for weekly, 1-28 for monthly). The response says which.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Not authenticated
+ '403':
+ description: Backups require SUPERAGENT
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: OAuth provider configuration not found
+ description: Project or database not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Failed to create the provider API request
+ '409':
+ description: |
+ The database is not active, or a restore is running on it — a restore
+ moves the data to a new branch, and the provider keeps the schedule
+ per branch.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '502':
- description: Provider transport failure, invalid JSON, or response body larger than 8 MiB
+ '503':
+ description: Backups are temporarily unavailable
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/anon-keys:
+ /projects/{id}/databases/{databaseName}/restores:
get:
tags:
- - Anon Keys
- summary: List anon keys
+ - Database Backups
+ summary: List a database's restores
description: |
- Supports two mutually exclusive pagination modes. Offset mode uses `page`
- and `limit` and is the default when neither `cursor` nor `search` is
- supplied (first page, default `limit`). Cursor mode uses `cursor` and
- `limit`, supports `search` (case-insensitive name match), and returns
- `next_cursor`. Sending both `page` and `cursor` (or `page` and `search`)
- returns 400.
- operationId: listAnonKeys
+ Returns the database's restore history, newest first, capped at the 50
+ most recent. There is no pagination: a database that has been restored
+ more than 50 times keeps the older records but does not return them.
+ operationId: listDatabaseRestores
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/Page'
- - $ref: '#/components/parameters/Limit'
- - $ref: '#/components/parameters/Cursor'
- - $ref: '#/components/parameters/EndingBefore'
- - $ref: '#/components/parameters/Offset'
- - $ref: '#/components/parameters/Search'
+ - $ref: '#/components/parameters/DatabaseName'
responses:
'200':
- description: List of anon keys
+ description: Successful response
content:
application/json:
schema:
- type: object
- properties:
- data:
- type: array
- items:
- $ref: '#/components/schemas/AnonKey'
- total:
- type: integer
- description: Total number of items matching the query (so the UI can render numbered pages).
- has_more:
- type: boolean
- description: Whether a next page exists.
- next_cursor:
- type: string
- description: Opaque cursor for the next page (cursor pagination only)
- prev_cursor:
- type: string
- description: Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`.
+ $ref: '#/components/schemas/DatabaseRestoreList'
+ '403':
+ description: Backups require SUPERAGENT
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Project or database not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Backups are temporarily unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
post:
tags:
- - Anon Keys
- summary: Create anon key
- operationId: createAnonKey
+ - Database Backups
+ summary: Restore a database
+ description: |
+ Replaces the database's data, either with a named backup or with its
+ state at a point in time. This is destructive: everything written after
+ that point is discarded.
+
+ Asynchronous: the response is `202` with the restore `pending` and the
+ database `restoring`. The database does not accept connections until the
+ restore reports `completed`; its connection string is unchanged
+ throughout, so nothing holding it needs updating.
+
+ Restores are in place. There is no way to restore into a second
+ database, and a database's branches are never restored — they keep
+ serving their own data, but resetting a branch from its parent is
+ refused by the storage provider for up to 24 hours afterwards.
+ operationId: createDatabaseRestore
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DatabaseName'
requestBody:
required: true
content:
application/json:
schema:
- type: object
- required:
- - name
- properties:
- name:
- type: string
- description: |
- Key name for identification.
- Can only contain letters, numbers, underscores, and hyphens.
- pattern: ^[A-Za-z0-9_-]+$
- minLength: 1
- maxLength: 255
- example: frontend-app
- permissions:
- type: array
- items:
- type: string
- enum:
- - auth.signup
- - auth.signin
- - auth.refresh
- - auth.logout
- - auth.password_reset
- - auth.confirm_email
- - auth.resend_confirmation
- - storage.upload
- - storage.download
- - storage.list
- - storage.delete
- - realtime.connect
- - realtime.subscribe
- - realtime.publish
- - functions.invoke
- description: |
- Optional list of permissions for this key.
- If not provided, defaults to auth-only permissions: auth.signup, auth.signin, auth.refresh, auth.logout, auth.password_reset, auth.confirm_email, auth.resend_confirmation.
- Storage, realtime, and functions permissions must be explicitly added if needed.
- example:
- - auth.signup
- - auth.signin
- - auth.refresh
- - auth.logout
+ $ref: '#/components/schemas/CreateDatabaseRestoreRequest'
responses:
- '201':
- description: Anon key created
+ '202':
+ description: Restore accepted and in progress
content:
application/json:
schema:
- $ref: '#/components/schemas/AnonKey'
- /projects/{id}/anon-keys/{keyId}:
- get:
- tags:
- - Anon Keys
- summary: Get anon key
- description: Get details of a specific anon key
- operationId: getAnonKey
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - name: keyId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '200':
- description: Anon key details
+ $ref: '#/components/schemas/DatabaseRestore'
+ '400':
+ description: |
+ Neither or both restore targets were named, or the requested time is
+ outside the available window.
content:
application/json:
schema:
- $ref: '#/components/schemas/AnonKey'
- '404':
- description: Key not found
- delete:
- tags:
- - Anon Keys
- summary: Revoke anon key
- description: Revokes key - it will immediately stop working
- operationId: revokeAnonKey
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - name: keyId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '204':
- description: Key revoked
- '401':
- description: Unauthorized
+ $ref: '#/components/schemas/Error'
'403':
- description: Forbidden
- '404':
- description: Key not found
- '409':
- description: Cannot delete the project's default anon key
+ description: |
+ The owner's plan does not include backups or point-in-time restore
+ (code `plan_required`). Both are available only on SUPERAGENT. Also
+ answers 403 without a code, with `restore history is not available
+ yet for the requested time`, when the plan includes restore history
+ but the database has not built any up yet; waiting fixes it, not
+ upgrading.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '500':
- description: Internal server error
+ '404':
+ description: Project, database, or backup not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/anon-keys/{keyId}/regenerate:
- post:
- tags:
- - Anon Keys
- summary: Regenerate anon key
- description: Generate new JWT value for existing key
- operationId: regenerateAnonKey
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - name: keyId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '200':
- description: Key regenerated
+ '409':
+ description: |
+ Code `migration_run_in_progress`: a migration run is backing up or
+ applying to the database, named by `run_id`. Wait for it to end,
+ then send the request again. Without a code: a restore is already
+ in progress, the database is not active, another database operation
+ is still running, or the database is holding as many pre-restore
+ branches as it may.
content:
application/json:
schema:
- $ref: '#/components/schemas/AnonKey'
- /projects/{id}/anon-keys/{keyId}/set-default:
- post:
+ $ref: '#/components/schemas/DatabaseRestoreConflictError'
+ '503':
+ description: Backups are temporarily unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/databases/{databaseName}/restores/{restoreId}:
+ get:
tags:
- - Anon Keys
- summary: Set default anon key
- description: Promotes the given key to the project's configured default. At most one key per project can be default.
- operationId: setDefaultAnonKey
+ - Database Backups
+ summary: Get a restore
+ description: |
+ Returns the restore. Poll this after starting one; the database is
+ connectable again once it reports `completed`.
+ operationId: getDatabaseRestore
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - name: keyId
- in: path
- required: true
- schema:
- type: string
- format: uuid
+ - $ref: '#/components/parameters/DatabaseName'
+ - $ref: '#/components/parameters/RestoreId'
responses:
'200':
- description: Key set as default
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/AnonKey'
- '401':
- description: Unauthorized
+ $ref: '#/components/schemas/DatabaseRestore'
'403':
- description: Forbidden
+ description: Backups require SUPERAGENT
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'404':
- description: Anon key not found
- '500':
- description: Internal server error
+ description: Project, database, or restore not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/access-tokens:
+ '503':
+ description: Backups are temporarily unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/databases/{databaseName}/migrations:
get:
tags:
- - Project Access Tokens
- summary: List a project's access tokens
+ - Database Migrations
+ summary: Get a database's migration history
description: |
- Lists the project's access tokens, newest first. Secrets are never
- returned: only a hash is stored, so a token's value exists solely in the
- response to the create call.
+ Returns the migrations the database has recorded, in name order, read
+ from the database's own `_volcano_migrations.history` table. The history
+ is empty until a migration run or a baseline first records a file.
- Only tokens that can still authenticate are returned by default, so
- revoked and expired ones are hidden. Pass `include_revoked=true` to see
- them, which is how you find out what a key did before it stopped working.
+ `active_run_id` is the run that is queued or running, if any.
- Requires a platform token. A project access token cannot manage project
- access tokens, so a leaked credential cannot enumerate or replace itself.
- operationId: listProjectAccessTokens
+ If the history table is gone from a database where migrations ran,
+ answers `409` with code `history_missing`, and every run fails with
+ that code, rather than running files again. Record a baseline of the
+ files that were already applied to rebuild it. Dropping the whole
+ `_volcano_migrations` schema is not supported: the database then reads
+ as new, and the next run applies every file again.
+
+ Volcano reads at most 1,000 history entries, as many files as one run
+ may carry. A history with more answers `409` with code
+ `history_too_large`. A baseline is refused with that code, and a run
+ fails with it. Deleting the entries of files no longer among your
+ migrations brings the history back under the bound.
+
+ Available whether or not migration runs are.
+ operationId: getDatabaseMigrations
security:
- UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/Page'
- - $ref: '#/components/parameters/Limit'
- - $ref: '#/components/parameters/Search'
- - name: include_revoked
- in: query
- required: false
- description: |
- Include tokens that can no longer authenticate — both revoked and
- expired ones.
- schema:
- type: boolean
- default: false
+ - $ref: '#/components/parameters/DatabaseName'
responses:
'200':
description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/PaginatedProjectAccessTokens'
- '401':
- description: Unauthorized - invalid or missing token
+ $ref: '#/components/schemas/DatabaseMigrations'
+ '404':
+ description: Project or database not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Forbidden - not the project owner, or a project access token was used
+ '409':
+ description: |
+ Code `history_missing`: the history table is gone from a database
+ where migrations ran; record a baseline of the files that were
+ already applied. Code `history_too_large`: the history has more
+ than 1,000 entries. Without a code: the database is not active, so
+ its history cannot be read.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '404':
- description: Project not found
+ '503':
+ description: Volcano could not reach the database
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
+ /projects/{id}/databases/{databaseName}/migrations/baseline:
post:
tags:
- - Project Access Tokens
- summary: Create a project access token
- description: |
- Creates a project access token and returns its secret.
+ - Database Migrations
+ summary: Record migrations as applied without running them
+ description: |
+ Records each file in the database's migration history as applied,
+ without running it. Use it once for a database whose schema already
+ reflects the files, such as one migrated before Volcano tracked its
+ migrations, so later runs apply only newer files. It is refused while
+ a run is queued or running, and no run starts while it records. It
+ does not queue: while another request is changing the database, or the
+ database holds it up, such as with a lock on the migration history, it
+ answers `409` with code `database_busy`.
- The secret is in this response and nowhere else. Only its hash is
- stored, so it cannot be retrieved, displayed, or recovered later — save
- it when you create it.
+ Files the history already records with the same checksum are skipped, so
+ repeating the request changes nothing. A file recorded with a different
+ checksum is refused, and nothing is recorded.
- The name must be unique within the project, so a retry cannot mint a
- second credential. It cannot recover the first one either. A retry that
- returns `409` with code `access_token_name_exists` means the original
- create committed and its secret is unrecoverable: list the project's
- tokens, revoke the one holding that name, and create it again.
+ It also rebuilds a history that was lost (`history_missing`): send
+ exactly the files that were already applied, and later runs apply only
+ the rest.
- Requires a platform token.
- operationId: createProjectAccessToken
+ Where migration runs are not available, answers `404` with code
+ `feature_unavailable`.
+ operationId: baselineDatabaseMigrations
security:
- UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DatabaseName'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/CreateProjectAccessTokenRequest'
+ $ref: '#/components/schemas/DatabaseMigrationFilesRequest'
responses:
- '201':
- description: Token created - save the secret now, it cannot be retrieved again
+ '200':
+ description: The files are recorded
content:
application/json:
schema:
- $ref: '#/components/schemas/CreatedProjectAccessToken'
+ $ref: '#/components/schemas/DatabaseMigrationBaseline'
'400':
- description: Bad request - invalid name, scope, or expiry
+ description: |
+ A file breaks a rule: too many files, a file over 1 MiB, a name that
+ is not a `.sql` file, a name repeated, or a directory other than
+ this database's. Nothing is recorded or queued. Code
+ `invalid_layout`: a path does not map to this database. Code
+ `invalid_file`: a name is repeated or too long. A request the
+ schema refuses carries no code. Without a code, the message
+ starting `storage limit reached`: the database is over its storage
+ allowance, so its writes are blocked, as they are over a
+ connection.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
+ '404':
+ description: |
+ Project or database not found, or migration runs are not available
+ here (code `feature_unavailable`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: Forbidden - not the project owner, or a project access token was used
+ '409':
+ description: |
+ Nothing was recorded. Code `checksum_mismatch`: a file is already
+ recorded with a different checksum. Code
+ `migration_run_in_progress`: a run is queued or running, named by
+ `run_id`. Code `history_too_large`: the history has more than 1,000
+ entries. Code `database_busy`: another request is changing the
+ database, or the database held the baseline up, such as with a lock
+ on its migration history; try again. Without a code: the database is not active or changed
+ while the request ran, or another session holds its migration
+ lock.
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- '404':
- description: Project not found
+ $ref: '#/components/schemas/DatabaseMigrationConflictError'
+ '413':
+ description: The request body is larger than 4 MiB
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: |
- Duplicate name, token limit reached, or the project is being
- deleted. Tell them apart with `code`, which is one of
- `access_token_name_exists`, `access_token_limit_reached`, or
- `project_deleting` — the message text is not a contract.
+ '503':
+ description: Volcano could not reach the database
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/access-tokens/usage:
+ /projects/{id}/databases/{databaseName}/migration-runs:
get:
tags:
- - Project Access Tokens
- summary: Per-day request counts for every access token in a project
+ - Database Migrations
+ summary: List a database's migration runs
description: |
- Returns a zero-filled daily series of request counts for each of the
- project's access tokens, oldest first. Every day in the window is
- present, so a gap reads as zero rather than missing.
-
- Revoked tokens are included, because the traffic they made before
- revocation is usually the reason you are looking.
+ Returns the database's 50 most recent migration runs, newest first,
+ without their files; get a run for its files. There is no pagination.
- `days` defaults to 30 and is capped at 60, which is also how long per-day
- counts are retained — a longer window cannot be answered.
-
- A platform token sees every token in the project. A project access token
- sees only its own row, so it can watch its own traffic without being
- able to enumerate the project's other credentials by name.
- operationId: listProjectAccessTokensUsage
+ Available whether or not migration runs are.
+ operationId: listDatabaseMigrationRuns
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - name: days
- in: query
- required: false
- description: Number of trailing days to return (1-60, default 30).
- schema:
- type: integer
- minimum: 1
- maximum: 60
- default: 30
+ - $ref: '#/components/parameters/DatabaseName'
responses:
'200':
description: Successful response
content:
application/json:
schema:
- type: array
- items:
- $ref: '#/components/schemas/ProjectAccessTokenUsage'
- '400':
- description: Bad request - invalid window
+ $ref: '#/components/schemas/DatabaseMigrationRunList'
+ '404':
+ description: Project or database not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Unauthorized - invalid or missing token
+ post:
+ tags:
+ - Database Migrations
+ summary: Apply migrations to a database
+ description: |
+ Starts a migration run: Volcano compares the files with the database's
+ history, rehearses the pending ones on a short-lived branch of the
+ database, takes a backup, and applies them in name order. Files the
+ history already records with the same checksum are skipped.
+
+ Asynchronous: the response is `202` with the run `queued`. Poll the run
+ until its `status` is `succeeded` or `failed`.
+
+ Send `Idempotency-Key` to make a retry safe: a repeat with a key this
+ database has seen returns that run with `200` and starts nothing. A
+ database runs one migration run at a time.
+
+ Where migration runs are not available, answers `404` with code
+ `feature_unavailable`.
+ operationId: createDatabaseMigrationRun
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DatabaseName'
+ - name: Idempotency-Key
+ in: header
+ required: false
+ description: |
+ Makes the request safe to retry. A repeat with a key this database
+ has seen returns the run it started. Reusing a key for different
+ files answers `409`. Up to 255 printable ASCII characters.
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 255
+ pattern: ^[!-~]+$
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DatabaseMigrationFilesRequest'
+ responses:
+ '200':
+ description: A run with this `Idempotency-Key` already exists; it is returned
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- '403':
- description: Forbidden - not the project owner
+ $ref: '#/components/schemas/DatabaseMigrationRun'
+ '202':
+ description: Run accepted and queued
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DatabaseMigrationRun'
+ '400':
+ description: |
+ A file breaks a rule: too many files, a file over 1 MiB, a name that
+ is not a `.sql` file, a name repeated, or a directory other than
+ this database's. Nothing is recorded or queued. Code
+ `invalid_layout`: a path does not map to this database. Code
+ `invalid_file`: a name is repeated or too long. A request the
+ schema refuses carries no code. Without a code, the message
+ starting `storage limit reached`: the database is over its storage
+ allowance, so its writes are blocked, as they are over a
+ connection.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Project not found
+ description: |
+ Project or database not found, or migration runs are not available
+ here (code `feature_unavailable`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/access-tokens/{tokenId}:
+ '409':
+ description: |
+ Code `migration_run_in_progress`: a run is already queued or running
+ for this database, named by `run_id`. Wait for it to end, then send
+ the request again. Without a code: the `Idempotency-Key` already
+ started a run of different files.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DatabaseMigrationConflictError'
+ '413':
+ description: The request body is larger than 4 MiB
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/databases/{databaseName}/migration-runs/{runId}:
get:
tags:
- - Project Access Tokens
- summary: Get a project access token
+ - Database Migrations
+ summary: Get a migration run
description: |
- Returns one token's metadata. Never its secret, which is not stored in a
- recoverable form.
+ Returns the run with each file's outcome. Poll this after starting a
+ run.
- Requires a platform token.
- operationId: getProjectAccessToken
+ Available whether or not migration runs are.
+ operationId: getDatabaseMigrationRun
security:
- UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/TokenId'
+ - $ref: '#/components/parameters/DatabaseName'
+ - $ref: '#/components/parameters/MigrationRunId'
responses:
'200':
description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectAccessToken'
- '401':
- description: Unauthorized - invalid or missing token
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '403':
- description: Forbidden - not the project owner, or a project access token was used
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
+ $ref: '#/components/schemas/DatabaseMigrationRun'
'404':
- description: Token not found
+ description: Project, database, or run not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- delete:
+ /projects/{id}/databases/{databaseName}/reset-password:
+ post:
tags:
- - Project Access Tokens
- summary: Revoke a project access token
+ - Databases
+ summary: Reset database password
description: |
- Revokes the token. It stops authenticating immediately in the region
- handling this call and within seconds across Volcano's other regions.
-
- The record is kept rather than deleted, so the token's name, prefix, last
- use, and request history stay available — which is what you need if you
- are revoking because a secret leaked. Revoking an already-revoked token
- succeeds.
-
- Revoking does not undo anything the token already did. Treat whatever it
- could reach as exposed and rotate accordingly.
+ Rotates the Volcano-managed PostgreSQL password used by clients when connecting
+ through pgproxy. This does not rotate or expose the internal owner password.
+ The returned password and connection string are the only client credentials that
+ will authenticate through pgproxy after reset.
- Requires a platform token.
- operationId: revokeProjectAccessToken
+ Existing connections are not interrupted; new ones must use the returned
+ string. Proxies pick the rotation up within a few seconds, so the previous
+ password can still open new connections until then.
+ operationId: resetDatabasePassword
security:
- UserToken: []
+ - ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/TokenId'
+ - $ref: '#/components/parameters/DatabaseName'
responses:
- '204':
- description: Token revoked
- '401':
- description: Unauthorized - invalid or missing token
+ '200':
+ description: Password reset successful
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- '403':
- description: Forbidden - not the project owner, or a project access token was used
+ type: object
+ properties:
+ message:
+ type: string
+ role_name:
+ type: string
+ description: Volcano-managed per-database client login (also the pgproxy routing username)
+ example: volcano_client_11111111-1111-1111-1111-111111111111
+ new_password:
+ type: string
+ description: New Volcano-managed client password. Always starts with `vpg_`.
+ connection_string:
+ type: string
+ description: Updated pgproxy connection string using Volcano-managed credentials.
+ '400':
+ description: Database is not active
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Token not found
+ description: Database not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
- description: Conflict - the project is being deleted
+ description: |
+ A restore is running on the database. A restore replaces the
+ credentials as it finishes, so wait for it and rotate afterwards.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/access-tokens/{tokenId}/usage:
- get:
+ '503':
+ description: |
+ Volcano could not check whether a restore is running, and will not
+ rotate a credential a restore might be about to replace. Retry.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/databases/{databaseName}/type:
+ patch:
tags:
- - Project Access Tokens
- summary: Per-day request counts for one access token
+ - Databases
+ summary: Update database size
description: |
- Returns a zero-filled daily series of request counts for a single token,
- oldest first, so the response always has exactly `days` entries.
-
- `days` defaults to 30 and is capped at 60, matching how long per-day
- counts are retained.
+ Change the size tier of a database. This may briefly interrupt active connections.
- A project access token may read only its own usage; asking for another
- token's returns `403`. A platform token may read any token in the
- project.
- operationId: getProjectAccessTokenUsage
+ **Available sizes:**
+ - `volcano-db-xs`: Up to ~1GB RAM - Development, small apps
+ - `volcano-db-s`: Up to ~4GB RAM - Production-ready, light traffic
+ - `volcano-db-m`: Up to ~8GB RAM - Medium traffic applications
+ - `volcano-db-l`: Up to ~16GB RAM - High traffic, larger datasets
+ - `volcano-db-xl`: Up to ~32GB RAM - Heavy workloads
+ - `volcano-db-2xl`: Up to ~64GB RAM - Enterprise-scale
+ operationId: updateDatabaseType
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/TokenId'
- - name: days
- in: query
- required: false
- description: Number of trailing days to return (1-60, default 30).
- schema:
- type: integer
- minimum: 1
- maximum: 60
- default: 30
+ - $ref: '#/components/parameters/DatabaseName'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateDatabaseTypeRequest'
responses:
'200':
- description: Successful response
+ description: Database type updated
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectAccessTokenUsage'
+ $ref: '#/components/schemas/Database'
'400':
- description: Bad request - invalid window
+ description: Invalid database type
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
- description: Unauthorized - invalid or missing token
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: Forbidden - not the project owner
+ description: Access denied or the requested size exceeds the plan allowance (code plan_required)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Token not found
+ description: Database not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/service-keys:
+ '409':
+ description: |
+ The database is not active — being provisioned, deleted, or
+ restored. Compute can only be changed while it is active.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: |
+ Volcano could not check whether a restore is running, and will not
+ reconfigure compute a restore might be moving. Retry.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/databases/{databaseName}/stats:
get:
tags:
- - Service Keys
- summary: List service keys (paginated)
+ - Databases
+ summary: Get database consumption metrics
description: |
- List all service role keys for a project with pagination.
+ Retrieve consumption metrics including storage, compute time, and data transfer.
+ Metrics are aggregated at the project level. Defaults to last 24 hours.
- **WARNING:** Service keys bypass RLS - for backend/admin use only!
- operationId: listServiceKeys
+ **Note:** Advanced metrics require an upgraded plan.
+ operationId: getDatabaseStats
security:
- UserToken: []
- ProjectAccessToken: []
parameters:
- $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/Page'
- - $ref: '#/components/parameters/Limit'
- - $ref: '#/components/parameters/Cursor'
- - $ref: '#/components/parameters/EndingBefore'
- - $ref: '#/components/parameters/Offset'
- - $ref: '#/components/parameters/Search'
- responses:
- '200':
- description: Paginated list of service keys
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/PaginatedServiceKeys'
- post:
- tags:
- - Service Keys
- summary: Create service key
- description: |
- Create a new service role key for admin operations.
-
- **WARNING:** Service keys bypass all RLS policies!
- Store securely and NEVER expose in frontend code.
- operationId: createServiceKey
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- type: object
- required:
- - name
- properties:
- name:
- type: string
- description: |
- Descriptive name for the key (e.g., "admin-dashboard", "background-jobs").
- Can only contain letters, numbers, underscores, and hyphens.
- pattern: ^[A-Za-z0-9_-]+$
- minLength: 1
- maxLength: 255
- example: admin-dashboard
- permissions:
- type: array
- items:
- type: string
- description: |
- Optional least-privilege scope for the key. When omitted, empty, or
- containing only blank strings, the key is granted full access (["*"])
- for backward compatibility. Provide an explicit list (e.g.
- ["functions.invoke", "locks.manage"]) to restrict the key; "*"
- grants everything. Scope enforcement applies to function invocation,
- storage object operations, project locks, and server-side auth proxy
- metadata (auth.signin, auth.signup, auth.refresh, auth.logout,
- auth.password_reset).
- example:
- - functions.invoke
- - locks.manage
- responses:
- '201':
- description: Service key created - save the key_value immediately!
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/ServiceKey'
- '409':
- description: Key with this name already exists
- /projects/{id}/service-keys/{keyId}:
- get:
- tags:
- - Service Keys
- summary: Get service key
- description: Get details of a specific service key
- operationId: getServiceKey
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - name: keyId
- in: path
- required: true
+ - $ref: '#/components/parameters/DatabaseName'
+ - name: from
+ in: query
+ required: false
schema:
type: string
- format: uuid
+ format: date-time
+ description: Start time in RFC3339 format (e.g., "2024-01-01T00:00:00Z"). Defaults to 24 hours ago.
+ - name: to
+ in: query
+ required: false
+ schema:
+ type: string
+ format: date-time
+ description: End time in RFC3339 format (e.g., "2024-01-02T00:00:00Z"). Defaults to now.
+ - name: granularity
+ in: query
+ required: false
+ schema:
+ type: string
+ enum:
+ - hourly
+ - daily
+ - monthly
+ default: hourly
+ description: Level of detail for metrics aggregation
responses:
'200':
- description: Service key details
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/ServiceKey'
+ $ref: '#/components/schemas/DatabaseStats'
+ '400':
+ description: Invalid parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'404':
- description: Key not found
- delete:
- tags:
- - Service Keys
- summary: Delete service key
- description: |
- Permanently delete a service key.
- Any services using this key will immediately lose access.
- operationId: deleteServiceKey
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - name: keyId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '204':
- description: Key deleted
- /projects/{id}/service-keys/{keyId}/regenerate:
+ description: Database not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Database metrics not available or requires upgraded plan
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /databases/{databaseName}/query/ping:
post:
tags:
- - Service Keys
- summary: Regenerate service key
+ - Database Queries
+ summary: Database connectivity probe (REST API)
description: |
- Generate new JWT value for existing key.
- The old key stops working within a few seconds.
- Update your backend services with the new key before regenerating in production.
- operationId: regenerateServiceKey
+ Connectivity probe that runs a fixed `SELECT 1` through pgproxy, using the
+ same authentication, status/bandwidth gating, and metering as the other
+ `/query/*` endpoints.
+
+ Unlike those endpoints, ping takes **no request body** and performs **no
+ table-name validation**, so it works on any database — including a freshly
+ provisioned, empty one. It is a real committed round-trip through pgproxy,
+ so a `200` means the database is reachable and queryable. Used by the
+ dashboard's database connection test.
+ operationId: queryDatabasePing
security:
- - UserToken: []
- - ProjectAccessToken: []
+ - AuthUserAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- - name: keyId
- in: path
- required: true
- schema:
- type: string
- format: uuid
+ - $ref: '#/components/parameters/DatabaseName'
responses:
'200':
- description: Key regenerated - save the new key_value immediately!
+ description: Database is reachable
+ headers:
+ X-Volcano-Proxy-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyMs'
+ X-Volcano-Proxy-Handler-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
+ X-Volcano-Compute-Ms:
+ $ref: '#/components/headers/DatabaseQueryComputeMs'
content:
application/json:
schema:
- $ref: '#/components/schemas/ServiceKey'
- /projects/{id}/storage/buckets:
- get:
- tags:
- - Storage Buckets
- summary: List all storage buckets in a project
- description: |
- With no pagination params, returns the full bucket list as a bare array
- (legacy). Supplying `cursor`, `ending_before`, `search`, or `limit`
- switches to keyset (cursor) pagination and returns a paginated envelope
- with `next_cursor`/`prev_cursor` and a filtered `total`.
- operationId: listStorageBuckets
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/Limit'
- - $ref: '#/components/parameters/Cursor'
- - $ref: '#/components/parameters/EndingBefore'
- - $ref: '#/components/parameters/Offset'
- - $ref: '#/components/parameters/Search'
- responses:
- '200':
- description: |
- Either the full bucket list (bare array, legacy) or a paginated
- envelope when cursor pagination is requested.
+ $ref: '#/components/schemas/DatabaseQueryResult'
+ example:
+ data:
+ - ?column?: 1
+ count: 1
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
- oneOf:
- - type: array
- items:
- $ref: '#/components/schemas/StorageBucket'
- - $ref: '#/components/schemas/PaginatedStorageBuckets'
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Access denied. A service key whose `permissions` leave out `*` is refused with `service key scope does not include database access` once Volcano applies service key scopes to the database API.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Database not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '429':
+ $ref: '#/components/responses/DatabaseQueryCapExceeded'
+ /databases/{databaseName}/query/select:
post:
tags:
- - Storage Buckets
- summary: Create a new storage bucket
- operationId: createStorageBucket
+ - Database Queries
+ summary: Query database with SELECT (REST API)
+ description: |
+ Query your database using a simple REST API - no SQL required!
+
+ **Authentication:** Requires auth user access token (from signup/signin)
+
+ **Row-Level Security:** Applied on tables with RLS enabled. A table without RLS returns every row your role is granted
+
+ **Use Cases:**
+ - Query from browser/mobile apps
+ - Simple data retrieval
+ - Filtered searches with sorting and pagination
+
+ **Note:** For complex queries (JOINs, CTEs), use functions with direct SQL
+ operationId: queryDatabaseSelect
security:
- - UserToken: []
- - ProjectAccessToken: []
+ - AuthUserAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DatabaseName'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/CreateStorageBucketRequest'
+ $ref: '#/components/schemas/DatabaseSelectRequest'
responses:
- '201':
- description: Bucket created
- content:
+ '200':
+ description: Query successful
+ headers:
+ X-Volcano-Proxy-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyMs'
+ X-Volcano-Proxy-Handler-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
+ X-Volcano-Compute-Ms:
+ $ref: '#/components/headers/DatabaseQueryComputeMs'
+ content:
application/json:
schema:
- $ref: '#/components/schemas/StorageBucket'
- '409':
- description: Bucket already exists
- /projects/{id}/storage/buckets/{bucketName}:
- get:
- tags:
- - Storage Buckets
- summary: Get storage bucket by name
- operationId: getStorageBucket
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/BucketName'
- responses:
- '200':
- description: Bucket details
+ $ref: '#/components/schemas/DatabaseQueryResult'
+ example:
+ data:
+ - id: uuid-123
+ title: My Post
+ content: Post content
+ status: published
+ views: 150
+ created_at: '2026-01-13T10:00:00Z'
+ count: 1
+ '400':
+ description: Invalid query
content:
application/json:
schema:
- $ref: '#/components/schemas/StorageBucket'
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Access denied. A service key whose `permissions` leave out `*` is refused with `service key scope does not include database access` once Volcano applies service key scopes to the database API.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'404':
- description: Bucket not found
- patch:
+ description: Database not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '429':
+ $ref: '#/components/responses/DatabaseQueryCapExceeded'
+ /databases/{databaseName}/query/insert:
+ post:
tags:
- - Storage Buckets
- summary: Update storage bucket settings
- operationId: updateStorageBucket
+ - Database Queries
+ summary: Insert data into database (REST API)
+ description: |
+ Insert new rows into your database using REST API.
+
+ **Authentication:** Requires auth user access token
+
+ **Auto-set user_id:** If your table has a trigger using `auth.uid()`,
+ user_id will be automatically set to the authenticated user
+
+ **Security:** Row-Level Security policies are enforced
+ operationId: queryDatabaseInsert
security:
- - UserToken: []
- - ProjectAccessToken: []
+ - AuthUserAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/BucketName'
+ - $ref: '#/components/parameters/DatabaseName'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/UpdateStorageBucketRequest'
+ $ref: '#/components/schemas/DatabaseInsertRequest'
responses:
'200':
- description: Bucket updated
+ description: Insert successful
+ headers:
+ X-Volcano-Proxy-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyMs'
+ X-Volcano-Proxy-Handler-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
+ X-Volcano-Compute-Ms:
+ $ref: '#/components/headers/DatabaseQueryComputeMs'
content:
application/json:
schema:
- $ref: '#/components/schemas/StorageBucket'
- delete:
- tags:
- - Storage Buckets
- summary: Delete storage bucket and all objects
- operationId: deleteStorageBucket
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/BucketName'
- responses:
- '200':
- description: Bucket deleted
- /projects/{id}/storage/buckets/{bucketName}/policies:
- get:
- tags:
- - Storage Policies
- summary: List storage policies for a bucket
- operationId: listStoragePolicies
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/BucketName'
- responses:
- '200':
- description: List of policies
+ $ref: '#/components/schemas/DatabaseQueryResult'
+ example:
+ data:
+ - id: uuid-123
+ title: My New Post
+ content: This is the content
+ status: draft
+ user_id: user-uuid
+ created_at: '2026-01-13T10:00:00Z'
+ count: 1
+ '400':
+ description: Invalid request
content:
application/json:
schema:
- type: array
- items:
- $ref: '#/components/schemas/StoragePolicy'
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Access denied. A service key whose `permissions` leave out `*` is refused with `service key scope does not include database access` once Volcano applies service key scopes to the database API.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Database not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '429':
+ $ref: '#/components/responses/DatabaseQueryCapExceeded'
+ /databases/{databaseName}/query/update:
post:
tags:
- - Storage Policies
- summary: Create a storage policy
- operationId: createStoragePolicy
+ - Database Queries
+ summary: Update data in database (REST API)
+ description: |
+ Update existing rows in your database using REST API.
+
+ **Security:** Row-Level Security ensures you can only update data you have access to
+
+ **Safety:** Requires at least one filter to prevent accidental mass updates. A
+ request with no `filters` is rejected with `400` (mirrors delete). This matters
+ for service-key queries, which run with full access and bypass RLS.
+
+ **Note:** If RLS blocks the update, an empty result is returned (not an error)
+ operationId: queryDatabaseUpdate
security:
- - UserToken: []
- - ProjectAccessToken: []
+ - AuthUserAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/BucketName'
+ - $ref: '#/components/parameters/DatabaseName'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/CreateStoragePolicyRequest'
+ $ref: '#/components/schemas/DatabaseUpdateRequest'
responses:
- '201':
- description: Policy created
+ '200':
+ description: Update successful
+ headers:
+ X-Volcano-Proxy-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyMs'
+ X-Volcano-Proxy-Handler-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
+ X-Volcano-Compute-Ms:
+ $ref: '#/components/headers/DatabaseQueryComputeMs'
content:
application/json:
schema:
- $ref: '#/components/schemas/StoragePolicy'
- /projects/{id}/storage/buckets/{bucketName}/policies/{policyId}:
- delete:
- tags:
- - Storage Policies
- summary: Delete a storage policy
- operationId: deleteStoragePolicy
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- - $ref: '#/components/parameters/BucketName'
- - name: policyId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '200':
- description: Policy deleted
+ $ref: '#/components/schemas/DatabaseQueryResult'
+ example:
+ data:
+ - id: post-uuid
+ title: Updated Title
+ status: published
+ updated_at: '2026-01-13T10:05:00Z'
+ count: 1
+ '400':
+ description: Invalid request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Access denied. A service key whose `permissions` leave out `*` is refused with `service key scope does not include database access` once Volcano applies service key scopes to the database API.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'404':
- description: Project, bucket, or policy not found. Also returned when the policy ID is malformed or belongs to another bucket.
+ description: Database not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/storage/objects:
- get:
+ '429':
+ $ref: '#/components/responses/DatabaseQueryCapExceeded'
+ /databases/{databaseName}/query/delete:
+ post:
tags:
- - Storage Admin
- summary: List all storage objects in a project
+ - Database Queries
+ summary: Delete data from database (REST API)
description: |
- Returns a paginated list of all storage objects across all buckets in the project.
- Supports filtering by owner and pagination.
- operationId: listStorageObjectsAdmin
+ Delete rows from your database using REST API.
+
+ **Safety:** Requires at least one filter to prevent accidental mass deletions
+
+ **Security:** Row-Level Security ensures you can only delete data you have access to
+
+ **Note:** If RLS blocks the delete, an empty result is returned (not an error)
+ operationId: queryDatabaseDelete
security:
- - UserToken: []
- - ProjectAccessToken: []
+ - AuthUserAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
- - name: owner_id
- in: query
- description: Filter by owner user ID
- schema:
- type: string
- format: uuid
- - name: page
- in: query
- description: Page number (1-based)
- schema:
- type: integer
- default: 1
- minimum: 1
- - name: limit
- in: query
- description: Items per page
- schema:
- type: integer
- default: 50
- minimum: 1
- maximum: 100
- - $ref: '#/components/parameters/Cursor'
- - $ref: '#/components/parameters/EndingBefore'
- - $ref: '#/components/parameters/Offset'
- - $ref: '#/components/parameters/Search'
+ - $ref: '#/components/parameters/DatabaseName'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DatabaseDeleteRequest'
responses:
'200':
- description: Paginated list of storage objects
+ description: Delete successful
+ headers:
+ X-Volcano-Proxy-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyMs'
+ X-Volcano-Proxy-Handler-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
+ X-Volcano-Compute-Ms:
+ $ref: '#/components/headers/DatabaseQueryComputeMs'
content:
application/json:
schema:
- type: object
- properties:
- data:
- type: array
- items:
- $ref: '#/components/schemas/StorageObjectWithBucket'
- page:
- type: integer
- limit:
- type: integer
- total:
- type: integer
- has_more:
- type: boolean
- next_cursor:
- type: string
- description: Opaque cursor for the next page (cursor pagination only)
- prev_cursor:
- type: string
- description: Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`.
- /projects/{id}/storage/stats:
- get:
- tags:
- - Storage Admin
- summary: Get storage statistics for a project
- description: Returns aggregate storage statistics including bucket count, object count, and total size.
- operationId: getStorageStats
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- responses:
- '200':
- description: Storage statistics
+ $ref: '#/components/schemas/DatabaseQueryResult'
+ example:
+ data:
+ - id: post-uuid
+ title: Deleted Post
+ count: 1
+ '400':
+ description: Invalid request or missing filters
content:
application/json:
schema:
- $ref: '#/components/schemas/StorageStats'
- /projects/{id}/realtime/config:
- get:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Access denied. A service key whose `permissions` leave out `*` is refused with `service key scope does not include database access` once Volcano applies service key scopes to the database API.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Database not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '429':
+ $ref: '#/components/responses/DatabaseQueryCapExceeded'
+ /databases/{databaseName}/branches/{branchName}/query/ping:
+ post:
tags:
- - Realtime
- summary: Get realtime configuration for a project
- description: Returns the realtime configuration including enabled features and limits.
- operationId: getRealtimeConfig
+ - Database Queries
+ summary: Database connectivity probe (REST API)
+ description: |
+ Connectivity probe that runs a fixed `SELECT 1` through pgproxy, using the
+ same authentication, status/bandwidth gating, and metering as the other
+ `/query/*` endpoints.
+
+ Unlike those endpoints, ping takes **no request body** and performs **no
+ table-name validation**, so it works on any database — including a freshly
+ provisioned, empty one. It is a real committed round-trip through pgproxy,
+ so a `200` means the database is reachable and queryable. Used by the
+ dashboard's database connection test.
+
+ **Branch-targeted.** Runs against the named branch instead of the parent
+ database, using the branch's own credentials. The branch must be `active`
+ and unexpired. Nothing about this request can reach the parent's data.
+ operationId: queryDatabaseBranchPing
security:
- - UserToken: []
- - ProjectAccessToken: []
+ - AuthUserAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DatabaseName'
+ - $ref: '#/components/parameters/BranchName'
responses:
'200':
- description: Realtime configuration
+ description: Database is reachable
+ headers:
+ X-Volcano-Proxy-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyMs'
+ X-Volcano-Proxy-Handler-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
+ X-Volcano-Compute-Ms:
+ $ref: '#/components/headers/DatabaseQueryComputeMs'
content:
application/json:
schema:
- $ref: '#/components/schemas/RealtimeConfig'
+ $ref: '#/components/schemas/DatabaseQueryResult'
+ example:
+ data:
+ - ?column?: 1
+ count: 1
'401':
- description: Unauthorized
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Access denied. A service key whose `permissions` leave out `*` is refused with `service key scope does not include database access` once Volcano applies service key scopes to the database API.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
- description: Project not found
+ description: Database or branch not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- put:
+ '429':
+ $ref: '#/components/responses/DatabaseQueryCapExceeded'
+ '503':
+ $ref: '#/components/responses/DatabaseBranchQueryUnavailable'
+ /databases/{databaseName}/branches/{branchName}/query/select:
+ post:
tags:
- - Realtime
- summary: Update realtime configuration for a project
- description: Updates realtime settings including feature toggles and limits.
- operationId: updateRealtimeConfig
+ - Database Queries
+ summary: Query database with SELECT (REST API)
+ description: |
+ Query your database using a simple REST API - no SQL required!
+
+ **Authentication:** Requires auth user access token (from signup/signin)
+
+ **Row-Level Security:** Applied on tables with RLS enabled. A table without RLS returns every row your role is granted
+
+ **Use Cases:**
+ - Query from browser/mobile apps
+ - Simple data retrieval
+ - Filtered searches with sorting and pagination
+
+ **Note:** For complex queries (JOINs, CTEs), use a function with direct SQL
+
+ **Branch-targeted.** Runs against the named branch instead of the parent
+ database, using the branch's own credentials. The branch must be `active`
+ and unexpired. Nothing about this request can reach the parent's data.
+ operationId: queryDatabaseBranchSelect
security:
- - UserToken: []
- - ProjectAccessToken: []
+ - AuthUserAccessToken: []
parameters:
- - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/DatabaseName'
+ - $ref: '#/components/parameters/BranchName'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/UpdateRealtimeConfigRequest'
+ $ref: '#/components/schemas/DatabaseSelectRequest'
responses:
'200':
- description: Updated realtime configuration
+ description: Query successful
+ headers:
+ X-Volcano-Proxy-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyMs'
+ X-Volcano-Proxy-Handler-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
+ X-Volcano-Compute-Ms:
+ $ref: '#/components/headers/DatabaseQueryComputeMs'
content:
application/json:
schema:
- $ref: '#/components/schemas/RealtimeConfig'
+ $ref: '#/components/schemas/DatabaseQueryResult'
+ example:
+ data:
+ - id: uuid-123
+ title: My Post
+ content: Post content
+ status: published
+ views: 150
+ created_at: '2026-01-13T10:00:00Z'
+ count: 1
'400':
- description: Invalid configuration values
+ description: Invalid query
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
- description: Unauthorized
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /projects/{id}/realtime/stats:
- get:
- tags:
- - Realtime
- summary: Get realtime statistics for a project
- description: Returns realtime usage statistics including connection counts and subscribed tables.
- operationId: getRealtimeStats
- security:
- - UserToken: []
- - ProjectAccessToken: []
- parameters:
- - $ref: '#/components/parameters/ProjectId'
- responses:
- '200':
- description: Realtime statistics
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/RealtimeStats'
- '401':
- description: Unauthorized
+ '403':
+ description: Access denied. A service key whose `permissions` leave out `*` is refused with `service key scope does not include database access` once Volcano applies service key scopes to the database API.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- /storage/{bucketName}:
- get:
- tags:
- - Storage Objects
- summary: List objects in a bucket
- operationId: listStorageObjects
- security:
- - AnonKey: []
- - ServiceRoleKey: []
- - AuthUserAccessToken: []
- parameters:
- - $ref: '#/components/parameters/BucketName'
- - name: prefix
- in: query
- description: Filter objects by path prefix
- schema:
- type: string
- - name: limit
- in: query
- description: Maximum objects to return
- schema:
- type: integer
- default: 50
- maximum: 1000
- - name: cursor
- in: query
- description: Pagination cursor
- schema:
- type: string
- responses:
- '200':
- description: List of objects
+ '404':
+ description: Database or branch not found
content:
application/json:
schema:
- $ref: '#/components/schemas/StorageListResponse'
- '403':
- description: Access denied by storage policy
+ $ref: '#/components/schemas/Error'
'429':
- $ref: '#/components/responses/BandwidthCapExceeded'
- /locks/{key}/lease:
+ $ref: '#/components/responses/DatabaseQueryCapExceeded'
+ '503':
+ $ref: '#/components/responses/DatabaseBranchQueryUnavailable'
+ /databases/{databaseName}/branches/{branchName}/query/insert:
post:
tags:
- - Locks
- summary: Acquire a project lock
+ - Database Queries
+ summary: Insert data into database (REST API)
description: |
- Acquires a project-scoped lease using the project embedded in the service-role key.
- The caller must hold the `locks.manage` permission. Repeating the request with the
- same lock token is idempotent and resets that lease to the requested TTL. A different
- live owner receives `409 lock_held`; a caller whose own lease already lapsed receives
- `409 lock_ownership_lost`.
- operationId: acquireProjectLock
+ Insert new rows into your database using REST API.
+
+ **Authentication:** Requires auth user access token
+
+ **Auto-set user_id:** If your table has a trigger using `auth.uid()`,
+ user_id will be automatically set to the authenticated user
+
+ **Security:** Row-Level Security policies are enforced
+
+ **Branch-targeted.** Runs against the named branch instead of the parent
+ database, using the branch's own credentials. The branch must be `active`
+ and unexpired. Nothing about this request can reach the parent's data.
+ operationId: queryDatabaseBranchInsert
security:
- - ServiceRoleKey: []
+ - AuthUserAccessToken: []
parameters:
- - $ref: '#/components/parameters/LockKey'
- - $ref: '#/components/parameters/LockToken'
- - $ref: '#/components/parameters/LockRequestId'
+ - $ref: '#/components/parameters/DatabaseName'
+ - $ref: '#/components/parameters/BranchName'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectLockLeaseRequest'
+ $ref: '#/components/schemas/DatabaseInsertRequest'
responses:
- '201':
- description: Lease acquired
+ '200':
+ description: Insert successful
+ headers:
+ X-Volcano-Proxy-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyMs'
+ X-Volcano-Proxy-Handler-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
+ X-Volcano-Compute-Ms:
+ $ref: '#/components/headers/DatabaseQueryComputeMs'
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectLockLease'
+ $ref: '#/components/schemas/DatabaseQueryResult'
+ example:
+ data:
+ - id: uuid-123
+ title: My New Post
+ content: This is the content
+ status: draft
+ user_id: user-uuid
+ created_at: '2026-01-13T10:00:00Z'
+ count: 1
'400':
- description: Invalid lock key, token, or TTL
+ description: Invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
- description: Missing or invalid credentials
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: A non-service credential was supplied or the service key lacks `locks.manage`
+ description: Access denied. A service key whose `permissions` leave out `*` is refused with `service key scope does not include database access` once Volcano applies service key scopes to the database API.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: |
- The lock is held by another live lease (`lock_held`), or the caller's own lease
- lapsed and is not yet reclaimable (`lock_ownership_lost`).
+ '404':
+ description: Database or branch not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
- description: Project lock request limit exceeded
- headers:
- Retry-After:
- description: Seconds until the current fixed-minute window ends.
- schema:
- type: integer
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
+ $ref: '#/components/responses/DatabaseQueryCapExceeded'
'503':
- description: Lock service unavailable
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- patch:
+ $ref: '#/components/responses/DatabaseBranchQueryUnavailable'
+ /databases/{databaseName}/branches/{branchName}/query/update:
+ post:
tags:
- - Locks
- summary: Renew a project lock
+ - Database Queries
+ summary: Update data in database (REST API)
description: |
- Renews a lease owned by the supplied lock token. The request must arrive
- more than one second before `expires_at`; this safety margin prevents
- clock skew between regional API instances from resurrecting an expired
- lease.
- operationId: renewProjectLock
+ Update existing rows in your database using REST API.
+
+ **Security:** Row-Level Security ensures you can only update data you have access to
+
+ **Safety:** Requires at least one filter to prevent accidental mass updates. A
+ request with no `filters` is rejected with `400` (mirrors delete). This matters
+ for service-key queries, which run with full access and bypass RLS.
+
+ **Note:** If RLS blocks the update, an empty result is returned (not an error)
+
+ **Branch-targeted.** Runs against the named branch instead of the parent
+ database, using the branch's own credentials. The branch must be `active`
+ and unexpired. Nothing about this request can reach the parent's data.
+ operationId: queryDatabaseBranchUpdate
security:
- - ServiceRoleKey: []
+ - AuthUserAccessToken: []
parameters:
- - $ref: '#/components/parameters/LockKey'
- - $ref: '#/components/parameters/LockToken'
- - $ref: '#/components/parameters/LockRequestId'
+ - $ref: '#/components/parameters/DatabaseName'
+ - $ref: '#/components/parameters/BranchName'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectLockLeaseRequest'
+ $ref: '#/components/schemas/DatabaseUpdateRequest'
responses:
'200':
- description: Lease renewed
+ description: Update successful
+ headers:
+ X-Volcano-Proxy-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyMs'
+ X-Volcano-Proxy-Handler-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
+ X-Volcano-Compute-Ms:
+ $ref: '#/components/headers/DatabaseQueryComputeMs'
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectLockLease'
+ $ref: '#/components/schemas/DatabaseQueryResult'
+ example:
+ data:
+ - id: post-uuid
+ title: Updated Title
+ status: published
+ updated_at: '2026-01-13T10:05:00Z'
+ count: 1
'400':
- description: Invalid lock key, token, or TTL
+ description: Invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
- description: Missing or invalid credentials
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
- description: A non-service credential was supplied or the service key lacks `locks.manage`
+ description: Access denied. A service key whose `permissions` leave out `*` is refused with `service key scope does not include database access` once Volcano applies service key scopes to the database API.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '409':
- description: The lease expired or is owned by another token
+ '404':
+ description: Database or branch not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
- description: Project lock request limit exceeded
+ $ref: '#/components/responses/DatabaseQueryCapExceeded'
+ '503':
+ $ref: '#/components/responses/DatabaseBranchQueryUnavailable'
+ /databases/{databaseName}/branches/{branchName}/query/delete:
+ post:
+ tags:
+ - Database Queries
+ summary: Delete data from database (REST API)
+ description: |
+ Delete rows from your database using REST API.
+
+ **Safety:** Requires at least one filter to prevent accidental mass deletions
+
+ **Security:** Row-Level Security ensures you can only delete data you have access to
+
+ **Note:** If RLS blocks the delete, an empty result is returned (not an error)
+
+ **Branch-targeted.** Runs against the named branch instead of the parent
+ database, using the branch's own credentials. The branch must be `active`
+ and unexpired. Nothing about this request can reach the parent's data.
+ operationId: queryDatabaseBranchDelete
+ security:
+ - AuthUserAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/DatabaseName'
+ - $ref: '#/components/parameters/BranchName'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DatabaseDeleteRequest'
+ responses:
+ '200':
+ description: Delete successful
headers:
- Retry-After:
- description: Seconds until the current fixed-minute window ends.
+ X-Volcano-Proxy-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyMs'
+ X-Volcano-Proxy-Handler-Ms:
+ $ref: '#/components/headers/DatabaseQueryProxyHandlerMs'
+ X-Volcano-Compute-Ms:
+ $ref: '#/components/headers/DatabaseQueryComputeMs'
+ content:
+ application/json:
schema:
- type: integer
+ $ref: '#/components/schemas/DatabaseQueryResult'
+ example:
+ data:
+ - id: post-uuid
+ title: Deleted Post
+ count: 1
+ '400':
+ description: Invalid request or missing filters
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '503':
- description: Lock service unavailable
+ '401':
+ description: Not authenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- delete:
- tags:
- - Locks
- summary: Release a project lock
- description: Releases a lease only when the supplied lock token still owns it.
- operationId: releaseProjectLock
- security:
- - ServiceRoleKey: []
- parameters:
- - $ref: '#/components/parameters/LockKey'
- - $ref: '#/components/parameters/LockToken'
- - $ref: '#/components/parameters/LockRequestId'
- responses:
- '204':
- description: Lease released
- '400':
- description: Invalid lock key or token
+ '403':
+ description: Access denied. A service key whose `permissions` leave out `*` is refused with `service key scope does not include database access` once Volcano applies service key scopes to the database API.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Missing or invalid credentials
+ '404':
+ description: Database or branch not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: A non-service credential was supplied or the service key lacks `locks.manage`
+ '429':
+ $ref: '#/components/responses/DatabaseQueryCapExceeded'
+ '503':
+ $ref: '#/components/responses/DatabaseBranchQueryUnavailable'
+ /databases/regions:
+ get:
+ tags:
+ - Databases
+ summary: List platform-supported regions for database provisioning
+ operationId: listDatabaseRegions
+ description: |
+ Returns the regions enabled for database provisioning in this platform environment.
+ These are the same regions offered for function deployment, and the only values
+ the `region` field of a database accepts.
+ This is a public endpoint that doesn't require authentication.
+ responses:
+ '200':
+ description: List of platform-supported regions
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- '409':
- description: The lease is owned by another token
+ type: array
+ items:
+ type: object
+ properties:
+ id:
+ type: string
+ example: us-east-1
+ description: Region identifier for API usage
+ name:
+ type: string
+ example: US East (N. Virginia)
+ description: Human-readable region location
+ /databases/postgres-versions:
+ get:
+ tags:
+ - Databases
+ summary: List available PostgreSQL versions
+ operationId: listPostgresVersions
+ description: |
+ Returns the PostgreSQL major versions a database can be created on,
+ newest first. Local mode lists only the version its server runs.
+ This is a public endpoint that doesn't require authentication.
+ responses:
+ '200':
+ description: List of available PostgreSQL versions
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- '429':
- description: Project lock request limit exceeded
- headers:
- Retry-After:
- description: Seconds until the current fixed-minute window ends.
- schema:
- type: integer
+ type: array
+ items:
+ type: object
+ properties:
+ version:
+ type: string
+ example: '18'
+ description: PostgreSQL major version number
+ name:
+ type: string
+ example: PostgreSQL 18
+ description: Human-readable version name
+ default:
+ type: boolean
+ description: True on the version to preselect for a new database; absent on the others
+ recommended:
+ type: boolean
+ description: True on the version recommended for new databases; absent on the others
+ deprecated:
+ type: boolean
+ description: Whether this version is deprecated (approaching EOL)
+ /functions/runtimes:
+ get:
+ tags:
+ - Functions
+ summary: List supported function runtimes
+ operationId: listFunctionRuntimes
+ security: []
+ description: |
+ Returns the public function runtime catalog: every runtime a deploy accepts, its display
+ label for runtime pickers, language defaults, durable capability, and local source packaging
+ metadata for deployments.
+ This is a public endpoint that doesn't require authentication.
+ responses:
+ '200':
+ description: Supported function runtimes
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- '503':
- description: Lock service unavailable
+ $ref: '#/components/schemas/FunctionRuntimesResponse'
+ /functions/regions:
+ get:
+ tags:
+ - Functions
+ summary: List available regions for function deployment
+ operationId: listFunctionRegions
+ security: []
+ description: |
+ Returns the configured regions where functions can be deployed, each annotated
+ with a human-readable label and country flag emoji for use in UI pickers.
+ This is a public endpoint that doesn't require authentication.
+ responses:
+ '200':
+ description: Available function deployment regions
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- /locks/{key}:
+ type: array
+ items:
+ $ref: '#/components/schemas/FunctionRegion'
+ /projects/{id}/variables/{name}:
get:
tags:
- - Locks
- summary: Read a project lock
+ - Variables
+ summary: Get variable by name
description: |
- Reports whether the lock is currently held, when its lease expires, and the
- holder's fencing token. `held` follows takeover eligibility rather than raw
- expiry, so `held: false` means an acquire would succeed now. No lock token is
- required, making this usable for monitoring and recovery.
- operationId: getProjectLock
+ Returns a project-level environment variable used by deployed functions and frontends.
+ operationId: getVariable
security:
- - ServiceRoleKey: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/LockKey'
- - $ref: '#/components/parameters/LockRequestId'
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/VariableName'
responses:
'200':
- description: Current lock state
+ description: Successful response
content:
application/json:
schema:
- $ref: '#/components/schemas/ProjectLockState'
- '400':
- description: Invalid lock key
+ $ref: '#/components/schemas/Variable'
+ '404':
+ description: Variable not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '401':
- description: Missing or invalid credentials
+ put:
+ tags:
+ - Variables
+ summary: Update a variable
+ description: |
+ Updates a project-level environment variable and triggers asynchronous propagation
+ to deployed functions and frontends in the project's configured regions.
+ operationId: updateVariable
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/VariableName'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateVariableRequest'
+ responses:
+ '200':
+ description: Variable updated
content:
application/json:
schema:
- $ref: '#/components/schemas/Error'
- '403':
- description: A non-service credential was supplied or the service key lacks `locks.manage`
+ $ref: '#/components/schemas/Variable'
+ '400':
+ description: Invalid or reserved variable name
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
- description: Project lock request limit exceeded
- headers:
- Retry-After:
- description: Seconds until the current fixed-minute window ends.
- schema:
- type: integer
+ '404':
+ description: Variable not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
- description: Lock service unavailable
+ description: Private variable membership writes are disabled during rollout
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
tags:
- - Locks
- summary: Force release a project lock
+ - Variables
+ summary: Delete a variable
description: |
- Drops the lease whatever token holds it, for recovering a lock whose holder
- died without releasing. Use `DELETE /locks/{key}/lease` for normal release.
-
- This breaks mutual exclusion by itself: the previous holder keeps working
- until its own renewal fails. Guard the protected resource with the lease's
- `fencing_token`, which the next acquisition raises, so a write from the
- displaced holder can be rejected. Succeeds when the lock is already absent.
- operationId: forceReleaseProjectLock
+ Deletes a project-level environment variable and triggers asynchronous propagation
+ of the removal to deployed functions and frontends in the project's configured regions.
+ operationId: deleteVariable
security:
- - ServiceRoleKey: []
+ - UserToken: []
+ - ProjectAccessToken: []
parameters:
- - $ref: '#/components/parameters/LockKey'
- - $ref: '#/components/parameters/LockRequestId'
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/VariableName'
responses:
'204':
- description: Lock released
- '400':
- description: Invalid lock key
+ description: Variable deleted
+ '404':
+ description: Variable not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
+ /auth/password-policy:
+ get:
+ tags:
+ - Authentication
+ summary: Get the effective password policy
+ description: |
+ Returns the backend-enforced password bounds and compromised-password
+ screening status for the project identified by the anon key. A valid
+ anon key is required, but no route-specific auth permission is needed.
+ operationId: authGetPasswordPolicy
+ security:
+ - AnonKey: []
+ parameters:
+ - $ref: '#/components/parameters/AuthProxyAuthorization'
+ - $ref: '#/components/parameters/AuthProxyClientIP'
+ responses:
+ '200':
+ description: Effective password policy
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AuthPasswordPolicy'
'401':
- description: Missing or invalid credentials
+ description: Invalid, missing, or revoked anon key; or invalid auth proxy metadata
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '403':
- description: A non-service credential was supplied or the service key lacks `locks.manage`
+ '404':
+ description: Project or auth configuration not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '429':
- description: Project lock request limit exceeded
- headers:
- Retry-After:
- description: Seconds until the current fixed-minute window ends.
- schema:
- type: integer
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- '503':
- description: Lock service unavailable
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- /storage/{bucketName}/move:
+ /auth/signup:
post:
tags:
- - Storage Objects
- summary: Move/rename an object
- operationId: moveStorageObject
+ - Authentication
+ summary: Sign up a new auth user
+ description: |
+ Create a new end-user account. The project is determined from the anon key.
+ Requires project-specific anon key in Authorization header.
+
+ **Session-less**: signup never issues a session. On success it returns a
+ uniform acknowledgement (`AuthSignupResponse`) with no tokens; the client
+ obtains a session with a subsequent `POST /auth/signin`. If email confirmation
+ is enabled for the project, a confirmation email is sent and
+ `confirmation_required` is `true`.
+
+ **Anti-enumeration**: a signup for an already-registered email returns the
+ exact same `201` response as a fresh signup — it never returns `409` — so the
+ response cannot be used to discover which emails are registered.
+ operationId: authSignup
security:
- - ServiceRoleKey: []
- - AuthUserAccessToken: []
+ - AnonKey: []
parameters:
- - $ref: '#/components/parameters/BucketName'
+ - $ref: '#/components/parameters/AuthProxyAuthorization'
+ - $ref: '#/components/parameters/AuthProxyClientIP'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/StorageMoveRequest'
+ type: object
+ required:
+ - email
+ - password
+ properties:
+ email:
+ type: string
+ format: email
+ password:
+ type: string
+ description: |
+ Password validated after NFC normalization against the
+ policy returned by GET /auth/password-policy.
+ user_metadata:
+ type: object
+ additionalProperties: true
responses:
- '200':
- description: Object moved
+ '201':
+ description: |
+ Signup acknowledged (session-less). Returned identically for a new
+ account and for an already-registered email (anti-enumeration).
content:
application/json:
schema:
- $ref: '#/components/schemas/StorageObject'
+ $ref: '#/components/schemas/AuthSignupResponse'
+ '400':
+ description: Invalid input (bad email/password format)
+ '401':
+ description: |
+ Unauthorized - Invalid, tampered, revoked, or wrong-project anon key.
+ Also returned for invalid, repeated, or under-scoped auth proxy metadata
+ (`invalid auth proxy metadata`).
'403':
- description: Access denied by storage policy
+ description: |
+ Forbidden - Signups disabled, anon key lacks signup permission, or the
+ email domain is not in `allowed_email_domains`. The internal
+ `anonymous.volcano.internal` and `volcano.local` domains are reserved
+ for the anonymous and Builder debug accounts Volcano creates, and are
+ refused whatever the project allows.
'429':
- $ref: '#/components/responses/BandwidthCapExceeded'
- /storage/{bucketName}/copy:
+ description: Rate limit exceeded
+ '503':
+ description: Compromised-password screening is temporarily unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/signin:
post:
tags:
- - Storage Objects
- summary: Copy an object
- operationId: copyStorageObject
+ - Authentication
+ summary: Sign in an auth user
+ description: |
+ Authenticate with email and password. Requires an anon key.
+
+ Set `session_mode` to `cookie` to request HttpOnly refresh-token
+ storage. Cookie mode is honored only for an exact, credentialed CORS
+ origin on the same schemeful site as this API. Otherwise the response
+ retains the refresh token in its body. A frontend on its default
+ Volcano URL is cross-site with this API and so always gets the body
+ token.
+ operationId: authSignin
security:
- - ServiceRoleKey: []
- - AuthUserAccessToken: []
+ - AnonKey: []
parameters:
- - $ref: '#/components/parameters/BucketName'
+ - $ref: '#/components/parameters/AuthProxyAuthorization'
+ - $ref: '#/components/parameters/AuthProxyClientIP'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/StorageCopyRequest'
+ type: object
+ required:
+ - email
+ - password
+ properties:
+ email:
+ type: string
+ password:
+ type: string
+ session_mode:
+ type: string
+ enum:
+ - cookie
responses:
- '201':
- description: Object copied
+ '200':
+ description: Signin successful
content:
application/json:
schema:
- $ref: '#/components/schemas/StorageObject'
+ $ref: '#/components/schemas/AuthTokenResponse'
+ '400':
+ description: Invalid input (missing email/password)
+ '401':
+ description: |
+ Unauthorized - Invalid credentials, invalid/tampered/revoked anon key,
+ or account banned/deleted; or invalid auth proxy metadata
'403':
- description: Access denied by storage policy
+ description: |
+ Forbidden - Email/password is turned off for the project
+ (`enable_email_password: false`), the anon key lacks signin
+ permission, or the email domain is not in `allowed_email_domains`
+ while `allowed_email_domains_mode` is `signup_and_signin`. Both the
+ account's canonical email (its primary identity) and the email signed
+ in with must be on the list.
'429':
- $ref: '#/components/responses/BandwidthCapExceeded'
- /storage/{bucketName}/{path}:
+ description: Rate limit exceeded
+ /auth/refresh:
post:
tags:
- - Storage Objects
- summary: Upload a file or create resumable session
+ - Authentication
+ summary: Refresh access token
description: |
- Unified endpoint for file uploads. Behavior depends on Content-Type and headers:
-
- **Simple Upload (multipart/form-data):**
- Upload a complete file in a single request. Best for files under 100MB.
-
- **Create Resumable Session (application/json):**
- Create a session for chunked uploads. Best for large files or unreliable networks.
- Requires: `Content-Type: application/json` with body `{"filename": "...", "content_type": "...", "total_size": ...}`
-
- **Complete Resumable Session:**
- Complete a session after all parts are uploaded.
- Requires: `X-Upload-Session` header with session ID and `X-Upload-Complete: true` header.
+ Get a new access token using a refresh token. Requires an anon key.
- **Resumable Session Ownership:**
- A session created with a user access token remains bound to that user. A session
- created with an anon key remains bound to that exact anon key. Reuse the same
- identity or anon key for part uploads, status, completion, and abort requests;
- an ownership mismatch returns `404`.
- operationId: uploadStorageObject
+ Send `refresh_token` in the body for the default flow. An eligible
+ cookie-mode browser request may instead send `session_mode: cookie`
+ with an empty token or omit the request body; the API reads and resets
+ the project's HttpOnly cookie and omits `refresh_token` from the
+ response.
+ operationId: authRefresh
security:
- AnonKey: []
- - ServiceRoleKey: []
- - AuthUserAccessToken: []
parameters:
- - $ref: '#/components/parameters/BucketName'
- - name: path
- in: path
- required: true
- description: Object path within bucket
- schema:
- type: string
- - name: X-Upload-Session
- in: header
- required: false
- description: Upload session ID (for completing resumable uploads)
- schema:
- type: string
- - name: X-Upload-Complete
- in: header
- required: false
- description: Set to "true" to complete a resumable upload session
- schema:
- type: string
- enum:
- - 'true'
+ - $ref: '#/components/parameters/AuthProxyAuthorization'
+ - $ref: '#/components/parameters/AuthProxyClientIP'
requestBody:
- required: true
+ required: false
content:
- multipart/form-data:
+ application/json:
schema:
type: object
- required:
- - file
properties:
- file:
+ refresh_token:
type: string
- format: binary
- description: File to upload (simple upload)
- application/json:
- schema:
- $ref: '#/components/schemas/CreateUploadSessionRequest'
+ session_mode:
+ type: string
+ enum:
+ - cookie
responses:
'200':
- description: Resumable upload completed (when X-Upload-Complete=true)
+ description: Token refreshed
content:
application/json:
schema:
- $ref: '#/components/schemas/CompleteUploadSessionResponse'
- '201':
- description: File uploaded or session created
+ $ref: '#/components/schemas/AuthTokenResponse'
+ '401':
+ description: Invalid or expired refresh token; or invalid auth proxy metadata
content:
application/json:
schema:
- oneOf:
- - $ref: '#/components/schemas/StorageObject'
- - $ref: '#/components/schemas/CreateUploadSessionResponse'
- '400':
- description: |
- Bad request. This can occur when:
- - MIME type is not in the bucket's allowed_mime_types list
- - File exceeds the bucket's configured file_size_limit
- - File exceeds the global maximum upload size (5GB)
- - Invalid request body or missing required fields
+ $ref: '#/components/schemas/Error'
'403':
- description: Access denied by storage policy
- '404':
- description: Resumable upload session not found or not owned by this credential
- '413':
description: |
- File size exceeds plan-based limits. This occurs when:
- - File exceeds the plan-based maximum file size (HOBBY or SUPERAGENT tier)
- - The account on the HOBBY plan holds its file-storage allowance.
- Enforcement is eventual: uploads are accepted until Volcano's
- next allowance check sees the account at its allowance
+ The account's canonical email, or the email of the identity the
+ session signed in with, is not in `allowed_email_domains` while
+ `allowed_email_domains_mode` is `signup_and_signin`, so the session
+ cannot be extended
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'429':
- $ref: '#/components/responses/BandwidthCapExceeded'
- put:
- tags:
- - Storage Objects
- summary: Upload a part of a resumable upload
- description: |
- Upload a single part of a resumable upload session.
-
- **Requirements:**
- - Part numbers start at 1
- - All parts except the last must be at least 5MB
- - Maximum part size is 25MB
- - Parts can be uploaded in any order
- - Re-uploading a part overwrites the previous upload
- - Anonymous sessions must reuse the exact anon key that created the session
- operationId: uploadPart
+ description: Rate limit exceeded
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/logout:
+ post:
+ tags:
+ - Authentication
+ summary: Logout (revoke refresh token)
+ description: |
+ Invalidate a refresh token. Requires an anon key.
+
+ Send `refresh_token` for the default flow. An eligible cookie-mode
+ browser request may instead send `session_mode: cookie` with an empty
+ token; logout remains idempotent when the cookie is missing or expired.
+ operationId: authLogout
security:
- AnonKey: []
- - ServiceRoleKey: []
- - AuthUserAccessToken: []
parameters:
- - $ref: '#/components/parameters/BucketName'
- - name: path
- in: path
- required: true
- description: Object path within bucket
- schema:
- type: string
- - name: X-Upload-Session
- in: header
- required: true
- description: Upload session ID
- schema:
- type: string
- - name: X-Part-Number
- in: header
- required: true
- description: Part number (1 to 10000)
- schema:
- type: integer
- minimum: 1
- maximum: 10000
+ - $ref: '#/components/parameters/AuthProxyAuthorization'
+ - $ref: '#/components/parameters/AuthProxyClientIP'
requestBody:
- required: true
+ required: false
content:
- application/octet-stream:
+ application/json:
schema:
- type: string
- format: binary
+ type: object
+ properties:
+ refresh_token:
+ type: string
+ session_mode:
+ type: string
+ enum:
+ - cookie
responses:
- '200':
- description: Part uploaded
+ '204':
+ description: Logged out successfully
+ '401':
+ description: Missing, invalid, or revoked anon key; or invalid, repeated, or under-scoped auth proxy metadata
content:
application/json:
schema:
- $ref: '#/components/schemas/UploadSessionPart'
- '400':
- description: Invalid part number or part data
- '403':
- description: Access denied
- '404':
- description: Session not found or not owned by this credential
- get:
+ $ref: '#/components/schemas/Error'
+ /auth/forgot-password:
+ post:
tags:
- - Storage Objects
- summary: Download a file or get upload session status
+ - Authentication
+ summary: Request password reset
description: |
- Download a file, or get the status of a resumable upload session.
-
- **File Download (default):**
- Downloads the file at the specified path.
-
- **Session Status (with X-Upload-Session header):**
- Returns the status of a resumable upload session, including which parts have been uploaded.
- Anonymous sessions must reuse the exact anon key that created the session.
- operationId: downloadStorageObject
+ Generates recovery token and stores it (email sending pending).
+ Returns generic message to prevent email enumeration.
+ Project is identified via the anon key.
+ operationId: authForgotPassword
security:
- AnonKey: []
- - ServiceRoleKey: []
- - AuthUserAccessToken: []
parameters:
- - $ref: '#/components/parameters/BucketName'
- - name: path
- in: path
- required: true
- description: Object path within bucket
- schema:
- type: string
- - name: Range
- in: header
- required: false
- description: |
- HTTP Range header for partial downloads.
- Format: bytes=start-end or bytes=start-
- Examples: bytes=0-1023, bytes=1000-
- schema:
- type: string
- pattern: ^bytes=\d+-\d*$
- - name: X-Upload-Session
- in: header
- required: false
- description: Upload session ID (to get session status instead of downloading)
- schema:
- type: string
+ - $ref: '#/components/parameters/AuthProxyAuthorization'
+ - $ref: '#/components/parameters/AuthProxyClientIP'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - email
+ properties:
+ email:
+ type: string
+ format: email
responses:
'200':
- description: File content or session status
- headers:
- Content-Type:
- schema:
- type: string
- Content-Length:
- schema:
- type: integer
- ETag:
- schema:
- type: string
+ description: Generic success message (doesn't reveal if email exists)
content:
- application/octet-stream:
+ application/json:
schema:
- type: string
- format: binary
+ type: object
+ properties:
+ message:
+ type: string
+ example: If the email exists, a password reset link has been sent
+ '401':
+ description: Missing, invalid, or revoked anon key; or invalid, repeated, or under-scoped auth proxy metadata
+ content:
application/json:
schema:
- $ref: '#/components/schemas/UploadSessionStatusResponse'
- '206':
- description: Partial content (range request)
- '400':
- description: Invalid Range header format
+ $ref: '#/components/schemas/Error'
'403':
- description: Access denied by storage policy
- '404':
- description: Object or session not found, or session not owned by this credential
+ description: Password reset or email/password is turned off for this project
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'429':
- $ref: '#/components/responses/BandwidthCapExceeded'
- delete:
+ description: Rate limit exceeded (10 requests per hour per IP)
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/reset-password:
+ post:
tags:
- - Storage Objects
- summary: Delete a file or abort upload session
+ - Authentication
+ summary: Reset password with recovery token
description: |
- Delete a file, or abort a resumable upload session.
-
- **File Delete (default):**
- Deletes the file at the specified path.
-
- **Abort Session (with X-Upload-Session header):**
- Aborts a resumable upload session and cleans up any uploaded parts.
- Anonymous sessions must reuse the exact anon key that created the session.
- operationId: deleteStorageObject
+ Reset password using recovery token from forgot-password.
+ Revokes all existing sessions for security.
+ operationId: authResetPassword
security:
- AnonKey: []
- - ServiceRoleKey: []
- - AuthUserAccessToken: []
- parameters:
- - $ref: '#/components/parameters/BucketName'
- - name: path
- in: path
- required: true
- description: Object path within bucket
- schema:
- type: string
- - name: X-Upload-Session
- in: header
- required: false
- description: Upload session ID (to abort session instead of deleting file)
- schema:
- type: string
- responses:
- '200':
- description: Object deleted or session aborted
- '403':
- description: Access denied by storage policy
- '404':
- description: Object or session not found, or session not owned by this credential
- '429':
- $ref: '#/components/responses/BandwidthCapExceeded'
- /storage/{bucketName}/{path}/visibility:
- patch:
- tags:
- - Storage Objects
- summary: Update file visibility (public/private)
- description: |
- Change whether a file is publicly accessible. Only the file owner or a service key can change visibility.
- If the bucket defines UPDATE policies, the owner must also satisfy one of them.
-
- - Public files can be downloaded with just an anon key (no user authentication required)
- - Private files (default) require authentication and must pass policy checks
- - All downloads go through the Volcano API - there is no direct access to the underlying store
- operationId: updateStorageObjectVisibility
- security:
- - ServiceRoleKey: []
- - AuthUserAccessToken: []
parameters:
- - $ref: '#/components/parameters/BucketName'
- - name: path
- in: path
- required: true
- description: Object path within bucket
- schema:
- type: string
+ - $ref: '#/components/parameters/AuthProxyAuthorization'
+ - $ref: '#/components/parameters/AuthProxyClientIP'
requestBody:
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/StorageVisibilityRequest'
- responses:
- '200':
- description: Visibility updated
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/StorageObject'
- '403':
- description: Not the file owner or denied by the bucket's UPDATE policies
- '404':
- description: Object not found
- /public/{projectId}/{bucketName}/{path}:
- get:
- tags:
- - Storage Objects
- summary: Download a public file (no authentication required)
- description: |
- Download a file that has been marked as public. This endpoint requires NO authentication.
-
- **Access Requirements:**
- - The file must have `is_public: true` set via the visibility endpoint
- - Private files will return 403 Forbidden
-
- **Use Cases:**
- - Shareable public URLs for profile pictures, public documents, etc.
- - Embedding public files on external websites
- - Direct linking without requiring SDK or authentication
-
- **URL Format:**
- ```
- GET /public/{projectId}/{bucketName}/{path}
- ```
-
- **Example:**
- ```
- https://api.volcano.dev/public/abc123/avatars/user-photo.jpg
- ```
-
- **CORS:**
- This endpoint allows all origins since the file is already public.
- operationId: downloadPublicFile
- parameters:
- - name: projectId
- in: path
- required: true
- description: Project ID
- schema:
- type: string
- format: uuid
- - $ref: '#/components/parameters/BucketName'
- - name: path
- in: path
- required: true
- description: Object path within bucket
- schema:
- type: string
+ type: object
+ required:
+ - token
+ - new_password
+ properties:
+ token:
+ type: string
+ description: Recovery token from forgot-password
+ new_password:
+ type: string
+ description: |
+ Password validated after NFC normalization against the
+ policy returned by GET /auth/password-policy.
responses:
'200':
- description: File content
+ description: Password reset successful
content:
- '*/*':
+ application/json:
schema:
- type: string
- format: binary
- '206':
- description: Partial content (range request)
- '404':
- description: Not found (file doesn't exist or is not public)
- '429':
- $ref: '#/components/responses/BandwidthCapExceeded'
- /health:
- get:
- tags:
- - System
- summary: Health check endpoint
- description: Returns server health status. Used for load balancer and monitoring checks.
- operationId: healthCheck
- responses:
- '200':
- description: Server is healthy
+ type: object
+ properties:
+ message:
+ type: string
+ '400':
+ description: Password doesn't meet requirements
+ '401':
+ description: Invalid or expired token; or invalid auth proxy metadata
+ '403':
+ description: Password reset or email/password is turned off for this project
content:
- text/plain:
+ application/json:
schema:
- type: string
- example: OK
- /capabilities:
- get:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Compromised-password screening is temporarily unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/confirm:
+ post:
tags:
- - System
- summary: List capabilities
+ - Authentication
+ summary: Confirm email address
description: |
- Lists which product capabilities accept new work in this environment. Check it
- to decide what to offer, instead of calling a route to see whether it fails.
-
- | ID | Covers |
- | --- | --- |
- | `sandboxes` | The Sandbox API: presets, templates, sessions, and executions |
- | `sandboxes.sessions` | Starting and resuming sessions, and one-shot executions |
- | `sandboxes.custom_templates` | Deploying a custom template; its validation waits while `sandboxes.sessions` is unavailable |
- | `issues` | The Issues API: listing, reading, and updating grouped runtime errors |
- | `autofix` | The Autofix API: a project's AI diagnosis and fix settings |
- | `autofix.managed_models` | Turning autofix on with Volcano-managed models instead of your own API key |
-
- A capability missing from the list is unavailable, and a capability under
- another, such as `sandboxes.sessions`, is unavailable whenever its parent is.
- While a capability is unavailable, requests that start new work answer `404`
- or `400` with code `feature_unavailable`; refresh this list when you receive
- that code. Reading, deleting, and terminating what already exists keep
- working unless the whole feature is absent from the environment. Every caller
- in an environment gets the same answer.
- operationId: listCapabilities
- security: []
+ Confirm email address using token sent via email.
+ Required if require_email_confirmation is enabled.
+ operationId: authConfirmEmail
+ security:
+ - AnonKey: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - token
+ properties:
+ token:
+ type: string
+ description: Confirmation token from email
responses:
'200':
- description: Capabilities in this environment
+ description: Email confirmed or already confirmed
content:
application/json:
schema:
- $ref: '#/components/schemas/CapabilityList'
- example:
- data:
- - id: sandboxes
- status: available
- - id: sandboxes.sessions
- status: available
- - id: sandboxes.custom_templates
- status: unavailable
- - id: issues
- status: available
- - id: autofix
- status: available
- - id: autofix.managed_models
- status: unavailable
- /openapi.json:
- get:
+ type: object
+ properties:
+ message:
+ type: string
+ enum:
+ - Email confirmed successfully
+ - Email already confirmed
+ examples:
+ confirmed:
+ summary: Fresh confirmation
+ value:
+ message: Email confirmed successfully
+ alreadyConfirmed:
+ summary: Token belongs to already-confirmed user
+ value:
+ message: Email already confirmed
+ '400':
+ description: Missing confirmation token in request body
+ '401':
+ description: Invalid or expired token
+ /auth/resend-confirmation:
+ post:
tags:
- - System
- summary: Fetch the OpenAPI specification as JSON
+ - Authentication
+ summary: Resend confirmation email
description: |
- Returns this specification as a self-contained JSON document, with every
- reference resolved. It is generated from the same document the server
- validates requests against, so a client generated from it cannot
- describe a different API than the one that answers.
-
- No credential is required: a client generator fetches this by URL before
- its user has a token, and every path here is already published in the
- API reference.
-
- The response carries a strong `ETag`; send it back as `If-None-Match` to
- get `304 Not Modified` instead of the whole document.
- operationId: getOpenAPISpecJSON
- security: []
- parameters:
- - $ref: '#/components/parameters/IfNoneMatch'
+ Resend email confirmation link.
+ Returns generic message to prevent email enumeration.
+ No email is sent when the account does not exist or is already confirmed.
+ If the account exists and is unconfirmed, a new token is generated and
+ any previous confirmation token is invalidated.
+ operationId: authResendConfirmation
+ security:
+ - AnonKey: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - email
+ properties:
+ email:
+ type: string
+ format: email
responses:
'200':
- description: The OpenAPI specification
- headers:
- ETag:
- $ref: '#/components/headers/ETag'
+ description: Generic success message
content:
application/json:
schema:
- $ref: '#/components/schemas/OpenAPISpecDocument'
- '304':
- $ref: '#/components/responses/OpenAPISpecNotModified'
+ type: object
+ properties:
+ message:
+ type: string
'429':
- $ref: '#/components/responses/OpenAPISpecThrottled'
- head:
+ description: Rate limit exceeded
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/signup-anonymous:
+ post:
tags:
- - System
- summary: Check the JSON OpenAPI specification
+ - Authentication
+ summary: Create anonymous user
description: |
- The headers `GET /openapi.json` would return, so a cache can pick up the
- current `ETag` without transferring the document.
- operationId: headOpenAPISpecJSON
- security: []
- parameters:
- - $ref: '#/components/parameters/IfNoneMatch'
- responses:
- '200':
- $ref: '#/components/responses/OpenAPISpecHeaders'
- '304':
- $ref: '#/components/responses/OpenAPISpecNotModified'
- '429':
- $ref: '#/components/responses/OpenAPISpecThrottled'
- /openapi.yaml:
- get:
- tags:
- - System
- summary: Fetch the OpenAPI specification as YAML
- description: |
- The same document as `/openapi.json`, serialized as YAML for tools that
- prefer it. See that operation for caching and authentication notes.
- operationId: getOpenAPISpecYAML
- security: []
+ Create guest user without email/password.
+
+ User metadata (like display_name) can be included and will appear in realtime presence events.
+ Requires enable_anonymous_signins to be true.
+ operationId: authSignupAnonymous
+ security:
+ - AnonKey: []
parameters:
- - $ref: '#/components/parameters/IfNoneMatch'
+ - $ref: '#/components/parameters/AuthProxyAuthorization'
+ - $ref: '#/components/parameters/AuthProxyClientIP'
+ requestBody:
+ description: Optional user metadata
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ user_metadata:
+ type: object
+ additionalProperties: true
+ description: Custom user metadata (e.g., display_name, avatar_url)
+ example:
+ display_name: Alice
+ avatar_url: https://example.com/alice.jpg
responses:
- '200':
- description: The OpenAPI specification
- headers:
- ETag:
- $ref: '#/components/headers/ETag'
+ '201':
+ description: Anonymous user created
content:
- application/yaml:
+ application/json:
schema:
- $ref: '#/components/schemas/OpenAPISpecDocument'
- '304':
- $ref: '#/components/responses/OpenAPISpecNotModified'
- '429':
- $ref: '#/components/responses/OpenAPISpecThrottled'
- head:
- tags:
- - System
- summary: Check the YAML OpenAPI specification
- description: |
- The headers `GET /openapi.yaml` would return, so a cache can pick up the
- current `ETag` without transferring the document.
- operationId: headOpenAPISpecYAML
- security: []
- parameters:
- - $ref: '#/components/parameters/IfNoneMatch'
- responses:
- '200':
- $ref: '#/components/responses/OpenAPISpecHeaders'
- '304':
- $ref: '#/components/responses/OpenAPISpecNotModified'
- '429':
- $ref: '#/components/responses/OpenAPISpecThrottled'
- /mcp:
+ $ref: '#/components/schemas/AuthTokenResponse'
+ '401':
+ description: Missing, invalid, or revoked anon key; or invalid, repeated, or under-scoped auth proxy metadata
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Anonymous signins disabled
+ /auth/user/convert-anonymous:
post:
tags:
- - System
- summary: Model Context Protocol endpoint
+ - Authentication
+ summary: Convert anonymous user to authenticated
description: |
- Streamable-HTTP MCP endpoint: one JSON-RPC 2.0 object per request, one
- response per request. There is no server-to-client stream, so a `GET`
- returns `405`, and a batched array is rejected.
-
- Authenticated with a **project access token**. The endpoint takes its
- project from the credential, so a platform token is refused with `403` —
- it names no project, and letting a tool argument choose one would hand an
- agent its own blast radius.
-
- Scope carries over from the REST API. A `read_only` token is not offered
- mutating tools or credential-returning reads, and is refused if it calls
- one anyway. Revoking the token ends MCP access on the same path it ends
- API access.
-
- Methods: `initialize`, `notifications/initialized`, `ping`,
- `tools/list`, `tools/call`. See the
- [MCP guide](https://docs.volcano.dev/platform/interfaces/mcp) for the
- tool surface and client configuration.
- operationId: callMCP
+ Add email and password to anonymous user.
+ Requires auth user access token.
+ If require_email_confirmation is enabled for the project, the converted
+ user remains unconfirmed until /auth/confirm succeeds. When email
+ sending is enabled, a confirmation email is sent during conversion.
+ operationId: authConvertAnonymous
security:
- - ProjectAccessToken: []
+ - AuthUserAccessToken: []
requestBody:
required: true
content:
application/json:
schema:
type: object
- description: A JSON-RPC 2.0 request object.
required:
- - jsonrpc
- - method
+ - email
+ - password
properties:
- jsonrpc:
+ email:
type: string
- enum:
- - '2.0'
- method:
+ format: email
+ password:
type: string
- description: The MCP method to call.
- id:
description: |
- Request identifier, echoed verbatim. Omit it to send a
- notification, which is answered with `202` and no body.
- oneOf:
- - type: string
- - type: integer
- params:
+ Password validated after NFC normalization against the
+ policy returned by GET /auth/password-policy.
+ user_metadata:
type: object
additionalProperties: true
responses:
'200':
- description: A JSON-RPC response object
+ description: User converted successfully
content:
application/json:
schema:
type: object
- required:
- - jsonrpc
- - id
properties:
- jsonrpc:
+ user:
+ $ref: '#/components/schemas/AuthUser'
+ '400':
+ description: Not an anonymous user
+ '403':
+ description: |
+ The chosen email domain is not in `allowed_email_domains`, or is
+ reserved (`anonymous.volcano.internal`, `volcano.local`)
+ '409':
+ description: Email already in use
+ '503':
+ description: Compromised-password screening is temporarily unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/user/change-email:
+ post:
+ tags:
+ - Authentication
+ summary: Request email change
+ description: |
+ Request to change user's email address.
+ Sends confirmation token to new email address.
+ operationId: authRequestEmailChange
+ security:
+ - AuthUserAccessToken: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - new_email
+ properties:
+ new_email:
+ type: string
+ format: email
+ responses:
+ '200':
+ description: Confirmation email sent
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ message:
type: string
- enum:
- - '2.0'
- id:
- description: Echoes the request's id. Null when the request could not be read well enough to determine one.
- nullable: true
- oneOf:
- - type: string
- - type: integer
- result:
- type: object
- additionalProperties: true
- error:
- type: object
- required:
- - code
- - message
- properties:
- code:
- type: integer
- message:
- type: string
- '202':
- description: A notification was accepted; there is no body
+ new_email:
+ type: string
+ '400':
+ description: Invalid email format or same as current email
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
'401':
description: Not authenticated
content:
@@ -16615,646 +16819,8008 @@ paths:
$ref: '#/components/schemas/Error'
'403':
description: |
- The credential is valid but may not use this endpoint — most often a
- platform token, which names no project.
+ The requested email domain is not in `allowed_email_domains`, or is
+ reserved (`anonymous.volcano.internal`, `volcano.local`)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- '413':
- description: The JSON-RPC frame exceeds the 1 MiB limit
-components:
- headers:
- ETag:
- description: |
- Strong validator for the returned document. Send it back as `If-None-Match`
- to revalidate without transferring the document again.
- required: true
- schema:
- type: string
- example: '"9f2c1e0b5a"'
- DatabaseQueryProxyMs:
- description: |
- Milliseconds Volcano spent before running the query, counted from the
- request arriving: authenticating the caller, validating the request,
- resolving the database, and building the SQL. Does not include query
- execution. Also present when the query itself failed.
- schema:
- type: integer
- minimum: 0
- DatabaseQueryProxyHandlerMs:
- description: |
- The part of `X-Volcano-Proxy-Ms` spent in the query endpoint itself.
- Subtract it from `X-Volcano-Proxy-Ms` to see what authentication and
- request validation cost. Also present when the query itself failed.
- schema:
- type: integer
- minimum: 0
- DatabaseQueryComputeMs:
- description: |
- Milliseconds the database took to run the query and return its rows.
- Does not include Volcano's preparation. Also present when the query
- itself failed.
- schema:
- type: integer
- minimum: 0
- securitySchemes:
- AnonKey:
- type: http
- scheme: bearer
- bearerFormat: JWT
- description: |
- Project-specific public key for frontend authentication.
- Required for signup, signin, refresh, and logout endpoints.
- Get from Project Settings → Authentication → Anon Keys.
- Safe to expose in frontend code (scoped to project, limited permissions).
- AuthUserAccessToken:
- type: http
- scheme: bearer
- bearerFormat: JWT
- description: |
- Auth user access token obtained from signup/signin.
- Used for authenticated function invocation and user profile access.
- Functions invoked with access tokens receive user context in event.__volcano_auth.
- Expires after configured lifetime (default: 1 hour).
- ServiceRoleKey:
- type: http
- scheme: bearer
- bearerFormat: JWT
- description: |
- Service role key for admin operations.
- **WARNING:** Bypasses Row-Level Security - backend use only!
- Create via POST /projects/{id}/service-keys.
- Used for function invocation with full database access.
- UserToken:
- type: http
- scheme: bearer
- bearerFormat: opaque
- description: |
- Platform token, which acts on every project in your account.
- Obtain one by running `volcano login`, or from the dashboard.
-
- For CI, scripts, and agents, prefer a project access token
- (`pt-`) instead: it reaches only the project it was created in,
- so a leak does not expose the rest of your account. See the
- ProjectAccessToken scheme.
- ProjectAccessToken:
- type: http
- scheme: bearer
- bearerFormat: opaque
+ '409':
+ description: Email already in use
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '429':
+ description: Rate limit exceeded (10 requests per hour per IP)
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/user/confirm-email-change:
+ post:
+ tags:
+ - Authentication
+ summary: Confirm email change
+ description: Confirm email change with token sent to new address
+ operationId: authConfirmEmailChange
+ security:
+ - AuthUserAccessToken: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - email_change_token
+ properties:
+ email_change_token:
+ type: string
+ responses:
+ '200':
+ description: Email changed successfully
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ message:
+ type: string
+ user:
+ $ref: '#/components/schemas/AuthUser'
+ '400':
+ description: Invalid or expired token, or no pending email change
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: |
+ The pending email domain is no longer in `allowed_email_domains`.
+ Re-checked here because the allowlist can narrow between the request
+ and the confirmation.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: Email is now in use by another user
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/user/cancel-email-change:
+ delete:
+ tags:
+ - Authentication
+ summary: Cancel pending email change
+ operationId: authCancelEmailChange
+ security:
+ - AuthUserAccessToken: []
+ responses:
+ '200':
+ description: Email change cancelled
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ message:
+ type: string
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/user/sessions:
+ get:
+ tags:
+ - Authentication
+ summary: Get current user's sessions
description: |
- Project access token, scoped to a single project. Starts with `pt-`.
+ Returns paginated sessions for the currently authenticated user.
+ Each session includes device info, IP addresses, and activity timestamps.
+ The current session is marked with `is_current: true`.
- Accepted on that project's control-plane routes and refused
- everywhere else, including account-wide endpoints and any other
- project. A `read_only` token additionally refuses mutations.
+ **Ordering and pagination.** Without `sort`, results are ordered by most
+ recent activity and paged with `page`/`limit`, returning the
+ `sessions`/`total`/`page`/`limit`/`total_pages` body below. This is the
+ legacy default and is preserved for existing clients.
- Create one with POST /projects/{id}/access-tokens using a platform
- token. The secret is returned once and is not recoverable, so a
- project access token cannot create, list, read, or revoke project
- access tokens.
- parameters:
- AuthProxyAuthorization:
- name: X-Volcano-Proxy-Authorization
- in: header
- required: false
- description: |
- Trusted server-side auth proxy credential in `Bearer SERVICE_KEY`
- form. When supplied, `X-Volcano-Client-IP` is also required. The service
- key must belong to the anon key's project and hold this operation's scope:
- `auth.signup` for signup and anonymous signup, `auth.signin` for signin
- and OAuth code exchange, `auth.refresh` for refresh, `auth.logout` for
- logout, and `auth.password_reset` for forgot-password and reset-password.
- The password policy accepts any service key for the project. Never expose
- a service key to browser code.
- schema:
- type: string
- AuthProxyClientIP:
- name: X-Volcano-Client-IP
- in: header
- required: false
- description: |
- Original browser IPv4 or IPv6 address supplied by a trusted server-side
- auth proxy. The proxy must derive this value from its platform-verified
- request metadata, never from a browser-supplied header. Requires a valid
- `X-Volcano-Proxy-Authorization` header.
- schema:
- type: string
- BackupName:
- name: backupName
- in: path
- required: true
- schema:
- type: string
- minLength: 1
- maxLength: 128
- description: |
- Backup name, unique within the database, exactly as returned by the list
- endpoint.
+ Send `sort=created_at` to opt into the standard list contract: results are
+ ordered by session start (newest first) and may be paged either with
+ `page`/`limit` or by cursor with `cursor`/`ending_before` plus a bounded
+ `offset` past the cursor anchor. Cursor responses use the shared
+ `data` envelope with `next_cursor`/`prev_cursor`.
- Deliberately looser than the names you can create: a backup made by a
- schedule is named for you, so reading or deleting one accepts any name a
- backup can have.
- BranchName:
- name: branchName
- in: path
- required: true
- schema:
- type: string
- pattern: ^[a-z0-9_]+$
- maxLength: 64
- description: Branch name (unique within the parent database, lowercase letters, numbers, and underscores only)
- BucketName:
- name: bucketName
- in: path
- required: true
- schema:
- type: string
- pattern: ^[a-zA-Z0-9_-]+$
- minLength: 1
- maxLength: 64
- description: Storage bucket name
- Cursor:
- name: cursor
- in: query
- required: false
- schema:
- type: string
- description: |
- Opaque keyset pagination cursor from a previous response's `next_cursor`
- — pages forward. Mutually exclusive with `page` and `ending_before`;
- combining them returns 400. When supplied, the request's `search` and
- `limit` must match the values bound to the cursor or the request returns 400.
- EndingBefore:
- name: ending_before
- in: query
- required: false
- schema:
- type: string
- description: |
- Opaque keyset pagination cursor from a previous response's `prev_cursor`
- — pages backward (the page immediately preceding this cursor). Mutually
- exclusive with `page` and `cursor`; combining them returns 400. `search`
- and `limit` must match the values bound to the cursor or the request
- returns 400.
- DatabaseName:
- name: databaseName
- in: path
- required: true
- schema:
- type: string
- pattern: ^[a-z0-9_]+$
- maxLength: 64
- description: Database name (unique within project, lowercase letters, numbers, and underscores only)
- DeploymentId:
- name: deploymentId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- description: Frontend deployment ID
- VariableEnvironmentId:
- name: environmentId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- description: Variable Environment ID
- FrontendId:
- name: frontendId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- description: Frontend ID
- FrontendFunctionRouteId:
- name: routeId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- description: Frontend Function route ID
- FunctionId:
- name: functionId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- description: Function ID
- DurableFunctionId:
- name: functionId
- in: path
- required: true
- schema:
- type: string
- description: Durable function ID, or its name within the project
- DurableExecutionId:
- name: executionId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- description: Durable execution ID
- DurableApprovalId:
- name: approvalId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- description: Durable approval ID
- IssueId:
- name: issueId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- description: Issue ID
- IssueCursor:
- name: cursor
- in: query
- required: false
- schema:
- type: string
- description: |
- Opaque cursor from a previous response's `next_cursor`. Pages forward;
- keep the same filters while paging.
- AutofixRunId:
- name: runId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- description: Autofix run ID
- DurableApprovalFunctionFilter:
- name: function
- in: query
- required: false
- schema:
- type: string
- minLength: 1
- maxLength: 255
+ Unlike other list endpoints, sending `limit` without `page` does **not**
+ select cursor mode here; `sort=created_at` is the only opt-in. Cursor
+ pagination is rejected with 400 for the activity order, because
+ `last_activity_at` changes whenever a session refreshes its token: a row
+ that crosses the cursor anchor between two requests would be skipped and
+ never shown. The `status=expired` filter is also offset-only because a
+ session can expire above the cursor anchor during a walk. Sending that
+ filter in cursor mode, `page` with `cursor` or `ending_before`, or both
+ cursor directions returns 400.
+ operationId: authGetMySessions
+ security:
+ - AuthUserAccessToken: []
+ parameters:
+ - name: page
+ in: query
+ description: Page number (1-indexed)
+ schema:
+ type: integer
+ minimum: 1
+ default: 1
+ - name: limit
+ in: query
+ description: Number of sessions per page (max 100)
+ schema:
+ type: integer
+ minimum: 1
+ maximum: 100
+ default: 20
+ - name: sort
+ in: query
+ description: |
+ Sort key. `last_activity` (default) orders by most recent activity and
+ supports offset pagination only. `created_at` orders by session start
+ and supports both offset and cursor pagination.
+ schema:
+ type: string
+ enum:
+ - last_activity
+ - created_at
+ default: last_activity
+ - name: status
+ in: query
+ description: |
+ Filter by whether the session can still be refreshed. Omit for every
+ stored session, including expired ones. `expired` is not supported
+ with cursor pagination.
+ schema:
+ type: string
+ enum:
+ - active
+ - expired
+ - name: cursor
+ in: query
+ description: |
+ Opaque keyset cursor from a previous response's `next_cursor`. Requires
+ `sort=created_at`; mutually exclusive with `page` and `ending_before`.
+ schema:
+ type: string
+ - name: ending_before
+ in: query
+ description: |
+ Opaque keyset cursor from a previous response's `prev_cursor`, paging
+ backward. Requires `sort=created_at`; mutually exclusive with `page`
+ and `cursor`.
+ schema:
+ type: string
+ - name: offset
+ in: query
+ description: |
+ Bounded number of rows to skip past the cursor anchor (the hybrid
+ jump, maximum 100000). Ignored unless `cursor` or `ending_before` is
+ supplied.
+ schema:
+ type: integer
+ minimum: 0
+ maximum: 100000
+ responses:
+ '200':
+ description: Paginated list of user sessions
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ sessions:
+ type: array
+ items:
+ $ref: '#/components/schemas/AuthSession'
+ total:
+ type: integer
+ description: Total number of sessions
+ page:
+ type: integer
+ description: Current page number
+ limit:
+ type: integer
+ description: Number of sessions per page
+ total_pages:
+ type: integer
+ description: Total number of pages
+ data:
+ type: array
+ description: Sessions for this page (cursor pagination only)
+ items:
+ $ref: '#/components/schemas/AuthSession'
+ has_more:
+ type: boolean
+ description: Whether a further page exists (cursor pagination only)
+ next_cursor:
+ type: string
+ description: Opaque cursor for the next page (cursor pagination only)
+ prev_cursor:
+ type: string
+ description: Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`.
+ '400':
+ description: Invalid or conflicting pagination parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ delete:
+ tags:
+ - Authentication
+ summary: Sign out from all other devices
description: |
- Only approvals requested by this durable function, given by id or by
- name. A name also matches approvals from a deleted function of that
- name.
- DurableMessageIdempotencyKey:
- name: Idempotency-Key
- in: header
- required: false
+ Deletes all sessions except the current one.
+ Use this to log out from all other devices while keeping the current session active.
+ operationId: authDeleteAllMySessions
+ security:
+ - AuthUserAccessToken: []
+ responses:
+ '204':
+ description: All other sessions deleted
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/user/sessions/{sessionId}:
+ delete:
+ tags:
+ - Authentication
+ summary: Sign out from specific device
description: |
- Makes a send safe to retry. A repeat with a key the same sender has
- used on the execution returns the first message and sends nothing.
- Keys of different senders never collide. Up to 255 printable ASCII
- characters.
- schema:
- type: string
- minLength: 1
- maxLength: 255
- pattern: ^[ -~]+$
- DurableClientToken:
- name: X-Volcano-Client-Token
- in: header
- required: false
- description: |
- The `client_token` the execution's start returned. Lets an anon key,
- or a user who did not start the execution, reach it.
- schema:
- type: string
- maxLength: 128
- DurableMessageDirectionFilter:
- name: direction
- in: query
- required: false
- description: Return only messages travelling this way.
- schema:
- $ref: '#/components/schemas/DurableMessageDirection'
- DurableMessageNameFilter:
- name: name
- in: query
- required: false
- description: Return only messages with this name.
- schema:
- $ref: '#/components/schemas/DurableMessageName'
- DurableMessageAfter:
- name: after
- in: query
- required: false
- description: Return only messages whose `seq` is greater than this.
- schema:
- type: integer
- format: int64
- minimum: 0
- default: 0
- DurableMessageLimit:
- name: limit
- in: query
- required: false
- description: Most messages to return.
- schema:
- type: integer
- minimum: 1
- maximum: 500
- default: 100
- Limit:
- name: limit
- in: query
- required: false
- schema:
- type: integer
- minimum: 1
- maximum: 100
- default: 10
- description: Number of items per page (max 100)
- LockKey:
- name: key
- in: path
- required: true
- description: Project-local lock name.
- schema:
- type: string
- minLength: 1
- maxLength: 128
- pattern: ^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$
- LockToken:
- name: X-Volcano-Lock-Token
- in: header
- required: true
- description: Opaque UUID generated once by the caller and retained for the lease lifetime.
- schema:
- type: string
- format: uuid
- LockRequestId:
- name: X-Volcano-Request-Id
- in: header
- required: true
+ Deletes a specific session, logging out that device.
+ You can get session IDs from the list sessions endpoint.
+ operationId: authDeleteMySession
+ security:
+ - AuthUserAccessToken: []
+ parameters:
+ - name: sessionId
+ in: path
+ required: true
+ description: The session ID to delete
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '204':
+ description: Session deleted
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Session not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/user:
+ get:
+ tags:
+ - Authentication
+ summary: Get current user profile
+ description: Returns authenticated user's profile. Requires access token.
+ operationId: authGetUser
+ security:
+ - AuthUserAccessToken: []
+ responses:
+ '200':
+ description: User profile
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ user:
+ $ref: '#/components/schemas/AuthUser'
+ '401':
+ description: Not authenticated - access token missing or invalid
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ put:
+ tags:
+ - Authentication
+ summary: Update user profile
+ description: Update password or metadata. Requires access token.
+ operationId: authUpdateUser
+ security:
+ - AuthUserAccessToken: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ password:
+ type: string
+ description: |
+ Password validated after NFC normalization against the
+ policy returned by GET /auth/password-policy.
+ user_metadata:
+ type: object
+ additionalProperties: true
+ description: |
+ Metadata keys to merge into the current user metadata.
+ Omitted keys remain unchanged; set a key to null to remove it.
+ Merging is shallow; nested objects replace the stored value for that top-level key.
+ responses:
+ '200':
+ description: Profile updated
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ user:
+ $ref: '#/components/schemas/AuthUser'
+ '400':
+ description: Bad request - invalid password or metadata format
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Not authenticated - access token missing or invalid
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: The request sent a non-empty `password` while email/password is turned off for the project; nothing is updated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Compromised-password screening is temporarily unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/user/identities:
+ get:
+ tags:
+ - Authentication
+ summary: List the current user's identities
description: |
- UUID correlating this request across client and server logs. Repeat safety comes from
- the lock token, so a retry under a reused request ID still counts against the quota.
- schema:
- type: string
- format: uuid
- DeploymentOperation:
- name: operation
- in: query
- required: false
- description: Restrict a deployment feed to one kind of operation.
- schema:
- type: string
- enum:
- - deploy
- - redeploy
- - update
- - delete
- DeploymentOwnerId:
- name: owner_id
- in: query
- required: false
+ Returns every real email identity the account owns. An account can own
+ multiple identities (for example a password identity plus one or more
+ OAuth identities on different emails). Anonymous accounts have no real
+ identity and return an empty list.
+ operationId: authListIdentities
+ security:
+ - AuthUserAccessToken: []
+ responses:
+ '200':
+ description: List of identities
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AuthIdentitiesResponse'
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/user/identities/{identityId}:
+ delete:
+ tags:
+ - Authentication
+ summary: Unlink an identity from the current user
description: |
- The user who owns the projects whose deployments to return
- (`projects.user_id`). This is ownership, not the actor that started the
- deployment — see `initiated_by_user_id` for that. Not a UUID: platform
- user ids are opaque strings.
- schema:
- type: string
- maxLength: 255
- DeploymentOrder:
- name: order
- in: query
- required: false
- description: |
- Sort key and direction. `created_at.desc` (default) is the feed order.
- `completed_at.asc` orders finished attempts by completion, oldest first,
- and excludes attempts that never completed.
- schema:
- type: string
- enum:
- - created_at.desc
- - completed_at.asc
- default: created_at.desc
- DeploymentResourceType:
- name: resource_type
- in: query
- required: false
- description: |
- Restrict a deployment feed to a single resource type. Omit to return
- both Function and Frontend deployments.
- schema:
- type: string
- enum:
- - function
- - frontend
- FunctionKindFilter:
- name: function_kind
- in: query
- required: false
- description: |
- Restrict results to functions of one kind. Omit to include both
- standard and durable functions.
- schema:
- $ref: '#/components/schemas/FunctionKindFilter'
- DeploymentStatus:
- name: status
- in: query
- required: false
- description: Restrict a deployment feed to attempts in one status.
- schema:
- type: string
- enum:
- - queued
- - provisioning
- - active
- - degraded
- - failed
- - superseded
- - deleting
- - deleted
- Offset:
- name: offset
- in: query
- required: false
- schema:
- type: integer
- minimum: 0
- default: 0
- description: |
- Bounded row offset past the keyset anchor named by `cursor` (forward) or
- `ending_before` (backward) — the hybrid jump. Seek to the anchor, then
- skip this many rows within. Used for numbered jump-to-page: from the
- current page, seek to its next/prev cursor and offset the remaining
- pages. Only honored on the cursor pagination path; ignored otherwise.
- Page:
- name: page
- in: query
- required: false
- schema:
- type: integer
- minimum: 1
- description: |
- Page number (1-indexed) for offset pagination. Declares no schema
- default so the request validator does not inject one: handlers that omit
- `page` see it unset (nil) and default to 1 in code, while cursor-first
- endpoints (e.g. the project deployments feed) can detect its absence to
- stay in keyset/search mode. Supplying `page` selects offset pagination.
- ProjectId:
- name: id
- in: path
- required: true
- schema:
- type: string
- format: uuid
- description: Project ID
- TokenId:
- name: tokenId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- description: Project access token ID
- Search:
- name: search
- in: query
- required: false
- schema:
- type: string
- maxLength: 256
- description: |
- Case-insensitive substring match on the resource `name`. See the
- endpoint description for supported pagination modes.
- RestoreId:
- name: restoreId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- description: Database restore ID
- SchedulerId:
- name: schedulerId
- in: path
- required: true
- schema:
- type: string
- format: uuid
- description: Function scheduler ID
- VariableName:
- name: name
- in: path
- required: true
- schema:
- type: string
- minLength: 1
- maxLength: 256
- pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
- description: Variable name. Function runtime names such as AWS_REGION are reserved and cannot be updated.
- IfNoneMatch:
- name: If-None-Match
- in: header
- required: false
- description: |
- Entity tag from an earlier response, returning `304 Not Modified` while it
- still matches. Accepts the full condition: `*`, a comma-separated list, and
- weak tags of the form `W/"tag"`.
- schema:
- type: string
- example: '"9f2c1e0b5a"'
- responses:
- OpenAPISpecThrottled:
- description: |
- Too many requests for the specification from one address. The document
- carries an `ETag`; revalidate with `If-None-Match` rather than
- re-fetching it.
- headers:
- Retry-After:
- description: Seconds to wait before requesting the specification again.
- schema:
- type: integer
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- BandwidthCapExceeded:
- description: |
- The platform user exceeded their billing-cycle bandwidth allowance (aggregate
- ingress + egress across owned projects). Enforcement is eventual:
- requests are rejected until the allowance increases or the next
- anniversary cycle begins.
- content:
- application/json:
+ Removes a non-primary identity and its attached sign-in methods. Refused
+ when the identity is the account's primary, its only identity, or when
+ removing it would leave the account with no way to sign in.
+ operationId: authUnlinkIdentity
+ security:
+ - AuthUserAccessToken: []
+ parameters:
+ - name: identityId
+ in: path
+ required: true
+ description: The identity ID to unlink
schema:
- $ref: '#/components/schemas/Error'
- DatabaseQueryCapExceeded:
+ type: string
+ format: uuid
+ responses:
+ '204':
+ description: Identity unlinked
+ '400':
+ description: Identity cannot be unlinked (primary, last, or would remove last sign-in method), or the identity id is malformed
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Identity not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/user/methods:
+ get:
+ tags:
+ - Authentication
+ summary: List the current user's sign-in methods
description: |
- The query was rejected by a billing-cycle allowance: either the owning
- platform user's bandwidth allowance (aggregate ingress + egress across
- owned projects) or their database-request allowance. Enforcement is
- eventual: queries are rejected until the allowance increases or the
- next anniversary cycle begins. The error message identifies the resource.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- DatabaseBranchQueryUnavailable:
+ Returns a flat list of every sign-in method the account owns (password,
+ each OAuth provider, and any active anonymous method), with the primary
+ method flagged. Password stubs and converted anonymous methods are excluded.
+ operationId: authListMethods
+ security:
+ - AuthUserAccessToken: []
+ responses:
+ '200':
+ description: List of sign-in methods
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AuthMethodsResponse'
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/user/methods/{methodId}/promote:
+ post:
+ tags:
+ - Authentication
+ summary: Set a method as the account's primary
description: |
- The branch exists but cannot serve queries: it is still provisioning,
- being reset, expired, or its parent is being restored. Distinct from
- `404` so a caller waiting on a branch can tell it apart from a typo.
- content:
- application/json:
+ Promotes the given method to the account's primary sign-in method. The
+ account's canonical email is re-derived from the promoted method's identity.
+ Refused for password stubs and converted anonymous methods, and for an
+ identity whose domain is outside the project's `allowed_email_domains`.
+ operationId: authPromoteMethod
+ security:
+ - AuthUserAccessToken: []
+ parameters:
+ - name: methodId
+ in: path
+ required: true
+ description: The method ID to promote
schema:
- $ref: '#/components/schemas/Error'
- OpenAPISpecNotModified:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: The promoted method
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AuthMethodSummary'
+ '400':
+ description: This method cannot be set as primary (password stub, converted anonymous method, or unverified email), or the method id is malformed
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: The promoted identity's email domain is not in the project's allowed_email_domains, or is reserved (`anonymous.volcano.internal`, `volcano.local`)
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Method not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/auth/insights:
+ get:
+ tags:
+ - Auth Admin
+ summary: Get auth user insights
+ description: |
+ Returns current and deleted auth-user totals, rolling 24-hour and 30-day
+ active users, and zero-filled daily activity and account-retention counts
+ for an inclusive UTC date range. Weeks start on Monday.
+ The existing deletions series counts accounts by deletion date; net_growth
+ remains signups minus deletions and is not affected by bans.
+ The banned_users, deleted_users, and available_users fields describe the
+ current state of users registered in each bucket. Banned users exclude
+ deleted users and expired bans. Available users are signups minus
+ banned_users minus deleted_users. Unban and expiry restore availability in
+ the original signup bucket. These current-state cohorts can change after
+ the requested dates have passed, without rewriting activity counts.
+ Sign-in counts remain grouped by session creation date. Deleted users
+ contribute to active counts until their last activity leaves the rolling
+ window. Token refreshes affect active users but not the sign-in series.
+ Signup history is backfilled from accounts present when collection was
+ deployed. Accounts hard-deleted before deletion-history collection cannot
+ be recovered. Current bans require no separate event-history collection.
+ operationId: getAuthInsights
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: from
+ in: query
+ description: Inclusive UTC start date. Defaults to 29 days before `to`.
+ schema:
+ type: string
+ format: date
+ - name: to
+ in: query
+ description: Inclusive UTC end date. Defaults to today.
+ schema:
+ type: string
+ format: date
+ - name: interval
+ in: query
+ description: Chart bucket size. Defaults to `day`.
+ schema:
+ $ref: '#/components/schemas/AuthInsightsInterval'
+ responses:
+ '200':
+ description: Auth insights retrieved
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AuthInsightsResponse'
+ example:
+ project_id: 4f165080-a931-4e03-b3bd-41c45c3f0058
+ observed_at: '2026-07-20T18:00:00Z'
+ window:
+ from: '2026-06-21'
+ to: '2026-07-20'
+ interval: day
+ summary:
+ total_users: 1234
+ deleted_users: 42
+ active_users_1d: 83
+ active_users_30d: 418
+ series:
+ - bucket_start: '2026-07-20'
+ signups: 12
+ signins: 97
+ deletions: 3
+ banned_users: 2
+ deleted_users: 3
+ available_users: 7
+ net_growth: 9
+ is_partial: true
+ '400':
+ description: Invalid date range or interval
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Access denied
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Project not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/auth/users:
+ get:
+ tags:
+ - Auth Admin
+ summary: List all auth users (admin)
+ description: List auth users in project. Requires platform token.
+ operationId: listAuthUsers
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/Page'
+ - $ref: '#/components/parameters/Limit'
+ - $ref: '#/components/parameters/Cursor'
+ - $ref: '#/components/parameters/EndingBefore'
+ - $ref: '#/components/parameters/Offset'
+ - $ref: '#/components/parameters/Search'
+ - name: status
+ in: query
+ required: false
+ description: Filter by effective status. `banned` returns only currently-banned users; an expired temporary ban lists as `active`.
+ schema:
+ type: string
+ enum:
+ - active
+ - banned
+ responses:
+ '200':
+ description: Successful response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PaginatedAuthUsers'
+ '400':
+ description: Invalid status or pagination parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/auth/users/{userId}:
+ get:
+ tags:
+ - Auth Admin
+ summary: Get specific auth user (admin)
+ operationId: getAuthUser
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: userId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: Auth user details
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AuthUser'
+ delete:
+ tags:
+ - Auth Admin
+ summary: Delete auth user (admin)
+ description: Soft-deletes user and revokes all sessions
+ operationId: deleteAuthUser
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: userId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '204':
+ description: User deleted
+ /projects/{id}/auth/users/{userId}/sessions:
+ get:
+ tags:
+ - Auth Admin
+ summary: List user sessions
+ description: |
+ List paginated sessions for a specific auth user.
+ Returns session details including device info, IP address, and activity timestamps.
+
+ Ordering and pagination match `GET /auth/user/sessions`: the default is
+ activity order with `page`/`limit` and the legacy `sessions` body, and
+ `sort=created_at` opts into the standard cursor/offset hybrid with the
+ shared `data` envelope. Cursor pagination is only available for
+ `sort=created_at`, because the activity timestamp changes under paging.
+ The `status=expired` filter is offset-only because sessions can expire
+ above a cursor anchor during a walk.
+ operationId: listUserSessions
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: userId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: page
+ in: query
+ description: Page number (1-indexed)
+ schema:
+ type: integer
+ minimum: 1
+ default: 1
+ - name: limit
+ in: query
+ description: Number of sessions per page (max 100)
+ schema:
+ type: integer
+ minimum: 1
+ maximum: 100
+ default: 20
+ - name: sort
+ in: query
+ description: |
+ Sort key. `last_activity` (default) orders by most recent activity and
+ supports offset pagination only. `created_at` orders by session start
+ and supports both offset and cursor pagination.
+ schema:
+ type: string
+ enum:
+ - last_activity
+ - created_at
+ default: last_activity
+ - name: status
+ in: query
+ description: |
+ Filter by whether the session can still be refreshed. Omit for every
+ stored session, including expired ones. `expired` is not supported
+ with cursor pagination.
+ schema:
+ type: string
+ enum:
+ - active
+ - expired
+ - name: cursor
+ in: query
+ description: |
+ Opaque keyset cursor from a previous response's `next_cursor`. Requires
+ `sort=created_at`; mutually exclusive with `page` and `ending_before`.
+ schema:
+ type: string
+ - name: ending_before
+ in: query
+ description: |
+ Opaque keyset cursor from a previous response's `prev_cursor`, paging
+ backward. Requires `sort=created_at`; mutually exclusive with `page`
+ and `cursor`.
+ schema:
+ type: string
+ - name: offset
+ in: query
+ description: |
+ Bounded number of rows to skip past the cursor anchor (the hybrid
+ jump, maximum 100000). Ignored unless `cursor` or `ending_before` is
+ supplied.
+ schema:
+ type: integer
+ minimum: 0
+ maximum: 100000
+ responses:
+ '200':
+ description: Paginated list of user sessions
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ sessions:
+ type: array
+ items:
+ $ref: '#/components/schemas/AuthSession'
+ total:
+ type: integer
+ description: Total number of sessions
+ page:
+ type: integer
+ description: Current page number
+ limit:
+ type: integer
+ description: Number of sessions per page
+ total_pages:
+ type: integer
+ description: Total number of pages
+ data:
+ type: array
+ description: Sessions for this page (cursor pagination only)
+ items:
+ $ref: '#/components/schemas/AuthSession'
+ has_more:
+ type: boolean
+ description: Whether a further page exists (cursor pagination only)
+ next_cursor:
+ type: string
+ description: Opaque cursor for the next page (cursor pagination only)
+ prev_cursor:
+ type: string
+ description: Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`.
+ '400':
+ description: Invalid or conflicting pagination parameters
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: User not found
+ delete:
+ tags:
+ - Auth Admin
+ summary: Delete all user sessions
+ description: |
+ Revokes all sessions for a user, forcing them to re-authenticate on all devices.
+ Use this to log out a user from everywhere.
+ operationId: deleteAllUserSessions
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: userId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '204':
+ description: All sessions deleted
+ '404':
+ description: User not found
+ /projects/{id}/auth/users/{userId}/sessions/{sessionId}:
+ delete:
+ tags:
+ - Auth Admin
+ summary: Delete specific session
+ description: |
+ Revokes a specific session for a user.
+ Use this to log out a user from a single device.
+ operationId: deleteUserSession
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: userId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: sessionId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '204':
+ description: Session deleted
+ '404':
+ description: Session or user not found
+ /projects/{id}/auth/users/{userId}/ban:
+ post:
+ tags:
+ - Auth Admin
+ summary: Ban a user
+ description: |
+ Bans a user temporarily or permanently. Banned users cannot sign in
+ and all their active sessions are immediately revoked.
+ Omitting banned_until clears any previous expiry. Deleted accounts cannot be banned.
+
+ - Omit `banned_until` for a permanent ban
+ - Provide `banned_until` ISO timestamp for a temporary ban
+ operationId: banAuthUser
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: userId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ banned_until:
+ type: string
+ format: date-time
+ description: When the ban expires (omit for permanent ban)
+ example: '2026-12-31T23:59:59Z'
+ responses:
+ '200':
+ description: User banned successfully
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/BanUserResponse'
+ '404':
+ description: User not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: Deleted accounts cannot be banned or restored
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/auth/users/{userId}/unban:
+ post:
+ tags:
+ - Auth Admin
+ summary: Unban a user
+ description: |
+ Removes a ban from a user, restoring their ability to sign in.
+ The user's status is set back to 'active'. Deleted accounts cannot be restored.
+ operationId: unbanAuthUser
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: userId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: User unbanned successfully
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UnbanUserResponse'
+ '404':
+ description: User not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: Deleted accounts cannot be banned or restored
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/email-templates:
+ get:
+ tags:
+ - Auth Configuration
+ summary: List email templates
+ description: Returns all custom email templates for this project.
+ operationId: listEmailTemplates
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ responses:
+ '200':
+ description: Email templates list
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/EmailTemplate'
+ post:
+ tags:
+ - Auth Configuration
+ summary: Create email template
+ description: |
+ Creates a custom email template for the project. Custom email templates
+ are a SUPERAGENT feature: requests from a HOBBY project owner are
+ rejected with 403, and HOBBY projects always send the built-in default
+ templates regardless of any previously saved custom rows.
+ Every project is created with one template per type, so customizing one
+ is usually a PUT; creating a type the project already has returns 409.
+ Valid template types: welcome, confirmation, password_reset, password_changed
+ operationId: createEmailTemplate
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateEmailTemplateRequest'
+ responses:
+ '201':
+ description: Template created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/EmailTemplate'
+ '400':
+ description: Invalid template type or subject containing a literal interior carriage return or newline
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Custom email templates require the SUPERAGENT plan
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: The project already has a template of this type
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/email-templates/{type}:
+ get:
+ tags:
+ - Auth Configuration
+ summary: Get email template
+ operationId: getEmailTemplate
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: type
+ in: path
+ required: true
+ schema:
+ type: string
+ enum:
+ - welcome
+ - confirmation
+ - password_reset
+ - password_changed
+ responses:
+ '200':
+ description: Email template
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/EmailTemplate'
+ '404':
+ description: Template not found
+ put:
+ tags:
+ - Auth Configuration
+ summary: Update email template
+ description: |
+ Updates a custom email template. Custom email templates are a SUPERAGENT
+ feature: requests from a HOBBY project owner are rejected with 403
+ (including after a downgrade), so a HOBBY project cannot modify
+ templates and always sends the built-in defaults.
+ operationId: updateEmailTemplate
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: type
+ in: path
+ required: true
+ schema:
+ type: string
+ enum:
+ - welcome
+ - confirmation
+ - password_reset
+ - password_changed
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateEmailTemplateRequest'
+ responses:
+ '200':
+ description: Template updated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/EmailTemplate'
+ '400':
+ description: Subject contains a literal interior carriage return or newline
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Custom email templates require the SUPERAGENT plan
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Template not found
+ delete:
+ tags:
+ - Auth Configuration
+ summary: Delete email template
+ description: |
+ Deletes a custom template, reverting to the default. Custom email
+ templates are a SUPERAGENT feature: requests from a HOBBY project owner
+ are rejected with 403.
+ operationId: deleteEmailTemplate
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: type
+ in: path
+ required: true
+ schema:
+ type: string
+ enum:
+ - welcome
+ - confirmation
+ - password_reset
+ - password_changed
+ responses:
+ '204':
+ description: Template deleted
+ '403':
+ description: Custom email templates require the SUPERAGENT plan
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Template not found
+ /email-templates/defaults:
+ get:
+ tags:
+ - Auth Configuration
+ summary: Get default email templates
+ description: Returns the default email templates used when no custom template is configured.
+ operationId: getDefaultEmailTemplates
+ responses:
+ '200':
+ description: Default templates
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/DefaultEmailTemplate'
+ /email-templates/defaults/{type}:
+ get:
+ tags:
+ - Auth Configuration
+ summary: Get default email template by type
+ operationId: getDefaultEmailTemplate
+ parameters:
+ - name: type
+ in: path
+ required: true
+ schema:
+ type: string
+ enum:
+ - welcome
+ - confirmation
+ - password_reset
+ - password_changed
+ responses:
+ '200':
+ description: Default template
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DefaultEmailTemplate'
+ '404':
+ description: Template type not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/auth/config:
+ get:
+ tags:
+ - Auth Configuration
+ summary: Get auth configuration
+ operationId: getAuthConfig
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ responses:
+ '200':
+ description: Auth configuration
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AuthConfig'
+ put:
+ tags:
+ - Auth Configuration
+ summary: Update auth configuration
+ description: |
+ Updates the project's auth configuration. Only the fields present in
+ the body are changed.
+ operationId: updateAuthConfig
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateAuthConfigRequest'
+ responses:
+ '200':
+ description: Configuration updated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AuthConfig'
+ '400':
+ description: Invalid auth configuration, including a subject with a literal interior carriage return or newline
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: |
+ The update would turn on, widen, or otherwise edit the email domain
+ allowlist (`allowed_email_domains`, `allowed_email_domains_mode`)
+ for a project that is not on the SUPERAGENT plan. A HOBBY project keeps
+ whatever allowlist it already has — parked, enforcing nothing until
+ it upgrades — and may still remove it, so a downgrade never leaves a
+ project locked out of its own signups.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/auth/config/test-email:
+ post:
+ tags:
+ - Auth Configuration
+ summary: Send a test email using the project's saved SMTP config
+ description: |
+ Sends a diagnostic email to `to_email` using the project's
+ persisted `auth_config` SMTP credentials. If `html_body` or
+ `text_body` is supplied, the override path is taken: those
+ values (plus optional `subject`) are rendered through
+ html/text templates against the project's `Data` and
+ used as the body — used by the template editor's "Send Test"
+ affordance to preview an unsaved template. With both bodies
+ omitted, a hardcoded diagnostic message is sent and any
+ `subject` field is ignored. Sending `subject` alone (no
+ bodies) is rejected with 400 to avoid a silently-dropped
+ subject or a blank message. Also rejects with 400 if
+ `email_enabled=false`, `smtp_host` is empty, or the saved
+ `smtp_password` can't be read and must be set again.
+ Sender values with interior line breaks return 400 before SMTP delivery.
+ Rendered override subjects containing a line break have outer whitespace
+ trimmed; any remaining interior line break returns 400 before delivery.
+ operationId: testEmailConfig
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/TestEmailRequest'
+ responses:
+ '200':
+ description: Test email sent
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/TestEmailResponse'
+ '400':
+ description: Invalid request, unsafe email headers, or email delivery not configured
+ '401':
+ description: Unauthorized
+ '403':
+ description: Forbidden
+ '404':
+ description: Project not found
+ '502':
+ description: Template render failure or SMTP delivery failed
+ /projects/{id}/auth/hosted-pages/{pageType}:
+ get:
+ tags:
+ - Auth Configuration
+ summary: Get hosted auth page
+ description: |
+ Returns the saved HTML/CSS for the page type, or `page: null` when the
+ project has not customized it yet. Always returns `defaults` (the theme
+ shell to seed an editor with, which is valid input to the update endpoint)
+ and `runtime` (the script the rendered page runs, plus a preview harness).
+ operationId: getAuthHostedPage
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: pageType
+ in: path
+ required: true
+ schema:
+ $ref: '#/components/schemas/HostedAuthPageType'
+ responses:
+ '200':
+ description: Hosted page loaded
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AuthHostedPageResponse'
+ put:
+ tags:
+ - Auth Configuration
+ summary: Update hosted auth page
+ description: |
+ Saves the current HTML/CSS for this page type.
+ Security validation rejects script tags, javascript: URLs, inline event handlers, iframe/object/embed/meta/link tags in HTML,
+ and closing style/head tags in CSS.
+ operationId: updateAuthHostedPage
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: pageType
+ in: path
+ required: true
+ schema:
+ $ref: '#/components/schemas/HostedAuthPageType'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateAuthHostedPageRequest'
+ responses:
+ '200':
+ description: Hosted page updated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AuthHostedPageResponse'
+ '400':
+ description: Invalid input or unsafe markup
+ '401':
+ description: Unauthorized
+ '403':
+ description: Forbidden
+ '404':
+ description: Project not found
+ /projects/{id}/auth/pages/appearance:
+ get:
+ tags:
+ - Auth Configuration
+ summary: Get managed auth page appearance
+ operationId: getAuthPageAppearance
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ responses:
+ '200':
+ description: Saved appearance and effective plan state
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AuthPageAppearanceResponse'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Access denied
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Project not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Appearance could not be read
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/auth/pages/theme:
+ put:
+ tags:
+ - Auth Configuration
+ summary: Save the managed auth page theme
+ operationId: updateAuthPageTheme
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateAuthPageThemeRequest'
+ responses:
+ '200':
+ description: Theme saved
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateAuthPageThemeRequest'
+ '400':
+ description: Invalid or unreadable theme
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Plan does not permit customisation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Project not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Theme could not be saved
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ delete:
+ tags:
+ - Auth Configuration
+ summary: Clear the managed auth page theme
+ operationId: deleteAuthPageTheme
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ responses:
+ '204':
+ description: Theme cleared
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Plan does not permit customisation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Project not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Theme could not be cleared
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/auth/pages/{pageType}/layout:
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: pageType
+ in: path
+ required: true
+ schema:
+ $ref: '#/components/schemas/HostedAuthPageType'
+ put:
+ tags:
+ - Auth Configuration
+ summary: Save one managed auth page layout
+ operationId: updateAuthPageLayout
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateAuthPageLayoutRequest'
+ responses:
+ '200':
+ description: Layout saved
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateAuthPageLayoutRequest'
+ '400':
+ description: Invalid page type or layout
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Plan does not permit customisation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Project not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Layout could not be saved
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ delete:
+ tags:
+ - Auth Configuration
+ summary: Clear one managed auth page layout
+ operationId: deleteAuthPageLayout
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ responses:
+ '204':
+ description: Layout cleared
+ '400':
+ description: Invalid page type
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Plan does not permit customisation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Project not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Layout could not be cleared
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/auth/pages/{pageType}/preview:
+ get:
+ tags:
+ - Auth Configuration
+ summary: Render a short-lived managed auth page preview
+ description: |
+ Public HTML endpoint for a preview URL returned by the POST operation.
+ The signed ticket contains the unsaved appearance, expires shortly, and
+ runs the production page runtime against mocked authentication responses.
+ operationId: renderAuthPagePreview
+ security: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: pageType
+ in: path
+ required: true
+ schema:
+ $ref: '#/components/schemas/HostedAuthPageType'
+ - name: ticket
+ in: query
+ required: true
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 4096
+ description: Short-lived signed preview ticket returned by the POST operation.
+ responses:
+ '200':
+ description: Rendered preview document
+ content:
+ text/html:
+ schema:
+ type: string
+ '404':
+ description: Ticket is invalid or expired, its path does not match, or managed authentication is disabled
+ content:
+ text/plain:
+ schema:
+ type: string
+ '500':
+ description: Preview could not be rendered
+ content:
+ text/plain:
+ schema:
+ type: string
+ post:
+ tags:
+ - Auth Configuration
+ summary: Preview an unsaved managed auth page appearance
+ operationId: previewAuthPage
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: pageType
+ in: path
+ required: true
+ schema:
+ $ref: '#/components/schemas/HostedAuthPageType'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PreviewAuthPageRequest'
+ responses:
+ '200':
+ description: Short-lived URL for the rendered preview document
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PreviewAuthPageResponse'
+ '400':
+ description: Invalid page type or draft
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Access denied
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Project not found or managed authentication is disabled
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Preview could not be rendered
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/auth/hosted/{pageType}:
+ get:
+ tags:
+ - Auth Configuration
+ summary: Render a managed auth page
+ description: |
+ Public HTML endpoint for signup, forgot-password, device approval,
+ verify-email, and reset-password pages. Login uses the path without a
+ page type.
+ Requires `Accept: text/html`.
+ Returns 404 when managed hosted pages are disabled for the project.
+ security: []
+ operationId: renderManagedAuthPage
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: pageType
+ in: path
+ required: true
+ schema:
+ $ref: '#/components/schemas/HostedRenderablePageType'
+ responses:
+ '200':
+ description: Hosted auth page HTML
+ content:
+ text/html:
+ schema:
+ type: string
+ '400':
+ description: Invalid project id or unsupported Accept header
+ '404':
+ description: Managed pages disabled or page type not found
+ /projects/{id}/auth/hosted:
+ get:
+ tags:
+ - Auth Configuration
+ summary: Render default managed auth page
+ description: |
+ Public HTML endpoint for the managed login page.
+ Requires `Accept: text/html`.
+ security: []
+ operationId: renderDefaultManagedAuthPage
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: action
+ in: query
+ required: false
+ schema:
+ type: string
+ enum:
+ - login
+ - signup
+ - forgot-password
+ - device
+ description: |
+ Optional deep-link action for the unified hosted page. Ignored when a
+ custom login page is configured. `action=device` renders the device
+ authorization approval UI inline (no redirect to any external app);
+ it signs the user in and calls `POST /auth/device/verify`.
+ - name: user_code
+ in: query
+ required: false
+ schema:
+ type: string
+ description: Device user code (from `POST /auth/device/authorize`) used with `action=device`.
+ - name: anon_key
+ in: query
+ required: false
+ schema:
+ type: string
+ description: Project anon key used by built-in managed auth flows (required for login/signup/device actions).
+ - name: state
+ in: query
+ required: false
+ schema:
+ type: string
+ description: |
+ Opaque one-time nonce generated by the client SDK before redirecting
+ here. On successful login/signup it is echoed back in the post-auth
+ redirect fragment as `state`, so the SDK can bind the returned session
+ to the flow it initiated (login-CSRF / session-fixation defense). The
+ SDK rejects a returned session whose `state` does not match.
+ responses:
+ '200':
+ description: Hosted auth page HTML
+ content:
+ text/html:
+ schema:
+ type: string
+ '400':
+ description: Invalid project id or unsupported Accept header
+ '404':
+ description: Managed pages disabled
+ /projects/{id}/auth/hosted/login/options:
+ get:
+ tags:
+ - Auth Configuration
+ summary: Get hosted login runtime options
+ description: |
+ Returns runtime options for the built-in managed login flow.
+ Requires `anon_key` query parameter.
+ Rate limited per project and client IP. Excess requests return `429` and `Retry-After`.
+ security: []
+ operationId: getHostedLoginOptions
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: anon_key
+ in: query
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: Hosted login options returned
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/HostedLoginOptionsResponse'
+ '401':
+ description: Invalid or missing anon key
+ '404':
+ description: Managed pages disabled
+ '429':
+ description: Rate limit exceeded
+ /projects/{id}/auth/hosted/login/check-email:
+ post:
+ tags:
+ - Auth Configuration
+ summary: Check whether email exists for hosted login flow
+ description: |
+ Used by the built-in managed login page to branch UI between signin and signup.
+ Requires anon key in Authorization header.
+ Rate limited per project and client IP. Excess requests return `429` and `Retry-After`.
+ security: []
+ operationId: hostedLoginCheckEmail
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: Authorization
+ in: header
+ required: true
+ schema:
+ type: string
+ description: Bearer anon key (`Bearer `)
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/HostedLoginEmailCheckRequest'
+ responses:
+ '200':
+ description: Email existence evaluated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/HostedLoginEmailCheckResponse'
+ '401':
+ description: Invalid or missing anon key
+ '429':
+ description: Rate limit exceeded
+ /projects/{id}/auth/methods:
+ get:
+ tags:
+ - Auth Configuration
+ summary: Get all authentication methods
+ description: |
+ Returns all configured authentication methods for this project,
+ including email/password, anonymous, device authorization, and OAuth providers.
+ operationId: getAuthMethods
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ responses:
+ '200':
+ description: Authentication methods configuration
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ email_password:
+ type: object
+ properties:
+ enabled:
+ type: boolean
+ method:
+ type: string
+ name:
+ type: string
+ anonymous:
+ type: object
+ properties:
+ enabled:
+ type: boolean
+ method:
+ type: string
+ name:
+ type: string
+ oauth_providers:
+ type: array
+ items:
+ type: object
+ properties:
+ enabled:
+ type: boolean
+ method:
+ type: string
+ provider:
+ type: string
+ name:
+ type: string
+ redirect_url:
+ type: string
+ scopes:
+ type: array
+ items:
+ type: string
+ available_methods:
+ type: array
+ items:
+ type: string
+ example:
+ - email_password
+ - oauth_google
+ - oauth_github
+ put:
+ tags:
+ - Auth Configuration
+ summary: Configure authentication methods (unified)
+ description: |
+ Configure all authentication methods in a single request.
+ At least one method must remain enabled.
+ operationId: configureAuthMethods
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ enable_email_password:
+ type: boolean
+ enable_anonymous:
+ type: boolean
+ oauth_providers:
+ type: array
+ items:
+ type: object
+ properties:
+ provider:
+ type: string
+ enabled:
+ type: boolean
+ responses:
+ '200':
+ description: Methods configured
+ '400':
+ description: At least one method must be enabled
+ /projects/{id}/oauth/configs:
+ get:
+ tags:
+ - OAuth Configuration
+ summary: List OAuth configurations
+ description: List all OAuth provider configurations for this project
+ operationId: listOAuthConfigs
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ responses:
+ '200':
+ description: List of OAuth configurations
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ configs:
+ type: array
+ items:
+ $ref: '#/components/schemas/OAuthConfig'
+ post:
+ tags:
+ - OAuth Configuration
+ summary: Create OAuth configuration
+ description: Configure OAuth provider (Google, GitHub, Microsoft, Apple, Device)
+ operationId: createOAuthConfig
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateOAuthConfigRequest'
+ responses:
+ '201':
+ description: OAuth config created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/OAuthConfig'
+ '409':
+ description: Provider already configured
+ /projects/{id}/oauth/configs/{provider}:
+ get:
+ tags:
+ - OAuth Configuration
+ summary: Get OAuth configuration
+ operationId: getOAuthConfig
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: provider
+ in: path
+ required: true
+ schema:
+ type: string
+ enum:
+ - google
+ - github
+ - microsoft
+ - apple
+ - device
+ - name: client_id
+ in: query
+ required: false
+ schema:
+ type: string
+ description: Required when `provider=device` to select a specific device client.
+ responses:
+ '200':
+ description: OAuth configuration
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/OAuthConfig'
+ put:
+ tags:
+ - OAuth Configuration
+ summary: Update OAuth configuration
+ operationId: updateOAuthConfig
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: provider
+ in: path
+ required: true
+ schema:
+ type: string
+ enum:
+ - google
+ - github
+ - microsoft
+ - apple
+ - device
+ - name: client_id
+ in: query
+ required: false
+ schema:
+ type: string
+ description: Required when `provider=device` to select a specific device client.
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateOAuthConfigRequest'
+ responses:
+ '200':
+ description: OAuth config updated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/OAuthConfig'
+ delete:
+ tags:
+ - OAuth Configuration
+ summary: Delete OAuth configuration
+ operationId: deleteOAuthConfig
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: provider
+ in: path
+ required: true
+ schema:
+ type: string
+ enum:
+ - google
+ - github
+ - microsoft
+ - apple
+ - device
+ - name: client_id
+ in: query
+ required: false
+ schema:
+ type: string
+ description: Required when `provider=device` to select a specific device client.
+ responses:
+ '204':
+ description: OAuth config deleted
+ /projects/{id}/oauth/providers:
+ get:
+ tags:
+ - OAuth Configuration
+ summary: List available OAuth providers
+ description: Get list of supported OAuth providers and their default scopes
+ operationId: listAvailableOAuthProviders
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ responses:
+ '200':
+ description: Available providers
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ providers:
+ type: array
+ items:
+ type: object
+ properties:
+ id:
+ type: string
+ name:
+ type: string
+ default_scopes:
+ type: array
+ items:
+ type: string
+ /auth/oauth/{provider}/authorize:
+ get:
+ tags:
+ - OAuth Authentication
+ summary: Start OAuth authorization
+ description: |
+ Redirects user to OAuth provider for authorization.
+ Handles CSRF protection with state parameter.
+ Project is identified via the anon_key query parameter.
+ operationId: authOAuthAuthorize
+ parameters:
+ - name: provider
+ in: path
+ required: true
+ schema:
+ type: string
+ enum:
+ - google
+ - github
+ - microsoft
+ - apple
+ - name: anon_key
+ in: query
+ required: true
+ schema:
+ type: string
+ description: Project anon key (required - identifies the project)
+ - name: redirect_url
+ in: query
+ schema:
+ type: string
+ description: |
+ URL to redirect to after the OAuth flow (optional). Must exactly
+ match an entry in the project's `allowed_redirect_urls`, including
+ its query string, or be the project's own managed hosted-auth page
+ URL.
+ - name: client_state
+ in: query
+ schema:
+ type: string
+ maxLength: 255
+ description: |
+ Optional application nonce. It is stored with the server-generated
+ provider state and echoed to redirect_url as `state`.
+ - name: response_mode
+ in: query
+ schema:
+ type: string
+ enum:
+ - code
+ description: |
+ Set to `code` to receive a short-lived authorization code at
+ redirect_url, then use POST /auth/oauth/exchange to obtain the
+ session. `redirect_url` is required in this mode. When omitted, the
+ established session-fragment response is retained for compatibility
+ with existing clients.
+ responses:
+ '307':
+ description: Redirect to OAuth provider
+ '400':
+ description: |
+ OAuth provider is disabled for this project, or `redirect_url` is
+ not registered in `allowed_redirect_urls`
+ '404':
+ description: OAuth provider not configured
+ /auth/oauth/{provider}/callback:
+ get:
+ tags:
+ - OAuth Authentication
+ summary: OAuth callback handler
+ description: |
+ Handles OAuth provider callback with authorization code.
+ Exchanges code for tokens and creates/signs in user.
+ operationId: authOAuthCallback
+ parameters:
+ - name: provider
+ in: path
+ required: true
+ schema:
+ type: string
+ enum:
+ - google
+ - github
+ - microsoft
+ - apple
+ - name: code
+ in: query
+ required: true
+ schema:
+ type: string
+ - name: state
+ in: query
+ required: true
+ schema:
+ type: string
+ - name: error
+ in: query
+ schema:
+ type: string
+ responses:
+ '200':
+ description: Existing user signed in (when redirect_url was omitted)
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AuthTokenResponse'
+ '201':
+ description: New user created and signed in (when redirect_url was omitted)
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AuthTokenResponse'
+ '303':
+ description: |
+ Redirect to the exact registered redirect_url. Flows that requested
+ response_mode=code receive a short-lived, single-use `code` and
+ optional application `state`; compatibility flows receive the
+ established session fragment.
+ '400':
+ description: |
+ Missing/invalid code or state, the state parameter expired, the
+ provider was disabled after the flow started, or the flow's stored
+ redirect_url is no longer registered in allowed_redirect_urls (both
+ re-checked at callback time)
+ '403':
+ description: |
+ The provider's email domain is not in `allowed_email_domains`. Creating
+ an account is refused under `signup` and `signup_and_signin`; signing in
+ an already-linked account is refused under `signup_and_signin`, as it is
+ when the account's canonical email is outside the list. A new account
+ at a reserved domain (`anonymous.volcano.internal`, `volcano.local`) is
+ refused whatever the project allows.
+ '404':
+ description: |
+ The provider's configuration was removed after the flow started
+ (re-checked at callback time), or the account a link started from
+ was deleted
+ '409':
+ description: Email already exists (requires linking)
+ /auth/oauth/exchange:
+ post:
+ tags:
+ - OAuth Authentication
+ summary: Exchange OAuth authorization code
+ description: |
+ Atomically consumes a short-lived callback code and returns the user's
+ session. The request must use the same project anon key and exact
+ redirect_url that initiated the flow.
+ operationId: authOAuthExchange
+ security:
+ - AnonKey: []
+ parameters:
+ - $ref: '#/components/parameters/AuthProxyAuthorization'
+ - $ref: '#/components/parameters/AuthProxyClientIP'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - code
+ - redirect_url
+ properties:
+ code:
+ type: string
+ redirect_url:
+ type: string
+ format: uri
+ responses:
+ '200':
+ description: Authorization code consumed and session created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AuthTokenResponse'
+ '400':
+ description: Invalid, expired, consumed, or redirect-mismatched code
+ '401':
+ description: Missing or invalid project anon key; or invalid auth proxy metadata
+ '403':
+ description: |
+ Email confirmation is now required, or the account's canonical email or
+ the provider identity's email is not in `allowed_email_domains` while
+ `allowed_email_domains_mode` is `signup_and_signin`. Both are re-checked here because the code outlives
+ the callback that issued it.
+ '429':
+ description: Too many exchange attempts from this client
+ /auth/device/authorize:
+ post:
+ tags:
+ - OAuth Authentication
+ summary: Start RFC8628 device authorization
+ description: |
+ Starts OAuth 2.0 Device Authorization Grant (RFC 8628).
+ Returns `device_code` for the CLI and `user_code` for browser verification.
+
+ By default the returned `verification_uri` / `verification_uri_complete`
+ point at the project's managed device-approval page served by this API
+ (`/projects/{projectId}/auth/hosted?action=device&user_code=...&anon_key=...`),
+ which requires managed auth enabled and a default anon key for the
+ project.
+
+ Projects can override this by setting `device_verification_url` on the
+ auth config (`PATCH /auth/config`). When set, that URL is returned as-is
+ with the `user_code` appended (no `action=device` hint and no embedded
+ anon key — the page brings its own), so a CLI's `login` command surfaces
+ the project's own RFC 8628 approval page. With a custom URL, device login
+ does **not** require managed auth to be enabled; the custom page's origin
+ must be in the project's auth CORS allowlist to call
+ `POST /auth/device/verify`. Either way the verification page must
+ authenticate the end user and call `POST /auth/device/verify` with the
+ `user_code`. See the device-auth guide for both approaches.
+ operationId: authDeviceAuthorize
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - client_id
+ properties:
+ client_id:
+ type: string
+ description: Enabled `device` OAuth client ID for the target project
+ responses:
+ '200':
+ description: Device authorization started
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DeviceAuthorizationResponse'
+ '400':
+ description: Invalid request or unauthorized client
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/OAuthErrorResponse'
+ /auth/device/token:
+ post:
+ tags:
+ - OAuth Authentication
+ summary: Poll device token endpoint
+ description: |
+ RFC8628 token polling endpoint.
+ Returns OAuth errors such as `authorization_pending`, `slow_down`, `access_denied`, and `expired_token`.
+ operationId: authDeviceToken
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - grant_type
+ - device_code
+ - client_id
+ properties:
+ grant_type:
+ type: string
+ enum:
+ - urn:ietf:params:oauth:grant-type:device_code
+ device_code:
+ type: string
+ client_id:
+ type: string
+ responses:
+ '200':
+ description: Device flow completed, auth-user session minted
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AuthTokenResponse'
+ '400':
+ description: Polling state/error response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/OAuthErrorResponse'
+ '403':
+ description: |
+ `access_denied` - the approving account's canonical email, or the email
+ of any of its identities, is not in `allowed_email_domains` while `allowed_email_domains_mode` is
+ `signup_and_signin`. Re-checked here because approval and redemption
+ are separate requests.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/OAuthErrorResponse'
+ /auth/device/verify:
+ post:
+ tags:
+ - OAuth Authentication
+ summary: Approve or deny a device code
+ description: |
+ Browser-side endpoint for authenticated auth-users to approve (`approve`) or deny (`deny`) a `user_code`.
+
+ Called by the verification page after the end user signs in. The grant is
+ scoped to the project the auth-user token belongs to: approving a
+ `user_code` issued for a different project returns `403`. This endpoint
+ does not require managed auth to be enabled, so a custom verification page
+ (hosted anywhere) can drive approval — it just needs an authenticated
+ project auth-user access token and, for cross-origin browser calls, the
+ page origin allowed in the project's auth CORS settings.
+ operationId: authDeviceVerify
+ security:
+ - AuthUserAccessToken: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - user_code
+ properties:
+ user_code:
+ type: string
+ action:
+ type: string
+ enum:
+ - approve
+ - deny
+ default: approve
+ responses:
+ '200':
+ description: Verification action accepted
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ success:
+ type: boolean
+ status:
+ type: string
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/platform/exchange:
+ post:
+ tags:
+ - OAuth Authentication
+ summary: Exchange auth-user device session for platform token
+ description: |
+ Exchanges a verified auth-user device-flow session into a platform token for CLI usage.
+ The target platform user is derived from authenticated auth-user mapping; client cannot select another user.
+ operationId: authPlatformExchange
+ security:
+ - AuthUserAccessToken: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - client_id
+ properties:
+ client_id:
+ type: string
+ responses:
+ '200':
+ description: Platform token minted
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PlatformExchangeResponse'
+ '403':
+ description: |
+ Exchange not allowed for this session/client/project, or the
+ account's canonical email, or the email of any of its identities, is
+ not in `allowed_email_domains` while `allowed_email_domains_mode` is
+ `signup_and_signin`. The domain is re-checked here because the minted platform token outlives the
+ session it is exchanged from.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/oauth/providers:
+ get:
+ tags:
+ - OAuth Authentication
+ summary: List user's linked providers
+ description: |
+ Lists the OAuth providers linked to the signed-in user, with the
+ user's own account ID at each provider. Match on `provider_user_id`,
+ which never changes, rather than on the login or email. For
+ GitHub, it is the numeric user ID that GitHub reports elsewhere, such
+ as a webhook's `sender.id`.
+ operationId: authListOAuthProviders
+ security:
+ - AuthUserAccessToken: []
+ responses:
+ '200':
+ description: Linked providers
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ providers:
+ type: array
+ items:
+ type: object
+ required:
+ - provider
+ - provider_user_id
+ - linked_at
+ - updated_at
+ properties:
+ provider:
+ type: string
+ provider_user_id:
+ type: string
+ description: |
+ The user's account ID at the provider, as a string.
+ It stays the same when the user renames the account.
+ example: '583231'
+ provider_login:
+ type: string
+ description: |
+ The account's login at the provider when it was
+ linked, such as a GitHub username. It isn't updated
+ when the user renames the account. Omitted for
+ providers without logins.
+ example: octocat
+ linked_at:
+ type: string
+ format: date-time
+ updated_at:
+ type: string
+ format: date-time
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/oauth/{provider}/link:
+ post:
+ tags:
+ - OAuth Authentication
+ summary: Link OAuth provider to current user
+ description: |
+ Generates authorization URL to link OAuth provider to existing account.
+ User must be authenticated.
+ operationId: authLinkOAuthProvider
+ security:
+ - AuthUserAccessToken: []
+ parameters:
+ - name: provider
+ in: path
+ required: true
+ schema:
+ type: string
+ enum:
+ - google
+ - github
+ - microsoft
+ - apple
+ - name: redirect_url
+ in: query
+ schema:
+ type: string
+ description: |
+ URL to redirect to after linking completes (optional). Same
+ allowed_redirect_urls requirement as GET /auth/oauth/{provider}/authorize.
+ - name: client_state
+ in: query
+ schema:
+ type: string
+ maxLength: 255
+ description: |
+ Optional application nonce echoed to redirect_url as `state`.
+ - name: response_mode
+ in: query
+ schema:
+ type: string
+ enum:
+ - code
+ description: |
+ Set to `code` to receive a short-lived authorization code at
+ redirect_url. `redirect_url` is required in this mode. When
+ omitted, the established session-fragment response is retained for
+ compatibility with existing clients.
+ responses:
+ '200':
+ description: Authorization URL generated
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ authorization_url:
+ type: string
+ '400':
+ description: redirect_url is not registered in allowed_redirect_urls
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: OAuth provider not configured
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: Provider already linked
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/oauth/{provider}/unlink:
+ delete:
+ tags:
+ - OAuth Authentication
+ summary: Unlink OAuth provider
+ description: |
+ Remove OAuth provider from user's account. Refused when the account would
+ have no other way to sign in: another linked OAuth provider that's enabled
+ for the project, or a password while email/password sign-in is on for the
+ project (`enable_email_password`).
+ operationId: authUnlinkOAuthProvider
+ security:
+ - AuthUserAccessToken: []
+ parameters:
+ - name: provider
+ in: path
+ required: true
+ schema:
+ type: string
+ enum:
+ - google
+ - github
+ - microsoft
+ - apple
+ responses:
+ '204':
+ description: Provider unlinked
+ '400':
+ description: Cannot unlink last authentication method
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Provider not linked
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/oauth/{provider}/refresh-token:
+ post:
+ tags:
+ - OAuth Authentication
+ summary: Refresh OAuth provider token
+ description: |
+ Refresh the access token for an OAuth provider using its refresh token.
+ Allows calling provider APIs on user's behalf (e.g., Google Drive, GitHub repos).
+ operationId: refreshOAuthProviderToken
+ security:
+ - AuthUserAccessToken: []
+ parameters:
+ - name: provider
+ in: path
+ required: true
+ schema:
+ type: string
+ enum:
+ - google
+ - github
+ - microsoft
+ - apple
+ responses:
+ '200':
+ description: Token refreshed successfully
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ message:
+ type: string
+ provider:
+ type: string
+ expires_in:
+ type: integer
+ '400':
+ description: No refresh token available or refresh failed
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Provider not linked
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/oauth/{provider}/token:
+ get:
+ tags:
+ - OAuth Authentication
+ summary: Get current provider access token
+ description: |
+ Get valid access token for OAuth provider.
+ Automatically refreshes if expired.
+ operationId: getOAuthProviderToken
+ security:
+ - AuthUserAccessToken: []
+ parameters:
+ - name: provider
+ in: path
+ required: true
+ schema:
+ type: string
+ enum:
+ - google
+ - github
+ - microsoft
+ - apple
+ responses:
+ '200':
+ description: Current access token
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ message:
+ type: string
+ provider:
+ type: string
+ expires_in:
+ type: integer
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Provider not linked
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/oauth/{provider}/call-api:
+ post:
+ tags:
+ - OAuth Authentication
+ summary: Call OAuth provider API
+ description: |
+ Make an authenticated request to an OAuth provider's API on behalf of the user.
+ The user's stored access token is automatically used and refreshed if needed.
+
+ The request is always sent to the provider's fixed API base URL joined with
+ the caller-supplied `endpoint`. `endpoint` must be a relative path beginning
+ with `/` (optionally with a query string); it cannot change the target host.
+ Absolute URLs, protocol-relative `//host` values, or userinfo (`@host`) are
+ rejected with `400` so the request can never be redirected to another host.
+
+ Examples of `endpoint`:
+ - Google userinfo: `/oauth2/v1/userinfo`
+ - GitHub repositories: `/user/repos`
+ - Microsoft Graph profile: `/me`
+
+ The response wraps the provider's raw JSON value with request metadata.
+ An empty provider body is represented as `data: null`; the envelope
+ preserves the provider's HTTP status in `status_code`, including errors.
+ Provider response bodies are limited to 8 MiB after decompression.
+ Transport failures, invalid JSON (including invalid UTF-8), and oversized
+ bodies return `502`. Provider redirects to another origin are blocked and
+ return `400`.
+ operationId: callOAuthProviderAPI
+ security:
+ - AuthUserAccessToken: []
+ parameters:
+ - name: provider
+ in: path
+ required: true
+ schema:
+ type: string
+ enum:
+ - google
+ - github
+ - microsoft
+ - apple
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - endpoint
+ properties:
+ endpoint:
+ type: string
+ description: |
+ Relative path on the provider's API, beginning with `/`. It is
+ joined with the provider's fixed base URL; it must not contain a
+ scheme, host, userinfo, or a leading `//`.
+ example: /user/repos
+ method:
+ type: string
+ enum:
+ - GET
+ - POST
+ default: GET
+ description: HTTP method to use
+ body:
+ type: object
+ additionalProperties: true
+ description: Request body for POST requests
+ responses:
+ '200':
+ description: Provider API response
+ content:
+ application/json:
+ schema:
+ type: object
+ description: OAuth provider API response envelope
+ required:
+ - provider
+ - endpoint
+ - status_code
+ - data
+ properties:
+ provider:
+ type: string
+ enum:
+ - google
+ - github
+ - microsoft
+ - apple
+ endpoint:
+ type: string
+ status_code:
+ type: integer
+ minimum: 100
+ maximum: 599
+ data:
+ description: Raw provider JSON value, or null when the provider returns no body
+ nullable: true
+ '400':
+ description: |
+ Invalid request (for example: missing `endpoint`, an `endpoint` that is
+ not a relative path, or an unsupported HTTP method), or a provider
+ redirect to another origin.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: OAuth provider configuration not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Failed to create the provider API request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '502':
+ description: Provider transport failure, invalid JSON, or response body larger than 8 MiB
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/anon-keys:
+ get:
+ tags:
+ - Anon Keys
+ summary: List anon keys
+ description: |
+ Supports two mutually exclusive pagination modes. Offset mode uses `page`
+ and `limit` and is the default when neither `cursor` nor `search` is
+ supplied (first page, default `limit`). Cursor mode uses `cursor` and
+ `limit`, supports `search` (case-insensitive name match), and returns
+ `next_cursor`. Sending both `page` and `cursor` (or `page` and `search`)
+ returns 400.
+ operationId: listAnonKeys
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/Page'
+ - $ref: '#/components/parameters/Limit'
+ - $ref: '#/components/parameters/Cursor'
+ - $ref: '#/components/parameters/EndingBefore'
+ - $ref: '#/components/parameters/Offset'
+ - $ref: '#/components/parameters/Search'
+ responses:
+ '200':
+ description: List of anon keys
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/AnonKey'
+ total:
+ type: integer
+ description: Total number of items matching the query (so the UI can render numbered pages).
+ has_more:
+ type: boolean
+ description: Whether a next page exists.
+ next_cursor:
+ type: string
+ description: Opaque cursor for the next page (cursor pagination only)
+ prev_cursor:
+ type: string
+ description: Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`.
+ post:
+ tags:
+ - Anon Keys
+ summary: Create anon key
+ operationId: createAnonKey
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ description: |
+ Key name for identification.
+ Can only contain letters, numbers, underscores, and hyphens.
+ pattern: ^[A-Za-z0-9_-]+$
+ minLength: 1
+ maxLength: 255
+ example: frontend-app
+ permissions:
+ type: array
+ items:
+ type: string
+ enum:
+ - auth.signup
+ - auth.signin
+ - auth.refresh
+ - auth.logout
+ - auth.password_reset
+ - auth.confirm_email
+ - auth.resend_confirmation
+ - storage.upload
+ - storage.download
+ - storage.list
+ - storage.delete
+ - realtime.connect
+ - realtime.subscribe
+ - realtime.publish
+ - functions.invoke
+ description: |
+ Optional list of permissions for this key.
+ If not provided, defaults to auth-only permissions: auth.signup, auth.signin, auth.refresh, auth.logout, auth.password_reset, auth.confirm_email, auth.resend_confirmation.
+ Storage, realtime, and functions permissions must be explicitly added if needed.
+ example:
+ - auth.signup
+ - auth.signin
+ - auth.refresh
+ - auth.logout
+ responses:
+ '201':
+ description: Anon key created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AnonKey'
+ '400':
+ description: Invalid key name or request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: Key with this name already exists
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/anon-keys/{keyId}:
+ get:
+ tags:
+ - Anon Keys
+ summary: Get anon key
+ description: Get details of a specific anon key
+ operationId: getAnonKey
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: keyId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: Anon key details
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AnonKey'
+ '404':
+ description: Key not found
+ delete:
+ tags:
+ - Anon Keys
+ summary: Revoke anon key
+ description: Revokes key - it will immediately stop working
+ operationId: revokeAnonKey
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: keyId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '204':
+ description: Key revoked
+ '401':
+ description: Unauthorized
+ '403':
+ description: Forbidden
+ '404':
+ description: Key not found
+ '409':
+ description: Cannot delete the project's default anon key
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/anon-keys/{keyId}/regenerate:
+ post:
+ tags:
+ - Anon Keys
+ summary: Regenerate anon key
+ description: Generate new JWT value for existing key
+ operationId: regenerateAnonKey
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: keyId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: Key regenerated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AnonKey'
+ '404':
+ description: Anon key not found, including deletion before the updated key can be returned
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/anon-keys/{keyId}/set-default:
+ post:
+ tags:
+ - Anon Keys
+ summary: Set default anon key
+ description: Promotes the given key to the project's configured default. At most one key per project can be default.
+ operationId: setDefaultAnonKey
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: keyId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: Key set as default
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AnonKey'
+ '401':
+ description: Unauthorized
+ '403':
+ description: Forbidden
+ '404':
+ description: Anon key not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '500':
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/access-tokens:
+ get:
+ tags:
+ - Project Access Tokens
+ summary: List a project's access tokens
+ description: |
+ Lists the project's access tokens, newest first. Secrets are never
+ returned: only a hash is stored, so a token's value exists solely in the
+ response to the create call.
+
+ Only tokens that can still authenticate are returned by default, so
+ revoked and expired ones are hidden. Pass `include_revoked=true` to see
+ them, which is how you find out what a key did before it stopped working.
+
+ Requires a platform token. A project access token cannot manage project
+ access tokens, so a leaked credential cannot enumerate or replace itself.
+ operationId: listProjectAccessTokens
+ security:
+ - UserToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/Page'
+ - $ref: '#/components/parameters/Limit'
+ - $ref: '#/components/parameters/Search'
+ - name: include_revoked
+ in: query
+ required: false
+ description: |
+ Include tokens that can no longer authenticate — both revoked and
+ expired ones.
+ schema:
+ type: boolean
+ default: false
+ responses:
+ '200':
+ description: Successful response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PaginatedProjectAccessTokens'
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - not the project owner, or a project access token was used
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Project not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ post:
+ tags:
+ - Project Access Tokens
+ summary: Create a project access token
+ description: |
+ Creates a project access token and returns its secret.
+
+ The secret is in this response and nowhere else. Only its hash is
+ stored, so it cannot be retrieved, displayed, or recovered later — save
+ it when you create it.
+
+ The name must be unique within the project, so a retry cannot mint a
+ second credential. It cannot recover the first one either. A retry that
+ returns `409` with code `access_token_name_exists` means the original
+ create committed and its secret is unrecoverable: list the project's
+ tokens, revoke the one holding that name, and create it again.
+
+ Requires a platform token.
+ operationId: createProjectAccessToken
+ security:
+ - UserToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateProjectAccessTokenRequest'
+ responses:
+ '201':
+ description: Token created - save the secret now, it cannot be retrieved again
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreatedProjectAccessToken'
+ '400':
+ description: Bad request - invalid name, scope, or expiry
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - not the project owner, or a project access token was used
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Project not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: |
+ Duplicate name, token limit reached, or the project is being
+ deleted. Tell them apart with `code`, which is one of
+ `access_token_name_exists`, `access_token_limit_reached`, or
+ `project_deleting` — the message text is not a contract.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/access-tokens/usage:
+ get:
+ tags:
+ - Project Access Tokens
+ summary: Per-day request counts for every access token in a project
+ description: |
+ Returns a zero-filled daily series of request counts for each of the
+ project's access tokens, oldest first. Every day in the window is
+ present, so a gap reads as zero rather than missing.
+
+ Revoked tokens are included, because the traffic they made before
+ revocation is usually the reason you are looking.
+
+ `days` defaults to 30 and is capped at 60, which is also how long per-day
+ counts are retained — a longer window cannot be answered.
+
+ A platform token sees every token in the project. A project access token
+ sees only its own row, so it can watch its own traffic without being
+ able to enumerate the project's other credentials by name.
+ operationId: listProjectAccessTokensUsage
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: days
+ in: query
+ required: false
+ description: Number of trailing days to return (1-60, default 30).
+ schema:
+ type: integer
+ minimum: 1
+ maximum: 60
+ default: 30
+ responses:
+ '200':
+ description: Successful response
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/ProjectAccessTokenUsage'
+ '400':
+ description: Bad request - invalid window
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - not the project owner
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Project not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/access-tokens/{tokenId}:
+ get:
+ tags:
+ - Project Access Tokens
+ summary: Get a project access token
+ description: |
+ Returns one token's metadata. Never its secret, which is not stored in a
+ recoverable form.
+
+ Requires a platform token.
+ operationId: getProjectAccessToken
+ security:
+ - UserToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/TokenId'
+ responses:
+ '200':
+ description: Successful response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProjectAccessToken'
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - not the project owner, or a project access token was used
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Token not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ delete:
+ tags:
+ - Project Access Tokens
+ summary: Revoke a project access token
+ description: |
+ Revokes the token. It stops authenticating immediately in the region
+ handling this call and within seconds across Volcano's other regions.
+
+ The record is kept rather than deleted, so the token's name, prefix, last
+ use, and request history stay available — which is what you need if you
+ are revoking because a secret leaked. Revoking an already-revoked token
+ succeeds.
+
+ Revoking does not undo anything the token already did. Treat whatever it
+ could reach as exposed and rotate accordingly.
+
+ Requires a platform token.
+ operationId: revokeProjectAccessToken
+ security:
+ - UserToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/TokenId'
+ responses:
+ '204':
+ description: Token revoked
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - not the project owner, or a project access token was used
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Token not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: Conflict - the project is being deleted
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/access-tokens/{tokenId}/usage:
+ get:
+ tags:
+ - Project Access Tokens
+ summary: Per-day request counts for one access token
+ description: |
+ Returns a zero-filled daily series of request counts for a single token,
+ oldest first, so the response always has exactly `days` entries.
+
+ `days` defaults to 30 and is capped at 60, matching how long per-day
+ counts are retained.
+
+ A project access token may read only its own usage; asking for another
+ token's returns `403`. A platform token may read any token in the
+ project.
+ operationId: getProjectAccessTokenUsage
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/TokenId'
+ - name: days
+ in: query
+ required: false
+ description: Number of trailing days to return (1-60, default 30).
+ schema:
+ type: integer
+ minimum: 1
+ maximum: 60
+ default: 30
+ responses:
+ '200':
+ description: Successful response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProjectAccessTokenUsage'
+ '400':
+ description: Bad request - invalid window
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized - invalid or missing token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: Forbidden - not the project owner
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Token not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/service-keys:
+ get:
+ tags:
+ - Service Keys
+ summary: List service keys (paginated)
+ description: |
+ List all service role keys for a project with pagination.
+
+ **WARNING:** Service keys bypass RLS - for backend/admin use only!
+ operationId: listServiceKeys
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/Page'
+ - $ref: '#/components/parameters/Limit'
+ - $ref: '#/components/parameters/Cursor'
+ - $ref: '#/components/parameters/EndingBefore'
+ - $ref: '#/components/parameters/Offset'
+ - $ref: '#/components/parameters/Search'
+ responses:
+ '200':
+ description: Paginated list of service keys
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PaginatedServiceKeys'
+ post:
+ tags:
+ - Service Keys
+ summary: Create service key
+ description: |
+ Create a new service role key for admin operations.
+
+ **WARNING:** Service keys bypass all RLS policies!
+ Store securely and NEVER expose in frontend code.
+ operationId: createServiceKey
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ description: |
+ Descriptive name for the key (e.g., "admin-dashboard", "background-jobs").
+ Can only contain letters, numbers, underscores, and hyphens.
+ pattern: ^[A-Za-z0-9_-]+$
+ minLength: 1
+ maxLength: 255
+ example: admin-dashboard
+ permissions:
+ type: array
+ items:
+ type: string
+ description: |
+ Optional least-privilege scope for the key. When omitted, empty, or
+ containing only blank strings, the key is granted full access (["*"])
+ for backward compatibility. Provide an explicit list (e.g.
+ ["functions.invoke", "locks.manage"]) to restrict the key; "*"
+ grants everything. Scope enforcement applies to function invocation,
+ storage object operations, project locks, sandboxes, and server-side auth proxy
+ metadata (auth.signin, auth.signup, auth.refresh, auth.logout,
+ auth.password_reset). A key scoped to a list without "*" reads, stops,
+ and messages a durable execution only with the `client_token` its
+ start returned. Today the scope doesn't restrict the database API, and
+ restricts realtime only on a durable run's channel: every service key
+ queries every table with RLS bypassed, subscribes to every other channel,
+ and publishes on broadcast channels. Once Volcano applies scopes to the
+ database API and realtime, a key without "*" gets 403 from the database
+ API, needs realtime.subscribe for broadcast and presence channels and
+ realtime.publish to publish, and needs "*" for table changes. `ai.invoke`
+ is reserved: this route refuses it with 400, and "*" doesn't include it.
+ example:
+ - functions.invoke
+ - locks.manage
+ responses:
+ '201':
+ description: Service key created - save the key_value immediately!
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ServiceKey'
+ '400':
+ description: Invalid key name or request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: Key with this name already exists
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/service-keys/{keyId}:
+ get:
+ tags:
+ - Service Keys
+ summary: Get service key
+ description: Get details of a specific service key
+ operationId: getServiceKey
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: keyId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: Service key details
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ServiceKey'
+ '403':
+ description: |
+ The key belongs to another project, a read-only project access token asked
+ for a credential, or a project access token asked for a key that holds
+ `ai.invoke`.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Key not found
+ delete:
+ tags:
+ - Service Keys
+ summary: Delete service key
+ description: |
+ Permanently delete a service key.
+ Any services using this key will immediately lose access.
+ operationId: deleteServiceKey
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: keyId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '204':
+ description: Key deleted
+ /projects/{id}/service-keys/{keyId}/regenerate:
+ post:
+ tags:
+ - Service Keys
+ summary: Regenerate service key
+ description: |
+ Generate new JWT value for existing key.
+ The old key stops working within a few seconds.
+ Update your backend services with the new key before regenerating in production.
+ operationId: regenerateServiceKey
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: keyId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: Key regenerated - save the new key_value immediately!
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ServiceKey'
+ '403':
+ description: |
+ The key belongs to another project, a read-only project access token asked
+ to regenerate it, or a project access token asked to regenerate a key that
+ holds `ai.invoke`.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/storage/buckets:
+ get:
+ tags:
+ - Storage Buckets
+ summary: List all storage buckets in a project
+ description: |
+ With no pagination params, returns the full bucket list as a bare array
+ (legacy). Supplying `cursor`, `ending_before`, `search`, or `limit`
+ switches to keyset (cursor) pagination and returns a paginated envelope
+ with `next_cursor`/`prev_cursor` and a filtered `total`.
+ operationId: listStorageBuckets
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/Limit'
+ - $ref: '#/components/parameters/Cursor'
+ - $ref: '#/components/parameters/EndingBefore'
+ - $ref: '#/components/parameters/Offset'
+ - $ref: '#/components/parameters/Search'
+ responses:
+ '200':
+ description: |
+ Either the full bucket list (bare array, legacy) or a paginated
+ envelope when cursor pagination is requested.
+ content:
+ application/json:
+ schema:
+ oneOf:
+ - type: array
+ items:
+ $ref: '#/components/schemas/StorageBucket'
+ - $ref: '#/components/schemas/PaginatedStorageBuckets'
+ post:
+ tags:
+ - Storage Buckets
+ summary: Create a new storage bucket
+ operationId: createStorageBucket
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateStorageBucketRequest'
+ responses:
+ '201':
+ description: Bucket created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/StorageBucket'
+ '409':
+ description: Bucket already exists
+ /projects/{id}/storage/buckets/{bucketName}:
+ get:
+ tags:
+ - Storage Buckets
+ summary: Get storage bucket by name
+ operationId: getStorageBucket
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/BucketName'
+ responses:
+ '200':
+ description: Bucket details
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/StorageBucket'
+ '404':
+ description: Bucket not found
+ patch:
+ tags:
+ - Storage Buckets
+ summary: Update storage bucket settings
+ operationId: updateStorageBucket
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/BucketName'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateStorageBucketRequest'
+ responses:
+ '200':
+ description: Bucket updated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/StorageBucket'
+ delete:
+ tags:
+ - Storage Buckets
+ summary: Delete storage bucket and all objects
+ operationId: deleteStorageBucket
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/BucketName'
+ responses:
+ '200':
+ description: Bucket deleted
+ /projects/{id}/storage/buckets/{bucketName}/policies:
+ get:
+ tags:
+ - Storage Policies
+ summary: List storage policies for a bucket
+ operationId: listStoragePolicies
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/BucketName'
+ responses:
+ '200':
+ description: List of policies
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/StoragePolicy'
+ post:
+ tags:
+ - Storage Policies
+ summary: Create a storage policy
+ operationId: createStoragePolicy
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/BucketName'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateStoragePolicyRequest'
+ responses:
+ '201':
+ description: Policy created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/StoragePolicy'
+ /projects/{id}/storage/buckets/{bucketName}/policies/{policyId}:
+ delete:
+ tags:
+ - Storage Policies
+ summary: Delete a storage policy
+ operationId: deleteStoragePolicy
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - $ref: '#/components/parameters/BucketName'
+ - name: policyId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: Policy deleted
+ '404':
+ description: Project, bucket, or policy not found. Also returned when the policy ID is malformed or belongs to another bucket.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/storage/objects:
+ get:
+ tags:
+ - Storage Admin
+ summary: List all storage objects in a project
+ description: |
+ Returns a paginated list of all storage objects across all buckets in the project.
+ Supports filtering by owner and pagination.
+ operationId: listStorageObjectsAdmin
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ - name: owner_id
+ in: query
+ description: Filter by owner user ID
+ schema:
+ type: string
+ format: uuid
+ - name: page
+ in: query
+ description: Page number (1-based)
+ schema:
+ type: integer
+ default: 1
+ minimum: 1
+ - name: limit
+ in: query
+ description: Items per page
+ schema:
+ type: integer
+ default: 50
+ minimum: 1
+ maximum: 100
+ - $ref: '#/components/parameters/Cursor'
+ - $ref: '#/components/parameters/EndingBefore'
+ - $ref: '#/components/parameters/Offset'
+ - $ref: '#/components/parameters/Search'
+ responses:
+ '200':
+ description: Paginated list of storage objects
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/StorageObjectWithBucket'
+ page:
+ type: integer
+ limit:
+ type: integer
+ total:
+ type: integer
+ has_more:
+ type: boolean
+ next_cursor:
+ type: string
+ description: Opaque cursor for the next page (cursor pagination only)
+ prev_cursor:
+ type: string
+ description: Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`.
+ /projects/{id}/storage/stats:
+ get:
+ tags:
+ - Storage Admin
+ summary: Get storage statistics for a project
+ description: Returns aggregate storage statistics including bucket count, object count, and total size.
+ operationId: getStorageStats
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ responses:
+ '200':
+ description: Storage statistics
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/StorageStats'
+ /projects/{id}/realtime/config:
+ get:
+ tags:
+ - Realtime
+ summary: Get realtime configuration for a project
+ description: Returns the realtime configuration including enabled features and limits.
+ operationId: getRealtimeConfig
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ responses:
+ '200':
+ description: Realtime configuration
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/RealtimeConfig'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '404':
+ description: Project not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ put:
+ tags:
+ - Realtime
+ summary: Update realtime configuration for a project
+ description: Updates realtime settings including feature toggles and limits.
+ operationId: updateRealtimeConfig
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateRealtimeConfigRequest'
+ responses:
+ '200':
+ description: Updated realtime configuration
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/RealtimeConfig'
+ '400':
+ description: Invalid configuration values
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /projects/{id}/realtime/stats:
+ get:
+ tags:
+ - Realtime
+ summary: Get realtime statistics for a project
+ description: Returns realtime usage statistics including connection counts and subscribed tables.
+ operationId: getRealtimeStats
+ security:
+ - UserToken: []
+ - ProjectAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/ProjectId'
+ responses:
+ '200':
+ description: Realtime statistics
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/RealtimeStats'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /storage/{bucketName}:
+ get:
+ tags:
+ - Storage Objects
+ summary: List objects in a bucket
+ operationId: listStorageObjects
+ security:
+ - AnonKey: []
+ - ServiceRoleKey: []
+ - AuthUserAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/BucketName'
+ - name: prefix
+ in: query
+ description: Filter objects by path prefix
+ schema:
+ type: string
+ - name: limit
+ in: query
+ description: Maximum objects to return
+ schema:
+ type: integer
+ default: 50
+ maximum: 1000
+ - name: cursor
+ in: query
+ description: Pagination cursor
+ schema:
+ type: string
+ responses:
+ '200':
+ description: List of objects
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/StorageListResponse'
+ '403':
+ description: Access denied by storage policy
+ '429':
+ $ref: '#/components/responses/BandwidthCapExceeded'
+ /locks/{key}/lease:
+ post:
+ tags:
+ - Locks
+ summary: Acquire a project lock
+ description: |
+ Acquires a project-scoped lease using the project embedded in the service-role key.
+ The caller must hold the `locks.manage` permission. Repeating the request with the
+ same lock token is idempotent and resets that lease to the requested TTL. A different
+ live owner receives `409 lock_held`; a caller whose own lease already lapsed receives
+ `409 lock_ownership_lost`.
+ operationId: acquireProjectLock
+ security:
+ - ServiceRoleKey: []
+ parameters:
+ - $ref: '#/components/parameters/LockKey'
+ - $ref: '#/components/parameters/LockToken'
+ - $ref: '#/components/parameters/LockRequestId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProjectLockLeaseRequest'
+ responses:
+ '201':
+ description: Lease acquired
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProjectLockLease'
+ '400':
+ description: Invalid lock key, token, or TTL
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Missing or invalid credentials
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: A non-service credential was supplied or the service key lacks `locks.manage`
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: |
+ The lock is held by another live lease (`lock_held`), or the caller's own lease
+ lapsed and is not yet reclaimable (`lock_ownership_lost`).
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '429':
+ description: Project lock request limit exceeded
+ headers:
+ Retry-After:
+ description: Seconds until the current fixed-minute window ends.
+ schema:
+ type: integer
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Lock service unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ patch:
+ tags:
+ - Locks
+ summary: Renew a project lock
+ description: |
+ Renews a lease owned by the supplied lock token. The request must arrive
+ more than one second before `expires_at`; this safety margin prevents
+ clock skew between regional API instances from resurrecting an expired
+ lease.
+ operationId: renewProjectLock
+ security:
+ - ServiceRoleKey: []
+ parameters:
+ - $ref: '#/components/parameters/LockKey'
+ - $ref: '#/components/parameters/LockToken'
+ - $ref: '#/components/parameters/LockRequestId'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProjectLockLeaseRequest'
+ responses:
+ '200':
+ description: Lease renewed
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProjectLockLease'
+ '400':
+ description: Invalid lock key, token, or TTL
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Missing or invalid credentials
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: A non-service credential was supplied or the service key lacks `locks.manage`
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: The lease expired or is owned by another token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '429':
+ description: Project lock request limit exceeded
+ headers:
+ Retry-After:
+ description: Seconds until the current fixed-minute window ends.
+ schema:
+ type: integer
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Lock service unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ delete:
+ tags:
+ - Locks
+ summary: Release a project lock
+ description: Releases a lease only when the supplied lock token still owns it.
+ operationId: releaseProjectLock
+ security:
+ - ServiceRoleKey: []
+ parameters:
+ - $ref: '#/components/parameters/LockKey'
+ - $ref: '#/components/parameters/LockToken'
+ - $ref: '#/components/parameters/LockRequestId'
+ responses:
+ '204':
+ description: Lease released
+ '400':
+ description: Invalid lock key or token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Missing or invalid credentials
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: A non-service credential was supplied or the service key lacks `locks.manage`
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '409':
+ description: The lease is owned by another token
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '429':
+ description: Project lock request limit exceeded
+ headers:
+ Retry-After:
+ description: Seconds until the current fixed-minute window ends.
+ schema:
+ type: integer
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Lock service unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /locks/{key}:
+ get:
+ tags:
+ - Locks
+ summary: Read a project lock
+ description: |
+ Reports whether the lock is currently held, when its lease expires, and the
+ holder's fencing token. `held` follows takeover eligibility rather than raw
+ expiry, so `held: false` means an acquire would succeed now. No lock token is
+ required, making this usable for monitoring and recovery.
+ operationId: getProjectLock
+ security:
+ - ServiceRoleKey: []
+ parameters:
+ - $ref: '#/components/parameters/LockKey'
+ - $ref: '#/components/parameters/LockRequestId'
+ responses:
+ '200':
+ description: Current lock state
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProjectLockState'
+ '400':
+ description: Invalid lock key
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Missing or invalid credentials
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: A non-service credential was supplied or the service key lacks `locks.manage`
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '429':
+ description: Project lock request limit exceeded
+ headers:
+ Retry-After:
+ description: Seconds until the current fixed-minute window ends.
+ schema:
+ type: integer
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Lock service unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ delete:
+ tags:
+ - Locks
+ summary: Force release a project lock
+ description: |
+ Drops the lease whatever token holds it, for recovering a lock whose holder
+ died without releasing. Use `DELETE /locks/{key}/lease` for normal release.
+
+ This breaks mutual exclusion by itself: the previous holder keeps working
+ until its own renewal fails. Guard the protected resource with the lease's
+ `fencing_token`, which the next acquisition raises, so a write from the
+ displaced holder can be rejected. Succeeds when the lock is already absent.
+ operationId: forceReleaseProjectLock
+ security:
+ - ServiceRoleKey: []
+ parameters:
+ - $ref: '#/components/parameters/LockKey'
+ - $ref: '#/components/parameters/LockRequestId'
+ responses:
+ '204':
+ description: Lock released
+ '400':
+ description: Invalid lock key
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '401':
+ description: Missing or invalid credentials
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: A non-service credential was supplied or the service key lacks `locks.manage`
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '429':
+ description: Project lock request limit exceeded
+ headers:
+ Retry-After:
+ description: Seconds until the current fixed-minute window ends.
+ schema:
+ type: integer
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '503':
+ description: Lock service unavailable
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /storage/{bucketName}/move:
+ post:
+ tags:
+ - Storage Objects
+ summary: Move/rename an object
+ operationId: moveStorageObject
+ security:
+ - ServiceRoleKey: []
+ - AuthUserAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/BucketName'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/StorageMoveRequest'
+ responses:
+ '200':
+ description: Object moved
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/StorageObject'
+ '403':
+ description: Access denied by storage policy
+ '429':
+ $ref: '#/components/responses/BandwidthCapExceeded'
+ /storage/{bucketName}/copy:
+ post:
+ tags:
+ - Storage Objects
+ summary: Copy an object
+ operationId: copyStorageObject
+ security:
+ - ServiceRoleKey: []
+ - AuthUserAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/BucketName'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/StorageCopyRequest'
+ responses:
+ '201':
+ description: Object copied
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/StorageObject'
+ '403':
+ description: Access denied by storage policy
+ '429':
+ $ref: '#/components/responses/BandwidthCapExceeded'
+ /storage/{bucketName}/{path}:
+ post:
+ tags:
+ - Storage Objects
+ summary: Upload a file or create resumable session
+ description: |
+ Unified endpoint for file uploads. Behavior depends on Content-Type and headers:
+
+ **Simple Upload (multipart/form-data):**
+ Upload a complete file in a single request. Best for files under 100MB.
+
+ **Create Resumable Session (application/json):**
+ Create a session for chunked uploads. Best for large files or unreliable networks.
+ Requires: `Content-Type: application/json` with body `{"filename": "...", "content_type": "...", "total_size": ...}`
+
+ **Complete Resumable Session:**
+ Complete a session after all parts are uploaded.
+ Requires: `X-Upload-Session` header with session ID and `X-Upload-Complete: true` header.
+
+ **Resumable Session Ownership:**
+ A session created with a user access token remains bound to that user. A session
+ created with an anon key remains bound to that exact anon key. Reuse the same
+ identity or anon key for part uploads, status, completion, and abort requests;
+ an ownership mismatch returns `404`.
+ operationId: uploadStorageObject
+ security:
+ - AnonKey: []
+ - ServiceRoleKey: []
+ - AuthUserAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/BucketName'
+ - name: path
+ in: path
+ required: true
+ description: Object path within bucket
+ schema:
+ type: string
+ - name: X-Upload-Session
+ in: header
+ required: false
+ description: Upload session ID (for completing resumable uploads)
+ schema:
+ type: string
+ - name: X-Upload-Complete
+ in: header
+ required: false
+ description: Set to "true" to complete a resumable upload session
+ schema:
+ type: string
+ enum:
+ - 'true'
+ requestBody:
+ required: true
+ content:
+ multipart/form-data:
+ schema:
+ type: object
+ required:
+ - file
+ properties:
+ file:
+ type: string
+ format: binary
+ description: File to upload (simple upload)
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateUploadSessionRequest'
+ responses:
+ '200':
+ description: Resumable upload completed (when X-Upload-Complete=true)
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CompleteUploadSessionResponse'
+ '201':
+ description: File uploaded or session created
+ content:
+ application/json:
+ schema:
+ oneOf:
+ - $ref: '#/components/schemas/StorageObject'
+ - $ref: '#/components/schemas/CreateUploadSessionResponse'
+ '400':
+ description: |
+ Bad request. This can occur when:
+ - MIME type is not in the bucket's allowed_mime_types list
+ - File exceeds the bucket's configured file_size_limit
+ - File exceeds the global maximum upload size (5GB)
+ - Invalid request body or missing required fields
+ '403':
+ description: Access denied by storage policy
+ '404':
+ description: Resumable upload session not found or not owned by this credential
+ '413':
+ description: |
+ File size exceeds plan-based limits. This occurs when:
+ - File exceeds the plan-based maximum file size (HOBBY or SUPERAGENT tier)
+ - The account on the HOBBY plan holds its file-storage allowance.
+ Enforcement is eventual: uploads are accepted until Volcano's
+ next allowance check sees the account at its allowance
+ '429':
+ $ref: '#/components/responses/BandwidthCapExceeded'
+ put:
+ tags:
+ - Storage Objects
+ summary: Upload a part of a resumable upload
+ description: |
+ Upload a single part of a resumable upload session.
+
+ **Requirements:**
+ - Part numbers start at 1
+ - All parts except the last must be at least 5MB
+ - Maximum part size is 25MB
+ - Parts can be uploaded in any order
+ - Re-uploading a part overwrites the previous upload
+ - Anonymous sessions must reuse the exact anon key that created the session
+ operationId: uploadPart
+ security:
+ - AnonKey: []
+ - ServiceRoleKey: []
+ - AuthUserAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/BucketName'
+ - name: path
+ in: path
+ required: true
+ description: Object path within bucket
+ schema:
+ type: string
+ - name: X-Upload-Session
+ in: header
+ required: true
+ description: Upload session ID
+ schema:
+ type: string
+ - name: X-Part-Number
+ in: header
+ required: true
+ description: Part number (1 to 10000)
+ schema:
+ type: integer
+ minimum: 1
+ maximum: 10000
+ requestBody:
+ required: true
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: binary
+ responses:
+ '200':
+ description: Part uploaded
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UploadSessionPart'
+ '400':
+ description: Invalid part number or part data
+ '403':
+ description: Access denied
+ '404':
+ description: Session not found or not owned by this credential
+ get:
+ tags:
+ - Storage Objects
+ summary: Download a file or get upload session status
+ description: |
+ Download a file, or get the status of a resumable upload session.
+
+ **File Download (default):**
+ Downloads the file at the specified path.
+
+ **Session Status (with X-Upload-Session header):**
+ Returns the status of a resumable upload session, including which parts have been uploaded.
+ Anonymous sessions must reuse the exact anon key that created the session.
+ operationId: downloadStorageObject
+ security:
+ - AnonKey: []
+ - ServiceRoleKey: []
+ - AuthUserAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/BucketName'
+ - name: path
+ in: path
+ required: true
+ description: Object path within bucket
+ schema:
+ type: string
+ - name: Range
+ in: header
+ required: false
+ description: |
+ HTTP Range header for partial downloads.
+ Format: bytes=start-end or bytes=start-
+ Examples: bytes=0-1023, bytes=1000-
+ schema:
+ type: string
+ pattern: ^bytes=\d+-\d*$
+ - name: X-Upload-Session
+ in: header
+ required: false
+ description: Upload session ID (to get session status instead of downloading)
+ schema:
+ type: string
+ responses:
+ '200':
+ description: File content or session status
+ headers:
+ Content-Type:
+ schema:
+ type: string
+ Content-Length:
+ schema:
+ type: integer
+ ETag:
+ schema:
+ type: string
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: binary
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UploadSessionStatusResponse'
+ '206':
+ description: Partial content (range request)
+ '400':
+ description: Invalid Range header format
+ '403':
+ description: Access denied by storage policy
+ '404':
+ description: Object or session not found, or session not owned by this credential
+ '416':
+ $ref: '#/components/responses/StorageRangeNotSatisfiable'
+ '429':
+ $ref: '#/components/responses/BandwidthCapExceeded'
+ delete:
+ tags:
+ - Storage Objects
+ summary: Delete a file or abort upload session
+ description: |
+ Delete a file, or abort a resumable upload session.
+
+ **File Delete (default):**
+ Deletes the file at the specified path.
+
+ **Abort Session (with X-Upload-Session header):**
+ Aborts a resumable upload session and cleans up any uploaded parts.
+ Anonymous sessions must reuse the exact anon key that created the session.
+ operationId: deleteStorageObject
+ security:
+ - AnonKey: []
+ - ServiceRoleKey: []
+ - AuthUserAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/BucketName'
+ - name: path
+ in: path
+ required: true
+ description: Object path within bucket
+ schema:
+ type: string
+ - name: X-Upload-Session
+ in: header
+ required: false
+ description: Upload session ID (to abort session instead of deleting file)
+ schema:
+ type: string
+ responses:
+ '200':
+ description: Object deleted or session aborted
+ '403':
+ description: Access denied by storage policy
+ '404':
+ description: Object or session not found, or session not owned by this credential
+ '429':
+ $ref: '#/components/responses/BandwidthCapExceeded'
+ /storage/{bucketName}/{path}/visibility:
+ patch:
+ tags:
+ - Storage Objects
+ summary: Update file visibility (public/private)
+ description: |
+ Change whether a file is publicly accessible. Only the file owner or a service key can change visibility.
+ If the bucket defines UPDATE policies, the owner must also satisfy one of them.
+
+ - Public files can be downloaded with just an anon key (no user authentication required)
+ - Private files (default) require authentication and must pass policy checks
+ - All downloads go through the Volcano API - there is no direct access to the underlying store
+ operationId: updateStorageObjectVisibility
+ security:
+ - ServiceRoleKey: []
+ - AuthUserAccessToken: []
+ parameters:
+ - $ref: '#/components/parameters/BucketName'
+ - name: path
+ in: path
+ required: true
+ description: Object path within bucket
+ schema:
+ type: string
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/StorageVisibilityRequest'
+ responses:
+ '200':
+ description: Visibility updated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/StorageObject'
+ '403':
+ description: Not the file owner or denied by the bucket's UPDATE policies
+ '404':
+ description: Object not found
+ /public/{projectId}/{bucketName}/{path}:
+ get:
+ tags:
+ - Storage Objects
+ summary: Download a public file (no authentication required)
+ description: |
+ Download a file that has been marked as public. This endpoint requires NO authentication.
+
+ **Access Requirements:**
+ - The file must have `is_public: true` set via the visibility endpoint
+ - Private files will return 403 Forbidden
+
+ **Use Cases:**
+ - Shareable public URLs for profile pictures, public documents, etc.
+ - Embedding public files on external websites
+ - Direct linking without requiring SDK or authentication
+
+ **URL Format:**
+ ```
+ GET /public/{projectId}/{bucketName}/{path}
+ ```
+
+ **Example:**
+ ```
+ https://api.volcano.dev/public/abc123/avatars/user-photo.jpg
+ ```
+
+ **CORS:**
+ This endpoint allows all origins since the file is already public.
+ operationId: downloadPublicFile
+ parameters:
+ - name: projectId
+ in: path
+ required: true
+ description: Project ID
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/BucketName'
+ - name: path
+ in: path
+ required: true
+ description: Object path within bucket
+ schema:
+ type: string
+ responses:
+ '200':
+ description: File content
+ content:
+ '*/*':
+ schema:
+ type: string
+ format: binary
+ '206':
+ description: Partial content (range request)
+ '404':
+ description: Not found (file doesn't exist or is not public)
+ '416':
+ $ref: '#/components/responses/StorageRangeNotSatisfiable'
+ '429':
+ $ref: '#/components/responses/BandwidthCapExceeded'
+ /health:
+ get:
+ tags:
+ - System
+ summary: Health check endpoint
+ description: Returns server health status. Used for load balancer and monitoring checks.
+ operationId: healthCheck
+ responses:
+ '200':
+ description: Server is healthy
+ content:
+ text/plain:
+ schema:
+ type: string
+ example: OK
+ /capabilities:
+ get:
+ tags:
+ - System
+ summary: List capabilities
+ description: |
+ Lists which product capabilities accept new work in this environment. Check it
+ to decide what to offer, instead of calling a route to see whether it fails.
+
+ | ID | Covers |
+ | --- | --- |
+ | `sandboxes` | The Sandbox API: presets, templates, sessions, and executions |
+ | `sandboxes.sessions` | Starting and resuming sessions, and one-shot executions |
+ | `sandboxes.custom_templates` | Deploying a custom template; its validation waits while `sandboxes.sessions` is unavailable |
+ | `sandboxes.network_isolation` | Creating sessions and one-shot executions with `network.egress` `deny_all`; existing `deny_all` sessions work either way |
+ | `sandboxes.output_not_kept` | Commands that keep no output: `keep_output: false` on a command, and `executions.keep_output: false` on a session; commands that keep output work either way |
+ | `issues` | The Issues API: listing, reading, and updating grouped runtime errors |
+ | `lavaflow` | LavaFlow, which diagnoses a project's issues and opens pull requests that fix them. Here it reports only whether LavaFlow is released in this environment; whether a project has it comes from `GET /projects/{id}/capabilities` |
+ | `lavaflow.merge` | LavaFlow merging its fixes, with `autonomy: merge`. Here it reports only whether merging is released in this environment; whether a project has it comes from `GET /projects/{id}/capabilities` |
+ | `lavaflow.lineage` | LavaFlow following up its fixes: linking a fix's recurrence or a new issue its deploy caused to the fix, the follow-up runs, and the lineage holds. Here it reports only whether fix lineage is released in this environment; whether a project has it comes from `GET /projects/{id}/capabilities` |
+ | `lavaflow.code_quality` | LavaFlow Code Quality, which reviews the code each frontend production deploy changes. Here it reports only whether Code Quality is released in this environment; whether a project has it comes from `GET /projects/{id}/capabilities` |
+ | `lavaflow.slack` | Reporting problems to LavaFlow from Slack: installing the Volcano Slack app, connecting Slack identities, and binding channels to projects. Here it reports whether LavaFlow is released, the Slack app is set up, and Slack reports have launched in this environment; whether a project has it comes from `GET /projects/{id}/capabilities` |
+ | `functions.response_streaming` | Streaming an HTTP-mode function's response on its own URL as the function writes it |
+ | `frontend_routes` | Creating and changing Frontend routes; listing, deleting, and serving existing ones work either way |
+ | `frontends.candidates` | Creating, redeploying, promoting and rolling back to a frontend Candidate; reading, deleting and rolling back to the frontend's own runtime always work |
+ | `databases.migrations` | Starting migration runs and recording a baseline; reading history and runs works either way |
+ | `shares` | Creating, switching on and publishing shares, and forking one |
+
+ A capability missing from the list is unavailable, and a capability under
+ another, such as `sandboxes.sessions`, is unavailable whenever its parent is.
+ While a capability is unavailable, requests that start new work answer `404`
+ or `400` with code `feature_unavailable`; refresh this list when you receive
+ that code. Reading, deleting, and terminating what already exists keep
+ working unless the whole feature is absent from the environment. Every caller
+ in an environment gets the same answer; `GET /projects/{id}/capabilities`
+ answers for one project.
+
+ `functions.response_streaming` refuses nothing: while it is unavailable, a
+ function's own URL still answers and sends a streamed response whole, once
+ the function finishes, up to 6 MiB with headers; a larger one fails the
+ invocation. Frontend Function routes stream either way.
+ operationId: listCapabilities
+ security: []
+ responses:
+ '200':
+ description: Capabilities in this environment
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CapabilityList'
+ example:
+ data:
+ - id: sandboxes
+ status: available
+ - id: sandboxes.sessions
+ status: available
+ - id: sandboxes.custom_templates
+ status: unavailable
+ - id: sandboxes.network_isolation
+ status: available
+ - id: sandboxes.output_not_kept
+ status: available
+ - id: issues
+ status: available
+ - id: functions.response_streaming
+ status: available
+ - id: frontend_routes
+ status: available
+ - id: frontends.candidates
+ status: unavailable
+ - id: databases.migrations
+ status: available
+ - id: shares
+ status: unavailable
+ /openapi.json:
+ get:
+ tags:
+ - System
+ summary: Fetch the OpenAPI specification as JSON
+ description: |
+ Returns this specification as a self-contained JSON document, with every
+ reference resolved. It is generated from the same document the server
+ validates requests against, so a client generated from it cannot
+ describe a different API than the one that answers.
+
+ No credential is required: a client generator fetches this by URL before
+ its user has a token, and every path here is already published in the
+ API reference.
+
+ The response carries a strong `ETag`; send it back as `If-None-Match` to
+ get `304 Not Modified` instead of the whole document.
+ operationId: getOpenAPISpecJSON
+ security: []
+ parameters:
+ - $ref: '#/components/parameters/IfNoneMatch'
+ responses:
+ '200':
+ description: The OpenAPI specification
+ headers:
+ ETag:
+ $ref: '#/components/headers/ETag'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/OpenAPISpecDocument'
+ '304':
+ $ref: '#/components/responses/OpenAPISpecNotModified'
+ '429':
+ $ref: '#/components/responses/OpenAPISpecThrottled'
+ head:
+ tags:
+ - System
+ summary: Check the JSON OpenAPI specification
+ description: |
+ The headers `GET /openapi.json` would return, so a cache can pick up the
+ current `ETag` without transferring the document.
+ operationId: headOpenAPISpecJSON
+ security: []
+ parameters:
+ - $ref: '#/components/parameters/IfNoneMatch'
+ responses:
+ '200':
+ $ref: '#/components/responses/OpenAPISpecHeaders'
+ '304':
+ $ref: '#/components/responses/OpenAPISpecNotModified'
+ '429':
+ $ref: '#/components/responses/OpenAPISpecThrottled'
+ /openapi.yaml:
+ get:
+ tags:
+ - System
+ summary: Fetch the OpenAPI specification as YAML
+ description: |
+ The same document as `/openapi.json`, serialized as YAML for tools that
+ prefer it. See that operation for caching and authentication notes.
+ operationId: getOpenAPISpecYAML
+ security: []
+ parameters:
+ - $ref: '#/components/parameters/IfNoneMatch'
+ responses:
+ '200':
+ description: The OpenAPI specification
+ headers:
+ ETag:
+ $ref: '#/components/headers/ETag'
+ content:
+ application/yaml:
+ schema:
+ $ref: '#/components/schemas/OpenAPISpecDocument'
+ '304':
+ $ref: '#/components/responses/OpenAPISpecNotModified'
+ '429':
+ $ref: '#/components/responses/OpenAPISpecThrottled'
+ head:
+ tags:
+ - System
+ summary: Check the YAML OpenAPI specification
+ description: |
+ The headers `GET /openapi.yaml` would return, so a cache can pick up the
+ current `ETag` without transferring the document.
+ operationId: headOpenAPISpecYAML
+ security: []
+ parameters:
+ - $ref: '#/components/parameters/IfNoneMatch'
+ responses:
+ '200':
+ $ref: '#/components/responses/OpenAPISpecHeaders'
+ '304':
+ $ref: '#/components/responses/OpenAPISpecNotModified'
+ '429':
+ $ref: '#/components/responses/OpenAPISpecThrottled'
+ /mcp:
+ post:
+ tags:
+ - System
+ summary: Model Context Protocol endpoint
+ description: |
+ Streamable-HTTP MCP endpoint: one JSON-RPC 2.0 object per request, one
+ response per request. There is no server-to-client stream, so a `GET`
+ returns `405`, and a batched array is rejected.
+
+ Authenticated with a **project access token**. The endpoint takes its
+ project from the credential, so a platform token is refused with `403` —
+ it names no project, and letting a tool argument choose one would hand an
+ agent its own blast radius.
+
+ Scope carries over from the REST API. A `read_only` token is not offered
+ mutating tools or credential-returning reads, and is refused if it calls
+ one anyway. Revoking the token ends MCP access on the same path it ends
+ API access.
+
+ Methods: `initialize`, `notifications/initialized`, `ping`,
+ `tools/list`, `tools/call`. See the
+ [MCP guide](https://docs.volcano.dev/platform/interfaces/mcp) for the
+ tool surface and client configuration.
+ operationId: callMCP
+ security:
+ - ProjectAccessToken: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ description: A JSON-RPC 2.0 request object.
+ required:
+ - jsonrpc
+ - method
+ properties:
+ jsonrpc:
+ type: string
+ enum:
+ - '2.0'
+ method:
+ type: string
+ description: The MCP method to call.
+ id:
+ description: |
+ Request identifier, echoed verbatim. Omit it to send a
+ notification, which is answered with `202` and no body.
+ oneOf:
+ - type: string
+ - type: integer
+ params:
+ type: object
+ additionalProperties: true
+ responses:
+ '200':
+ description: A JSON-RPC response object
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - jsonrpc
+ - id
+ properties:
+ jsonrpc:
+ type: string
+ enum:
+ - '2.0'
+ id:
+ description: Echoes the request's id. Null when the request could not be read well enough to determine one.
+ nullable: true
+ oneOf:
+ - type: string
+ - type: integer
+ result:
+ type: object
+ additionalProperties: true
+ error:
+ type: object
+ required:
+ - code
+ - message
+ properties:
+ code:
+ type: integer
+ message:
+ type: string
+ '202':
+ description: A notification was accepted; there is no body
+ '401':
+ description: Not authenticated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '403':
+ description: |
+ The credential is valid but may not use this endpoint — most often a
+ platform token, which names no project.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ '413':
+ description: The JSON-RPC frame exceeds the 1 MiB limit
+components:
+ headers:
+ ETag:
+ description: |
+ Strong validator for the returned document. Send it back as `If-None-Match`
+ to revalidate without transferring the document again.
+ required: true
+ schema:
+ type: string
+ example: '"9f2c1e0b5a"'
+ DatabaseQueryProxyMs:
+ description: |
+ Milliseconds Volcano spent before running the query, counted from the
+ request arriving: authenticating the caller, validating the request,
+ resolving the database, and building the SQL. Does not include query
+ execution. Also present when the query itself failed.
+ schema:
+ type: integer
+ minimum: 0
+ DatabaseQueryProxyHandlerMs:
+ description: |
+ The part of `X-Volcano-Proxy-Ms` spent in the query endpoint itself.
+ Subtract it from `X-Volcano-Proxy-Ms` to see what authentication and
+ request validation cost. Also present when the query itself failed.
+ schema:
+ type: integer
+ minimum: 0
+ DatabaseQueryComputeMs:
+ description: |
+ Milliseconds the database took to run the query and return its rows.
+ Does not include Volcano's preparation. Also present when the query
+ itself failed.
+ schema:
+ type: integer
+ minimum: 0
+ securitySchemes:
+ AnonKey:
+ type: http
+ scheme: bearer
+ bearerFormat: JWT
+ description: |
+ Project-specific public key for frontend authentication.
+ Required for signup, signin, refresh, and logout endpoints.
+ Get from Project Settings → Authentication → Anon Keys.
+ Safe to expose in frontend code (scoped to project, limited permissions).
+ AuthUserAccessToken:
+ type: http
+ scheme: bearer
+ bearerFormat: JWT
+ description: |
+ Auth user access token obtained from signup/signin.
+ Used for authenticated function invocation and user profile access.
+ Functions invoked with access tokens receive user context in event.__volcano_auth.
+ Expires after configured lifetime (default: 1 hour).
+ ServiceRoleKey:
+ type: http
+ scheme: bearer
+ bearerFormat: JWT
+ description: |
+ Service role key for admin operations.
+ **WARNING:** Bypasses Row-Level Security - backend use only!
+ Create via POST /projects/{id}/service-keys.
+ Used for function invocation with full database access.
+ UserToken:
+ type: http
+ scheme: bearer
+ bearerFormat: opaque
+ description: |
+ Platform token, which acts on every project in your account.
+ Obtain one by running `volcano login`, or from the dashboard.
+
+ For CI, scripts, and agents, prefer a project access token
+ (`pt-`) instead: it reaches only the project it was created in,
+ so a leak does not expose the rest of your account. See the
+ ProjectAccessToken scheme.
+ ProjectAccessToken:
+ type: http
+ scheme: bearer
+ bearerFormat: opaque
+ description: |
+ Project access token, scoped to a single project. Starts with `pt-`.
+
+ Accepted on that project's control-plane routes and refused
+ everywhere else, including account-wide endpoints and any other
+ project. A `read_only` token additionally refuses mutations.
+
+ Create one with POST /projects/{id}/access-tokens using a platform
+ token. The secret is returned once and is not recoverable, so a
+ project access token cannot create, list, read, or revoke project
+ access tokens.
+ parameters:
+ AuthProxyAuthorization:
+ name: X-Volcano-Proxy-Authorization
+ in: header
+ required: false
+ description: |
+ Trusted server-side auth proxy credential in `Bearer SERVICE_KEY`
+ form. When supplied, `X-Volcano-Client-IP` is also required. The service
+ key must belong to the anon key's project and hold this operation's scope:
+ `auth.signup` for signup and anonymous signup, `auth.signin` for signin
+ and OAuth code exchange, `auth.refresh` for refresh, `auth.logout` for
+ logout, and `auth.password_reset` for forgot-password and reset-password.
+ The password policy accepts any service key for the project. Never expose
+ a service key to browser code.
+ schema:
+ type: string
+ AuthProxyClientIP:
+ name: X-Volcano-Client-IP
+ in: header
+ required: false
+ description: |
+ Original browser IPv4 or IPv6 address supplied by a trusted server-side
+ auth proxy. The proxy must derive this value from its platform-verified
+ request metadata, never from a browser-supplied header. Requires a valid
+ `X-Volcano-Proxy-Authorization` header.
+ schema:
+ type: string
+ BackupName:
+ name: backupName
+ in: path
+ required: true
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 128
+ description: |
+ Backup name, unique within the database, exactly as returned by the list
+ endpoint.
+
+ Deliberately looser than the names you can create: a backup made by a
+ schedule is named for you, so reading or deleting one accepts any name a
+ backup can have.
+ BranchName:
+ name: branchName
+ in: path
+ required: true
+ schema:
+ type: string
+ pattern: ^[a-z0-9_]+$
+ maxLength: 64
+ description: Branch name (unique within the parent database, lowercase letters, numbers, and underscores only)
+ BucketName:
+ name: bucketName
+ in: path
+ required: true
+ schema:
+ type: string
+ pattern: ^[a-zA-Z0-9_-]+$
+ minLength: 1
+ maxLength: 64
+ description: Storage bucket name
+ Cursor:
+ name: cursor
+ in: query
+ required: false
+ schema:
+ type: string
+ description: |
+ Opaque keyset pagination cursor from a previous response's `next_cursor`
+ — pages forward. Mutually exclusive with `page` and `ending_before`;
+ combining them returns 400. When supplied, the request's `search` and
+ `limit` must match the values bound to the cursor or the request returns 400.
+ EndingBefore:
+ name: ending_before
+ in: query
+ required: false
+ schema:
+ type: string
+ description: |
+ Opaque keyset pagination cursor from a previous response's `prev_cursor`
+ — pages backward (the page immediately preceding this cursor). Mutually
+ exclusive with `page` and `cursor`; combining them returns 400. `search`
+ and `limit` must match the values bound to the cursor or the request
+ returns 400.
+ DatabaseName:
+ name: databaseName
+ in: path
+ required: true
+ schema:
+ type: string
+ pattern: ^[a-z0-9_]+$
+ maxLength: 64
+ description: Database name (unique within project, lowercase letters, numbers, and underscores only)
+ DeploymentId:
+ name: deploymentId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ description: Frontend deployment ID
+ SessionListPage:
+ name: page
+ in: query
+ description: |
+ Page number (1-indexed). Omit it for the first page, and always with
+ `cursor` or `ending_before`.
+ schema:
+ type: integer
+ minimum: 1
+ SessionListLimit:
+ name: limit
+ in: query
+ description: Number of sessions per page (max 100, default 20)
+ schema:
+ type: integer
+ minimum: 1
+ maximum: 100
+ SessionListSort:
+ name: sort
+ in: query
+ description: |
+ Sort key. `last_activity` (default) orders by most recent activity and
+ supports offset pagination only. `created_at` orders by session start
+ and supports both offset and cursor pagination.
+ schema:
+ type: string
+ enum:
+ - last_activity
+ - created_at
+ default: last_activity
+ SessionListStatus:
+ name: status
+ in: query
+ description: |
+ Filter by whether the session can still be refreshed. Omit for every
+ stored session, including expired ones. `expired` is not supported
+ with cursor pagination.
+ schema:
+ type: string
+ enum:
+ - active
+ - expired
+ SessionListCursor:
+ name: cursor
+ in: query
+ description: |
+ Opaque keyset cursor from a previous response's `next_cursor`. Requires
+ `sort=created_at`; mutually exclusive with `page` and `ending_before`.
+ schema:
+ type: string
+ SessionListEndingBefore:
+ name: ending_before
+ in: query
+ description: |
+ Opaque keyset cursor from a previous response's `prev_cursor`, paging
+ backward. Requires `sort=created_at`; mutually exclusive with `page`
+ and `cursor`.
+ schema:
+ type: string
+ SessionListOffset:
+ name: offset
+ in: query
+ description: |
+ Bounded number of rows to skip past the cursor anchor (the hybrid
+ jump, maximum 100000). Ignored unless `cursor` or `ending_before` is
+ supplied.
+ schema:
+ type: integer
+ minimum: 0
+ maximum: 100000
+ VariableEnvironmentId:
+ name: environmentId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ description: Variable Environment ID
+ FrontendId:
+ name: frontendId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ description: Frontend ID
+ FrontendCandidateId:
+ name: candidateId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ description: Frontend Candidate ID
+ FrontendFunctionRouteId:
+ name: routeId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ description: Frontend Function route ID
+ FrontendRouteId:
+ name: routeId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ description: Frontend route ID
+ FrontendCustomDomainHostname:
+ name: domain
+ in: path
+ required: true
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 253
+ description: The custom domain's hostname, such as `www.example.com`
+ FunctionId:
+ name: functionId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ description: Function ID
+ DurableFunctionId:
+ name: functionId
+ in: path
+ required: true
+ schema:
+ type: string
+ description: Durable function ID, or its name within the project
+ DurableExecutionId:
+ name: executionId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ description: Durable execution ID
+ DurableApprovalId:
+ name: approvalId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ description: Durable approval ID
+ IssueId:
+ name: issueId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ description: Issue ID
+ IssueCursor:
+ name: cursor
+ in: query
+ required: false
+ schema:
+ type: string
+ description: |
+ Opaque cursor from a previous response's `next_cursor`. Pages forward;
+ keep the same filters while paging.
+ DurableApprovalFunctionFilter:
+ name: function
+ in: query
+ required: false
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 255
+ description: |
+ Only approvals requested by this durable function, given by id or by
+ name. A name also matches approvals from a deleted function of that
+ name.
+ DurableMessageIdempotencyKey:
+ name: Idempotency-Key
+ in: header
+ required: false
+ description: |
+ Makes a send safe to retry. A repeat with a key the same sender has
+ used on the execution returns the first message and sends nothing.
+ Keys of different senders never collide. Up to 255 printable ASCII
+ characters.
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 255
+ pattern: ^[ -~]+$
+ DurableClientToken:
+ name: X-Volcano-Client-Token
+ in: header
+ required: false
+ description: |
+ The `client_token` the execution's start returned. Lets an anon key, a
+ service key scoped to a list without `*`, or a user who did not start
+ the execution, reach it.
+ schema:
+ type: string
+ maxLength: 128
+ DurableMessageDirectionFilter:
+ name: direction
+ in: query
+ required: false
+ description: Return only messages travelling this way.
+ schema:
+ $ref: '#/components/schemas/DurableMessageDirection'
+ DurableMessageNameFilter:
+ name: name
+ in: query
+ required: false
+ description: Return only messages with this name.
+ schema:
+ $ref: '#/components/schemas/DurableMessageName'
+ DurableMessageAfter:
+ name: after
+ in: query
+ required: false
+ description: Return only messages whose `seq` is greater than this.
+ schema:
+ type: integer
+ format: int64
+ minimum: 0
+ default: 0
+ DurableMessageLimit:
+ name: limit
+ in: query
+ required: false
+ description: Most messages to return.
+ schema:
+ type: integer
+ minimum: 1
+ maximum: 500
+ default: 100
+ Limit:
+ name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ minimum: 1
+ maximum: 100
+ default: 10
+ description: Number of items per page (max 100)
+ LockKey:
+ name: key
+ in: path
+ required: true
+ description: Project-local lock name.
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 128
+ pattern: ^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$
+ LockToken:
+ name: X-Volcano-Lock-Token
+ in: header
+ required: true
+ description: Opaque UUID generated once by the caller and retained for the lease lifetime.
+ schema:
+ type: string
+ format: uuid
+ LockRequestId:
+ name: X-Volcano-Request-Id
+ in: header
+ required: true
+ description: |
+ UUID correlating this request across client and server logs. Repeat safety comes from
+ the lock token, so a retry under a reused request ID still counts against the quota.
+ schema:
+ type: string
+ format: uuid
+ DeploymentOperation:
+ name: operation
+ in: query
+ required: false
+ description: Restrict a deployment feed to one kind of operation.
+ schema:
+ type: string
+ enum:
+ - deploy
+ - redeploy
+ - update
+ - delete
+ DeploymentOwnerId:
+ name: owner_id
+ in: query
+ required: false
+ description: |
+ The user who owns the projects whose deployments to return
+ (`projects.user_id`). This is ownership, not the actor that started the
+ deployment — see `initiated_by_user_id` for that. Not a UUID: platform
+ user ids are opaque strings.
+ schema:
+ type: string
+ maxLength: 255
+ DeploymentOrder:
+ name: order
+ in: query
+ required: false
+ description: |
+ Sort key and direction. `created_at.desc` (default) is the feed order.
+ `completed_at.asc` orders finished attempts by completion, oldest first,
+ and excludes attempts that never completed.
+ schema:
+ type: string
+ enum:
+ - created_at.desc
+ - completed_at.asc
+ default: created_at.desc
+ DeploymentResourceType:
+ name: resource_type
+ in: query
+ required: false
+ description: |
+ Restrict a deployment feed to a single resource type. Omit to return
+ both Function and Frontend deployments.
+ schema:
+ type: string
+ enum:
+ - function
+ - frontend
+ FunctionKindFilter:
+ name: function_kind
+ in: query
+ required: false
+ description: |
+ Restrict results to functions of one kind. Omit to include both
+ standard and durable functions.
+ schema:
+ $ref: '#/components/schemas/FunctionKindFilter'
+ DeploymentStatus:
+ name: status
+ in: query
+ required: false
+ description: Restrict a deployment feed to attempts in one status.
+ schema:
+ type: string
+ enum:
+ - queued
+ - provisioning
+ - active
+ - degraded
+ - failed
+ - superseded
+ - deleting
+ - deleted
+ Offset:
+ name: offset
+ in: query
+ required: false
+ schema:
+ type: integer
+ minimum: 0
+ default: 0
+ description: |
+ Bounded row offset past the keyset anchor named by `cursor` (forward) or
+ `ending_before` (backward) — the hybrid jump. Seek to the anchor, then
+ skip this many rows within. Used for numbered jump-to-page: from the
+ current page, seek to its next/prev cursor and offset the remaining
+ pages. Only honored on the cursor pagination path; ignored otherwise.
+ Page:
+ name: page
+ in: query
+ required: false
+ schema:
+ type: integer
+ minimum: 1
+ description: |
+ Page number (1-indexed) for offset pagination. Declares no schema
+ default so the request validator does not inject one: handlers that omit
+ `page` see it unset (nil) and default to 1 in code, while cursor-first
+ endpoints (e.g. the project deployments feed) can detect its absence to
+ stay in keyset/search mode. Supplying `page` selects offset pagination.
+ LavaflowDays:
+ name: days
+ in: query
+ required: false
+ schema:
+ type: integer
+ minimum: 1
+ maximum: 90
+ default: 30
+ description: Number of UTC days in the window, ending today.
+ LavaflowResourceIdFilter:
+ name: resource_id
+ in: query
+ required: false
+ schema:
+ type: string
+ format: uuid
+ description: Only runs for issues of this resource.
+ LavaflowRunId:
+ name: run_id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ description: LavaFlow run ID
+ LavaflowRunCursor:
+ name: cursor
+ in: query
+ required: false
+ schema:
+ type: string
+ description: |
+ Opaque cursor from a previous response's `next_cursor`. Pages forward,
+ and works only for the same `project_id` and caller; keep the same
+ filters while paging.
+ LavaflowRunLimit:
+ name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ minimum: 1
+ maximum: 100
+ default: 25
+ description: Number of runs per page (max 100)
+ LavaflowScanLimit:
+ name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ minimum: 1
+ maximum: 100
+ default: 25
+ description: Number of scans per page (max 100)
+ LavaflowRunStatusFilter:
+ name: status
+ in: query
+ required: false
+ schema:
+ $ref: '#/components/schemas/LavaflowRunStatus'
+ description: Only runs in this status.
+ LavaflowSkillId:
+ name: skill_id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ description: LavaFlow skill ID
+ LavaflowSkillIdQuery:
+ name: skill_id
+ in: query
+ required: true
+ schema:
+ type: string
+ format: uuid
+ description: The skill whose versions to list.
+ LavaflowSkillStatusFilter:
+ name: status
+ in: query
+ required: false
+ schema:
+ $ref: '#/components/schemas/LavaflowSkillStatus'
+ description: Only skills in this status.
+ SlackRedirect:
+ name: redirect
+ in: query
+ required: false
+ description: Where to send the browser after Slack's callback. It must be on the Volcano dashboard's origin, or `http` to `127.0.0.1` or `[::1]` with a port.
+ schema:
+ type: string
+ LavaflowCategoryFilter:
+ name: category
+ in: query
+ required: false
+ schema:
+ type: string
+ enum:
+ - bug
+ - performance
+ - security
+ - improvement
+ - configuration
+ - dependency
+ - external
+ - uncategorized
+ description: Only runs in this category; `uncategorized` for runs without one.
+ LavaflowInvolvedResourceFilter:
+ name: involved_resource_id
+ in: query
+ required: false
+ schema:
+ type: string
+ format: uuid
+ description: 'Only runs that involve this function, durable function or frontend in any role: the issue came from it, the diagnosis traced the cause to it, or the fix changes it.'
+ LavaflowIssueIdFilter:
+ name: issue_id
+ in: query
+ required: false
+ schema:
+ type: string
+ format: uuid
+ description: Only runs on this issue. An issue the project doesn't have answers `404`, like an unknown issue.
+ LavaflowPullRequestStateFilter:
+ name: pull_request_state
+ in: query
+ required: false
+ schema:
+ type: string
+ enum:
+ - open
+ - merged
+ - closed
+ - none
+ description: Only runs whose pull request is in this state; `none` for runs without one.
+ LavaflowRunDays:
+ name: days
+ in: query
+ required: false
+ schema:
+ type: integer
+ minimum: 1
+ maximum: 90
+ description: Only runs created in the last `days` UTC days, today included. Omit for every run.
+ LavaflowRunOrder:
+ name: order
+ in: query
+ required: false
+ schema:
+ type: string
+ enum:
+ - created_at.desc
+ - created_at.asc
+ - issue_events.desc
+ default: created_at.desc
+ description: '`created_at.desc` is newest first and `created_at.asc` oldest first. `issue_events.desc` orders by the issue''s current `event_count`, most first, then newest first. That count grows as errors arrive or scans see a finding again, so paging this order can skip runs, not only move them between pages. To read every run, for an export say, page `created_at.desc` or `created_at.asc`. A cursor works only with the order it came from.'
+ LavaflowRunInclude:
+ name: include
+ in: query
+ required: false
+ style: form
+ explode: false
+ schema:
+ type: array
+ uniqueItems: true
+ items:
+ type: string
+ enum:
+ - counts
+ description: '`counts` adds `counts` to the response. Ask on the first page; the counts don''t depend on the cursor.'
+ ProjectId:
+ name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ description: Project ID
+ ProjectIdQuery:
+ name: project_id
+ in: query
+ required: true
+ schema:
+ type: string
+ format: uuid
+ description: The project to read. A project the caller can't read answers like one that doesn't exist.
+ ConnectorId:
+ name: connector_id
+ in: path
+ required: true
+ description: The connector's ID, from listing connectors
+ schema:
+ type: string
+ format: uuid
+ ItemProjectIdQuery:
+ name: project_id
+ in: query
+ required: false
+ schema:
+ type: string
+ format: uuid
+ description: Optional. The item's own project authorizes the request; when given, the item must belong to this project, or it answers like an unknown one.
+ ShareId:
+ name: share_id
+ in: path
+ required: true
+ schema:
+ type: string
+ pattern: ^[A-Za-z0-9]{12}$
+ description: Share ID, the 12 characters at the end of the share's deploy URL
+ ShareIdQuery:
+ name: share_id
+ in: query
+ required: true
+ schema:
+ type: string
+ pattern: ^[A-Za-z0-9]{12}$
+ description: The share to read. The share's own project authorizes the read; a share the caller can't read answers like one that doesn't exist.
+ ShareReleaseCursor:
+ name: cursor
+ in: query
+ required: false
+ schema:
+ type: string
+ description: |
+ Opaque cursor from a previous response's `next_cursor`. Pages forward, and
+ works only for the same `share_id` and `limit`.
+ TokenId:
+ name: tokenId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ description: Project access token ID
+ Search:
+ name: search
+ in: query
+ required: false
+ schema:
+ type: string
+ maxLength: 256
+ description: |
+ Case-insensitive substring match on the resource `name`. See the
+ endpoint description for supported pagination modes.
+ RestoreId:
+ name: restoreId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ description: Database restore ID
+ MigrationRunId:
+ name: runId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ description: Database migration run ID
+ SchedulerId:
+ name: schedulerId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ description: Function scheduler ID
+ VariableName:
+ name: name
+ in: path
+ required: true
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 256
+ pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
+ description: Variable name. Function runtime names such as AWS_REGION are reserved and cannot be updated.
+ IfNoneMatch:
+ name: If-None-Match
+ in: header
+ required: false
+ description: |
+ Entity tag from an earlier response, returning `304 Not Modified` while it
+ still matches. Accepts the full condition: `*`, a comma-separated list, and
+ weak tags of the form `W/"tag"`.
+ schema:
+ type: string
+ example: '"9f2c1e0b5a"'
+ responses:
+ StorageRangeNotSatisfiable:
+ description: The requested byte range does not overlap the file content.
+ headers:
+ Content-Range:
+ description: Current file size as `bytes */size`, when available.
+ schema:
+ type: string
+ pattern: ^bytes \*/\d+$
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ OpenAPISpecThrottled:
+ description: |
+ Too many requests for the specification from one address. The document
+ carries an `ETag`; revalidate with `If-None-Match` rather than
+ re-fetching it.
+ headers:
+ Retry-After:
+ description: Seconds to wait before requesting the specification again.
+ schema:
+ type: integer
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ BandwidthCapExceeded:
+ description: |
+ The platform user exceeded their billing-cycle bandwidth allowance (aggregate
+ ingress + egress across owned projects). Enforcement is eventual:
+ requests are rejected until the allowance increases or the next
+ anniversary cycle begins.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ DatabaseQueryCapExceeded:
+ description: |
+ The query was rejected by a billing-cycle allowance: either the owning
+ platform user's bandwidth allowance (aggregate ingress + egress across
+ owned projects) or their database-request allowance. Enforcement is
+ eventual: queries are rejected until the allowance increases or the
+ next anniversary cycle begins. The error message identifies the resource.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ DatabaseBranchQueryUnavailable:
+ description: |
+ The branch exists but cannot serve queries: it is still provisioning,
+ being reset, expired, or its parent is being restored. Distinct from
+ `404` so a caller waiting on a branch can tell it apart from a typo.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ OpenAPISpecNotModified:
+ description: |
+ The specification still matches the supplied `If-None-Match`, so no body
+ is returned.
+ headers:
+ ETag:
+ $ref: '#/components/headers/ETag'
+ OpenAPISpecHeaders:
+ description: |
+ The headers a `GET` would return, without the document. The declared
+ `ETag` is the one to revalidate against.
+ headers:
+ ETag:
+ $ref: '#/components/headers/ETag'
+ schemas:
+ AccountSession:
+ type: object
+ description: A sign-in to your Volcano account, from the CLI or a browser.
+ properties:
+ id:
+ type: string
+ format: uuid
+ description: Unique session identifier
+ user_id:
+ type: string
+ format: uuid
+ description: |
+ The sign-in identity (auth user) the session belongs to. This is
+ not your account ID: an identity linked to your account has its
+ own ID.
+ provider:
+ type: string
+ description: |
+ How the session was created: `email`, `google`, `github`,
+ `microsoft`, `apple`, or `device:` for a device-code
+ login such as the `volcano` CLI. More values may be added; use
+ `kind` to tell CLI logins from browser sign-ins.
+ example: github
+ kind:
+ type: string
+ description: |
+ `cli` for a device-code login, such as `volcano login`, and
+ `browser` for every other sign-in.
+ enum:
+ - cli
+ - browser
+ example: cli
+ user_agent:
+ type: string
+ description: Browser/device user agent string
+ ip_address:
+ type: string
+ description: IP address of the client when the session was created
+ last_ip_address:
+ type: string
+ description: IP address of the most recent activity (token refresh)
+ expires_at:
+ type: string
+ format: date-time
+ description: When this session expires
+ last_activity_at:
+ type: string
+ format: date-time
+ description: Last activity timestamp
+ session_started_at:
+ type: string
+ format: date-time
+ description: When the session was created
+ is_active:
+ type: boolean
+ description: Whether the session is currently active (not expired)
+ is_current:
+ type: boolean
+ description: Whether this is the session making the current request
+ created_at:
+ type: string
+ format: date-time
+ updated_at:
+ type: string
+ format: date-time
+ required:
+ - id
+ - user_id
+ - provider
+ - kind
+ - expires_at
+ - is_active
+ - is_current
+ AccountSessionList:
+ type: object
+ description: |
+ A page of sessions. Without `sort` the body is the legacy
+ `sessions`/`total`/`page`/`limit`/`total_pages` shape; with
+ `sort=created_at` and a cursor it is the shared `data` envelope.
+ properties:
+ sessions:
+ type: array
+ items:
+ $ref: '#/components/schemas/AccountSession'
+ total:
+ type: integer
+ description: Total number of sessions
+ page:
+ type: integer
+ description: Current page number
+ limit:
+ type: integer
+ description: Number of sessions per page
+ total_pages:
+ type: integer
+ description: Total number of pages
+ data:
+ type: array
+ description: Sessions for this page (cursor pagination only)
+ items:
+ $ref: '#/components/schemas/AccountSession'
+ has_more:
+ type: boolean
+ description: Whether a further page exists (cursor pagination only)
+ next_cursor:
+ type: string
+ description: Opaque cursor for the next page (cursor pagination only)
+ prev_cursor:
+ type: string
+ description: Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`.
+ SandboxPreset:
+ type: object
+ additionalProperties: false
+ properties:
+ id:
+ type: string
+ runtime:
+ type: string
+ version:
+ type: string
+ memory_mb:
+ type: integer
+ enum:
+ - 1024
+ - 2048
+ regions:
+ type: array
+ items:
+ type: string
+ required:
+ - id
+ - runtime
+ - version
+ - memory_mb
+ - regions
+ SandboxTemplate:
+ type: object
+ additionalProperties: false
+ properties:
+ id:
+ type: string
+ format: uuid
+ project_id:
+ type: string
+ format: uuid
+ name:
+ type: string
+ pattern: ^[a-z][a-z0-9-]{0,62}$
+ preset:
+ type: string
+ memory_mb:
+ type: integer
+ status:
+ type: string
+ enum:
+ - ready
+ - unavailable
+ - deleting
+ created_at:
+ type: string
+ format: date-time
+ required:
+ - id
+ - project_id
+ - name
+ - status
+ - created_at
+ CreateSandboxTemplateRequest:
+ type: object
+ additionalProperties: false
+ properties:
+ name:
+ type: string
+ pattern: ^[a-z][a-z0-9-]{0,62}$
+ preset:
+ type: string
+ description: Preset ID from the available Sandbox preset catalog.
+ memory_mb:
+ type: integer
+ enum:
+ - 1024
+ - 2048
+ default: 1024
+ required:
+ - name
+ - preset
+ UpdateSandboxTemplateRequest:
+ type: object
+ additionalProperties: false
+ properties:
+ name:
+ type: string
+ pattern: ^[a-z][a-z0-9-]{0,62}$
+ required:
+ - name
+ SandboxSession:
+ type: object
+ additionalProperties: false
+ properties:
+ id:
+ type: string
+ format: uuid
+ project_id:
+ type: string
+ format: uuid
+ last_error_code:
+ type: string
+ description: Last recorded lifecycle reason, such as sandbox_run_hook_timeout or sandbox_authority_or_expiry. Historical information, not a current error; use state for the current session state. Retained when later observations supply no reason, including after termination or recovery. Omitted when no reason is known. Values may be added; this field does not imply whether a command ran or whether it can be retried.
+ sandbox_id:
+ type: string
+ format: uuid
+ nullable: true
+ description: Explicit template used to create the session. Null when created directly from a preset.
+ state:
+ type: string
+ enum:
+ - starting
+ - running
+ - suspending
+ - suspended
+ - resuming
+ - terminating
+ - terminated
+ - unknown
+ desired_state:
+ type: string
+ enum:
+ - running
+ - suspended
+ - terminated
+ region:
+ type: string
+ memory_mb:
+ type: integer
+ created_at:
+ type: string
+ format: date-time
+ started_at:
+ type: string
+ format: date-time
+ expires_at:
+ type: string
+ format: date-time
+ nullable: true
+ description: Absolute VM expiry. Null means unlimited in local mode.
+ network:
+ $ref: '#/components/schemas/SandboxSessionNetwork'
+ executions:
+ $ref: '#/components/schemas/SandboxSessionExecutions'
+ limits:
+ $ref: '#/components/schemas/SandboxSessionAppliedLimits'
+ required:
+ - id
+ - project_id
+ - sandbox_id
+ - state
+ - desired_state
+ - region
+ - memory_mb
+ - created_at
+ - expires_at
+ - network
+ - executions
+ SandboxSessionNetwork:
+ type: object
+ additionalProperties: false
+ properties:
+ egress:
+ type: string
+ enum:
+ - default
+ - deny_all
+ description: The outbound network policy the session was created with. It never changes.
+ applied:
+ type: string
+ enum:
+ - default
+ - deny_all
+ - unknown
+ description: The outbound network policy Volcano last observed on the session's VM, never the request alone. It is `unknown` until the session is first observed, from a suspend or resume request until it is observed again, briefly while Volcano rolls out an update, and whenever the observation does not match the request. A terminated session keeps what Volcano last observed, so a `deny_all` session ended because Volcano observed outbound access reads `default`. A session first reports `state` `running` only once its network has been observed. To depend on `deny_all`, wait for `running`, then terminate the session unless `applied` is `deny_all`. Act on `applied` only while the session is `running`, and on a later `unknown` only while `desired_state` is `running`.
+ required:
+ - egress
+ - applied
+ SandboxSessionNetworkRequest:
+ type: object
+ additionalProperties: false
+ description: Outbound network policy for the session. Omitting `network` is the same as `egress` `default`.
+ properties:
+ egress:
+ type: string
+ enum:
+ - default
+ - deny_all
+ x-enum-varnames:
+ - SandboxSessionNetworkRequestEgressDefault
+ - SandboxSessionNetworkRequestEgressDenyAll
+ description: '`default` gives the session the region''s standard outbound internet access. `deny_all` gives it no outbound network for its whole lifetime: DNS lookups, internet and link-local addresses, and connections back out through Volcano all fail, and the session accepts no port access. Commands, files and the rest of the session API work as usual. The policy cannot be changed after creation; suspend and resume keep it. Check `network.applied` before relying on it. Where `GET /capabilities` lists `sandboxes.network_isolation` as unavailable, `deny_all` answers `400` with code `feature_unavailable`.'
+ required:
+ - egress
+ CreateSandboxSessionRequest:
+ type: object
+ additionalProperties: false
+ properties:
+ preset:
+ type: string
+ description: Preset ID from the available Sandbox preset catalog.
+ sandbox_id:
+ type: string
+ format: uuid
+ memory_mb:
+ description: Baseline memory in MiB. Cloud HOBBY supports 1024; SUPERAGENT supports 1024 or 2048. Omission uses the preset or template default; a template requiring more than the plan permits is rejected. Local sessions are exempt from cloud plan limits.
+ type: integer
+ enum:
+ - 1024
+ - 2048
+ region:
+ type: string
+ pattern: ^(aws-)?[a-z]{2}(-[a-z]+)+-[0-9]+$
+ description: Region such as `us-east-1`, from the preset catalog. Region IDs issued by earlier versions of the API are still accepted. A temporarily unavailable region answers 400 with code `sandbox_region_unavailable`.
+ max_duration_seconds:
+ type: integer
+ minimum: 0
+ maximum: 2147483647
+ description: Inherits the template TTL when omitted (cloud default 3600 seconds; local default 0, unlimited). Cloud HOBBY accepts 30–3600 seconds; SUPERAGENT accepts 30–28800 seconds. Inherited template defaults are clamped to the plan limit; explicit values above it are rejected. Local accepts 0 for unlimited or a positive lifetime.
+ network:
+ $ref: '#/components/schemas/SandboxSessionNetworkRequest'
+ executions:
+ $ref: '#/components/schemas/SandboxSessionExecutions'
+ limits:
+ $ref: '#/components/schemas/SandboxSessionLimits'
+ required:
+ - region
+ oneOf:
+ - required:
+ - preset
+ not:
+ required:
+ - sandbox_id
+ - required:
+ - sandbox_id
+ not:
+ required:
+ - preset
+ SandboxSessionLimits:
+ type: object
+ additionalProperties: false
+ minProperties: 1
+ description: |
+ Caps the session's code runs under, enforced inside the session. Each
+ cap is an upper bound; the session's own size still bounds both.
+ properties:
+ vcpus:
+ type: integer
+ minimum: 1
+ maximum: 4
+ description: |
+ CPU time the session's commands and template service may use
+ together, in vCPUs. A 1024 MiB session has 2 vCPUs and a 2048 MiB
+ session has 4; asking for more answers 400 with code
+ `sandbox_limits_exceed_session`.
+ disk_mib:
+ type: integer
+ minimum: 64
+ maximum: 6144
+ description: |
+ Space the session can write beyond its image's contents, in MiB.
+ It covers every path commands and the template service can write,
+ including `/workspace` and `/tmp`. A write past it fails with
+ `ENOSPC`. `/dev/shm` is memory, capped separately at 64 MiB.
+ SandboxSessionAppliedLimits:
+ type: object
+ additionalProperties: false
+ description: |
+ The caps the session enforces, as the session reports them. Present only
+ when the session was created with `limits`. The session stays
+ `starting` until `applied` is known.
+ properties:
+ vcpus:
+ type: integer
+ description: Enforced vCPU cap. Never higher than requested; lower when the session has fewer vCPUs.
+ disk_mib:
+ type: integer
+ description: Enforced disk cap in MiB. Never higher than requested; lower when the session's disk has less free space.
+ applied:
+ $ref: '#/components/schemas/SandboxLimitsApplied'
+ required:
+ - applied
+ SandboxLimitsApplied:
+ type: string
+ description: |
+ `enforced` when every requested cap is enforced, `not_enforced` when the
+ session could not enforce them, and `unknown` until the session reports.
+ Terminate a session that reports anything but `enforced` if you rely on
+ the caps.
+ enum:
+ - enforced
+ - not_enforced
+ - unknown
+ x-enum-varnames:
+ - SandboxLimitsEnforced
+ - SandboxLimitsNotEnforced
+ - SandboxLimitsUnknown
+ SandboxCommandRequest:
+ type: object
+ additionalProperties: false
+ properties:
+ command:
+ type: string
+ minLength: 1
+ maxLength: 65536
+ timeout_seconds:
+ type: integer
+ minimum: 0
+ maximum: 2147483647
+ description: Command execution time from process start. Cloud defaults to 60 seconds and accepts 1–28800; local defaults to 0 (unlimited) and accepts nonnegative values. VM expiry always takes precedence. Cloud synchronous requests must return within the public connection idle limit (1000 seconds); use a session with a background process and short polling requests for longer work.
+ environment:
+ type: object
+ additionalProperties:
+ type: string
+ maxProperties: 64
+ keep_output:
+ type: boolean
+ description: Set false to keep no output. stdout and stderr are returned once in this response, and Volcano's control plane never stores them in the execution journal, database, logs or traces. This does not cover the Sandbox's memory or a suspended session's snapshot. A retry with the same Idempotency-Key returns the exit code with `output_kept` false and empty streams, without running the command again. Omit it to use the session's `executions.keep_output`. True in a session that keeps no output is refused with 400 and code `sandbox_session_keeps_no_output`. False is refused with 400 and code `feature_unavailable` while the `sandboxes.output_not_kept` capability is unavailable.
+ required:
+ - command
+ SandboxExecutionRequest:
+ type: object
+ additionalProperties: false
+ properties:
+ preset:
+ type: string
+ description: Preset ID from the available Sandbox preset catalog.
+ sandbox_id:
+ type: string
+ format: uuid
+ memory_mb:
+ description: Baseline memory in MiB. Cloud HOBBY supports 1024; SUPERAGENT supports 1024 or 2048. Omission uses the preset or template default; a template requiring more than the plan permits is rejected. Local sessions are exempt from cloud plan limits.
+ type: integer
+ enum:
+ - 1024
+ - 2048
+ region:
+ type: string
+ pattern: ^(aws-)?[a-z]{2}(-[a-z]+)+-[0-9]+$
+ description: Region such as `us-east-1`, from the preset catalog. Region IDs issued by earlier versions of the API are still accepted. A temporarily unavailable region answers 400 with code `sandbox_region_unavailable`.
+ max_duration_seconds:
+ type: integer
+ minimum: 0
+ maximum: 2147483647
+ description: Absolute VM lifetime including startup, bounded by environment capacity policy. Inherits the template TTL when omitted (cloud default 3600 seconds; local default 0, unlimited). Cloud HOBBY accepts 30–3600 seconds; SUPERAGENT accepts 30–28800 seconds. Inherited template defaults are clamped to the plan limit; explicit values above it are rejected. Local accepts 0 for unlimited or a positive lifetime. The VM is reclaimed early when the command finishes.
+ command:
+ type: string
+ minLength: 1
+ maxLength: 65536
+ timeout_seconds:
+ type: integer
+ minimum: 0
+ maximum: 2147483647
+ description: Command execution time from process start. Cloud defaults to 60 seconds and accepts 1–28800; local defaults to 0 (unlimited) and accepts nonnegative values. VM expiry always takes precedence. Cloud synchronous requests must return within the public connection idle limit (1000 seconds); use a session with a background process and short polling requests for longer work.
+ environment:
+ type: object
+ additionalProperties:
+ type: string
+ maxProperties: 64
+ network:
+ $ref: '#/components/schemas/SandboxSessionNetworkRequest'
+ keep_output:
+ type: boolean
+ default: true
+ description: Set false to keep no output. stdout and stderr are returned once in this response, and Volcano's control plane never stores them in the execution journal, database, logs or traces. This does not cover the Sandbox's memory or a suspended session's snapshot. A retry with the same Idempotency-Key returns the exit code with `output_kept` false and empty streams, without running the command again. False is refused with 400 and code `feature_unavailable` while the `sandboxes.output_not_kept` capability is unavailable.
+ required:
+ - region
+ - command
+ oneOf:
+ - required:
+ - preset
+ not:
+ required:
+ - sandbox_id
+ - required:
+ - sandbox_id
+ not:
+ required:
+ - preset
+ SandboxCommandResult:
+ type: object
+ additionalProperties: false
+ properties:
+ stdout:
+ type: string
+ description: The first 1 MiB (1,048,576 bytes) the command wrote to stdout. Empty in a replay of a command that kept no output.
+ stderr:
+ type: string
+ description: The first 1 MiB (1,048,576 bytes) the command wrote to stderr. Empty in a replay of a command that kept no output.
+ exit_code:
+ type: integer
+ stdout_truncated:
+ type: boolean
+ description: True when the command wrote more than 1 MiB to stdout. False in a replay of a command that kept no output.
+ stderr_truncated:
+ type: boolean
+ description: True when the command wrote more than 1 MiB to stderr. False in a replay of a command that kept no output.
+ timed_out:
+ type: boolean
+ output_kept:
+ type: boolean
+ description: False when the command kept no output. Its streams appear only in the response to the request that ran it, and Volcano's control plane never stores them in the execution journal, database, logs or traces. This does not cover the Sandbox's memory or a suspended session's snapshot. A retry with the same Idempotency-Key returns them empty.
+ required:
+ - stdout
+ - stderr
+ - exit_code
+ - stdout_truncated
+ - stderr_truncated
+ - timed_out
+ - output_kept
+ SandboxExecutionResult:
+ type: object
+ additionalProperties: false
+ properties:
+ stdout:
+ type: string
+ description: The first 1 MiB (1,048,576 bytes) the command wrote to stdout. Empty in a replay of a command that kept no output.
+ stderr:
+ type: string
+ description: The first 1 MiB (1,048,576 bytes) the command wrote to stderr. Empty in a replay of a command that kept no output.
+ exit_code:
+ type: integer
+ stdout_truncated:
+ type: boolean
+ description: True when the command wrote more than 1 MiB to stdout. False in a replay of a command that kept no output.
+ stderr_truncated:
+ type: boolean
+ description: True when the command wrote more than 1 MiB to stderr. False in a replay of a command that kept no output.
+ timed_out:
+ type: boolean
+ output_kept:
+ type: boolean
+ description: False when the command kept no output. Its streams appear only in the response to the request that ran it, and Volcano's control plane never stores them in the execution journal, database, logs or traces. This does not cover the Sandbox's memory or a suspended session's snapshot. A retry with the same Idempotency-Key returns them empty.
+ session_id:
+ type: string
+ format: uuid
+ region:
+ type: string
+ duration_ms:
+ type: integer
+ format: int64
+ minimum: 0
+ required:
+ - stdout
+ - stderr
+ - exit_code
+ - stdout_truncated
+ - stderr_truncated
+ - timed_out
+ - output_kept
+ - session_id
+ - region
+ - duration_ms
+ SandboxFileWriteRequest:
+ type: object
+ additionalProperties: false
+ properties:
+ path:
+ type: string
+ minLength: 1
+ maxLength: 4096
+ data:
+ type: string
+ format: byte
+ maxLength: 11184812
+ required:
+ - path
+ - data
+ SandboxFileReadRequest:
+ type: object
+ additionalProperties: false
+ properties:
+ path:
+ type: string
+ minLength: 1
+ maxLength: 4096
+ required:
+ - path
+ SandboxFileResult:
+ type: object
+ additionalProperties: false
+ properties:
+ data:
+ type: string
+ format: byte
+ required:
+ - data
+ SandboxFileArchiveForm:
+ type: object
+ description: Send `project_id`, `session_id` and `path`, in any order, then the `archive` part.
+ properties:
+ project_id:
+ type: string
+ format: uuid
+ session_id:
+ type: string
+ format: uuid
+ path:
+ type: string
+ minLength: 1
+ maxLength: 4096
+ description: Workspace directory to extract into, relative to `/workspace`. It must name a directory below the workspace root; a path that resolves to the root or to `/`, such as `.`, `./`, `/`, `/workspace` or `/workspace/.`, is refused.
+ archive:
+ type: string
+ format: binary
+ description: A tar archive, optionally gzip-compressed.
+ required:
+ - project_id
+ - session_id
+ - path
+ - archive
+ SandboxFileArchive:
+ type: object
+ additionalProperties: false
+ properties:
+ project_id:
+ type: string
+ format: uuid
+ session_id:
+ type: string
+ format: uuid
+ path:
+ type: string
+ files:
+ type: integer
+ format: int64
+ minimum: 0
+ description: Regular files written.
+ bytes:
+ type: integer
+ format: int64
+ minimum: 0
+ description: Bytes of file content written.
+ required:
+ - project_id
+ - session_id
+ - path
+ - files
+ - bytes
+ SandboxFilePartRequest:
+ type: object
+ additionalProperties: false
+ properties:
+ project_id:
+ type: string
+ format: uuid
+ session_id:
+ type: string
+ format: uuid
+ path:
+ type: string
+ minLength: 1
+ maxLength: 4096
+ description: Workspace file to write, relative to `/workspace`.
+ offset:
+ type: integer
+ format: int64
+ minimum: 0
+ description: Byte offset of this part's data in the file.
+ size:
+ type: integer
+ format: int64
+ minimum: 1
+ maximum: 1073741824
+ description: Size of the whole file in bytes, at most 1 GiB.
+ sha256:
+ type: string
+ pattern: ^[0-9a-f]{64}$
+ description: Lowercase hex SHA-256 of the whole file.
+ data:
+ type: string
+ format: byte
+ minLength: 4
+ maxLength: 11184812
+ description: This part's bytes, at most 8 MiB.
+ required:
+ - project_id
+ - session_id
+ - path
+ - offset
+ - size
+ - sha256
+ - data
+ SandboxFilePart:
+ type: object
+ additionalProperties: false
+ properties:
+ project_id:
+ type: string
+ format: uuid
+ session_id:
+ type: string
+ format: uuid
+ path:
+ type: string
+ offset:
+ type: integer
+ format: int64
+ minimum: 0
+ size:
+ type: integer
+ format: int64
+ minimum: 1
+ received:
+ type: integer
+ format: int64
+ minimum: 1
+ description: Bytes of the file received through the end of this part.
+ complete:
+ type: boolean
+ description: True when this part finished the file and it is now at `path`.
+ required:
+ - project_id
+ - session_id
+ - path
+ - offset
+ - size
+ - received
+ - complete
+ SandboxFileEntry:
+ type: object
+ additionalProperties: false
+ properties:
+ path:
+ type: string
+ description: Path relative to the workspace root, usable with the read and write file routes.
+ type:
+ type: string
+ enum:
+ - file
+ - directory
+ - symlink
+ - other
+ description: Entry type from the entry itself. A symlink is reported, never followed.
+ size:
+ type: integer
+ format: int64
+ minimum: 0
+ description: Size in bytes of a regular file; 0 for every other type.
+ mode:
+ type: integer
+ minimum: 0
+ maximum: 4095
+ description: Permission bits, including setuid, setgid and sticky (`st_mode & 07777`). For example, 420 is `0644` and 493 is `0755`.
+ sha256:
+ type: string
+ pattern: ^[0-9a-f]{64}$
+ description: Lowercase hex SHA-256 of a regular file's content, present only when `include_sha256` is true and the file could be hashed.
+ sha256_skipped:
+ type: string
+ enum:
+ - budget
+ - changing
+ - unreadable
+ description: Why a regular file has no `sha256` when `include_sha256` is true. `budget` is a file over 256 MiB. `changing` is a file that changed while it was hashed or kept changing; list it again later. `unreadable` is a file the session user doesn't own, whose owner-read bit (`0400`) is clear, or that has more than one hard link. Treat such a file as unverified.
+ unreadable:
+ type: boolean
+ description: 'True on a directory the session user can''t list; the listing doesn''t enter it. The user''s permission bits on the directory lack read or execute: the owner bits when the user owns it, the group bits when it belongs to the user''s group, and the other bits otherwise. Absent on every other entry.'
+ unsupported_names:
+ type: integer
+ minimum: 1
+ description: 'In a recursive listing, how many names directly inside this directory no entry can carry: names that are not UTF-8, or whose path would pass 4096 bytes. The listing skips them and everything below them. Absent when there are none.'
+ required:
+ - path
+ - type
+ - size
+ - mode
+ SandboxFileListResult:
+ type: object
+ additionalProperties: false
+ properties:
+ project_id:
+ type: string
+ format: uuid
+ description: The project the session belongs to.
+ session_id:
+ type: string
+ format: uuid
+ description: The session listed.
+ entries:
+ type: array
+ items:
+ $ref: '#/components/schemas/SandboxFileEntry'
+ description: Entries sorted by path, compared one path element at a time by bytes, so a directory comes right before its contents.
+ unsupported_names:
+ type: integer
+ minimum: 1
+ description: 'How many names directly inside the listed directory no entry can carry: names that are not UTF-8, or whose path would pass 4096 bytes. The listing skips them and everything below them. Every page reports it. Absent when there are none.'
+ next_cursor:
+ type: string
+ description: Present when more entries remain. Pass it as `cursor` to get the next page.
+ required:
+ - project_id
+ - session_id
+ - entries
+ SandboxSubjectGrantRequest:
+ type: object
+ additionalProperties: false
+ properties:
+ expires_at:
+ type: string
+ format: date-time
+ required:
+ - expires_at
+ SandboxAccessRequest:
+ type: object
+ additionalProperties: false
+ properties:
+ port:
+ type: integer
+ minimum: 1
+ maximum: 65532
+ expires_in_seconds:
+ type: integer
+ minimum: 1
+ maximum: 300
+ default: 300
+ required:
+ - port
+ SandboxAccess:
+ type: object
+ additionalProperties: false
+ properties:
+ url:
+ type: string
+ format: uri
+ token:
+ type: string
+ expires_at:
+ type: string
+ format: date-time
+ required:
+ - url
+ - token
+ - expires_at
+ SandboxBuildLogPage:
+ type: object
+ required:
+ - data
+ properties:
+ data:
+ type: array
+ items:
+ type: object
+ required:
+ - timestamp
+ - message
+ properties:
+ timestamp:
+ type: string
+ format: date-time
+ message:
+ type: string
+ next_cursor:
+ type: string
+ description: Opaque cursor for the next page. Absent when caught up.
+ SandboxDeployment:
+ type: object
+ additionalProperties: false
+ properties:
+ id:
+ type: string
+ format: uuid
+ status:
+ type: string
+ created_at:
+ type: string
+ format: date-time
+ updated_at:
+ type: string
+ format: date-time
+ required:
+ - id
+ - status
+ - created_at
+ - updated_at
+ SandboxPagination:
+ type: object
+ additionalProperties: false
+ properties:
+ limit:
+ type: integer
+ has_more:
+ type: boolean
+ next_cursor:
+ type: string
+ required:
+ - limit
+ - has_more
+ SandboxTemplatePage:
+ type: object
+ additionalProperties: false
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/SandboxTemplate'
+ pagination:
+ $ref: '#/components/schemas/SandboxPagination'
+ required:
+ - data
+ - pagination
+ SandboxSessionPage:
+ type: object
+ additionalProperties: false
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/SandboxSession'
+ pagination:
+ $ref: '#/components/schemas/SandboxPagination'
+ required:
+ - data
+ - pagination
+ SandboxDeploymentPage:
+ type: object
+ additionalProperties: false
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/SandboxDeployment'
+ pagination:
+ $ref: '#/components/schemas/SandboxPagination'
+ required:
+ - data
+ - pagination
+ SandboxPresetList:
+ type: object
+ additionalProperties: false
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/SandboxPreset'
+ required:
+ - data
+ Capability:
+ type: object
+ additionalProperties: false
+ description: A product capability and whether it accepts new work in this environment.
+ properties:
+ id:
+ type: string
+ description: Stable capability ID, such as `sandboxes`, `sandboxes.sessions`, `sandboxes.custom_templates`, or `issues`. New IDs may appear at any time.
+ example: sandboxes.sessions
+ status:
+ $ref: '#/components/schemas/CapabilityStatus'
+ code:
+ type: string
+ description: Why an `unavailable` capability refuses new work, named like the error code its requests answer with, such as `plan_required`. Absent on any other status, and when requests answer `feature_unavailable`. Treat an unknown code as absent.
+ example: plan_required
+ required:
+ - id
+ - status
+ CapabilityStatus:
+ type: string
+ enum:
+ - available
+ - unavailable
+ - read_only
+ description: '`available` means the capability accepts new work; a temporary outage still answers `503`. `unavailable` means requests that start new work answer `404` or `400` with code `feature_unavailable`, or with the capability''s `code` when it has one; while the owner''s plan can''t be read, they answer `403` without a code. `read_only` means the capability takes no new work for the project, but what the project already has stays readable; only a project''s list reports it. Treat any other value as `unavailable`.'
+ CapabilityList:
+ type: object
+ additionalProperties: false
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/Capability'
+ required:
+ - data
+ SandboxCapacity:
+ type: object
+ additionalProperties: false
+ properties:
+ region:
+ type: string
+ allocated_memory_mb:
+ type: integer
+ format: int64
+ minimum: 0
+ required:
+ - region
+ - allocated_memory_mb
+ SandboxCapacityList:
+ type: object
+ additionalProperties: false
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/SandboxCapacity'
+ required:
+ - data
+ PublishSandboxPresetRequest:
+ type: object
+ additionalProperties: false
+ properties:
+ id:
+ type: string
+ format: uuid
+ preset:
+ type: string
+ enum:
+ - python3.12
+ - node22
+ memory_mb:
+ type: integer
+ enum:
+ - 1024
+ - 2048
+ deployment_id:
+ type: string
+ format: uuid
+ required:
+ - id
+ - preset
+ - memory_mb
+ - deployment_id
+ AnonKey:
+ type: object
+ properties:
+ id:
+ type: string
+ format: uuid
+ project_id:
+ type: string
+ format: uuid
+ name:
+ type: string
+ key_value:
+ type: string
+ description: JWT token - use this in frontend Authorization header
+ permissions:
+ type: array
+ items:
+ type: string
+ description: |
+ Permissions granted to this anon key.
+ Auth permissions: auth.signup, auth.signin, auth.refresh, auth.logout, auth.password_reset, auth.confirm_email, auth.resend_confirmation
+ Storage permissions: storage.upload, storage.download, storage.list, storage.delete
+ Realtime permissions: realtime.connect, realtime.subscribe, realtime.publish
+ Functions permissions: functions.invoke
+ example:
+ - auth.signup
+ - auth.signin
+ - auth.refresh
+ - auth.logout
+ is_default:
+ type: boolean
+ description: Whether this is the project's configured default anon key. Only one key per project can be default.
+ created_at:
+ type: string
+ format: date-time
+ required:
+ - id
+ - name
+ - key_value
+ AuthConfig:
+ type: object
+ properties:
+ project_id:
+ type: string
+ format: uuid
+ access_token_lifetime:
+ type: integer
+ description: Access token lifetime in seconds
+ default: 3600
+ refresh_token_lifetime:
+ type: integer
+ description: Refresh token lifetime in seconds
+ default: 2592000
+ refresh_token_reuse_interval:
+ type: integer
+ description: A refresh within this many seconds of the refresh token being issued returns the same refresh token instead of rotating it, so concurrent refreshes from several tabs all succeed
+ default: 10
+ inactivity_timeout:
+ type: integer
+ description: Force re-login after inactivity (seconds, 0=never)
+ default: 0
+ max_session_duration:
+ type: integer
+ description: Force re-login after duration (seconds, 0=never)
+ default: 0
+ min_password_length:
+ type: integer
+ minimum: 15
+ maximum: 128
+ default: 15
+ description: Configured minimum password length in Unicode characters.
+ password_policy:
+ $ref: '#/components/schemas/AuthPasswordPolicy'
+ require_uppercase:
+ type: boolean
+ default: false
+ require_lowercase:
+ type: boolean
+ default: false
+ require_numbers:
+ type: boolean
+ default: false
+ require_special_chars:
+ type: boolean
+ default: false
+ enable_signup:
+ type: boolean
+ description: Master switch - allow new user signups via ANY provider
+ default: true
+ enable_email_password:
+ type: boolean
+ description: Enable email/password authentication as a provider
+ default: true
+ rate_limit_signup:
+ type: integer
+ description: Signups per hour per IP
+ default: 100
+ rate_limit_signin:
+ type: integer
+ description: Signins per hour per IP
+ default: 100
+ rate_limit_token_refresh:
+ type: integer
+ description: Refreshes per hour per IP
+ default: 1000
+ rate_limit_password_reset:
+ type: integer
+ description: Password reset requests per hour per IP. Unlike the other limits, 0 applies the default of 10 instead of turning the limit off.
+ default: 10
+ cors_enabled:
+ type: boolean
+ default: false
+ cors_allowed_origins:
+ type: array
+ items:
+ type: string
+ example:
+ - https://myapp.com
+ - http://localhost:3000
+ enable_anonymous_signins:
+ type: boolean
+ description: Allow creating users without email/password
+ default: false
+ allowed_email_domains:
+ type: array
+ description: |
+ Email domains allowed to create users in this project. Applies to
+ email/password signup, OAuth/SSO signup, anonymous conversion, and
+ email changes. Empty (the default) allows every domain.
+
+ Entries are stored normalized (lowercase, no `@` prefix) and match
+ the domain part exactly: `domain1.com` does not cover
+ `mail.domain1.com`. Signups from other domains are rejected with
+ 403, and `allowed_email_domains_mode` decides whether sign-in is
+ covered as well.
+
+ The allowlist is a SUPERAGENT feature to configure and to enforce. A
+ downgrade parks it: the domains are still returned here and stop
+ being applied until the project is back on SUPERAGENT.
+ items:
+ type: string
+ example:
+ - domain1.com
+ - domain2.com
+ allowed_email_domains_mode:
+ type: string
+ description: |
+ How far `allowed_email_domains` reaches. `signup` only gates account
+ creation, so accounts that predate the list keep signing in.
+ `signup_and_signin` also refuses to issue a session to an account
+ whose domain is not listed. `disabled` keeps the list without
+ enforcing it.
+ enum:
+ - disabled
+ - signup
+ - signup_and_signin
+ default: signup
+ platform_token_ttl:
+ type: integer
+ description: TTL in seconds for platform tokens minted via `/auth/platform/exchange`
+ default: 2592000
+ allow_password_reset:
+ type: boolean
+ description: Enable forgot password flow
+ default: true
+ password_reset_timeout:
+ type: integer
+ description: Recovery token expiry in seconds
+ default: 3600
+ max_password_history:
+ type: integer
+ description: Number of previous passwords to remember (0=disabled)
+ default: 0
+ cors_allow_credentials:
+ type: boolean
+ description: Allow credentials in CORS requests
+ default: true
+ cors_max_age:
+ type: integer
+ description: CORS preflight cache duration (seconds)
+ default: 86400
+ cors_allow_frontend_previews:
+ type: boolean
+ description: Allow the exact origins of the project's own live frontend previews in its CORS checks, in addition to `cors_allowed_origins`. A preview's origin stops being allowed within seconds of the preview being deleted or expiring, with no configuration change.
+ default: false
+ frontend_preview_origins:
+ type: array
+ readOnly: true
+ description: Origins of the project's live frontend previews that its CORS checks currently allow. Empty unless `cors_allow_frontend_previews` is true. Omitted when the live previews could not be read; the rest of the response, and any update it answers, is unaffected.
+ items:
+ type: string
+ require_email_confirmation:
+ type: boolean
+ description: Require users to confirm email before sign-in. Can only be true when email_enabled is true.
+ default: false
+ email_confirmation_timeout:
+ type: integer
+ description: Email confirmation token expiry in seconds.
+ default: 86400
+ auto_link_verified_oauth:
+ type: boolean
+ description: Link a verified OAuth identity to an existing confirmed account with the same email instead of returning a conflict. Requires require_email_confirmation to be true.
+ default: false
+ email_enabled:
+ type: boolean
+ description: Enable transactional email sending (confirmation, reset, change notifications). Must be true when require_email_confirmation is true.
+ default: false
+ email_from_address:
+ type: string
+ description: Sender email address. New or changed values containing carriage returns or newlines return 400. Unchanged stored or exported values are preserved. Leading and trailing whitespace in previously saved settings is trimmed in responses and exports, and ignored when sending.
+ email_from_name:
+ type: string
+ description: Sender display name; supports punctuation and Unicode. New or changed values containing carriage returns or newlines return 400. Unchanged stored or exported values are preserved. Leading and trailing whitespace in previously saved settings is trimmed in responses and exports, and ignored when sending.
+ smtp_host:
+ type: string
+ smtp_port:
+ type: integer
+ default: 587
+ smtp_username:
+ type: string
+ smtp_password_configured:
+ type: boolean
+ description: Whether an SMTP password is configured. The password itself is never returned.
+ default: false
+ smtp_use_tls:
+ type: boolean
+ default: true
+ email_confirmation_subject:
+ type: string
+ email_password_reset_subject:
+ type: string
+ email_password_changed_subject:
+ type: string
+ managed_auth_enabled:
+ type: boolean
+ description: Enables project-hosted managed auth pages.
+ default: false
+ post_auth_redirect_url:
+ type: string
+ description: Default redirect target after successful hosted auth.
+ allowed_redirect_urls:
+ type: array
+ description: Redirect allowlist used to validate post_auth_redirect_url and post_logout_redirect_url.
+ items:
+ type: string
+ post_logout_redirect_url:
+ type: string
+ description: Redirect target after logout from hosted pages.
+ device_verification_url:
+ type: string
+ description: |
+ Optional override for the device-authorization verification page.
+ When set, POST /auth/device/authorize returns this URL (with the
+ user_code) as verification_uri/verification_uri_complete instead of
+ the built-in managed device page. Lets a CLI surface the project's
+ own RFC 8628 approval page. Empty falls back to the managed page.
+ example: https://app.acme.com/device
+ created_at:
+ type: string
+ format: date-time
+ updated_at:
+ type: string
+ format: date-time
+ required:
+ - password_policy
+ AuthInsightsInterval:
+ type: string
+ enum:
+ - day
+ - week
+ - month
+ AuthInsightsResponse:
+ type: object
+ additionalProperties: false
+ properties:
+ project_id:
+ type: string
+ format: uuid
+ observed_at:
+ type: string
+ format: date-time
+ window:
+ $ref: '#/components/schemas/AuthInsightsWindow'
+ summary:
+ $ref: '#/components/schemas/AuthInsightsSummary'
+ series:
+ type: array
+ items:
+ $ref: '#/components/schemas/AuthInsightsSeriesPoint'
+ required:
+ - project_id
+ - observed_at
+ - window
+ - summary
+ - series
+ AuthInsightsSeriesPoint:
+ type: object
+ additionalProperties: false
+ properties:
+ bucket_start:
+ type: string
+ format: date
+ signups:
+ type: integer
+ format: int64
+ minimum: 0
+ description: Registrations during the bucket. Subsequent deletion does not subtract from this count. Historical counts removed before deletion-history collection cannot be reconstructed.
+ signins:
+ type: integer
+ format: int64
+ minimum: 0
+ description: Successful session creations during the bucket.
+ banned_users:
+ type: integer
+ format: int64
+ minimum: 0
+ description: Users registered in this bucket who are currently banned. Excludes deleted users, lifted bans, expired temporary bans, and internal test identities.
+ deleted_users:
+ type: integer
+ format: int64
+ minimum: 0
+ description: Users registered in this bucket who are now deleted, counted once across soft and hard deletion. Grouped by signup date, not deletion date.
+ available_users:
+ type: integer
+ format: int64
+ minimum: 0
+ description: Currently available users registered in this bucket (signups minus banned_users minus deleted_users). Unban or expiry restores availability in the original signup bucket. This measures account availability, not return activity.
+ deletions:
+ type: integer
+ format: int64
+ minimum: 0
+ description: Accounts deleted during this bucket, counted once across soft and hard deletion.
+ net_growth:
+ type: integer
+ format: int64
+ description: Registrations minus deletions during this bucket. May be negative. Bans do not affect this value.
+ is_partial:
+ type: boolean
+ description: Whether the requested window or observation time clips this bucket.
+ required:
+ - bucket_start
+ - signups
+ - signins
+ - is_partial
+ - deletions
+ - banned_users
+ - deleted_users
+ - available_users
+ - net_growth
+ AuthInsightsSummary:
+ type: object
+ additionalProperties: false
+ properties:
+ total_users:
+ type: integer
+ format: int64
+ minimum: 0
+ description: Current auth-user count, excluding accounts with deleted status.
+ deleted_users:
+ type: integer
+ format: int64
+ minimum: 0
+ description: Recorded deletions, excluding internal test identities. Includes soft and hard deletion, counted once per account.
+ active_users_1d:
+ type: integer
+ format: int64
+ minimum: 0
+ description: Distinct users active in the trailing 24 hours, including activity before account deletion.
+ active_users_30d:
+ type: integer
+ format: int64
+ minimum: 0
+ description: Distinct users with a successful session creation or refresh in the trailing 30 days, including activity before account deletion.
+ required:
+ - total_users
+ - active_users_30d
+ - active_users_1d
+ - deleted_users
+ AuthInsightsWindow:
+ type: object
+ additionalProperties: false
+ properties:
+ from:
+ type: string
+ format: date
+ to:
+ type: string
+ format: date
+ interval:
+ $ref: '#/components/schemas/AuthInsightsInterval'
+ required:
+ - from
+ - to
+ - interval
+ AuthHostedPage:
+ type: object
+ properties:
+ id:
+ type: string
+ format: uuid
+ project_id:
+ type: string
+ format: uuid
+ page_type:
+ $ref: '#/components/schemas/HostedAuthPageType'
+ html:
+ type: string
+ description: HTML content for this page type.
+ css:
+ type: string
+ description: CSS content for this page type.
+ created_at:
+ type: string
+ format: date-time
+ updated_at:
+ type: string
+ format: date-time
+ AuthPageAppearanceResponse:
+ type: object
+ required:
+ - theme
+ - layouts
+ - customisation_allowed
+ - parked
+ - defaults
+ - options
+ properties:
+ theme:
+ $ref: '#/components/schemas/AuthPageTheme'
+ layouts:
+ type: object
+ additionalProperties:
+ $ref: '#/components/schemas/AuthPageLayout'
+ customisation_allowed:
+ type: boolean
+ parked:
+ type: object
+ additionalProperties:
+ type: boolean
+ description: Per-page saved-but-not-live state.
+ defaults:
+ $ref: '#/components/schemas/AuthPageAppearanceDefaults'
+ options:
+ $ref: '#/components/schemas/AuthPageAppearanceOptions'
+ AuthPageDensity:
+ type: string
+ enum:
+ - compact
+ - comfortable
+ - spacious
+ AuthPageFont:
+ type: string
+ enum:
+ - system
+ - humanist
+ - geometric
+ - slab
+ - mono
+ AuthPageLayout:
+ type: string
+ enum:
+ - centered
+ - split-left
+ - split-right
+ AuthPageRadius:
+ type: string
+ enum:
+ - none
+ - small
+ - medium
+ - large
+ AuthPageScale:
+ type: string
+ enum:
+ - small
+ - default
+ - large
+ AuthPageTheme:
+ type: object
+ additionalProperties: false
+ required:
+ - version
+ - colors
+ - font
+ - scale
+ - density
+ - radius
+ properties:
+ version:
+ type: integer
+ enum:
+ - 1
+ colors:
+ $ref: '#/components/schemas/AuthPageThemeColors'
+ font:
+ $ref: '#/components/schemas/AuthPageFont'
+ scale:
+ $ref: '#/components/schemas/AuthPageScale'
+ density:
+ $ref: '#/components/schemas/AuthPageDensity'
+ radius:
+ $ref: '#/components/schemas/AuthPageRadius'
+ AuthHostedPageResponse:
+ type: object
+ required:
+ - page
+ - defaults
+ - runtime
+ properties:
+ page:
+ allOf:
+ - $ref: '#/components/schemas/AuthHostedPage'
+ nullable: true
+ description: The saved page, or null when the project has not customized this page type yet.
+ defaults:
+ $ref: '#/components/schemas/AuthHostedPageDefaults'
+ runtime:
+ $ref: '#/components/schemas/AuthHostedPageRuntime'
+ AuthIdentity:
+ type: object
description: |
- The specification still matches the supplied `If-None-Match`, so no body
- is returned.
- headers:
- ETag:
- $ref: '#/components/headers/ETag'
- OpenAPISpecHeaders:
+ A real email identity owned by the account. One account can own multiple
+ identities (for example a work email plus a personal email linked via OAuth).
+ properties:
+ id:
+ type: string
+ format: uuid
+ description: Unique identity identifier
+ email:
+ type: string
+ format: email
+ description: The email address this identity represents
+ email_verified:
+ type: boolean
+ description: Whether ownership of this email has been verified
+ is_primary:
+ type: boolean
+ description: Whether the account's primary sign-in method resolves to this identity
+ created_at:
+ type: string
+ format: date-time
+ required:
+ - id
+ - email
+ - email_verified
+ - is_primary
+ - created_at
+ AuthIdentitiesResponse:
+ type: object
+ properties:
+ identities:
+ type: array
+ items:
+ $ref: '#/components/schemas/AuthIdentity'
+ required:
+ - identities
+ AuthMethodSummary:
+ type: object
description: |
- The headers a `GET` would return, without the document. The declared
- `ETag` is the one to revalidate against.
- headers:
- ETag:
- $ref: '#/components/headers/ETag'
- schemas:
- SandboxPreset:
+ A single sign-in method the account owns (password, an OAuth provider, or an
+ active anonymous method). `is_primary` reflects the account's primary_method_id.
+ properties:
+ id:
+ type: string
+ format: uuid
+ description: Unique method identifier
+ type:
+ type: string
+ x-go-type: string
+ description: The kind of sign-in method
+ enum:
+ - password
+ - oauth
+ - anonymous
+ provider:
+ type: string
+ description: OAuth provider name; present only when type is oauth
+ example: google
+ identity_id:
+ type: string
+ description: |
+ The identity this method signs in to — a UUID for password/oauth methods,
+ empty for anonymous methods.
+ email:
+ type: string
+ description: The email of the method's identity (empty for anonymous)
+ is_primary:
+ type: boolean
+ description: Whether this is the account's primary sign-in method
+ last_used_at:
+ type: string
+ format: date-time
+ description: When this method was last used to sign in, if ever
+ created_at:
+ type: string
+ format: date-time
+ updated_at:
+ type: string
+ format: date-time
+ required:
+ - id
+ - type
+ - identity_id
+ - email
+ - is_primary
+ - created_at
+ - updated_at
+ AuthMethodsResponse:
+ type: object
+ properties:
+ methods:
+ type: array
+ items:
+ $ref: '#/components/schemas/AuthMethodSummary'
+ required:
+ - methods
+ AuthPasswordPolicy:
type: object
additionalProperties: false
+ description: Effective backend-enforced password policy.
+ properties:
+ effective_min_length:
+ type: integer
+ minimum: 15
+ maximum: 128
+ description: Effective minimum password length in Unicode characters.
+ min_configurable_length:
+ type: integer
+ minimum: 15
+ maximum: 15
+ description: Lowest minimum password length accepted by the auth configuration endpoint.
+ max_length:
+ type: integer
+ minimum: 128
+ maximum: 128
+ description: Maximum password length in Unicode characters.
+ require_uppercase:
+ type: boolean
+ description: Whether passwords must contain an ASCII uppercase letter (A-Z).
+ require_lowercase:
+ type: boolean
+ description: Whether passwords must contain an ASCII lowercase letter (a-z).
+ require_numbers:
+ type: boolean
+ description: Whether passwords must contain an ASCII digit (0-9).
+ require_special_chars:
+ type: boolean
+ description: Whether passwords must contain one of the backend-supported special characters.
+ compromised_passwords_rejected:
+ type: boolean
+ description: Whether common and known-compromised passwords are rejected by the backend.
+ required:
+ - effective_min_length
+ - min_configurable_length
+ - max_length
+ - require_uppercase
+ - require_lowercase
+ - require_numbers
+ - require_special_chars
+ - compromised_passwords_rejected
+ AuthSession:
+ type: object
+ description: An authentication session for a user
properties:
id:
type: string
- runtime:
+ format: uuid
+ description: Unique session identifier
+ user_id:
type: string
- version:
+ format: uuid
+ description: The user this session belongs to
+ provider:
type: string
- memory_mb:
- type: integer
+ description: Authentication provider used to create this session
enum:
- - 1024
- - 2048
- regions:
- type: array
- items:
- type: string
+ - email
+ - google
+ - github
+ - microsoft
+ - apple
+ - anonymous
+ example: email
+ user_agent:
+ type: string
+ description: Browser/device user agent string
+ example: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
+ ip_address:
+ type: string
+ description: IP address of the client when the session was created
+ example: 192.168.1.1
+ last_ip_address:
+ type: string
+ description: IP address of the most recent activity (token refresh)
+ example: 192.168.1.100
+ expires_at:
+ type: string
+ format: date-time
+ description: When this session expires
+ last_activity_at:
+ type: string
+ format: date-time
+ description: Last activity timestamp
+ session_started_at:
+ type: string
+ format: date-time
+ description: When the session was created
+ is_active:
+ type: boolean
+ description: Whether the session is currently active (not expired)
+ is_current:
+ type: boolean
+ description: Whether this is the session making the current request
+ created_at:
+ type: string
+ format: date-time
+ updated_at:
+ type: string
+ format: date-time
required:
- id
- - runtime
- - version
- - memory_mb
- - regions
- SandboxTemplate:
+ - user_id
+ - provider
+ - expires_at
+ - is_active
+ - is_current
+ AuthSignupResponse:
+ type: object
+ description: |
+ Uniform, session-less response returned by POST /auth/signup. It carries no
+ tokens and no user object, and is identical for a new account and for an
+ already-registered email (anti-enumeration). Clients obtain a session with a
+ subsequent POST /auth/signin.
+ properties:
+ confirmation_required:
+ type: boolean
+ description: |
+ Whether the project requires email confirmation. Reflects project config
+ only (identical for a new and an existing email), so it leaks nothing about
+ account existence.
+ message:
+ type: string
+ description: Human-readable acknowledgement.
+ required:
+ - confirmation_required
+ - message
+ AuthTokenResponse:
+ type: object
+ properties:
+ access_token:
+ type: string
+ description: JWT access token (expires after configured lifetime)
+ token_type:
+ type: string
+ example: bearer
+ expires_in:
+ type: integer
+ description: Access token lifetime in seconds
+ refresh_token:
+ type: string
+ x-go-type-skip-optional-pointer: true
+ description: |
+ Long-lived token for getting new access tokens. Omitted when the
+ request uses eligible HttpOnly cookie session storage.
+ user:
+ $ref: '#/components/schemas/AuthUser'
+ required:
+ - access_token
+ - token_type
+ - expires_in
+ - user
+ AuthUser:
type: object
- additionalProperties: false
properties:
id:
type: string
@@ -17262,386 +24828,525 @@ components:
project_id:
type: string
format: uuid
- name:
+ email:
type: string
- pattern: ^[a-z][a-z0-9-]{0,62}$
- preset:
+ format: email
+ email_confirmed:
+ type: boolean
+ user_metadata:
+ type: object
+ additionalProperties: true
+ description: User-editable metadata
+ app_metadata:
+ type: object
+ additionalProperties: true
+ description: Application-controlled metadata (read-only for users)
+ avatar_url:
type: string
- memory_mb:
- type: integer
+ format: uri
+ description: User avatar URL (from OAuth provider or manually set)
status:
type: string
enum:
- - ready
- - unavailable
- - deleting
+ - active
+ - banned
+ - deleted
+ banned_until:
+ type: string
+ format: date-time
+ nullable: true
+ description: When temporary ban expires (null if not banned or permanent)
+ last_sign_in_at:
+ type: string
+ format: date-time
created_at:
type: string
format: date-time
+ updated_at:
+ type: string
+ format: date-time
required:
- id
- - project_id
- - name
+ - email
- status
- - created_at
- CreateSandboxTemplateRequest:
+ BanUserResponse:
+ type: object
+ description: Response when banning a user
+ properties:
+ message:
+ type: string
+ example: User banned until 2026-12-31T23:59:59Z
+ user_id:
+ type: string
+ format: uuid
+ email:
+ type: string
+ format: email
+ status:
+ type: string
+ enum:
+ - banned
+ banned_until:
+ type: string
+ format: date-time
+ nullable: true
+ description: When the ban expires (null for permanent ban)
+ required:
+ - message
+ - user_id
+ - email
+ - status
+ BatchFunctionDeployFailure:
type: object
- additionalProperties: false
properties:
name:
type: string
- pattern: ^[a-z][a-z0-9-]{0,62}$
- preset:
+ function_id:
+ type: string
+ format: uuid
+ operation:
type: string
- description: Preset ID from the available Sandbox preset catalog.
- memory_mb:
- type: integer
enum:
- - 1024
- - 2048
- default: 1024
+ - deploy
+ - update
+ error:
+ type: string
required:
- name
- - preset
- UpdateSandboxTemplateRequest:
+ - error
+ BatchFunctionDeployResponse:
+ type: object
+ properties:
+ batch_id:
+ type: string
+ format: uuid
+ data:
+ type: array
+ description: Functions whose deployment workflows were started successfully
+ items:
+ $ref: '#/components/schemas/Function'
+ failed:
+ type: array
+ description: Functions that failed before their workflow started. Successful functions are left running; failed new functions are deleted and failed updates are rolled back where possible.
+ items:
+ $ref: '#/components/schemas/BatchFunctionDeployFailure'
+ required:
+ - batch_id
+ - data
+ CompleteUploadSessionResponse:
+ type: object
+ description: Response when completing an upload
+ properties:
+ object:
+ $ref: '#/components/schemas/StorageObject'
+ CreateDatabaseBackupRequest:
type: object
- additionalProperties: false
properties:
name:
type: string
- pattern: ^[a-z][a-z0-9-]{0,62}$
+ description: |
+ Backup name, unique within the database. Names beginning with
+ `volcano-` are reserved for the platform's own snapshots, and names
+ beginning with `before-migration-` for the backups migration runs
+ take.
+ pattern: ^[a-z0-9][a-z0-9_-]{0,62}$
+ maxLength: 63
+ example: before_migration
required:
- name
- SandboxSession:
+ CreateDatabaseBranchRequest:
type: object
- additionalProperties: false
properties:
- id:
- type: string
- format: uuid
- project_id:
- type: string
- format: uuid
- sandbox_id:
- type: string
- format: uuid
- nullable: true
- description: Explicit template used to create the session. Null when created directly from a preset.
- state:
- type: string
- enum:
- - starting
- - running
- - suspending
- - suspended
- - resuming
- - terminating
- - terminated
- - unknown
- desired_state:
- type: string
- enum:
- - running
- - suspended
- - terminated
- region:
+ name:
type: string
- memory_mb:
+ description: |
+ Branch name, unique within the parent database. Names beginning
+ with `migration_rehearsal_` are reserved for the branches migration
+ runs rehearse on.
+ pattern: ^[a-z0-9_]+$
+ maxLength: 64
+ example: feature_checkout
+ ttl_seconds:
type: integer
- created_at:
- type: string
- format: date-time
- started_at:
+ format: int64
+ minimum: 3600
+ maximum: 2592000
+ description: |
+ How long the branch should live, between one hour and 30 days.
+ Defaults to 7 days when omitted.
+ example: 86400
+ required:
+ - name
+ CreateDatabaseRestoreRequest:
+ type: object
+ description: |
+ Names what to restore. Supply exactly one of `backup_name` or
+ `restore_to`.
+ properties:
+ backup_name:
type: string
- format: date-time
- expires_at:
+ minLength: 1
+ maxLength: 128
+ description: |
+ A backup of this database to restore, exactly as returned by the list
+ endpoint.
+
+ Deliberately looser than the names you can create, like the backup
+ path parameter: a backup made by a schedule is named for you, so
+ restoring one accepts any name a backup can have.
+ example: before_migration
+ restore_to:
type: string
format: date-time
- nullable: true
- description: Absolute VM expiry. Null means unlimited in local mode.
- required:
- - id
- - project_id
- - sandbox_id
- - state
- - desired_state
- - region
- - memory_mb
- - created_at
- - expires_at
- CreateSandboxSessionRequest:
+ description: |
+ A point in time to restore to, which must fall inside the
+ `restore_window` reported when listing backups.
+ example: '2026-01-15T09:30:00Z'
+ CreateDatabaseRequest:
type: object
- additionalProperties: false
+ description: |
+ Create a new PostgreSQL database. Volcano automatically sets up:
+ - Auth helpers (auth.uid(), auth.email(), auth.role())
+ - Database roles (anon for unauthenticated, authenticated for signed-in users)
+ - Secure multi-tenant isolation
+ - Ready for Row-Level Security
properties:
- preset:
+ name:
type: string
- description: Preset ID from the available Sandbox preset catalog.
- sandbox_id:
+ description: Database name (must be unique within project)
+ pattern: ^[a-z0-9_]+$
+ maxLength: 64
+ example: my_database
+ region:
type: string
- format: uuid
- memory_mb:
- description: Baseline memory in MiB. Cloud HOBBY supports 1024; SUPERAGENT supports 1024 or 2048. Omission uses the preset or template default; a template requiring more than the plan permits is rejected. Local sessions are exempt from cloud plan limits.
- type: integer
+ description: |
+ Region for database hosting, such as `us-east-1`. The accepted values
+ are the regions this environment runs in, so read them from
+ `GET /databases/regions` rather than hardcoding a list. A region the
+ environment does not offer is rejected with 400. Region IDs issued by
+ earlier versions of the API are still accepted.
+ example: us-east-1
+ pg_version:
+ type: string
+ description: |
+ PostgreSQL major version. `GET /databases/postgres-versions` lists
+ the versions this environment accepts; local mode accepts only the
+ version its server runs. Any other value is rejected with 400.
+ example: '18'
enum:
- - 1024
- - 2048
- region:
+ - '16'
+ - '17'
+ - '18'
+ database_type:
type: string
- pattern: ^(aws-)?[a-z]{2}(-[a-z]+)+-[0-9]+$
- description: Region such as `us-east-1`. Region IDs issued by earlier versions of the API are still accepted.
- max_duration_seconds:
- type: integer
- minimum: 0
- maximum: 2147483647
- description: Inherits the template TTL when omitted (cloud default 3600 seconds; local default 0, unlimited). Cloud HOBBY accepts 30–3600 seconds; SUPERAGENT accepts 30–28800 seconds. Inherited template defaults are clamped to the plan limit; explicit values above it are rejected. Local accepts 0 for unlimited or a positive lifetime.
+ description: |
+ Compute size tier (optional, defaults to volcano-db-xs).
+ Determines autoscaling limits for the database.
+ enum:
+ - volcano-db-xs
+ - volcano-db-s
+ - volcano-db-m
+ - volcano-db-l
+ - volcano-db-xl
+ - volcano-db-2xl
+ default: volcano-db-xs
+ example: volcano-db-xs
required:
+ - name
- region
- oneOf:
- - required:
- - preset
- not:
- required:
- - sandbox_id
- - required:
- - sandbox_id
- not:
- required:
- - preset
- SandboxCommandRequest:
+ - pg_version
+ CreateEmailTemplateRequest:
type: object
- additionalProperties: false
properties:
- command:
+ template_type:
type: string
- minLength: 1
- maxLength: 65536
- timeout_seconds:
- type: integer
- minimum: 0
- maximum: 2147483647
- description: Command execution time from process start. Cloud defaults to 60 seconds and accepts 1–28800; local defaults to 0 (unlimited) and accepts nonnegative values. VM expiry always takes precedence. Cloud synchronous requests must return within the public connection idle limit (1000 seconds); use a session with a background process and short polling requests for longer work.
- environment:
- type: object
- additionalProperties:
- type: string
- maxProperties: 64
+ enum:
+ - welcome
+ - confirmation
+ - password_reset
+ - password_changed
+ description: Type of email template
+ subject:
+ type: string
+ description: Subject template. After Go template whitespace trimming, literal interior carriage returns or newlines return 400. Outer whitespace and trailing block-scalar newlines are allowed.
+ example: Confirm your email
+ html_body:
+ type: string
+ description: |
+ HTML template body. Available placeholders:
+ - {{.Token}} - The confirmation/reset token
+ - {{.ProjectName}} - The project name
+ - {{.Email}} - User's email address
+ text_body:
+ type: string
+ description: Plain text template body (same placeholders as HTML)
required:
- - command
- SandboxExecutionRequest:
+ - template_type
+ - subject
+ - html_body
+ - text_body
+ CreateFrontendCustomDomainRequest:
type: object
additionalProperties: false
properties:
- preset:
- type: string
- description: Preset ID from the available Sandbox preset catalog.
- sandbox_id:
- type: string
- format: uuid
- memory_mb:
- description: Baseline memory in MiB. Cloud HOBBY supports 1024; SUPERAGENT supports 1024 or 2048. Omission uses the preset or template default; a template requiring more than the plan permits is rejected. Local sessions are exempt from cloud plan limits.
- type: integer
- enum:
- - 1024
- - 2048
- region:
- type: string
- pattern: ^(aws-)?[a-z]{2}(-[a-z]+)+-[0-9]+$
- description: Region such as `us-east-1`. Region IDs issued by earlier versions of the API are still accepted.
- max_duration_seconds:
- type: integer
- minimum: 0
- maximum: 2147483647
- description: Absolute VM lifetime including startup, bounded by environment capacity policy. Inherits the template TTL when omitted (cloud default 3600 seconds; local default 0, unlimited). Cloud HOBBY accepts 30–3600 seconds; SUPERAGENT accepts 30–28800 seconds. Inherited template defaults are clamped to the plan limit; explicit values above it are rejected. Local accepts 0 for unlimited or a positive lifetime. The VM is reclaimed early when the command finishes.
- command:
+ domain:
type: string
- minLength: 1
- maxLength: 65536
- timeout_seconds:
- type: integer
- minimum: 0
- maximum: 2147483647
- description: Command execution time from process start. Cloud defaults to 60 seconds and accepts 1–28800; local defaults to 0 (unlimited) and accepts nonnegative values. VM expiry always takes precedence. Cloud synchronous requests must return within the public connection idle limit (1000 seconds); use a session with a background process and short polling requests for longer work.
- environment:
- type: object
- additionalProperties:
- type: string
- maxProperties: 64
+ maxLength: 253
+ description: 'Fully-qualified domain name (hostname only, no scheme/path). Managed TLS (`tls.mode: managed`) accepts at most 219 characters; BYOC accepts 253.'
+ example: app.example.com
+ tls:
+ $ref: '#/components/schemas/FrontendCustomDomainTLSConfig'
required:
- - region
- - command
- oneOf:
- - required:
- - preset
- not:
- required:
- - sandbox_id
- - required:
- - sandbox_id
- not:
- required:
- - preset
- SandboxCommandResult:
+ - domain
+ - tls
+ CreateFrontendDomainRequest:
type: object
additionalProperties: false
properties:
- stdout:
+ domain:
type: string
- stderr:
+ maxLength: 253
+ description: 'Fully-qualified domain name (hostname only, no scheme/path). Managed TLS (`tls.mode: managed`) accepts at most 219 characters; BYOC accepts 253.'
+ example: www.example.com
+ tls:
+ $ref: '#/components/schemas/FrontendCustomDomainTLSConfig'
+ redirect:
+ $ref: '#/components/schemas/FrontendCustomDomainRedirectRequest'
+ required:
+ - domain
+ - tls
+ CreateFunctionSchedulerRequest:
+ type: object
+ required:
+ - name
+ - schedule
+ properties:
+ name:
type: string
- exit_code:
- type: integer
- stdout_truncated:
- type: boolean
- stderr_truncated:
- type: boolean
- timed_out:
+ maxLength: 200
+ enabled:
type: boolean
- required:
- - stdout
- - stderr
- - exit_code
- - stdout_truncated
- - stderr_truncated
- - timed_out
- SandboxExecutionResult:
+ default: true
+ schedule:
+ $ref: '#/components/schemas/ScheduleRequest'
+ payload:
+ type: object
+ additionalProperties: true
+ regions:
+ type: array
+ description: Optional single explicit deployed region. If omitted, the scheduler chooses one deployed region and invokes according to the cron expression.
+ maxItems: 1
+ items:
+ type: string
+ CreateOAuthConfigRequest:
type: object
- additionalProperties: false
+ required:
+ - provider
properties:
- stdout:
+ provider:
type: string
- stderr:
+ enum:
+ - google
+ - github
+ - microsoft
+ - apple
+ - device
+ example: google
+ client_id:
type: string
- exit_code:
- type: integer
- stdout_truncated:
- type: boolean
- stderr_truncated:
- type: boolean
- timed_out:
- type: boolean
- session_id:
+ example: 123456789.apps.googleusercontent.com
+ description: Required for non-device providers. Must not be provided for `provider=device`; server always auto-generates it.
+ client_secret:
type: string
- format: uuid
- region:
+ example: GOCSPX-abc123def456
+ description: Required for non-device providers. Must not be provided for `provider=device`; server always auto-generates it.
+ redirect_url:
type: string
- duration_ms:
- type: integer
- format: int64
- minimum: 0
- required:
- - stdout
- - stderr
- - exit_code
- - stdout_truncated
- - stderr_truncated
- - timed_out
- - session_id
- - region
- - duration_ms
- SandboxFileWriteRequest:
+ description: Required for non-device providers. Not used for `provider=device`.
+ format: uri
+ example: https://yourapp.com/auth/callback
+ scopes:
+ type: array
+ items:
+ type: string
+ example:
+ - openid
+ - email
+ - profile
+ description: Optional for non-device providers, uses provider defaults if omitted. Not used for `provider=device`.
+ CreateProjectRequest:
type: object
- additionalProperties: false
+ description: Request to create a new project
properties:
- path:
+ name:
type: string
+ description: |
+ Project name. A name you already use is not refused: the project is
+ created with a short random suffix added to it.
+ Can only contain letters, numbers, underscores, and hyphens.
+ pattern: ^[A-Za-z0-9_-]+$
minLength: 1
- maxLength: 4096
- data:
+ maxLength: 255
+ example: my-awesome-app
+ template_id:
type: string
- format: byte
- maxLength: 11184812
+ description: Optional trusted starter template identifier. The server resolves immutable source and database initialization artifacts. Callers cannot supply artifact locations or database credentials. Creation accepts an asynchronous installation; poll the individual project until template_installation.status is ready before using the app. Use pixel-board, trellini, or collab-pad for the configured starter bundles. The official-starter legacy identifier has environment-specific availability. Cannot be combined with initialPrompt.
+ enum:
+ - pixel-board
+ - trellini
+ - collab-pad
+ - official-starter
+ example: pixel-board
+ initialPrompt:
+ type: string
+ description: Optional initial builder prompt. Cannot be combined with template_id.
+ all_regions:
+ type: boolean
+ description: |
+ Optional region policy.
+ - `true` (default): project functions deploy to all configured regions
+ - `false`: project deploys only to `selected_regions`
+ default: true
+ selected_regions:
+ type: array
+ items:
+ type: string
+ description: |
+ Optional region subset. Requires `all_regions=false`.
+ Region names must be a subset of platform `AWS_REGIONS`.
+ example:
+ - us-east-1
+ - us-west-2
required:
- - path
- - data
- SandboxFileReadRequest:
+ - name
+ CreateStorageBucketRequest:
type: object
- additionalProperties: false
properties:
- path:
+ name:
type: string
+ description: Bucket name (alphanumeric, dashes, underscores)
+ pattern: ^[a-zA-Z0-9_-]+$
minLength: 1
- maxLength: 4096
+ maxLength: 64
+ file_size_limit:
+ type: integer
+ format: int64
+ description: Maximum file size in bytes
+ allowed_mime_types:
+ type: array
+ items:
+ type: string
+ description: Allowed MIME types (e.g., ["image/png", "image/jpeg"])
required:
- - path
- SandboxFileResult:
+ - name
+ CreateStoragePolicyRequest:
type: object
- additionalProperties: false
properties:
- data:
+ name:
type: string
- format: byte
- required:
- - data
- SandboxSubjectGrantRequest:
- type: object
- additionalProperties: false
- properties:
- expires_at:
+ description: Policy name
+ operation:
type: string
- format: date-time
- required:
- - expires_at
- SandboxAccessRequest:
+ enum:
+ - SELECT
+ - INSERT
+ - UPDATE
+ - DELETE
+ description: Operation this policy applies to
+ definition:
+ type: string
+ description: Policy expression
+ required:
+ - name
+ - operation
+ - definition
+ CreateUploadSessionRequest:
type: object
- additionalProperties: false
+ description: Request to create a resumable upload session
properties:
- port:
+ object_path:
+ type: string
+ description: Target file path within the bucket
+ example: videos/large-file.mp4
+ content_type:
+ type: string
+ description: MIME type of the file
+ example: video/mp4
+ total_size:
type: integer
+ format: int64
+ description: Total file size in bytes (max 5TB)
minimum: 1
- maximum: 65532
- expires_in_seconds:
+ maximum: 5497558138880
+ example: 5368709120
+ part_size:
type: integer
- minimum: 1
- maximum: 300
- default: 300
+ format: int64
+ description: 'Part size in bytes (default: 25MB, min: 5MB, max: 25MB)'
+ minimum: 5242880
+ maximum: 26214400
+ example: 26214400
required:
- - port
- SandboxAccess:
+ - object_path
+ - content_type
+ - total_size
+ CreateUploadSessionResponse:
type: object
- additionalProperties: false
+ description: Response when creating an upload session
properties:
- url:
- type: string
- format: uri
- token:
+ session_id:
type: string
+ description: Upload session ID
+ example: session-abc123
+ part_size:
+ type: integer
+ format: int64
+ description: Actual part size to use
+ example: 26214400
+ total_parts:
+ type: integer
+ description: Number of parts to upload
+ example: 52
expires_at:
type: string
format: date-time
- required:
- - url
- - token
- - expires_at
- SandboxBuildLogPage:
+ description: When the session expires (7 days from creation)
+ example: '2024-01-22T10:30:00Z'
+ CreateVariableRequest:
type: object
- required:
- - data
properties:
- data:
- type: array
- items:
- type: object
- required:
- - timestamp
- - message
- properties:
- timestamp:
- type: string
- format: date-time
- message:
- type: string
- next_cursor:
+ shared:
+ type: boolean
+ description: Include this name in the project's shared function variables. Omission preserves existing membership; new variables default to true for legacy clients. Send false explicitly to create a non-shared variable.
+ name:
type: string
- description: Opaque cursor for the next page. Absent when caught up.
- SandboxDeployment:
+ description: Project variable name. Function runtime names such as AWS_REGION are reserved and return 400; see the environment variables guide for the full list.
+ minLength: 1
+ maxLength: 256
+ pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
+ value:
+ type: string
+ required:
+ - name
+ - value
+ VariableEnvironment:
type: object
- additionalProperties: false
+ description: Stable identity for a Project-owned variable Environment.
properties:
id:
type: string
format: uuid
- status:
+ project_id:
type: string
+ format: uuid
+ name:
+ type: string
+ pattern: ^[A-Za-z0-9_-]{1,64}$
+ minLength: 1
+ maxLength: 64
+ is_global:
+ type: boolean
+ description: Whether this is the reserved Global Environment.
created_at:
type: string
format: date-time
@@ -17650,394 +25355,567 @@ components:
format: date-time
required:
- id
- - status
+ - project_id
+ - name
+ - is_global
- created_at
- updated_at
- SandboxPagination:
- type: object
- additionalProperties: false
- properties:
- limit:
- type: integer
- has_more:
- type: boolean
- next_cursor:
- type: string
- required:
- - limit
- - has_more
- SandboxTemplatePage:
- type: object
- additionalProperties: false
- properties:
- data:
- type: array
- items:
- $ref: '#/components/schemas/SandboxTemplate'
- pagination:
- $ref: '#/components/schemas/SandboxPagination'
- required:
- - data
- - pagination
- SandboxSessionPage:
+ VariableEnvironmentList:
type: object
- additionalProperties: false
properties:
data:
type: array
+ maxItems: 101
items:
- $ref: '#/components/schemas/SandboxSession'
- pagination:
- $ref: '#/components/schemas/SandboxPagination'
+ $ref: '#/components/schemas/VariableEnvironment'
required:
- data
- - pagination
- SandboxDeploymentPage:
+ CreateVariableEnvironmentRequest:
type: object
additionalProperties: false
properties:
- data:
- type: array
- items:
- $ref: '#/components/schemas/SandboxDeployment'
- pagination:
- $ref: '#/components/schemas/SandboxPagination'
+ name:
+ type: string
+ description: Leading and trailing ASCII whitespace is trimmed before validating 1–64 ASCII letters, digits, underscores, or hyphens. Global is reserved.
+ pattern: ^[ \t\n\f\r]*[A-Za-z0-9_-]{1,64}[ \t\n\f\r]*$
required:
- - data
- - pagination
- SandboxPresetList:
+ - name
+ RenameVariableEnvironmentRequest:
type: object
additionalProperties: false
properties:
- data:
- type: array
- items:
- $ref: '#/components/schemas/SandboxPreset'
+ name:
+ type: string
+ description: Leading and trailing ASCII whitespace is trimmed before validating 1–64 ASCII letters, digits, underscores, or hyphens. Global is reserved.
+ pattern: ^[ \t\n\f\r]*[A-Za-z0-9_-]{1,64}[ \t\n\f\r]*$
required:
- - data
- Capability:
+ - name
+ Database:
type: object
- additionalProperties: false
- description: A product capability and whether it accepts new work in this environment.
+ description: |
+ PostgreSQL database with automatic scalability and security features.
properties:
id:
type: string
- description: Stable capability ID, such as `sandboxes`, `sandboxes.sessions`, `sandboxes.custom_templates`, `issues`, or `autofix`. New IDs may appear at any time.
- example: sandboxes.sessions
- status:
- $ref: '#/components/schemas/CapabilityStatus'
+ format: uuid
+ project_id:
+ type: string
+ format: uuid
+ name:
+ type: string
+ description: Database name
+ pattern: ^[a-z0-9_]+$
+ maxLength: 64
+ status:
+ type: string
+ enum:
+ - provisioning
+ - active
+ - failed
+ - restoring
+ - deleting
+ description: |
+ Database status. `restoring` means a restore is replacing the
+ database's data: it does not accept connections, and the operations
+ that would race the restore are rejected until it finishes. Its
+ branches keep serving throughout.
+ provisioning_started_at:
+ type: string
+ format: date-time
+ description: Timestamp when the current provisioning phase started
+ connection_string:
+ type: string
+ description: |
+ Secure PostgreSQL connection URI for your database.
+
+ The database is identified by the globally-unique username
+ (`volcano_client_{database_id}`) already in this URI; the
+ `application_name` parameter only selects the access mode:
+ - `volcano_full_access` — Full admin access (DDL, migrations)
+ - `volcano_user_access:{user_id}` — User impersonation (RLS enforced)
+ - `volcano_user_access` — Anonymous access (anon role, RLS enforced)
+ region:
+ type: string
+ description: Region where the database is hosted
+ example: us-east-1
+ pg_version:
+ type: string
+ description: PostgreSQL major version
+ example: '18'
+ database_type:
+ type: string
+ description: |
+ Database size tier that determines available RAM and scaling limits.
+ enum:
+ - volcano-db-xs
+ - volcano-db-s
+ - volcano-db-m
+ - volcano-db-l
+ - volcano-db-xl
+ - volcano-db-2xl
+ example: volcano-db-xs
+ storage_bytes:
+ type: integer
+ format: int64
+ minimum: 0
+ description: |
+ Latest observed storage for this database, in bytes: its own on-disk
+ size, plus what each branch has diverged from it, plus what its
+ backups cost to hold. This is the figure the storage allowance is
+ enforced against, and the stats endpoint breaks it down. A
+ point-in-time gauge recorded by a background pass, so it may be
+ absent until the database has been sampled, and it can trail the
+ stats endpoint's `current_storage_bytes`, which measures on request.
+ Summing the latest samples for every database in a project produces
+ the project's "Database Storage (Bytes)" usage gauge. Populated on
+ database list responses; single-database responses omit it.
+ last_invoked_at:
+ type: string
+ format: date-time
+ description: Most recent request timestamp for this database
+ created_at:
+ type: string
+ format: date-time
+ updated_at:
+ type: string
+ format: date-time
required:
- id
+ - project_id
+ - name
- status
- CapabilityStatus:
- type: string
- enum:
- - available
- - unavailable
- description: '`available` means the capability accepts new work; a temporary outage still answers `503`. `unavailable` means requests that start new work answer `404` or `400` with code `feature_unavailable`. Treat any other value as `unavailable`.'
- CapabilityList:
- type: object
- additionalProperties: false
- properties:
- data:
- type: array
- items:
- $ref: '#/components/schemas/Capability'
- required:
- - data
- SandboxCapacity:
+ - created_at
+ - updated_at
+ DatabaseBackup:
type: object
- additionalProperties: false
+ description: |
+ A point-in-time copy of a database, kept by the storage provider and
+ restorable in place.
+
+ Backups cover the database itself, not its branches. Restoring one
+ replaces the database's data and keeps its connection string.
properties:
- region:
+ name:
type: string
- allocated_memory_mb:
+ description: |
+ Backup name, unique within the database. Backups you create are
+ named by you; scheduled backups are named by the storage provider.
+ source:
+ type: string
+ enum:
+ - manual
+ - scheduled
+ - migration
+ description: |
+ Whether the backup was requested explicitly, produced by the backup
+ schedule, or taken before migrations were applied to the database.
+ Only `manual` backups count against the plan's backup allowance.
+ size_bytes:
type: integer
format: int64
minimum: 0
+ description: |
+ Storage the backup occupies. Absent until the provider has costed
+ it, which takes a few minutes after the backup is taken; absent is
+ not the same as empty.
+ expires_at:
+ type: string
+ format: date-time
+ description: |
+ When the backup is deleted automatically, from the plan's retention.
+ Absent means it is kept until deleted explicitly.
+ created_at:
+ type: string
+ format: date-time
+ description: The point in time the backup captures.
required:
- - region
- - allocated_memory_mb
- SandboxCapacityList:
+ - name
+ - source
+ - created_at
+ DatabaseBackupList:
type: object
- additionalProperties: false
properties:
data:
type: array
items:
- $ref: '#/components/schemas/SandboxCapacity'
+ $ref: '#/components/schemas/DatabaseBackup'
+ restore_window:
+ $ref: '#/components/schemas/DatabaseRestoreWindow'
required:
- data
- PublishSandboxPresetRequest:
+ DatabaseBackupSchedule:
type: object
- additionalProperties: false
+ description: |
+ The database's automated backup schedule. An empty list means no
+ scheduled backups; sending one clears the schedule.
properties:
- id:
- type: string
- format: uuid
- preset:
+ entries:
+ type: array
+ items:
+ $ref: '#/components/schemas/DatabaseBackupScheduleEntry'
+ required:
+ - entries
+ DatabaseBackupScheduleEntry:
+ type: object
+ description: One recurrence of the automated backup schedule.
+ properties:
+ frequency:
type: string
enum:
- - python3.12
- - node22
- memory_mb:
+ - daily
+ - weekly
+ - monthly
+ hour:
type: integer
- enum:
- - 1024
- - 2048
- deployment_id:
- type: string
- format: uuid
+ minimum: 0
+ maximum: 23
+ description: Hour of the day in UTC.
+ day:
+ type: integer
+ minimum: 1
+ maximum: 28
+ description: |
+ Day of the week (1-7, Monday to Sunday) for a weekly schedule, or day
+ of the month (1-28) for a monthly one. Required for both, ignored for
+ a daily schedule. Monthly stops at 28 so the schedule fires in every
+ month.
+ retention_seconds:
+ type: integer
+ format: int64
+ minimum: 3600
+ description: |
+ How long each backup from this recurrence is kept. Clamped to the
+ plan's retention, and defaulted to it when omitted.
required:
- - id
- - preset
- - memory_mb
- - deployment_id
- AnonKey:
+ - frequency
+ - hour
+ DatabaseBranch:
type: object
+ description: |
+ A copy-on-write fork of a database, for development and testing.
+
+ A branch starts as an exact copy of its parent's data and diverges from
+ there. It has its own connection string and its own credential, so a
+ branch password cannot reach the parent.
+
+ Every branch expires. `expires_at` is a hard deadline: once it passes the
+ branch stops accepting connections and is deleted. Use `PATCH` to extend
+ a branch you are still working on.
properties:
id:
type: string
format: uuid
+ database_id:
+ type: string
+ format: uuid
+ description: The parent database this branch was forked from.
project_id:
type: string
format: uuid
name:
type: string
- key_value:
+ description: Branch name, unique within the parent database.
+ pattern: ^[a-z0-9_]+$
+ maxLength: 64
+ status:
type: string
- description: JWT token - use this in frontend Authorization header
- permissions:
- type: array
- items:
- type: string
+ enum:
+ - provisioning
+ - active
+ - failed
+ - deleting
description: |
- Permissions granted to this anon key.
- Auth permissions: auth.signup, auth.signin, auth.refresh, auth.logout, auth.password_reset, auth.confirm_email, auth.resend_confirmation
- Storage permissions: storage.upload, storage.download, storage.list, storage.delete
- Realtime permissions: realtime.connect, realtime.subscribe, realtime.publish
- Functions permissions: functions.invoke
- example:
- - auth.signup
- - auth.signin
- - auth.refresh
- - auth.logout
- is_default:
- type: boolean
- description: Whether this is the project's configured default anon key. Only one key per project can be default.
+ Branch status. A new branch starts `provisioning` and is not
+ connectable until it reports `active`; poll this endpoint until it
+ does. `connection_string` is only present while `active`.
+
+ `provisioning` also covers a branch being rebuilt after a `reset`,
+ and a build that is between retries, so it is the status to keep
+ waiting on. `failed` is terminal: it means the platform gave up, and
+ the branch will not become `active` on its own.
+ connection_string:
+ type: string
+ description: |
+ PostgreSQL connection URI for this branch. Present only while the
+ branch is `active`.
+
+ The URI carries the branch's own globally-unique username and
+ password; `application_name` selects the access mode exactly as it
+ does for the parent database:
+ - `volcano_full_access` — Full admin access (DDL, migrations)
+ - `volcano_user_access:{user_id}` — User impersonation (RLS enforced)
+ - `volcano_user_access` — Anonymous access (anon role, RLS enforced)
+ ttl_seconds:
+ type: integer
+ format: int64
+ minimum: 1
+ description: |
+ The lifetime the branch was created with. Resetting a branch re-arms
+ this same duration, so a reset never shortens a branch's remaining
+ life.
+ expires_at:
+ type: string
+ format: date-time
+ description: |
+ When the branch stops serving connections and becomes eligible for
+ deletion. Enforced on the connection path, so it holds even if
+ reclamation is delayed.
+ storage_bytes:
+ type: integer
+ format: int64
+ minimum: 0
+ description: |
+ Bytes this branch has diverged from its parent, which is what a
+ branch actually costs. Shared pages are not counted twice. Counts
+ against the parent database's storage allowance. Absent until the
+ branch has been sampled.
+ last_invoked_at:
+ type: string
+ format: date-time
+ description: Most recent request timestamp for this branch
created_at:
type: string
- format: date-time
+ format: date-time
+ updated_at:
+ type: string
+ format: date-time
+ required:
+ - id
+ - database_id
+ - project_id
+ - name
+ - status
+ - ttl_seconds
+ - expires_at
+ - created_at
+ - updated_at
+ DatabaseBranchList:
+ type: object
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/DatabaseBranch'
+ required:
+ - data
+ DatabaseBranchStorage:
+ type: object
+ description: One branch's contribution to its parent database's storage.
+ properties:
+ id:
+ type: string
+ format: uuid
+ name:
+ type: string
+ description: Branch name
+ storage_bytes:
+ type: integer
+ format: int64
+ minimum: 0
+ description: |
+ Bytes this branch has diverged from its parent. Pages the branch
+ still shares with the parent are not counted, so this is what the
+ branch actually adds to the total rather than its apparent size.
required:
- id
- name
- - key_value
- AuthConfig:
+ - storage_bytes
+ DatabaseSelectRequest:
type: object
properties:
- project_id:
+ table:
type: string
- format: uuid
- access_token_lifetime:
- type: integer
- description: Access token lifetime in seconds
- default: 3600
- refresh_token_lifetime:
- type: integer
- description: Refresh token lifetime in seconds
- default: 2592000
- refresh_token_reuse_interval:
- type: integer
- description: A refresh within this many seconds of the refresh token being issued returns the same refresh token instead of rotating it, so concurrent refreshes from several tabs all succeed
- default: 10
- inactivity_timeout:
- type: integer
- description: Force re-login after inactivity (seconds, 0=never)
- default: 0
- max_session_duration:
- type: integer
- description: Force re-login after duration (seconds, 0=never)
- default: 0
- min_password_length:
- type: integer
- minimum: 15
- maximum: 128
- default: 15
- description: Configured minimum password length in Unicode characters.
- password_policy:
- $ref: '#/components/schemas/AuthPasswordPolicy'
- require_uppercase:
- type: boolean
- default: false
- require_lowercase:
- type: boolean
- default: false
- require_numbers:
- type: boolean
- default: false
- require_special_chars:
- type: boolean
- default: false
- enable_signup:
- type: boolean
- description: Master switch - allow new user signups via ANY provider
- default: true
- enable_email_password:
- type: boolean
- description: Enable email/password authentication as a provider
- default: true
- rate_limit_signup:
- type: integer
- description: Signups per hour per IP
- default: 100
- rate_limit_signin:
- type: integer
- description: Signins per hour per IP
- default: 100
- rate_limit_token_refresh:
- type: integer
- description: Refreshes per hour per IP
- default: 1000
- rate_limit_password_reset:
- type: integer
- description: Password reset requests per hour per IP. Unlike the other limits, 0 applies the default of 10 instead of turning the limit off.
- default: 10
- cors_enabled:
- type: boolean
- default: false
- cors_allowed_origins:
+ description: Table name to query
+ example: posts
+ select:
type: array
items:
type: string
+ description: Columns to select (omit for *)
example:
- - https://myapp.com
- - http://localhost:3000
- enable_anonymous_signins:
- type: boolean
- description: Allow creating users without email/password
- default: false
- allowed_email_domains:
+ - id
+ - title
+ - content
+ - created_at
+ filters:
type: array
- description: |
- Email domains allowed to create users in this project. Applies to
- email/password signup, OAuth/SSO signup, anonymous conversion, and
- email changes. Empty (the default) allows every domain.
-
- Entries are stored normalized (lowercase, no `@` prefix) and match
- the domain part exactly: `domain1.com` does not cover
- `mail.domain1.com`. Signups from other domains are rejected with
- 403, and `allowed_email_domains_mode` decides whether sign-in is
- covered as well.
-
- The allowlist is a SUPERAGENT feature to configure and to enforce. A
- downgrade parks it: the domains are still returned here and stop
- being applied until the project is back on SUPERAGENT.
items:
- type: string
+ $ref: '#/components/schemas/DatabaseQueryFilter'
+ description: WHERE conditions (combined with AND)
example:
- - domain1.com
- - domain2.com
- allowed_email_domains_mode:
- type: string
- description: |
- How far `allowed_email_domains` reaches. `signup` only gates account
- creation, so accounts that predate the list keep signing in.
- `signup_and_signin` also refuses to issue a session to an account
- whose domain is not listed. `disabled` keeps the list without
- enforcing it.
- enum:
- - disabled
- - signup
- - signup_and_signin
- default: signup
- platform_token_ttl:
- type: integer
- description: TTL in seconds for platform tokens minted via `/auth/platform/exchange`
- default: 2592000
- allow_password_reset:
- type: boolean
- description: Enable forgot password flow
- default: true
- password_reset_timeout:
- type: integer
- description: Recovery token expiry in seconds
- default: 3600
- max_password_history:
- type: integer
- description: Number of previous passwords to remember (0=disabled)
- default: 0
- cors_allow_credentials:
- type: boolean
- description: Allow credentials in CORS requests
- default: true
- cors_max_age:
+ - column: status
+ operator: eq
+ value: published
+ - column: views
+ operator: gt
+ value: 100
+ order:
+ type: array
+ items:
+ $ref: '#/components/schemas/DatabaseQueryOrder'
+ description: ORDER BY clauses
+ example:
+ - column: created_at
+ ascending: false
+ limit:
type: integer
- description: CORS preflight cache duration (seconds)
- default: 86400
- require_email_confirmation:
- type: boolean
- description: Require users to confirm email before sign-in. Can only be true when email_enabled is true.
- default: false
- email_confirmation_timeout:
+ minimum: 1
+ maximum: 1000
+ description: Maximum rows to return
+ example: 10
+ offset:
type: integer
- description: Email confirmation token expiry in seconds.
- default: 86400
- auto_link_verified_oauth:
- type: boolean
- description: Link a verified OAuth identity to an existing confirmed account with the same email instead of returning a conflict. Requires require_email_confirmation to be true.
- default: false
- email_enabled:
- type: boolean
- description: Enable transactional email sending (confirmation, reset, change notifications). Must be true when require_email_confirmation is true.
- default: false
- email_from_address:
+ minimum: 0
+ description: Number of rows to skip (for pagination)
+ example: 0
+ required:
+ - table
+ DatabaseInsertRequest:
+ type: object
+ properties:
+ table:
+ type: string
+ description: Table name
+ example: posts
+ values:
+ type: object
+ additionalProperties: true
+ description: |
+ Column values to insert. JSON objects and arrays are stored as JSON,
+ so send them to `json` or `jsonb` columns. For a Postgres array
+ column, send an array literal string such as `"{a,b}"`.
+ example:
+ title: My New Post
+ content: This is the content
+ status: draft
+ required:
+ - table
+ - values
+ DatabaseUpdateRequest:
+ type: object
+ properties:
+ table:
+ type: string
+ description: Table name
+ example: posts
+ values:
+ type: object
+ additionalProperties: true
+ description: |
+ Column values to update. JSON objects and arrays are stored as JSON,
+ so send them to `json` or `jsonb` columns. For a Postgres array
+ column, send an array literal string such as `"{a,b}"`.
+ example:
+ title: Updated Title
+ status: published
+ filters:
+ type: array
+ minItems: 1
+ items:
+ $ref: '#/components/schemas/DatabaseQueryFilter'
+ description: |
+ WHERE conditions for which rows to update. At least one filter is
+ required; a filterless update is rejected to avoid rewriting every
+ row.
+ example:
+ - column: id
+ operator: eq
+ value: post-uuid
+ required:
+ - table
+ - values
+ - filters
+ DatabaseDeleteRequest:
+ type: object
+ properties:
+ table:
type: string
- email_from_name:
+ description: Table name
+ example: posts
+ filters:
+ type: array
+ minItems: 1
+ items:
+ $ref: '#/components/schemas/DatabaseQueryFilter'
+ description: WHERE conditions (required for safety)
+ example:
+ - column: id
+ operator: eq
+ value: post-uuid
+ required:
+ - table
+ - filters
+ DatabaseQueryResult:
+ type: object
+ description: |
+ Rows returned by a data API request. RLS-filtered unless the request was
+ made with a service key.
+ properties:
+ data:
+ type: array
+ items:
+ type: object
+ additionalProperties: true
+ description: Result rows
+ count:
+ type: integer
+ description: Number of rows returned
+ DatabaseRestore:
+ type: object
+ description: |
+ A restore of a database, either from a named backup or to a point in
+ time. Restores run in the background and take longer than a request, so
+ the database is unavailable until this reports `completed`.
+ properties:
+ id:
type: string
- smtp_host:
+ format: uuid
+ database_id:
type: string
- smtp_port:
- type: integer
- default: 587
- smtp_username:
+ format: uuid
+ project_id:
type: string
- smtp_password_configured:
- type: boolean
- description: Whether an SMTP password is configured. The password itself is never returned.
- default: false
- smtp_use_tls:
- type: boolean
- default: true
- email_confirmation_subject:
+ format: uuid
+ kind:
type: string
- email_password_reset_subject:
+ enum:
+ - snapshot
+ - point_in_time
+ description: |
+ Whether the restore targets a named backup or an arbitrary point in
+ time. Both replace the database's data in place.
+ status:
type: string
- email_password_changed_subject:
+ enum:
+ - pending
+ - running
+ - completed
+ - failed
+ - exhausted
+ description: |
+ Restore status. `pending` and `running` both mean the restore is
+ still in flight and the database is not connectable; an attempt that
+ fails with tries left goes back to `pending`. `failed` and
+ `exhausted` both mean Volcano gave up: the database is left `failed`
+ if its data may already have been replaced, and `active` if the
+ restore never started — a backup that no longer exists at the
+ provider ends the restore without touching the database. A restore
+ cannot be cancelled once it starts.
+ backup_name:
type: string
- managed_auth_enabled:
- type: boolean
- description: Enables project-hosted managed auth pages.
- default: false
- post_auth_redirect_url:
+ description: |
+ The backup restored, kept even if that backup is later deleted.
+ Absent for a point-in-time restore.
+ restore_to:
type: string
- description: Default redirect target after successful hosted auth.
- allowed_redirect_urls:
- type: array
- description: Redirect allowlist used to validate post_auth_redirect_url and post_logout_redirect_url.
- items:
- type: string
- post_logout_redirect_url:
+ format: date-time
+ description: The point in time restored to. Absent for a backup restore.
+ error:
type: string
- description: Redirect target after logout from hosted pages.
- device_verification_url:
+ description: Why the most recent attempt failed, when one has.
+ completed_at:
type: string
- description: |
- Optional override for the device-authorization verification page.
- When set, POST /auth/device/authorize returns this URL (with the
- user_code) as verification_uri/verification_uri_complete instead of
- the built-in managed device page. Lets a CLI surface the project's
- own RFC 8628 approval page. Empty falls back to the managed page.
- example: https://app.acme.com/device
+ format: date-time
created_at:
type: string
format: date-time
@@ -18045,335 +25923,645 @@ components:
type: string
format: date-time
required:
- - password_policy
- AuthInsightsInterval:
- type: string
- enum:
- - day
- - week
- - month
- AuthInsightsResponse:
+ - id
+ - database_id
+ - project_id
+ - kind
+ - status
+ - created_at
+ - updated_at
+ DatabaseRestoreList:
type: object
- additionalProperties: false
properties:
- project_id:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/DatabaseRestore'
+ required:
+ - data
+ DatabaseRestoreWindow:
+ type: object
+ description: |
+ The span a point-in-time restore may target. Absent from the response
+ when the owner's plan does not include point-in-time restore, and while
+ the storage provider has no history window in place yet — briefly the
+ case after an upgrade, since the window is applied asynchronously. The
+ window is read from the provider rather than from the plan, so it never
+ advertises a point a restore could not actually reach.
+ properties:
+ earliest_restore_at:
type: string
- format: uuid
- observed_at:
+ format: date-time
+ description: |
+ The oldest point that can still be restored. Moves forward
+ continuously as history ages out, so treat it as a lower bound at
+ the moment it was read rather than a fixed value.
+ latest_restore_at:
type: string
format: date-time
- window:
- $ref: '#/components/schemas/AuthInsightsWindow'
- summary:
- $ref: '#/components/schemas/AuthInsightsSummary'
- series:
+ description: The most recent point that can be restored, which is now.
+ DatabaseRestoreConflictError:
+ description: |
+ A restore refused by the database's state. With code
+ `migration_run_in_progress`, `run_id` names the migration run backing up
+ or applying to the database.
+ allOf:
+ - $ref: '#/components/schemas/Error'
+ - type: object
+ properties:
+ run_id:
+ type: string
+ format: uuid
+ DatabaseMigrationFile:
+ type: object
+ description: One migration file and its SQL.
+ properties:
+ name:
+ type: string
+ minLength: 5
+ maxLength: 320
+ pattern: ^([a-z0-9_]+/)?[^/\\]+\.sql$
+ description: |
+ The file's path under `volcano/migrations/`: a file name such as
+ `001_create_users.sql`, or `/001_create_users.sql` in a
+ project with more than one database, where `` must be
+ this database. Every file in a request takes the same form. Files
+ run in byte order of their file name, which the history records.
+ example: 001_create_users.sql
+ sql:
+ type: string
+ maxLength: 1048576
+ description: |
+ The file's SQL, at most 1 MiB. A file may hold several statements
+ and runs in one transaction. A file cannot commit, roll back, use
+ savepoints, or `COPY` from the client; such a file fails with
+ `migration_failed`. A statement that cannot run in a transaction,
+ such as `CREATE INDEX CONCURRENTLY`, goes alone in a file whose
+ first line is `-- volcano:no-transaction`. That file runs outside a
+ transaction and runs again from its start when a run retries it. A
+ run refuses with `invalid_file`, before anything runs, a file with
+ the marker on any other line, and a marked file that builds an
+ unnamed index with `CREATE INDEX CONCURRENTLY` or starts with
+ `COPY`.
+ required:
+ - name
+ - sql
+ DatabaseMigrationFilesRequest:
+ type: object
+ properties:
+ files:
type: array
+ minItems: 1
+ maxItems: 1000
items:
- $ref: '#/components/schemas/AuthInsightsSeriesPoint'
+ $ref: '#/components/schemas/DatabaseMigrationFile'
required:
- - project_id
- - observed_at
- - window
- - summary
- - series
- AuthInsightsSeriesPoint:
+ - files
+ DatabaseMigrationHistoryEntry:
type: object
- additionalProperties: false
+ description: One file the database's migration history records.
properties:
- bucket_start:
+ name:
type: string
- format: date
- signups:
- type: integer
- format: int64
- minimum: 0
- description: Registrations during the bucket. Subsequent deletion does not subtract from this count. Historical counts removed before deletion-history collection cannot be reconstructed.
- signins:
- type: integer
- format: int64
- minimum: 0
- description: Successful session creations during the bucket.
- banned_users:
- type: integer
- format: int64
- minimum: 0
- description: Users registered in this bucket who are currently banned. Excludes deleted users, lifted bans, expired temporary bans, and internal test identities.
- deleted_users:
- type: integer
- format: int64
- minimum: 0
- description: Users registered in this bucket who are now deleted, counted once across soft and hard deletion. Grouped by signup date, not deletion date.
- available_users:
- type: integer
- format: int64
- minimum: 0
- description: Currently available users registered in this bucket (signups minus banned_users minus deleted_users). Unban or expiry restores availability in the original signup bucket. This measures account availability, not return activity.
- deletions:
- type: integer
- format: int64
- minimum: 0
- description: Accounts deleted during this bucket, counted once across soft and hard deletion.
- net_growth:
- type: integer
- format: int64
- description: Registrations minus deletions during this bucket. May be negative. Bans do not affect this value.
- is_partial:
- type: boolean
- description: Whether the requested window or observation time clips this bucket.
+ example: 001_create_users.sql
+ checksum:
+ type: string
+ description: |
+ `sha256:` and the hex digest of the file as recorded, with a leading
+ byte order mark removed and CRLF line endings converted to LF.
+ example: sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
+ status:
+ type: string
+ enum:
+ - applied
+ - baselined
+ description: |
+ `applied`: a run ran the file and it committed. `baselined`: the file
+ was recorded as applied without running.
+ applied_at:
+ type: string
+ format: date-time
+ run_id:
+ type: string
+ format: uuid
+ description: The run that recorded the file. Absent for a baseline.
+ required:
+ - name
+ - checksum
+ - status
+ - applied_at
+ DatabaseMigrations:
+ type: object
+ properties:
+ history:
+ type: array
+ description: Every file the history records, in name order.
+ items:
+ $ref: '#/components/schemas/DatabaseMigrationHistoryEntry'
+ active_run_id:
+ type: string
+ format: uuid
+ description: The run that is queued or running, if any.
+ required:
+ - history
+ DatabaseMigrationBaseline:
+ type: object
+ properties:
+ recorded:
+ type: array
+ description: |
+ The files this request recorded, in name order. Empty when the
+ history already recorded every file.
+ items:
+ type: string
required:
- - bucket_start
- - signups
- - signins
- - is_partial
- - deletions
- - banned_users
- - deleted_users
- - available_users
- - net_growth
- AuthInsightsSummary:
+ - recorded
+ DatabaseMigrationConflictError:
+ description: |
+ A migration request refused by the database's state. With code
+ `migration_run_in_progress`, `run_id` names the run that is queued or
+ running.
+ allOf:
+ - $ref: '#/components/schemas/Error'
+ - type: object
+ properties:
+ run_id:
+ type: string
+ format: uuid
+ DatabaseMigrationRunFile:
type: object
- additionalProperties: false
properties:
- total_users:
- type: integer
- format: int64
- minimum: 0
- description: Current auth-user count, excluding accounts with deleted status.
- deleted_users:
- type: integer
- format: int64
- minimum: 0
- description: Recorded deletions, excluding internal test identities. Includes soft and hard deletion, counted once per account.
- active_users_1d:
- type: integer
- format: int64
- minimum: 0
- description: Distinct users active in the trailing 24 hours, including activity before account deletion.
- active_users_30d:
+ name:
+ type: string
+ example: 001_create_users.sql
+ outcome:
+ type: string
+ enum:
+ - pending
+ - already_applied
+ - applied
+ - failed
+ - not_run
+ - unknown
+ description: |
+ `pending`: not settled yet, including a file the run will try again
+ on its next attempt. `already_applied`: the history already recorded
+ it, so it did not run; a file can also end this way in `apply`, when
+ another session applied or baselined it after the run planned.
+ `applied`: this run applied it. `failed`: its own SQL failed and
+ its transaction rolled back, in the rehearsal or in the database as
+ the run's `phase` says, including when the run's time limit stopped
+ it; a file whose `COMMIT` failed is `unknown` instead. A file whose
+ first line is `-- volcano:no-transaction` runs outside a
+ transaction, so nothing rolls back what it did before failing, such
+ as the invalid index a failed `CREATE INDEX CONCURRENTLY` leaves.
+ `not_run`: the run ended before the file committed, without its
+ SQL failing: before `apply`, after an earlier file failed or lost
+ its `COMMIT`, or after the connection was lost or Volcano's own
+ statements around the file failed, which rolled it back. `unknown`:
+ the run ended in `apply` without confirming whether the file ran,
+ for example because its attempts ran out, its `COMMIT` failed or
+ was cut short, or it ran outside a transaction and the connection
+ was lost or Volcano's own statements after it failed. The file may
+ have committed. The database's history says whether a file that
+ ran in a transaction committed, and the next run's plan applies a
+ file only if the history does not record it.
+ While the run is `queued` or `running`, each attempt reads the
+ history again before it runs a file, and sets every file the run
+ has not applied from it: `already_applied` if the history holds
+ it, `pending` otherwise. The exception is a file that runs outside
+ a transaction: it is `unknown` from just before Volcano sends it
+ until Volcano confirms what became of it. If it may have run, it
+ stays `unknown` until an attempt applies it or the history holds
+ it, and keeps the `error` of a later attempt that fails it.
+ error:
+ $ref: '#/components/schemas/DatabaseMigrationFileError'
+ required:
+ - name
+ - outcome
+ DatabaseMigrationFileError:
+ type: object
+ description: |
+ The database's error for a `failed` file, or for an `unknown` file
+ that runs outside a transaction, when a later attempt failed it after
+ an earlier one may have run it. `message` is the database's own
+ message and can quote values from the file or the data.
+ properties:
+ message:
+ type: string
+ description: |
+ At most 8 KiB (8,192 bytes). A longer message is cut and ends with
+ ` … [truncated]`. Volcano reads each reply the database sends about
+ the file up to 4 MiB, which leaves room for a reply that quotes the
+ whole file twice. A larger reply is not read: the file fails, and
+ this message says so instead.
+ example: column "email" of relation "users" already exists
+ sqlstate:
+ type: string
+ description: The Postgres error code, when the database reported one.
+ example: '42701'
+ line:
type: integer
- format: int64
- minimum: 0
- description: Distinct users with a successful session creation or refresh in the trailing 30 days, including activity before account deletion.
+ minimum: 1
+ description: The line of the file the database reported, when known.
required:
- - total_users
- - active_users_30d
- - active_users_1d
- - deleted_users
- AuthInsightsWindow:
+ - message
+ DatabaseMigrationWarning:
type: object
- additionalProperties: false
+ description: A condition the run reports that did not stop it.
properties:
- from:
+ code:
type: string
- format: date
- to:
+ enum:
+ - out_of_order
+ - missing_file
+ - rehearsal_skipped
+ - backup_skipped
+ - backup_prune_failed
+ - warnings_truncated
+ description: |
+ `out_of_order`: a pending file sorts before one the history already
+ records; it still ran. `missing_file`: the history records a file
+ the run did not include. `rehearsal_skipped`: the files were not
+ rehearsed, because branches are not available here or on the plan.
+ `backup_skipped`: no backup was taken, because backups are not
+ available here or on the plan. `backup_prune_failed`: Volcano
+ could not delete older migration backups beyond the 20 it keeps;
+ the run's outcome is unaffected, and the next run that takes a
+ backup tries again. `warnings_truncated`: the run raised more than
+ 100 warnings; it is the last one, and its message says how many
+ more were not kept.
+ file:
+ type: string
+ description: The file the warning is about, when it is about one.
+ message:
type: string
- format: date
- interval:
- $ref: '#/components/schemas/AuthInsightsInterval'
required:
- - from
- - to
- - interval
- AuthHostedPage:
+ - code
+ - message
+ DatabaseMigrationRunError:
+ type: object
+ description: Why the run failed, or why its last attempt did.
+ properties:
+ code:
+ type: string
+ enum:
+ - migration_failed
+ - checksum_mismatch
+ - history_missing
+ - history_too_large
+ - invalid_file
+ - invalid_layout
+ - plan_changed
+ - branch_limit
+ - rehearsal_unavailable
+ - backup_failed
+ - restore_in_progress
+ - database_unavailable
+ - owner_not_active
+ - locked
+ - connection_failed
+ - timeout
+ - attempts_exhausted
+ - internal_error
+ - operator_failed
+ description: |
+ Stable machine-readable reason. `migration_failed`: a file's SQL,
+ or its `COMMIT`, failed; `phase` says whether in the rehearsal,
+ leaving the database untouched, or in the database, where the files
+ before it stay applied. `checksum_mismatch`: an applied file changed.
+ `history_missing`: the database's history table is gone though
+ migrations ran there; record a baseline of the files already
+ applied. Dropping the whole `_volcano_migrations` schema is not
+ supported and not detected: the database reads as new, and the run
+ applies every file again. `history_too_large`: the history has
+ more than the 1,000 entries Volcano reads. `invalid_file`: a file
+ Volcano refuses to run. `invalid_layout`: file paths that do not map
+ to the database.
+ `plan_changed`: the history changed after the rehearsal.
+ `branch_limit`: the rehearsal branch would exceed the plan's branch
+ allowance. `backup_failed` and `rehearsal_unavailable`: Volcano
+ could not take the backup or prepare the rehearsal.
+ `restore_in_progress` and `database_unavailable`: the database could
+ not take the run. `owner_not_active`: the project owner's account
+ was not `active` when Volcano picked the run up, or before its
+ `backup` or `apply`, or before a file in `apply` unless held
+ `read_only` only for the plan's limits, so the run applied nothing
+ further; files it already applied stay applied.
+ `locked`: another session held the migration lock,
+ or a file, or Volcano's drop of a failed build's index, waited too
+ long for a lock. `connection_failed`: the
+ database could not be reached, or the connection was lost,
+ including while a file ran. `internal_error`: Volcano failed for a
+ reason of its own, such as its own statements around a file.
+ `timeout` and `attempts_exhausted`: the run could not finish.
+ `operator_failed`: Volcano ended a run that stopped making
+ progress; read the history to see which files were applied, then
+ start a new run.
+ message:
+ type: string
+ description: |
+ What happened, naming files and Postgres error codes. The
+ database's own message is on the failed file.
+ required:
+ - code
+ - message
+ DatabaseMigrationRun:
type: object
+ description: |
+ One application of migration files to a database. A run plans the files
+ against the database's history, rehearses the pending ones on a
+ short-lived branch, takes a backup, and applies them.
properties:
id:
type: string
format: uuid
- project_id:
+ database:
+ $ref: '#/components/schemas/ResourceReference'
+ status:
type: string
- format: uuid
- page_type:
- $ref: '#/components/schemas/HostedAuthPageType'
- html:
+ enum:
+ - queued
+ - running
+ - succeeded
+ - failed
+ description: |
+ `queued` and `running` mean the run has not ended; a run waiting
+ to retry stays `running`. `succeeded`: every pending file was
+ applied, or none was pending. `failed`: `error` says why.
+ phase:
type: string
- description: HTML content for this page type.
- css:
+ enum:
+ - plan
+ - rehearse
+ - backup
+ - apply
+ x-enum-varnames:
+ - DatabaseMigrationRunPhasePlan
+ - DatabaseMigrationRunPhaseRehearse
+ - DatabaseMigrationRunPhaseBackup
+ - DatabaseMigrationRunPhaseApply
+ description: |
+ The step the run is on, or the one it ended on. `plan` compares the
+ files with the history. `rehearse` applies the pending files to a
+ short-lived branch of the database, which is deleted afterwards.
+ `backup` takes the backup named by `backup_name`. `apply` applies
+ the files to the database.
+ source:
type: string
- description: CSS content for this page type.
+ enum:
+ - git_deploy
+ - api
+ description: What started the run.
+ commit_sha:
+ type: string
+ description: The commit whose files the run applies. Present for `git_deploy` runs.
+ backup_name:
+ type: string
+ description: |
+ The backup the run takes before it applies the files, named once
+ the run starts taking it. It is listed with the database's backups
+ with `source: migration`. A run that ended in its `backup` phase
+ may name a backup that was never created.
+ example: before-migration-7f3a1c2e-5d4b-4a91-8c6f-2b1e9d0a4c73
+ files:
+ type: array
+ description: |
+ The run's files, in the order they run, with what became of each.
+ Absent when listing runs.
+ items:
+ $ref: '#/components/schemas/DatabaseMigrationRunFile'
+ warnings:
+ type: array
+ maxItems: 101
+ description: |
+ A run keeps at most 100 warnings, keeping those about the run, such
+ as a skipped backup, ahead of those about files. A run that raised
+ more ends the list with a `warnings_truncated` warning.
+ items:
+ $ref: '#/components/schemas/DatabaseMigrationWarning'
+ error:
+ $ref: '#/components/schemas/DatabaseMigrationRunError'
+ started_at:
+ type: string
+ format: date-time
+ description: When a worker first picked the run up.
+ completed_at:
+ type: string
+ format: date-time
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
- AuthPageAppearanceResponse:
- type: object
required:
- - theme
- - layouts
- - customisation_allowed
- - parked
- - defaults
- - options
- properties:
- theme:
- $ref: '#/components/schemas/AuthPageTheme'
- layouts:
- type: object
- additionalProperties:
- $ref: '#/components/schemas/AuthPageLayout'
- customisation_allowed:
- type: boolean
- parked:
- type: object
- additionalProperties:
- type: boolean
- description: Per-page saved-but-not-live state.
- defaults:
- $ref: '#/components/schemas/AuthPageAppearanceDefaults'
- options:
- $ref: '#/components/schemas/AuthPageAppearanceOptions'
- AuthPageDensity:
- type: string
- enum:
- - compact
- - comfortable
- - spacious
- AuthPageFont:
- type: string
- enum:
- - system
- - humanist
- - geometric
- - slab
- - mono
- AuthPageLayout:
- type: string
- enum:
- - centered
- - split-left
- - split-right
- AuthPageRadius:
- type: string
- enum:
- - none
- - small
- - medium
- - large
- AuthPageScale:
- type: string
- enum:
- - small
- - default
- - large
- AuthPageTheme:
+ - id
+ - database
+ - status
+ - phase
+ - source
+ - warnings
+ - created_at
+ - updated_at
+ DatabaseMigrationRunList:
type: object
- additionalProperties: false
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/DatabaseMigrationRun'
required:
- - version
- - colors
- - font
- - scale
- - density
- - radius
+ - data
+ DatabaseStats:
+ type: object
properties:
- version:
+ current_storage_bytes:
+ type: integer
+ format: int64
+ minimum: 0
+ description: |
+ On-disk size right now, in bytes: the database itself, plus every
+ branch's divergence from it, plus what its backups cost to hold. This
+ is the figure the storage allowance is enforced against. `branches`
+ and `backup_storage_bytes` break it down.
+ current_storage_mb:
+ type: number
+ format: double
+ minimum: 0
+ description: '`current_storage_bytes` expressed in megabytes.'
+ branches:
+ type: array
+ description: |
+ Per-branch contribution to `current_storage_bytes`. Empty when the
+ database has no branches. A branch that has not diverged from its
+ parent contributes nothing.
+ items:
+ $ref: '#/components/schemas/DatabaseBranchStorage'
+ backup_storage_bytes:
+ type: integer
+ format: int64
+ minimum: 0
+ description: |
+ What this database's backups contribute to `current_storage_bytes`.
+
+ A backup taken on request is charged as a full copy of the database
+ as it was at that moment, so two backups of a 2 GB database are 4 GB.
+ A backup schedule is charged its first snapshot in full and each
+ later one only for the storage it adds. Deleting a backup releases
+ its storage immediately.
+
+ Sampled from the provider rather than measured live, so it can lag a
+ change by a few minutes, and a backup taken seconds ago may not be
+ costed yet. Zero on a plan without backups.
+ storage_bytes:
+ type: integer
+ format: int64
+ description: Total storage used in bytes (data + WAL)
+ data_written_bytes:
+ type: integer
+ format: int64
+ description: Total data written in bytes
+ data_transfer_bytes:
type: integer
+ format: int64
+ description: Total data transferred in bytes
+ compute_time_seconds:
+ type: number
+ format: double
+ description: Total CPU seconds consumed
+ active_time_seconds:
+ type: number
+ format: double
+ description: Total active compute time in seconds
+ time_range:
+ type: string
+ description: Time range of the metrics (e.g., "2024-01-01T00:00:00Z to 2024-01-02T00:00:00Z")
+ granularity:
+ type: string
enum:
- - 1
- colors:
- $ref: '#/components/schemas/AuthPageThemeColors'
- font:
- $ref: '#/components/schemas/AuthPageFont'
- scale:
- $ref: '#/components/schemas/AuthPageScale'
- density:
- $ref: '#/components/schemas/AuthPageDensity'
- radius:
- $ref: '#/components/schemas/AuthPageRadius'
- AuthHostedPageResponse:
+ - hourly
+ - daily
+ - monthly
+ description: Granularity of the aggregated metrics
+ required:
+ - current_storage_bytes
+ - current_storage_mb
+ - backup_storage_bytes
+ - storage_bytes
+ - data_written_bytes
+ - data_transfer_bytes
+ - compute_time_seconds
+ - active_time_seconds
+ DatabaseQueryPerformanceResponse:
type: object
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/DatabaseQueryPerformanceItem'
required:
- - page
- - defaults
- - runtime
+ - data
+ UpdateDatabaseBranchRequest:
+ type: object
+ description: Replace the branch's lifetime and restart its countdown from now.
properties:
- page:
- allOf:
- - $ref: '#/components/schemas/AuthHostedPage'
- nullable: true
- description: The saved page, or null when the project has not customized this page type yet.
- defaults:
- $ref: '#/components/schemas/AuthHostedPageDefaults'
- runtime:
- $ref: '#/components/schemas/AuthHostedPageRuntime'
- AuthIdentity:
+ ttl_seconds:
+ type: integer
+ format: int64
+ minimum: 3600
+ maximum: 2592000
+ description: The new lifetime, between one hour and 30 days.
+ example: 86400
+ required:
+ - ttl_seconds
+ DeviceAuthorizationResponse:
type: object
- description: |
- A real email identity owned by the account. One account can own multiple
- identities (for example a work email plus a personal email linked via OAuth).
properties:
- id:
+ device_code:
type: string
- format: uuid
- description: Unique identity identifier
- email:
+ user_code:
type: string
- format: email
- description: The email address this identity represents
- email_verified:
- type: boolean
- description: Whether ownership of this email has been verified
- is_primary:
- type: boolean
- description: Whether the account's primary sign-in method resolves to this identity
- created_at:
+ verification_uri:
type: string
- format: date-time
+ description: |
+ Browser verification URL. Points at the project's managed device
+ approval page served by this API:
+ `/projects/{projectId}/auth/hosted?action=device&anon_key=...`.
+ Requires the project to have managed auth enabled and a default anon
+ key. A custom CLI may ignore this and direct users to its own
+ RFC 8628-compatible page instead (see the device-auth guide).
+ verification_uri_complete:
+ type: string
+ description: |
+ Same as `verification_uri` but with the `user_code` prefilled
+ (`&user_code=...`). This is the URL most device clients open.
+ expires_in:
+ type: integer
+ interval:
+ type: integer
required:
- - id
- - email
- - email_verified
- - is_primary
- - created_at
- AuthIdentitiesResponse:
+ - device_code
+ - user_code
+ - verification_uri
+ - verification_uri_complete
+ - expires_in
+ - interval
+ DefaultEmailTemplate:
type: object
+ description: Built-in email template used when no custom template applies.
properties:
- identities:
- type: array
- items:
- $ref: '#/components/schemas/AuthIdentity'
+ type:
+ type: string
+ enum:
+ - welcome
+ - confirmation
+ - password_reset
+ - password_changed
+ x-enum-varnames:
+ - DefaultEmailTemplateWelcome
+ - DefaultEmailTemplateConfirmation
+ - DefaultEmailTemplatePasswordReset
+ - DefaultEmailTemplatePasswordChanged
+ subject:
+ type: string
+ html_body:
+ type: string
+ description: HTML template with placeholders
+ text_body:
+ type: string
+ description: Plain text template with placeholders
required:
- - identities
- AuthMethodSummary:
+ - type
+ - subject
+ - html_body
+ - text_body
+ EmailTemplate:
type: object
- description: |
- A single sign-in method the account owns (password, an OAuth provider, or an
- active anonymous method). `is_primary` reflects the account's primary_method_id.
+ description: Custom email template
properties:
id:
type: string
format: uuid
- description: Unique method identifier
- type:
+ project_id:
type: string
- x-go-type: string
- description: The kind of sign-in method
- enum:
- - password
- - oauth
- - anonymous
- provider:
+ format: uuid
+ template_type:
type: string
- description: OAuth provider name; present only when type is oauth
- example: google
- identity_id:
+ enum:
+ - welcome
+ - confirmation
+ - password_reset
+ - password_changed
+ subject:
type: string
- description: |
- The identity this method signs in to — a UUID for password/oauth methods,
- empty for anonymous methods.
- email:
+ example: Confirm your email address
+ html_body:
type: string
- description: The email of the method's identity (empty for anonymous)
- is_primary:
- type: boolean
- description: Whether this is the account's primary sign-in method
- last_used_at:
+ description: HTML template with placeholders
+ text_body:
type: string
- format: date-time
- description: When this method was last used to sign in, if ever
+ description: Plain text template with placeholders
created_at:
type: string
format: date-time
@@ -18381,119 +26569,58 @@ components:
type: string
format: date-time
required:
- - id
- - type
- - identity_id
- - email
- - is_primary
- - created_at
- - updated_at
- AuthMethodsResponse:
+ - template_type
+ Error:
type: object
properties:
- methods:
- type: array
- items:
- $ref: '#/components/schemas/AuthMethodSummary'
+ error:
+ type: string
+ code:
+ type: string
+ description: 'Stable machine-readable error code when a specific recovery path is available. `plan_required` (403) means the project owner''s plan does not include the requested feature or option; upgrading the plan unlocks it. `person_required` (403) means a project access token tried to change LavaFlow settings, which only the project''s owner changes, with a platform token, or that the change needs the owner''s own credential that expires, a project repository, and an owner whose GitHub account can push to it; `error` says which. A 403 without a code leaves the reason unspecified: it can be an access refusal, a reached limit, or a plan check that could not read the owner''s plan. Match on the code, not the message text.'
required:
- - methods
- AuthPasswordPolicy:
- type: object
- additionalProperties: false
- description: Effective backend-enforced password policy.
- properties:
- effective_min_length:
- type: integer
- minimum: 15
- maximum: 128
- description: Effective minimum password length in Unicode characters.
- min_configurable_length:
- type: integer
- minimum: 15
- maximum: 15
- description: Lowest minimum password length accepted by the auth configuration endpoint.
- max_length:
- type: integer
- minimum: 128
- maximum: 128
- description: Maximum password length in Unicode characters.
- require_uppercase:
- type: boolean
- description: Whether passwords must contain an ASCII uppercase letter (A-Z).
- require_lowercase:
- type: boolean
- description: Whether passwords must contain an ASCII lowercase letter (a-z).
- require_numbers:
- type: boolean
- description: Whether passwords must contain an ASCII digit (0-9).
- require_special_chars:
- type: boolean
- description: Whether passwords must contain one of the backend-supported special characters.
- compromised_passwords_rejected:
- type: boolean
- description: Whether common and known-compromised passwords are rejected by the backend.
+ - error
+ ImportProvider:
+ type: string
+ enum:
+ - vercel
+ default: vercel
+ x-enum-varnames:
+ - ImportProviderVercel
+ ImportConnectStartResponse:
+ type: object
+ properties:
+ authorization_url:
+ type: string
required:
- - effective_min_length
- - min_configurable_length
- - max_length
- - require_uppercase
- - require_lowercase
- - require_numbers
- - require_special_chars
- - compromised_passwords_rejected
- AuthSession:
+ - authorization_url
+ ImportConnection:
type: object
- description: An authentication session for a user
properties:
id:
type: string
format: uuid
- description: Unique session identifier
- user_id:
- type: string
- format: uuid
- description: The user this session belongs to
provider:
+ $ref: '#/components/schemas/ImportProvider'
+ account_id:
type: string
- description: Authentication provider used to create this session
- enum:
- - email
- - google
- - github
- - microsoft
- - apple
- - anonymous
- example: email
- user_agent:
+ account_name:
type: string
- description: Browser/device user agent string
- example: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
- ip_address:
+ configuration_id:
type: string
- description: IP address of the client when the session was created
- example: 192.168.1.1
- last_ip_address:
+ granted_scopes:
+ type: array
+ items:
+ type: string
+ status:
type: string
- description: IP address of the most recent activity (token refresh)
- example: 192.168.1.100
expires_at:
type: string
format: date-time
- description: When this session expires
- last_activity_at:
- type: string
- format: date-time
- description: Last activity timestamp
- session_started_at:
+ nullable: true
+ last_authenticated_at:
type: string
format: date-time
- description: When the session was created
- is_active:
- type: boolean
- description: Whether the session is currently active (not expired)
- is_current:
- type: boolean
- description: Whether this is the session making the current request
created_at:
type: string
format: date-time
@@ -18502,96 +26629,209 @@ components:
format: date-time
required:
- id
- - user_id
- provider
- - expires_at
- - is_active
- - is_current
- AuthSignupResponse:
+ - account_id
+ - account_name
+ - configuration_id
+ - granted_scopes
+ - status
+ - last_authenticated_at
+ - created_at
+ - updated_at
+ ImportConnectionsResponse:
type: object
- description: |
- Uniform, session-less response returned by POST /auth/signup. It carries no
- tokens and no user object, and is identical for a new account and for an
- already-registered email (anti-enumeration). Clients obtain a session with a
- subsequent POST /auth/signin.
properties:
- confirmation_required:
- type: boolean
- description: |
- Whether the project requires email confirmation. Reflects project config
- only (identical for a new and an existing email), so it leaks nothing about
- account existence.
- message:
+ connections:
+ type: array
+ items:
+ $ref: '#/components/schemas/ImportConnection'
+ required:
+ - connections
+ ImportSource:
+ type: object
+ properties:
+ id:
+ type: string
+ name:
+ type: string
+ account_id:
+ type: string
+ framework:
type: string
- description: Human-readable acknowledgement.
required:
- - confirmation_required
- - message
- AuthTokenResponse:
+ - id
+ - name
+ - account_id
+ - framework
+ ImportSourcesResponse:
type: object
properties:
- access_token:
+ sources:
+ type: array
+ items:
+ $ref: '#/components/schemas/ImportSource'
+ required:
+ - sources
+ ProjectImportTarget:
+ type: string
+ enum:
+ - production
+ x-enum-varnames:
+ - ProjectImportTargetProduction
+ ProjectImportDestinationMode:
+ type: string
+ enum:
+ - create
+ x-enum-varnames:
+ - ProjectImportDestinationCreate
+ ProjectImportDisposition:
+ type: string
+ enum:
+ - automatic
+ - manual
+ - deferred
+ - unsupported
+ x-enum-varnames:
+ - ProjectImportDispositionAutomatic
+ - ProjectImportDispositionManual
+ - ProjectImportDispositionDeferred
+ - ProjectImportDispositionUnsupported
+ ProjectImportImpact:
+ type: string
+ enum:
+ - none
+ - warning
+ - blocking
+ x-enum-varnames:
+ - ProjectImportImpactNone
+ - ProjectImportImpactWarning
+ - ProjectImportImpactBlocking
+ ProjectImportReadiness:
+ type: string
+ enum:
+ - importable
+ - needs_input
+ - blocked
+ x-enum-varnames:
+ - ProjectImportReadinessImportable
+ - ProjectImportReadinessNeedsInput
+ - ProjectImportReadinessBlocked
+ ProjectImportActionCode:
+ type: string
+ enum:
+ - project.create
+ - git.connect
+ - frontend.configure
+ - variable.set
+ x-enum-varnames:
+ - ProjectImportActionProjectCreate
+ - ProjectImportActionGitConnect
+ - ProjectImportActionFrontendConfigure
+ - ProjectImportActionVariableSet
+ ProjectImportResourceKind:
+ type: string
+ enum:
+ - project
+ - git_repository
+ - frontend
+ - variable
+ - domain
+ x-enum-varnames:
+ - ProjectImportResourceProject
+ - ProjectImportResourceGitRepository
+ - ProjectImportResourceFrontend
+ - ProjectImportResourceVariable
+ - ProjectImportResourceDomain
+ ProjectImportPreflightRequest:
+ type: object
+ properties:
+ connection_id:
type: string
- description: JWT access token (expires after configured lifetime)
- token_type:
+ format: uuid
+ source_id:
type: string
- example: bearer
- expires_in:
- type: integer
- description: Access token lifetime in seconds
- refresh_token:
+ minLength: 1
+ project_name:
type: string
- x-go-type-skip-optional-pointer: true
- description: |
- Long-lived token for getting new access tokens. Omitted when the
- request uses eligible HttpOnly cookie session storage.
- user:
- $ref: '#/components/schemas/AuthUser'
+ maxLength: 255
+ pattern: ^[A-Za-z0-9_-]+$
+ target:
+ $ref: '#/components/schemas/ProjectImportTarget'
+ confirm_environment_variable_read:
+ type: boolean
+ default: false
+ description: Set to true only after the user confirms an immediately preceding disclosure that the Vercel Integration grant permits reads and writes, while this preflight reads production variable values only. When false or omitted, preflight reads variable metadata only and reports readable values as manual input.
required:
- - access_token
- - token_type
- - expires_in
- - user
- AuthUser:
+ - connection_id
+ - source_id
+ - project_name
+ - target
+ ProjectImportStartRequest:
+ type: object
+ properties:
+ connection_id:
+ type: string
+ format: uuid
+ source_id:
+ type: string
+ minLength: 1
+ maxLength: 255
+ project_name:
+ type: string
+ maxLength: 255
+ pattern: ^[A-Za-z0-9_-]+$
+ target:
+ $ref: '#/components/schemas/ProjectImportTarget'
+ confirm_environment_variable_read:
+ type: boolean
+ enum:
+ - true
+ preflight_fingerprint:
+ type: string
+ pattern: ^sha256:[0-9a-f]{64}$
+ required:
+ - connection_id
+ - source_id
+ - project_name
+ - target
+ - confirm_environment_variable_read
+ - preflight_fingerprint
+ ProjectImportRunStatus:
+ type: string
+ enum:
+ - pending
+ - running
+ - succeeded
+ - failed
+ - superseded
+ x-enum-varnames:
+ - ProjectImportRunStatusPending
+ - ProjectImportRunStatusRunning
+ - ProjectImportRunStatusSucceeded
+ - ProjectImportRunStatusFailed
+ - ProjectImportRunStatusSuperseded
+ ProjectImportRun:
type: object
properties:
id:
type: string
- format: uuid
- project_id:
- type: string
- format: uuid
- email:
+ provider:
+ $ref: '#/components/schemas/ImportProvider'
+ source_id:
type: string
- format: email
- email_confirmed:
- type: boolean
- user_metadata:
- type: object
- additionalProperties: true
- description: User-editable metadata
- app_metadata:
- type: object
- additionalProperties: true
- description: Application-controlled metadata (read-only for users)
- avatar_url:
+ destination_project_name:
type: string
- format: uri
- description: User avatar URL (from OAuth provider or manually set)
+ resource:
+ $ref: '#/components/schemas/ResourceReference'
+ deployment:
+ $ref: '#/components/schemas/DeploymentReference'
status:
+ $ref: '#/components/schemas/ProjectImportRunStatus'
+ error_code:
type: string
- enum:
- - active
- - banned
- - deleted
- banned_until:
- type: string
- format: date-time
- nullable: true
- description: When temporary ban expires (null if not banned or permanent)
- last_sign_in_at:
+ description: 'Set when `status` is `failed`: `import.deployment_skipped` when the import''s deployment was skipped, otherwise the error code of the Git deployment run the import started (see `GitDeploymentRunError.code`), such as `source_invalid`, `deploy_refused`, `child_deploy_failed`, `child_deploy_not_started`, or `deploy_failed`. Treat a code you do not know as a failure.'
+ error_message:
type: string
- format: date-time
created_at:
type: string
format: date-time
@@ -18600,464 +26840,541 @@ components:
format: date-time
required:
- id
- - email
+ - provider
+ - source_id
+ - destination_project_name
+ - resource
+ - deployment
- status
- BanUserResponse:
+ - created_at
+ - updated_at
+ ProjectImportDestination:
type: object
- description: Response when banning a user
properties:
- message:
- type: string
- example: User banned until 2026-12-31T23:59:59Z
- user_id:
- type: string
- format: uuid
- email:
- type: string
- format: email
- status:
- type: string
- enum:
- - banned
- banned_until:
+ mode:
+ $ref: '#/components/schemas/ProjectImportDestinationMode'
+ project_name:
type: string
- format: date-time
- nullable: true
- description: When the ban expires (null for permanent ban)
+ target:
+ $ref: '#/components/schemas/ProjectImportTarget'
required:
- - message
- - user_id
- - email
- - status
- BatchFunctionDeployFailure:
+ - mode
+ - project_name
+ - target
+ ProjectImportResource:
type: object
properties:
+ kind:
+ $ref: '#/components/schemas/ProjectImportResourceKind'
name:
type: string
- function_id:
- type: string
- format: uuid
- operation:
+ source_id:
type: string
- enum:
- - deploy
- - update
- error:
+ minLength: 1
+ description: Stable provider identifier for a scoped source resource.
+ scope:
type: string
+ minLength: 1
+ description: URL-encoded source scope, including target, branch, and custom environment identifiers.
required:
+ - kind
- name
- - error
- BatchFunctionDeployResponse:
+ ProjectImportAction:
type: object
properties:
- batch_id:
- type: string
- format: uuid
- data:
- type: array
- description: Functions whose deployment workflows were started successfully
- items:
- $ref: '#/components/schemas/Function'
- failed:
- type: array
- description: Functions that failed before their workflow started. Successful functions are left running; failed new functions are deleted and failed updates are rolled back where possible.
- items:
- $ref: '#/components/schemas/BatchFunctionDeployFailure'
+ code:
+ $ref: '#/components/schemas/ProjectImportActionCode'
+ resource:
+ $ref: '#/components/schemas/ProjectImportResource'
+ disposition:
+ $ref: '#/components/schemas/ProjectImportDisposition'
required:
- - batch_id
- - data
- CompleteUploadSessionResponse:
- type: object
- description: Response when completing an upload
- properties:
- object:
- $ref: '#/components/schemas/StorageObject'
- CreateDatabaseBackupRequest:
+ - code
+ - resource
+ - disposition
+ ProjectImportFinding:
type: object
properties:
- name:
+ code:
+ type: string
+ pattern: ^(vercel|volcano|import)\.[a-z0-9_]+$
+ resource:
+ $ref: '#/components/schemas/ProjectImportResource'
+ disposition:
+ $ref: '#/components/schemas/ProjectImportDisposition'
+ impact:
+ $ref: '#/components/schemas/ProjectImportImpact'
+ message:
+ type: string
+ remediation:
type: string
- description: |
- Backup name, unique within the database. Names beginning with
- `volcano-` are reserved for the platform's own snapshots.
- pattern: ^[a-z0-9][a-z0-9_-]{0,62}$
- maxLength: 63
- example: before_migration
required:
- - name
- CreateDatabaseBranchRequest:
+ - code
+ - resource
+ - disposition
+ - impact
+ - message
+ - remediation
+ ProjectImportSummary:
type: object
properties:
- name:
- type: string
- description: Branch name (must be unique within the parent database)
- pattern: ^[a-z0-9_]+$
- maxLength: 64
- example: feature_checkout
- ttl_seconds:
+ automatic:
type: integer
- format: int64
- minimum: 3600
- maximum: 2592000
- description: |
- How long the branch should live, between one hour and 30 days.
- Defaults to 7 days when omitted.
- example: 86400
+ minimum: 0
+ manual:
+ type: integer
+ minimum: 0
+ deferred:
+ type: integer
+ minimum: 0
+ unsupported:
+ type: integer
+ minimum: 0
+ warnings:
+ type: integer
+ minimum: 0
+ blocking:
+ type: integer
+ minimum: 0
required:
- - name
- CreateDatabaseRestoreRequest:
+ - automatic
+ - manual
+ - deferred
+ - unsupported
+ - warnings
+ - blocking
+ ProjectImportReport:
type: object
- description: |
- Names what to restore. Supply exactly one of `backup_name` or
- `restore_to`.
properties:
- backup_name:
+ schema_version:
type: string
- minLength: 1
- maxLength: 128
- description: |
- A backup of this database to restore, exactly as returned by the list
- endpoint.
-
- Deliberately looser than the names you can create, like the backup
- path parameter: a backup made by a schedule is named for you, so
- restoring one accepts any name a backup can have.
- example: before_migration
- restore_to:
+ provider:
+ $ref: '#/components/schemas/ImportProvider'
+ source:
+ $ref: '#/components/schemas/ImportSource'
+ destination:
+ $ref: '#/components/schemas/ProjectImportDestination'
+ actions:
+ type: array
+ items:
+ $ref: '#/components/schemas/ProjectImportAction'
+ findings:
+ type: array
+ items:
+ $ref: '#/components/schemas/ProjectImportFinding'
+ summary:
+ $ref: '#/components/schemas/ProjectImportSummary'
+ readiness:
+ $ref: '#/components/schemas/ProjectImportReadiness'
+ source_fingerprint:
+ type: string
+ capability_fingerprint:
+ type: string
+ fingerprint:
+ type: string
+ generated_at:
type: string
format: date-time
- description: |
- A point in time to restore to, which must fall inside the
- `restore_window` reported when listing backups.
- example: '2026-01-15T09:30:00Z'
- CreateDatabaseRequest:
+ required:
+ - schema_version
+ - provider
+ - source
+ - destination
+ - actions
+ - findings
+ - summary
+ - readiness
+ - source_fingerprint
+ - capability_fingerprint
+ - fingerprint
+ - generated_at
+ GitConnection:
type: object
- description: |
- Create a new PostgreSQL database. Volcano automatically sets up:
- - Auth helpers (auth.uid(), auth.email(), auth.role())
- - Database roles (anon for unauthenticated, authenticated for signed-in users)
- - Secure multi-tenant isolation
- - Ready for Row-Level Security
properties:
- name:
+ id:
type: string
- description: Database name (must be unique within project)
- pattern: ^[a-z0-9_]+$
- maxLength: 64
- example: my_database
- region:
+ format: uuid
+ provider:
type: string
- description: |
- Region for database hosting, such as `us-east-1`. The accepted values
- are the regions this environment runs in, so read them from
- `GET /databases/regions` rather than hardcoding a list. A region the
- environment does not offer is rejected with 400. Region IDs issued by
- earlier versions of the API are still accepted.
- example: us-east-1
- pg_version:
+ provider_user_id:
type: string
- description: |
- PostgreSQL major version. `GET /databases/postgres-versions` lists
- the versions this environment accepts; local mode accepts only the
- version its server runs. Any other value is rejected with 400.
- example: '18'
- enum:
- - '16'
- - '17'
- - '18'
- database_type:
+ provider_login:
type: string
- description: |
- Compute size tier (optional, defaults to volcano-db-xs).
- Determines autoscaling limits for the database.
- enum:
- - volcano-db-xs
- - volcano-db-s
- - volcano-db-m
- - volcano-db-l
- - volcano-db-xl
- - volcano-db-2xl
- default: volcano-db-xs
- example: volcano-db-xs
- required:
- - name
- - region
- - pg_version
- CreateEmailTemplateRequest:
- type: object
- properties:
- template_type:
+ status:
type: string
- enum:
- - welcome
- - confirmation
- - password_reset
- - password_changed
- description: Type of email template
- subject:
+ last_authenticated_at:
type: string
- description: Email subject line
- example: Confirm your email
- html_body:
+ format: date-time
+ created_at:
type: string
- description: |
- HTML template body. Available placeholders:
- - {{.Token}} - The confirmation/reset token
- - {{.ProjectName}} - The project name
- - {{.Email}} - User's email address
- text_body:
+ format: date-time
+ updated_at:
type: string
- description: Plain text template body (same placeholders as HTML)
+ format: date-time
required:
- - template_type
- - subject
- - html_body
- - text_body
- CreateFrontendCustomDomainRequest:
+ - id
+ - provider
+ - provider_user_id
+ - provider_login
+ - status
+ - last_authenticated_at
+ - created_at
+ - updated_at
+ SlackTeamId:
+ type: string
+ description: A Slack workspace ID, such as `T0123ABCD`.
+ pattern: ^T[A-Z0-9]{2,31}$
+ SlackChannelId:
+ type: string
+ description: A Slack channel ID, such as `C0123ABCD`.
+ pattern: ^[CG][A-Z0-9]{2,31}$
+ SlackAuthorizationResponse:
type: object
- additionalProperties: false
properties:
- domain:
+ authorization_url:
type: string
- maxLength: 253
- description: 'Fully-qualified domain name (hostname only, no scheme/path). Managed TLS (`tls.mode: managed`) accepts at most 219 characters; BYOC accepts 253.'
- example: app.example.com
- tls:
- $ref: '#/components/schemas/FrontendCustomDomainTLSConfig'
+ description: The Slack page to send the browser to.
required:
- - domain
- - tls
- CreateFunctionSchedulerRequest:
+ - authorization_url
+ SlackConnection:
type: object
- required:
- - name
- - schedule
+ description: A Slack identity connected to the caller's Volcano account.
properties:
- name:
+ id:
type: string
- maxLength: 200
- enabled:
+ format: uuid
+ team_id:
+ $ref: '#/components/schemas/SlackTeamId'
+ team_name:
+ type: string
+ description: The workspace's name, or empty until the Volcano app is installed in it.
+ slack_user_id:
+ type: string
+ description: The Slack user ID Slack verified.
+ installed:
type: boolean
- default: true
- schedule:
- $ref: '#/components/schemas/ScheduleRequest'
- payload:
- type: object
- additionalProperties: true
- regions:
+ description: Whether the Volcano app is installed in the workspace.
+ created_at:
+ type: string
+ format: date-time
+ required:
+ - id
+ - team_id
+ - team_name
+ - slack_user_id
+ - installed
+ - created_at
+ SlackConnectionsResponse:
+ type: object
+ properties:
+ connections:
type: array
- description: Optional single explicit deployed region. If omitted, the scheduler chooses one deployed region and invokes according to the cron expression.
- maxItems: 1
items:
- type: string
- CreateOAuthConfigRequest:
- type: object
+ $ref: '#/components/schemas/SlackConnection'
required:
- - provider
+ - connections
+ SlackChannel:
+ type: object
properties:
- provider:
- type: string
- enum:
- - google
- - github
- - microsoft
- - apple
- - device
- example: google
- client_id:
- type: string
- example: 123456789.apps.googleusercontent.com
- description: Required for non-device providers. Must not be provided for `provider=device`; server always auto-generates it.
- client_secret:
- type: string
- example: GOCSPX-abc123def456
- description: Required for non-device providers. Must not be provided for `provider=device`; server always auto-generates it.
- redirect_url:
+ id:
+ $ref: '#/components/schemas/SlackChannelId'
+ name:
type: string
- description: Required for non-device providers. Not used for `provider=device`.
- format: uri
- example: https://yourapp.com/auth/callback
- scopes:
+ is_private:
+ type: boolean
+ required:
+ - id
+ - name
+ - is_private
+ SlackChannelsResponse:
+ type: object
+ properties:
+ channels:
type: array
items:
- type: string
- example:
- - openid
- - email
- - profile
- description: Optional for non-device providers, uses provider defaults if omitted. Not used for `provider=device`.
- CreateProjectRequest:
+ $ref: '#/components/schemas/SlackChannel'
+ required:
+ - channels
+ ConnectorType:
+ type: string
+ description: The outside service a connector links to.
+ enum:
+ - slack
+ Connector:
type: object
- description: Request to create a new project
+ description: A link from Volcano to an outside service. A `slack` connector is a Slack workspace the Volcano app is installed in, shared by every Volcano account with a Slack identity connected there.
properties:
- name:
- type: string
- description: |
- Project name (must be unique).
- Can only contain letters, numbers, underscores, and hyphens.
- pattern: ^[A-Za-z0-9_-]+$
- minLength: 1
- maxLength: 255
- example: my-awesome-app
- template_id:
+ id:
type: string
- description: Optional trusted starter template identifier. The server resolves immutable source and database initialization artifacts. Callers cannot supply artifact locations or database credentials. Creation accepts an asynchronous installation; poll the individual project until template_installation.status is ready before using the app. Use pixel-board, trellini, or collab-pad for the configured starter bundles. The official-starter legacy identifier has environment-specific availability. Cannot be combined with initialPrompt.
- enum:
- - pixel-board
- - trellini
- - collab-pad
- - official-starter
- example: pixel-board
- initialPrompt:
+ format: uuid
+ type:
+ $ref: '#/components/schemas/ConnectorType'
+ name:
type: string
- description: Optional initial builder prompt. Cannot be combined with template_id.
- all_regions:
+ description: The connector's name in its service, such as the Slack workspace's name.
+ slack:
+ $ref: '#/components/schemas/SlackConnector'
+ removable:
type: boolean
- description: |
- Optional region policy.
- - `true` (default): project functions deploy to all configured regions
- - `false`: project deploys only to `selected_regions`
- default: true
- selected_regions:
- type: array
- items:
- type: string
- description: |
- Optional region subset. Requires `all_regions=false`.
- Region names must be a subset of platform `AWS_REGIONS`.
- example:
- - us-east-1
- - us-west-2
+ description: Whether the caller can remove the connector. Only the person who installed the Volcano app in a Slack workspace can.
+ created_at:
+ type: string
+ format: date-time
required:
+ - id
+ - type
- name
- CreateStorageBucketRequest:
+ - removable
+ - created_at
+ SlackConnector:
+ type: object
+ description: A `slack` connector's workspace. Present when `type` is `slack`.
+ properties:
+ team_id:
+ $ref: '#/components/schemas/SlackTeamId'
+ required:
+ - team_id
+ ConnectorsResponse:
type: object
properties:
- name:
- type: string
- description: Bucket name (alphanumeric, dashes, underscores)
- pattern: ^[a-zA-Z0-9_-]+$
- minLength: 1
- maxLength: 64
- file_size_limit:
- type: integer
- format: int64
- description: Maximum file size in bytes
- allowed_mime_types:
+ connectors:
type: array
items:
- type: string
- description: Allowed MIME types (e.g., ["image/png", "image/jpeg"])
+ $ref: '#/components/schemas/Connector'
required:
- - name
- CreateStoragePolicyRequest:
+ - connectors
+ LavaflowConnectorBinding:
type: object
+ description: A place in a connector, such as a Slack channel, that reports problems to LavaFlow for a project.
properties:
- name:
+ id:
type: string
- description: Policy name
- operation:
+ format: uuid
+ description: The binding's ID, which removing it takes.
+ project_id:
type: string
- enum:
- - SELECT
- - INSERT
- - UPDATE
- - DELETE
- description: Operation this policy applies to
- definition:
+ format: uuid
+ connector_type:
+ $ref: '#/components/schemas/ConnectorType'
+ connector_id:
type: string
- description: Policy expression
+ format: uuid
+ description: The connector the binding reports through. Omitted while the Volcano app is not installed in the binding's Slack workspace; the binding reports again once it is.
+ slack:
+ $ref: '#/components/schemas/LavaflowSlackBinding'
+ created_at:
+ type: string
+ format: date-time
required:
- - name
- - operation
- - definition
- CreateUploadSessionRequest:
+ - id
+ - project_id
+ - connector_type
+ - created_at
+ LavaflowSlackBinding:
type: object
- description: Request to create a resumable upload session
+ description: The Slack channel a binding reports from. Present when `connector_type` is `slack`.
properties:
- object_path:
+ team_id:
+ $ref: '#/components/schemas/SlackTeamId'
+ team_name:
type: string
- description: Target file path within the bucket
- example: videos/large-file.mp4
- content_type:
+ description: The workspace's name, or empty while the Volcano app is not installed in it.
+ channel_id:
+ $ref: '#/components/schemas/SlackChannelId'
+ required:
+ - team_id
+ - team_name
+ - channel_id
+ LavaflowConnectorBindingsResponse:
+ type: object
+ properties:
+ bindings:
+ type: array
+ items:
+ $ref: '#/components/schemas/LavaflowConnectorBinding'
+ required:
+ - bindings
+ LavaflowConnectorBindingCreate:
+ type: object
+ additionalProperties: false
+ properties:
+ project_id:
type: string
- description: MIME type of the file
- example: video/mp4
- total_size:
- type: integer
- format: int64
- description: Total file size in bytes (max 5TB)
- minimum: 1
- maximum: 5497558138880
- example: 5368709120
- part_size:
- type: integer
- format: int64
- description: 'Part size in bytes (default: 25MB, min: 5MB, max: 25MB)'
- minimum: 5242880
- maximum: 26214400
- example: 26214400
+ format: uuid
+ description: The project the place reports for.
+ connector_id:
+ type: string
+ format: uuid
+ description: The connector to bind, from `GET /connectors`.
+ slack:
+ $ref: '#/components/schemas/LavaflowSlackBindingTarget'
required:
- - object_path
- - content_type
- - total_size
- CreateUploadSessionResponse:
+ - project_id
+ - connector_id
+ - slack
+ LavaflowSlackBindingTarget:
type: object
- description: Response when creating an upload session
+ additionalProperties: false
+ description: The channel to bind, for a `slack` connector.
properties:
- session_id:
+ channel_id:
+ $ref: '#/components/schemas/SlackChannelId'
+ required:
+ - channel_id
+ GitConnectStartResponse:
+ type: object
+ properties:
+ authorization_url:
type: string
- description: Upload session ID
- example: session-abc123
- part_size:
- type: integer
- format: int64
- description: Actual part size to use
- example: 26214400
- total_parts:
- type: integer
- description: Number of parts to upload
- example: 52
- expires_at:
+ required:
+ - authorization_url
+ VerifiedDomain:
+ type: object
+ description: A domain the account owns, along with every name below it.
+ properties:
+ domain:
+ type: string
+ example: example.com
+ verified_at:
type: string
format: date-time
- description: When the session expires (7 days from creation)
- example: '2024-01-22T10:30:00Z'
- CreateVariableRequest:
+ description: When the account last proved ownership.
+ required:
+ - domain
+ - verified_at
+ VerifiedDomainsResponse:
type: object
properties:
- shared:
- type: boolean
- description: Include this name in the project's shared function variables. Omission preserves existing membership; new variables default to true for legacy clients. Send false explicitly to create a non-shared variable.
- name:
+ domains:
+ type: array
+ items:
+ $ref: '#/components/schemas/VerifiedDomain'
+ required:
+ - domains
+ VerifyDomainRequest:
+ type: object
+ properties:
+ domain:
type: string
- description: Project variable name. Function runtime names such as AWS_REGION are reserved and return 400; see the environment variables guide for the full list.
minLength: 1
- maxLength: 256
- pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
- value:
+ maxLength: 253
+ description: The domain to verify, such as `example.com`.
+ required:
+ - domain
+ GitConnectionsResponse:
+ type: object
+ properties:
+ connections:
+ type: array
+ items:
+ $ref: '#/components/schemas/GitConnection'
+ required:
+ - connections
+ GitInstallation:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ account_login:
+ type: string
+ account_type:
+ type: string
+ repository_selection:
type: string
required:
- - name
- - value
- VariableEnvironment:
+ - id
+ - account_login
+ - account_type
+ - repository_selection
+ GitInstallationsResponse:
+ type: object
+ properties:
+ installations:
+ type: array
+ items:
+ $ref: '#/components/schemas/GitInstallation'
+ required:
+ - installations
+ GitRepository:
+ allOf:
+ - $ref: '#/components/schemas/GitRepositoryReference'
+ - type: object
+ properties:
+ default_branch:
+ type: string
+ private:
+ type: boolean
+ is_empty:
+ type: boolean
+ description: Whether the repository has no commits and can receive an initial source export.
+ required:
+ - default_branch
+ - private
+ - is_empty
+ GitRepositoriesResponse:
+ type: object
+ properties:
+ repositories:
+ type: array
+ items:
+ $ref: '#/components/schemas/GitRepository'
+ required:
+ - repositories
+ Share:
type: object
- description: Stable identity for a Project-owned variable Environment.
properties:
id:
type: string
- format: uuid
+ pattern: ^[A-Za-z0-9]{12}$
+ description: The link's public identifier. Its address is `https://volcano.dev/deploy/`.
project_id:
type: string
format: uuid
- name:
+ suggested_name:
type: string
- pattern: ^[A-Za-z0-9_-]{1,64}$
- minLength: 1
- maxLength: 64
- is_global:
+ description: A project name for clients to offer a visitor as the default. The create request still carries its own `name`; Volcano does not fill one in from the link.
+ description:
+ type: string
+ maxLength: 280
+ description: What the project does, in the owner's words, shown to visitors before they deploy. One line of plain text; empty when the owner wrote none.
+ allow_reshare:
type: boolean
- description: Whether this is the reserved Global Environment.
+ description: Whether the projects made from this link, and the projects made from those, may be shared again by their owners. False by default, so a copy of this project cannot create, draft, publish or switch on a deploy link of its own, and its links serve nothing. Read at each request, so switching it off stops copies' links that are already on.
+ status:
+ type: string
+ enum:
+ - active
+ - disabled
+ description: Whether the owner, or Volcano, has the link on. An `active` link can still not serve; see `serving`.
+ serving:
+ type: boolean
+ description: |
+ Whether the link's address serves its current release now: it is
+ `active`, published, and nothing stops it, such as deploy links not being
+ available in this environment, the project being deleted, the owner's
+ account not allowing traffic, or the project being a copy that may no
+ longer be shared. An `active` link that is not serving
+ answers visitors as one switched off, and switching it on again changes
+ nothing until what stops it is resolved.
+ disabled_reason:
+ type: string
+ nullable: true
+ example: owner
+ description: |
+ Why the link is off. Set only while it is disabled. New reasons can be
+ added, so treat an unknown one as disabled. `owner`: its owner switched
+ it off. `operator`: Volcano took it down; its owner cannot switch it back
+ on or delete it (`PATCH` and `DELETE` answer `403` with code
+ `operator_disabled`), but can still edit it. While it is down, its
+ project cannot be shared any more (no new link, draft or publish, and no
+ link switched on), and no project made from it, or from a copy of it, can
+ be shared either.
+ current_release:
+ allOf:
+ - $ref: '#/components/schemas/ShareReleaseRef'
+ nullable: true
+ description: The release visitors are offered. Null until the first publish; until then the link's preview answers `404`.
created_at:
type: string
format: date-time
@@ -19067,1041 +27384,1157 @@ components:
required:
- id
- project_id
- - name
- - is_global
+ - suggested_name
+ - description
+ - allow_reshare
+ - status
+ - serving
+ - current_release
- created_at
- updated_at
- VariableEnvironmentList:
+ ShareReleaseRef:
type: object
properties:
- data:
+ id:
+ type: string
+ format: uuid
+ published_at:
+ type: string
+ format: date-time
+ required:
+ - id
+ - published_at
+ SharesResponse:
+ type: object
+ properties:
+ shares:
type: array
- maxItems: 101
items:
- $ref: '#/components/schemas/VariableEnvironment'
+ $ref: '#/components/schemas/Share'
required:
- - data
- CreateVariableEnvironmentRequest:
+ - shares
+ ShareCreateRequest:
+ type: object
+ additionalProperties: false
+ properties:
+ project_id:
+ type: string
+ format: uuid
+ description: The project to share. A project the caller can't share answers like one that doesn't exist.
+ suggested_name:
+ type: string
+ maxLength: 64
+ pattern: ^[A-Za-z0-9_-]*$
+ description: A project name for clients to offer visitors as the default; the create request still carries its own `name`. It may contain only letters, numbers, underscores and hyphens.
+ description:
+ type: string
+ maxLength: 280
+ description: What the project does, shown to visitors before they deploy. One line of plain text with no control characters; surrounding spaces are trimmed.
+ allow_reshare:
+ type: boolean
+ description: Lets the projects made from this link be shared again by their owners. Defaults to false.
+ required:
+ - project_id
+ ShareUpdateRequest:
+ type: object
+ additionalProperties: false
+ minProperties: 1
+ properties:
+ suggested_name:
+ type: string
+ maxLength: 64
+ pattern: ^[A-Za-z0-9_-]*$
+ description:
+ type: string
+ maxLength: 280
+ description: What the project does, shown to visitors before they deploy. One line of plain text with no control characters; surrounding spaces are trimmed. Send an empty string to remove it.
+ allow_reshare:
+ type: boolean
+ description: Lets the projects made from this link be shared again by their owners. Switching it off stops their copies, and copies of those, from sharing again, read at each request, including links of theirs that are already on.
+ status:
+ type: string
+ enum:
+ - active
+ - disabled
+ ShareReleaseCreateRequest:
type: object
additionalProperties: false
properties:
- name:
+ share_id:
type: string
- description: Leading and trailing ASCII whitespace is trimmed before validating 1–64 ASCII letters, digits, underscores, or hyphens. Global is reserved.
- pattern: ^[ \t\n\f\r]*[A-Za-z0-9_-]{1,64}[ \t\n\f\r]*$
+ pattern: ^[A-Za-z0-9]{12}$
+ description: The share to publish to. Its own project authorizes the publish.
+ draft_id:
+ type: string
+ minLength: 1
+ maxLength: 128
+ description: |
+ The `draft_id` of the draft the owner reviewed. If a fresh build of the
+ project is not that draft, nothing is published and the answer is `409`
+ `draft_changed` with the new draft.
+ variables:
+ type: array
+ maxItems: 100
+ items:
+ type: string
+ minLength: 1
+ maxLength: 256
+ description: |
+ Every name in the draft's `variables`, which a project created from the
+ release gets. Values are never carried: each is created empty unless the
+ visitor gives one.
+ service_key_functions:
+ type: array
+ maxItems: 100
+ items:
+ type: string
+ minLength: 1
+ maxLength: 255
+ description: |
+ The functions that receive the new project's `VOLCANO_SERVICE_KEY`, which
+ bypasses row-level security. Must be exactly the draft's
+ `service_key_functions`.
required:
- - name
- RenameVariableEnvironmentRequest:
+ - share_id
+ - draft_id
+ - variables
+ - service_key_functions
+ ForkCreateRequest:
type: object
additionalProperties: false
properties:
+ share_id:
+ type: string
+ pattern: ^[A-Za-z0-9]{12}$
+ description: The share to fork, the id at the end of its deploy URL.
+ release_id:
+ type: string
+ format: uuid
+ description: The `release.id` the share's preview returned, so only the release the visitor saw is installed.
name:
type: string
- description: Leading and trailing ASCII whitespace is trimmed before validating 1–64 ASCII letters, digits, underscores, or hyphens. Global is reserved.
- pattern: ^[ \t\n\f\r]*[A-Za-z0-9_-]{1,64}[ \t\n\f\r]*$
+ minLength: 1
+ maxLength: 255
+ description: The new project's name, which may contain only letters, numbers, underscores and hyphens. A name you already use gets a short random suffix. An invalid name answers `400` before anything is counted against the share or your hourly fork limit.
+ variables:
+ type: object
+ maxProperties: 100
+ additionalProperties:
+ type: string
+ maxLength: 4096
+ description: |
+ Values for the variables the preview lists, by name. Any may be left out
+ and is then created empty; only listed names are accepted (`422`
+ otherwise). Each value is at most 4096 bytes of UTF-8, since a function's
+ environment is limited in bytes; a longer one, or one containing a NUL
+ character, answers `400`. Values are never logged, and `Idempotency-Key` compares only the names given a value.
required:
+ - share_id
+ - release_id
- name
- Database:
+ ShareReleaseFunction:
type: object
- description: |
- PostgreSQL database with automatic scalability and security features.
properties:
- id:
- type: string
- format: uuid
- project_id:
- type: string
- format: uuid
name:
type: string
- description: Database name
- pattern: ^[a-z0-9_]+$
- maxLength: 64
- status:
+ kind:
type: string
enum:
- - provisioning
- - active
- - failed
- - restoring
- - deleting
- description: |
- Database status. `restoring` means a restore is replacing the
- database's data: it does not accept connections, and the operations
- that would race the restore are rejected until it finishes. Its
- branches keep serving throughout.
- provisioning_started_at:
- type: string
- format: date-time
- description: Timestamp when the current provisioning phase started
- connection_string:
+ - standard
+ - durable
+ visibility:
type: string
- description: |
- Secure PostgreSQL connection URI for your database.
-
- The database is identified by the globally-unique username
- (`volcano_client_{database_id}`) already in this URI; the
- `application_name` parameter only selects the access mode:
- - `volcano_full_access` — Full admin access (DDL, migrations)
- - `volcano_user_access:{user_id}` — User impersonation (RLS enforced)
- - `volcano_user_access` — Anonymous access (anon role, RLS enforced)
- region:
+ description: The function's invocation visibility, as installed.
+ invocation_mode:
type: string
- description: Region where the database is hosted
- example: us-east-1
- pg_version:
+ description: The function's invocation mode, when it is not the default.
+ http_auth_mode:
type: string
- description: PostgreSQL major version
- example: '18'
- database_type:
+ description: |
+ How the function's HTTP invocations authenticate, when its invocation
+ settings are not the default; omitted means `volcano`. `none` lets
+ anyone call the function without a credential in every project made from
+ the release. Releases published before this was recorded omit it.
+ openapi_spec_sha256:
type: string
+ pattern: ^[0-9a-f]{64}$
description: |
- Database size tier that determines available RAM and scaling limits.
+ The SHA-256 of the function's OpenAPI document as the release carries it,
+ when it has one, so a draft shows when the document changed. Releases
+ published before this was recorded omit it.
+ variable_scope:
+ type: string
enum:
- - volcano-db-xs
- - volcano-db-s
- - volcano-db-m
- - volcano-db-l
- - volcano-db-xl
- - volcano-db-2xl
- example: volcano-db-xs
- storage_bytes:
- type: integer
- format: int64
- minimum: 0
+ - scoped
description: |
- Latest observed storage for this database, in bytes: its own on-disk
- size, plus what each branch has diverged from it, plus what its
- backups cost to hold. This is the figure the storage allowance is
- enforced against, and the stats endpoint breaks it down. A
- point-in-time gauge recorded by a background pass, so it may be
- absent until the database has been sampled, and it can trail the
- stats endpoint's `current_storage_bytes`, which measures on request.
- Summing the latest samples for every database in a project produces
- the project's "Database Storage (Bytes)" usage gauge. Populated on
- database list responses; single-database responses omit it.
- last_invoked_at:
- type: string
- format: date-time
- description: Most recent request timestamp for this database
- created_at:
- type: string
- format: date-time
- updated_at:
- type: string
- format: date-time
+ `scoped` when the function receives only the variables it declares, as
+ your project's function does, listed in `variables`. Omitted when it
+ receives every variable shared with functions. The service key is not
+ part of it: `service_key_functions` says which functions receive that.
+ Releases published before this was recorded omit it.
+ variables:
+ type: array
+ items:
+ type: string
+ description: For a `scoped` function, the variables it declares that a project made from the release has.
required:
- - id
- - project_id
- name
- - status
- - created_at
- - updated_at
- DatabaseBackup:
+ - kind
+ ShareReleaseOmission:
type: object
- description: |
- A point-in-time copy of a database, kept by the storage provider and
- restorable in place.
-
- Backups cover the database itself, not its branches. Restoring one
- replaces the database's data and keeps its connection string.
+ description: Something a release does not carry.
properties:
- name:
- type: string
- description: |
- Backup name, unique within the database. Backups you create are
- named by you; scheduled backups are named by the storage provider.
- source:
+ kind:
type: string
enum:
- - manual
- - scheduled
- description: |
- Whether the backup was requested explicitly or produced by the
- backup schedule. Only `manual` backups count against the plan's
- backup allowance.
- size_bytes:
- type: integer
- format: int64
- minimum: 0
- description: |
- Storage the backup occupies. Absent until the provider has costed
- it, which takes a few minutes after the backup is taken; absent is
- not the same as empty.
- expires_at:
+ - no_source
+ - database
+ - sandbox
+ - secret_file
+ - unsupported_entry
+ description: |
+ `no_source`: a function or frontend whose current deployment has no stored
+ source to carry. `database`: a database; a visitor's project starts without
+ one. `sandbox`: a sandbox, which releases do not deploy. `secret_file`: a
+ file that may hold credentials, such as a dotenv or `.envrc` file, a tool's
+ token file like `.netrc` or an `.npmrc` holding a registry credential, a
+ private key, a credential JSON or a Terraform variables file. `unsupported_entry`: a file that is not a regular file,
+ such as a symbolic link.
+ resource:
type: string
- format: date-time
- description: |
- When the backup is deleted automatically, from the plan's retention.
- Absent means it is kept until deleted explicitly.
- created_at:
+ description: The function, frontend, database or sandbox, when there is one.
+ path:
type: string
- format: date-time
- description: The point in time the backup captures.
+ description: The file left out, for a file.
required:
- - name
- - source
- - created_at
- DatabaseBackupList:
+ - kind
+ ShareReleaseDraft:
type: object
properties:
- data:
+ draft_id:
+ type: string
+ description: |
+ Opaque. Names exactly what a release built now would carry: each
+ function's and frontend's current deployment, and everything the draft
+ lists, including each function's settings (`http_auth_mode`,
+ `openapi_spec_sha256`, `variable_scope`), the `variables`, the
+ `frontend_variables` and the `omissions`. It stays the same while those
+ do, and changes when a function or frontend is redeployed or anything the
+ draft lists changes. A sandbox is not part of it, since a release does not
+ carry one: rebuilding only a sandbox leaves it unchanged. Send it with the
+ publish.
+ functions:
type: array
items:
- $ref: '#/components/schemas/DatabaseBackup'
- restore_window:
- $ref: '#/components/schemas/DatabaseRestoreWindow'
- required:
- - data
- DatabaseBackupSchedule:
- type: object
- description: |
- The database's automated backup schedule. An empty list means no
- scheduled backups; sending one clears the schedule.
- properties:
- entries:
+ $ref: '#/components/schemas/ShareReleaseFunction'
+ frontends:
type: array
items:
- $ref: '#/components/schemas/DatabaseBackupScheduleEntry'
+ type: string
+ variables:
+ type: array
+ items:
+ $ref: '#/components/schemas/ShareVariable'
+ description: The project's variables a visitor could be asked to supply. Volcano's own, such as `VOLCANO_API_URL`, are never listed.
+ service_key_functions:
+ type: array
+ items:
+ type: string
+ description: The functions whose code reads `VOLCANO_SERVICE_KEY`. A release gives them the visitor project's service key once the owner confirms them.
+ omissions:
+ type: array
+ items:
+ $ref: '#/components/schemas/ShareReleaseOmission'
+ frontend_variables:
+ type: object
+ additionalProperties:
+ type: array
+ items:
+ type: string
+ description: |
+ The draft's variables each frontend receives, by frontend name, as your
+ project's frontend of that name selects them by its variable scope now.
+ A frontend receives no others.
required:
- - entries
- DatabaseBackupScheduleEntry:
+ - draft_id
+ - functions
+ - frontends
+ - variables
+ - service_key_functions
+ - omissions
+ - frontend_variables
+ ShareDraftChangedError:
type: object
- description: One recurrence of the automated backup schedule.
properties:
- frequency:
+ error:
+ type: string
+ code:
type: string
enum:
- - daily
- - weekly
- - monthly
- hour:
- type: integer
- minimum: 0
- maximum: 23
- description: Hour of the day in UTC.
- day:
- type: integer
- minimum: 1
- maximum: 28
- description: |
- Day of the week (1-7, Monday to Sunday) for a weekly schedule, or day
- of the month (1-28) for a monthly one. Required for both, ignored for
- a daily schedule. Monthly stops at 28 so the schedule fires in every
- month.
- retention_seconds:
- type: integer
- format: int64
- minimum: 3600
- description: |
- How long each backup from this recurrence is kept. Clamped to the
- plan's retention, and defaulted to it when omitted.
+ - draft_changed
+ draft:
+ $ref: '#/components/schemas/ShareReleaseDraft'
required:
- - frequency
- - hour
- DatabaseBranch:
- type: object
- description: |
- A copy-on-write fork of a database, for development and testing.
-
- A branch starts as an exact copy of its parent's data and diverges from
- there. It has its own connection string and its own credential, so a
- branch password cannot reach the parent.
-
- Every branch expires. `expires_at` is a hard deadline: once it passes the
- branch stops accepting connections and is deleted. Use `PATCH` to extend
- a branch you are still working on.
+ - error
+ - code
+ - draft
+ ShareRelease:
+ type: object
properties:
id:
type: string
format: uuid
- database_id:
+ share_id:
type: string
- format: uuid
- description: The parent database this branch was forked from.
+ pattern: ^[A-Za-z0-9]{12}$
project_id:
type: string
format: uuid
- name:
- type: string
- description: Branch name, unique within the parent database.
- pattern: ^[a-z0-9_]+$
- maxLength: 64
- status:
+ published_at:
type: string
- enum:
- - provisioning
- - active
- - failed
- - deleting
- description: |
- Branch status. A new branch starts `provisioning` and is not
- connectable until it reports `active`; poll this endpoint until it
- does. `connection_string` is only present while `active`.
-
- `provisioning` also covers a branch being rebuilt after a `reset`,
- and a build that is between retries, so it is the status to keep
- waiting on. `failed` is terminal: it means the platform gave up, and
- the branch will not become `active` on its own.
- connection_string:
+ format: date-time
+ published_by:
type: string
- description: |
- PostgreSQL connection URI for this branch. Present only while the
- branch is `active`.
-
- The URI carries the branch's own globally-unique username and
- password; `application_name` selects the access mode exactly as it
- does for the parent database:
- - `volcano_full_access` — Full admin access (DDL, migrations)
- - `volcano_user_access:{user_id}` — User impersonation (RLS enforced)
- - `volcano_user_access` — Anonymous access (anon role, RLS enforced)
- ttl_seconds:
- type: integer
- format: int64
- minimum: 1
- description: |
- The lifetime the branch was created with. Resetting a branch re-arms
- this same duration, so a reset never shortens a branch's remaining
- life.
- expires_at:
+ description: The id of the user who published the release.
+ sha256:
type: string
- format: date-time
- description: |
- When the branch stops serving connections and becomes eligible for
- deletion. Enforced on the connection path, so it holds even if
- reclamation is delayed.
- storage_bytes:
+ pattern: ^[0-9a-f]{64}$
+ description: The digest of the stored release archive. An install refuses an archive that does not match it.
+ size_bytes:
type: integer
format: int64
- minimum: 0
- description: |
- Bytes this branch has diverged from its parent, which is what a
- branch actually costs. Shared pages are not counted twice. Counts
- against the parent database's storage allowance. Absent until the
- branch has been sampled.
- last_invoked_at:
- type: string
- format: date-time
- description: Most recent request timestamp for this branch
- created_at:
- type: string
- format: date-time
- updated_at:
- type: string
- format: date-time
+ functions:
+ type: array
+ items:
+ $ref: '#/components/schemas/ShareReleaseFunction'
+ frontends:
+ type: array
+ items:
+ type: string
+ variables:
+ type: array
+ items:
+ $ref: '#/components/schemas/ShareVariable'
+ service_key_functions:
+ type: array
+ items:
+ type: string
+ omissions:
+ type: array
+ items:
+ $ref: '#/components/schemas/ShareReleaseOmission'
required:
- id
- - database_id
+ - share_id
- project_id
- - name
- - status
- - ttl_seconds
- - expires_at
- - created_at
- - updated_at
- DatabaseBranchList:
+ - published_at
+ - published_by
+ - sha256
+ - size_bytes
+ - functions
+ - frontends
+ - variables
+ - service_key_functions
+ - omissions
+ PaginatedShareReleases:
type: object
properties:
data:
type: array
items:
- $ref: '#/components/schemas/DatabaseBranch'
+ $ref: '#/components/schemas/ShareRelease'
+ limit:
+ type: integer
+ description: Number of items per page
+ has_more:
+ type: boolean
+ description: Whether a next page exists
+ next_cursor:
+ type: string
+ description: Opaque cursor for the next page, present if has_more is true. It works only for the same share_id and limit.
required:
- data
- DatabaseBranchStorage:
+ - limit
+ - has_more
+ SharePreview:
type: object
- description: One branch's contribution to its parent database's storage.
properties:
id:
type: string
- format: uuid
- name:
+ pattern: ^[A-Za-z0-9]{12}$
+ suggested_name:
type: string
- description: Branch name
- storage_bytes:
- type: integer
- format: int64
- minimum: 0
- description: |
- Bytes this branch has diverged from its parent. Pages the branch
- still shares with the parent are not counted, so this is what the
- branch actually adds to the total rather than its apparent size.
+ description: A project name the link's owner suggests, for clients to offer as the default. The create request still carries its own `name`; Volcano does not fill one in from the link.
+ description:
+ type: string
+ description: What the project does, in the owner's words. Plain text; empty when the owner wrote none.
+ release:
+ $ref: '#/components/schemas/SharePreviewRelease'
required:
- id
- - name
- - storage_bytes
- DatabaseSelectRequest:
+ - suggested_name
+ - description
+ - release
+ SharePreviewRelease:
type: object
+ description: The release a project created from the link installs.
properties:
- table:
+ id:
type: string
- description: Table name to query
- example: posts
- select:
+ format: uuid
+ description: Send it as `release_id` in `POST /forks` to confirm this release.
+ published_at:
+ type: string
+ format: date-time
+ sha256:
+ type: string
+ pattern: ^[0-9a-f]{64}$
+ description: The digest of the stored release archive.
+ frontends:
type: array
items:
type: string
- description: Columns to select (omit for *)
- example:
- - id
- - title
- - content
- - created_at
- filters:
+ description: Names of the frontends installing the release creates.
+ functions:
type: array
items:
- $ref: '#/components/schemas/DatabaseQueryFilter'
- description: WHERE conditions (combined with AND)
- example:
- - column: status
- operator: eq
- value: published
- - column: views
- operator: gt
- value: 100
- order:
+ type: string
+ description: Names of the functions installing the release creates.
+ service_key_functions:
type: array
items:
- $ref: '#/components/schemas/DatabaseQueryOrder'
- description: ORDER BY clauses
- example:
- - column: created_at
- ascending: false
- limit:
- type: integer
- minimum: 1
- maximum: 1000
- description: Maximum rows to return
- example: 10
- offset:
- type: integer
- minimum: 0
- description: Number of rows to skip (for pagination)
- example: 0
+ type: string
+ description: |
+ Names of the functions that receive the new project's `VOLCANO_SERVICE_KEY`,
+ which bypasses row-level security. Show them to the visitor before they
+ confirm. Empty when no function receives it.
+ variables:
+ type: array
+ items:
+ $ref: '#/components/schemas/ShareVariable'
+ description: |
+ The project variables the new project gets, sorted by name. A visitor may
+ give a value for any of them as `variables` when creating
+ the fork with `POST /forks`; each one left out is created empty, for the visitor to set
+ later. Volcano's own variables, such as `VOLCANO_API_URL`, are never
+ listed: the install sets them.
+ omissions:
+ type: array
+ items:
+ $ref: '#/components/schemas/ShareReleaseOmission'
+ description: What the release does not carry. A `database` entry means the new project starts without that database.
required:
- - table
- DatabaseInsertRequest:
+ - id
+ - published_at
+ - sha256
+ - frontends
+ - functions
+ - service_key_functions
+ - variables
+ - omissions
+ ShareVariable:
type: object
+ description: A project variable a deploy link's release declares. A project created from the link always gets it.
properties:
- table:
+ name:
type: string
- description: Table name
- example: posts
- values:
- type: object
- additionalProperties: true
+ description: The variable's name.
+ required:
+ type: boolean
description: |
- Column values to insert. JSON objects and arrays are stored as JSON,
- so send them to `json` or `jsonb` columns. For a Postgres array
- column, send an array literal string such as `"{a,b}"`.
- example:
- title: My New Post
- content: This is the content
- status: draft
+ Always true: a project created from the link always gets this variable,
+ created empty when the visitor gives no value. It never means a value must
+ be given.
+ secret:
+ type: boolean
+ description: |
+ Whether to treat the value as a secret: take it masked and never show it back. Only a
+ `NEXT_PUBLIC_` name, which a Next.js build copies into the browser, is not secret.
+ unshared:
+ type: boolean
+ description: |
+ True when the source project gives the variable only to the scoped
+ functions that declare it, not to every function, and so does a project
+ made from the release. Omitted when false.
required:
- - table
- - values
- DatabaseUpdateRequest:
+ - name
+ - required
+ - secret
+ ShareKindCount:
type: object
properties:
- table:
+ kind:
type: string
- description: Table name
- example: posts
- values:
- type: object
- additionalProperties: true
- description: |
- Column values to update. JSON objects and arrays are stored as JSON,
- so send them to `json` or `jsonb` columns. For a Postgres array
- column, send an array literal string such as `"{a,b}"`.
- example:
- title: Updated Title
- status: published
- filters:
- type: array
- minItems: 1
- items:
- $ref: '#/components/schemas/DatabaseQueryFilter'
- description: |
- WHERE conditions for which rows to update. At least one filter is
- required; a filterless update is rejected to avoid rewriting every
- row.
- example:
- - column: id
- operator: eq
- value: post-uuid
+ enum:
+ - click
+ - preview
+ - confirm
+ - accepted
+ - ready
+ - failed
+ events:
+ type: integer
+ format: int64
+ visitors:
+ type: integer
+ format: int64
+ description: Unique daily visitors among the events that carried one. A visitor is pseudonymised per day, so one who returns on another day counts again.
required:
- - table
- - values
- - filters
- DatabaseDeleteRequest:
+ - kind
+ - events
+ - visitors
+ ShareDailyCount:
type: object
properties:
- table:
+ day:
type: string
- description: Table name
- example: posts
- filters:
- type: array
- minItems: 1
- items:
- $ref: '#/components/schemas/DatabaseQueryFilter'
- description: WHERE conditions (required for safety)
- example:
- - column: id
- operator: eq
- value: post-uuid
+ format: date
+ description: UTC day.
+ kind:
+ type: string
+ enum:
+ - click
+ - preview
+ - confirm
+ - accepted
+ - ready
+ - failed
+ events:
+ type: integer
+ format: int64
required:
- - table
- - filters
- DatabaseQueryResult:
+ - day
+ - kind
+ - events
+ ShareStats:
type: object
- description: |
- Rows returned by a data API request. RLS-filtered unless the request was
- made with a service key.
properties:
- data:
+ since:
+ type: string
+ format: date-time
+ description: Start of the counted window.
+ totals:
type: array
items:
- type: object
- additionalProperties: true
- description: Result rows
- count:
- type: integer
- description: Number of rows returned
- DatabaseRestore:
+ $ref: '#/components/schemas/ShareKindCount'
+ daily:
+ type: array
+ items:
+ $ref: '#/components/schemas/ShareDailyCount'
+ required:
+ - since
+ - totals
+ - daily
+ ProjectGitConnection:
type: object
- description: |
- A restore of a database, either from a named backup or to a point in
- time. Restores run in the background and take longer than a request, so
- the database is unavailable until this reports `completed`.
properties:
- id:
- type: string
- format: uuid
- database_id:
- type: string
- format: uuid
- project_id:
- type: string
- format: uuid
- kind:
+ repo_installation_id:
+ type: integer
+ format: int64
+ repo_id:
+ type: integer
+ format: int64
+ description: Stable GitHub repository id (repository.id), the authoritative binding.
+ repo_full_name:
type: string
- enum:
- - snapshot
- - point_in_time
- description: |
- Whether the restore targets a named backup or an arbitrary point in
- time. Both replace the database's data in place.
- status:
+ root_directory:
type: string
- enum:
- - pending
- - running
- - completed
- - failed
- - exhausted
- description: |
- Restore status. `pending` and `running` both mean the restore is
- still in flight and the database is not connectable; an attempt that
- fails with tries left goes back to `pending`. `failed` and
- `exhausted` both mean Volcano gave up: the database is left `failed`
- if its data may already have been replaced, and `active` if the
- restore never started — a backup that no longer exists at the
- provider ends the restore without touching the database. A restore
- cannot be cancelled once it starts.
- backup_name:
+ production_branch:
type: string
- description: |
- The backup restored, kept even if that backup is later deleted.
- Absent for a point-in-time restore.
- restore_to:
+ description: The branch a push must land on to deploy. Follows the repository's GitHub default branch unless the project set its own, which a default-branch rename on GitHub then leaves alone.
+ production_branch_follows_default:
+ type: boolean
+ description: True when `production_branch` follows the repository's default branch and moves with a default-branch rename on GitHub. False when the project pinned a branch, even one that matches the current default. Pin a branch with `PUT /projects/{id}/git-connection/production-branch`; send an empty `production_branch` there to follow the default again.
+ updated_at:
type: string
format: date-time
- description: The point in time restored to. Absent for a backup restore.
- error:
+ description: 'When the connection last changed: its repository, root directory or production branch. Naming the branch it already uses, and other changes to the project, leave it alone. A connection that has not changed since Volcano began tracking this reports the project''s last change before then.'
+ required:
+ - repo_installation_id
+ - repo_id
+ - repo_full_name
+ - root_directory
+ - production_branch
+ - production_branch_follows_default
+ - updated_at
+ ProjectGitOwnerPush:
+ type: object
+ description: Whether the project owner can push to the project's connected repository.
+ properties:
+ repository_id:
+ type: integer
+ format: int64
+ description: Stable GitHub repository id of the connected repository, the `repo_id` of the project's git connection.
+ can_push:
+ type: boolean
+ description: True when the project owner's GitHub account can push to the repository.
+ reason:
type: string
- description: Why the most recent attempt failed, when one has.
- completed_at:
+ enum:
+ - owner_not_connected
+ - owner_reconnect_required
+ - repository_access_lost
+ - no_push_permission
+ x-enum-varnames:
+ - ProjectGitOwnerPushReasonOwnerNotConnected
+ - ProjectGitOwnerPushReasonOwnerReconnectRequired
+ - ProjectGitOwnerPushReasonRepositoryAccessLost
+ - ProjectGitOwnerPushReasonNoPushPermission
+ description: 'Why `can_push` is false; absent when it is true. `owner_not_connected`: the owner has not connected a GitHub account. `owner_reconnect_required`: the owner''s GitHub connection expired or was revoked; the owner reconnects GitHub. `repository_access_lost`: the owner''s GitHub account can no longer see the repository. `no_push_permission`: the owner''s GitHub account can read the repository but not push to it.'
+ required:
+ - repository_id
+ - can_push
+ ProjectGitDeploySettings:
+ type: object
+ description: 'A project''s GitHub auto-deploy settings: what a push to the connected repo''s production branch deploys. All settings are default-off.'
+ properties:
+ auto_deploy_enabled:
+ type: boolean
+ description: Whether a production-branch push triggers a deployment.
+ deploy_functions:
+ type: boolean
+ description: Whether the repo's functions are deployed on push.
+ frontend_name:
type: string
- format: date-time
- created_at:
+ description: Name of the frontend to build and deploy on push. Omitted when no frontend is deployed. Resolved at deploy time; need not exist yet.
+ frontend_app_root:
type: string
- format: date-time
+ description: App root (subdirectory) the frontend builds from. Omitted for the repo root.
+ apply_migrations:
+ type: boolean
+ description: Whether a push applies the commit's pending migrations, the SQL files under volcano/migrations, before it deploys anything. Each database gets a migration run with source `git_deploy`; when one fails, nothing from the push deploys and the live version keeps serving. A push starts a migration run only while the project owner's account is `active`; otherwise it starts none, deploys nothing, and fails with code `owner_not_active`. A run an earlier attempt of the push started before the account changed keeps its outcome, but the push still deploys none of its code and fails with `owner_not_active`; its message says the schema changes stay. Nothing retries that push; push again once the account is `active`, and that push skips the migrations already applied. Reads back as saved even where the `databases.migrations` capability is unavailable; there, a push whose commit has migrations deploys nothing.
updated_at:
type: string
format: date-time
+ description: When the settings were last saved, or last changed by connecting a repository. Other changes to the project leave it alone. Settings a connection turned on before Volcano began tracking this report the project's last change before then; settings never saved or changed report when the project was created.
required:
- - id
- - database_id
- - project_id
- - kind
- - status
- - created_at
+ - auto_deploy_enabled
+ - deploy_functions
+ - apply_migrations
- updated_at
- DatabaseRestoreList:
+ UpdateProjectGitDeploySettingsRequest:
type: object
+ description: Full replace of a project's Git auto-deploy settings, except apply_migrations, which keeps its saved value when omitted.
properties:
- data:
- type: array
- items:
- $ref: '#/components/schemas/DatabaseRestore'
+ auto_deploy_enabled:
+ type: boolean
+ deploy_functions:
+ type: boolean
+ frontend_name:
+ type: string
+ description: Legacy frontend to deploy on push. In Git mode, explicitly send an empty string to stop deploying the selected frontend; omit frontend_app_root too. This keeps the serving frontend and Git handover intact. Omitting an existing selection or renaming it is refused in Git mode. In platform mode, omit or empty to deploy no frontend. Explicit source-layout mappings are independent of this legacy selection.
+ frontend_app_root:
+ type: string
+ description: App root the frontend builds from. Requires frontend_name; omit for the repo root.
+ apply_migrations:
+ type: boolean
+ description: Apply the commit's pending migrations before each push deploys. Anyone who can push to the production branch can then run any SQL as the database owner, so protect that branch first. Off until set. Omit to leave the saved value unchanged. Turning it on answers `400` with code `feature_unavailable` where the `databases.migrations` capability is unavailable; `false`, or the saved `true` sent back, is accepted even there. While the project owner's account is `read_only`, the request answers `403` whatever it sends; an `inactive` owner's credentials answer `401`.
required:
- - data
- DatabaseRestoreWindow:
+ - auto_deploy_enabled
+ - deploy_functions
+ GitDeploymentRunStatus:
+ type: string
+ enum:
+ - pending
+ - running
+ - succeeded
+ - failed
+ - superseded
+ - skipped
+ x-enum-varnames:
+ - GitDeploymentRunStatusPending
+ - GitDeploymentRunStatusRunning
+ - GitDeploymentRunStatusSucceeded
+ - GitDeploymentRunStatusFailed
+ - GitDeploymentRunStatusSuperseded
+ - GitDeploymentRunStatusSkipped
+ description: 'Where a run is. `pending` and `running` have not ended. `succeeded`: every deployment the run dispatched succeeded, or the commit only had migrations to apply. `failed`: `error` says why. `superseded`: a newer push replaced the run before it started. `skipped`: there was nothing to deploy; `error` says why.'
+ GitDeploymentRunError:
type: object
- description: |
- The span a point-in-time restore may target. Absent from the response
- when the owner's plan does not include point-in-time restore, and while
- the storage provider has no history window in place yet — briefly the
- case after an upgrade, since the window is applied asynchronously. The
- window is read from the provider rather than from the plan, so it never
- advertises a point a restore could not actually reach.
+ description: Why a run failed or was skipped.
properties:
- earliest_restore_at:
+ code:
type: string
- format: date-time
- description: |
- The oldest point that can still be restored. Moves forward
- continuously as history ages out, so treat it as a lower bound at
- the moment it was read rather than a fixed value.
- latest_restore_at:
+ description: 'Stable machine-readable reason. For a failed run: `migration_failed`, `migration_invalid_layout`, `migration_timeout`, `feature_unavailable`, `source_invalid`, `child_deploy_failed`, `child_deploy_not_started`, `deploy_refused`, `typescript_not_compiled`, `deploy_failed`, `max_attempts_exhausted`, `owner_not_active`, or `project_deleting`. `source_invalid`, `deploy_refused`, and `typescript_not_compiled` fail the same way if the same commit is pushed again; `child_deploy_not_started`, `deploy_failed`, and `max_attempts_exhausted` may succeed on another push; for `owner_not_active`, reactivating the owner''s account restores deployment eligibility; push again to deploy. `project_deleting` means the project is being deleted. For a skipped run: `auto_deploy_disabled`, `binding_changed`, `disconnected`, `project_missing`, or `nothing_to_deploy`. Treat a code you do not know as a failure.'
+ message:
type: string
- format: date-time
- description: The most recent point that can be restored, which is now.
- DatabaseStats:
+ description: What happened. For `migration_failed`, `migration_invalid_layout`, `source_invalid`, `deploy_refused`, `child_deploy_not_started`, and `typescript_not_compiled` it names the database, files, resource, or setting at fault when Volcano has them.
+ required:
+ - code
+ - message
+ GitDeploymentMigrationRun:
type: object
+ description: A migration run a deployment run started. Get it at `GET /projects/{id}/databases/{databaseName}/migration-runs/{runId}` with `database.name` and `id`.
properties:
- current_storage_bytes:
- type: integer
- format: int64
- minimum: 0
- description: |
- On-disk size right now, in bytes: the database itself, plus every
- branch's divergence from it, plus what its backups cost to hold. This
- is the figure the storage allowance is enforced against. `branches`
- and `backup_storage_bytes` break it down.
- current_storage_mb:
- type: number
- format: double
- minimum: 0
- description: '`current_storage_bytes` expressed in megabytes.'
- branches:
- type: array
- description: |
- Per-branch contribution to `current_storage_bytes`. Empty when the
- database has no branches. A branch that has not diverged from its
- parent contributes nothing.
- items:
- $ref: '#/components/schemas/DatabaseBranchStorage'
- backup_storage_bytes:
- type: integer
- format: int64
- minimum: 0
- description: |
- What this database's backups contribute to `current_storage_bytes`.
-
- A backup taken on request is charged as a full copy of the database
- as it was at that moment, so two backups of a 2 GB database are 4 GB.
- A backup schedule is charged its first snapshot in full and each
- later one only for the storage it adds. Deleting a backup releases
- its storage immediately.
-
- Sampled from the provider rather than measured live, so it can lag a
- change by a few minutes, and a backup taken seconds ago may not be
- costed yet. Zero on a plan without backups.
- storage_bytes:
- type: integer
- format: int64
- description: Total storage used in bytes (data + WAL)
- data_written_bytes:
- type: integer
- format: int64
- description: Total data written in bytes
- data_transfer_bytes:
- type: integer
- format: int64
- description: Total data transferred in bytes
- compute_time_seconds:
- type: number
- format: double
- description: Total CPU seconds consumed
- active_time_seconds:
- type: number
- format: double
- description: Total active compute time in seconds
- time_range:
+ id:
+ type: string
+ format: uuid
+ database:
+ $ref: '#/components/schemas/ResourceReference'
+ required:
+ - id
+ - database
+ GitDeploymentRun:
+ type: object
+ description: One push's deployment through Git auto deploy.
+ properties:
+ id:
+ type: string
+ format: uuid
+ status:
+ $ref: '#/components/schemas/GitDeploymentRunStatus'
+ branch:
type: string
- description: Time range of the metrics (e.g., "2024-01-01T00:00:00Z to 2024-01-02T00:00:00Z")
- granularity:
+ description: The branch the push updated, the project's production branch at the time.
+ commit_sha:
type: string
- enum:
- - hourly
- - daily
- - monthly
- description: Granularity of the aggregated metrics
+ description: The commit the run deploys.
+ apply_migrations:
+ type: boolean
+ description: 'Whether the run applies the commit''s migrations: the project''s `apply_migrations` Git deploy setting when the push arrived.'
+ migration_runs:
+ type: array
+ description: The migration runs the run started, one per database, ordered by database name. Empty when it started none.
+ items:
+ $ref: '#/components/schemas/GitDeploymentMigrationRun'
+ error:
+ $ref: '#/components/schemas/GitDeploymentRunError'
+ created_at:
+ type: string
+ format: date-time
+ description: When the push was recorded.
+ started_at:
+ type: string
+ format: date-time
+ description: When a worker first picked the run up.
+ completed_at:
+ type: string
+ format: date-time
+ description: When the run ended.
required:
- - current_storage_bytes
- - current_storage_mb
- - backup_storage_bytes
- - storage_bytes
- - data_written_bytes
- - data_transfer_bytes
- - compute_time_seconds
- - active_time_seconds
- DatabaseQueryPerformanceResponse:
+ - id
+ - status
+ - branch
+ - commit_sha
+ - apply_migrations
+ - migration_runs
+ - created_at
+ PaginatedGitDeploymentRuns:
type: object
properties:
data:
type: array
items:
- $ref: '#/components/schemas/DatabaseQueryPerformanceItem'
+ $ref: '#/components/schemas/GitDeploymentRun'
+ limit:
+ type: integer
+ description: Number of items per page
+ has_more:
+ type: boolean
+ description: Whether a next page exists
+ next_cursor:
+ type: string
+ description: Opaque cursor for the next page (present if has_more is true)
required:
- data
- UpdateDatabaseBranchRequest:
+ - limit
+ - has_more
+ ProjectLockLeaseRequest:
type: object
- description: Replace the branch's lifetime and restart its countdown from now.
+ additionalProperties: false
properties:
ttl_seconds:
type: integer
- format: int64
- minimum: 3600
- maximum: 2592000
- description: The new lifetime, between one hour and 30 days.
- example: 86400
+ minimum: 5
+ maximum: 7776000
+ description: |
+ Lease duration in seconds, from 5 seconds through 90 days, measured
+ from when the request is served. Renew before it elapses. A renewal
+ sets the new expiry outright, so a shorter TTL shortens the lease.
+ Renewals cannot extend an acquisition beyond its absolute 90-day
+ deadline.
required:
- ttl_seconds
- DeviceAuthorizationResponse:
+ ProjectLockLease:
type: object
+ additionalProperties: false
properties:
- device_code:
- type: string
- user_code:
- type: string
- verification_uri:
+ expires_at:
type: string
+ format: date-time
+ description: Advisory lease expiry timestamp in UTC.
+ fencing_token:
+ type: integer
+ format: int64
description: |
- Browser verification URL. Points at the project's managed device
- approval page served by this API:
- `/projects/{projectId}/auth/hosted?action=device&anon_key=...`.
- Requires the project to have managed auth enabled and a default anon
- key. A custom CLI may ignore this and direct users to its own
- RFC 8628-compatible page instead (see the device-auth guide).
- verification_uri_complete:
- type: string
+ Monotonically increasing token for this acquisition. It rises whenever the
+ lock changes hands and stays the same across renewals of one lease. Pass it
+ to the resource you are protecting and reject any write carrying a token
+ lower than the highest already seen; that is what stops a displaced holder
+ from writing after its lease lapsed.
+ required:
+ - expires_at
+ - fencing_token
+ ProjectLockState:
+ type: object
+ additionalProperties: false
+ properties:
+ held:
+ type: boolean
description: |
- Same as `verification_uri` but with the `user_code` prefilled
- (`&user_code=...`). This is the URL most device clients open.
- expires_in:
- type: integer
- interval:
+ Whether the lock is unavailable right now. False means an acquire would
+ succeed. It remains true during the brief grace window after expiry.
+ expires_at:
+ type: string
+ format: date-time
+ description: Advisory lease expiry timestamp in UTC. Present only when held.
+ fencing_token:
type: integer
+ format: int64
+ description: Current holder's fencing token. Present only when held.
required:
- - device_code
- - user_code
- - verification_uri
- - verification_uri_complete
- - expires_in
- - interval
- EmailTemplate:
+ - held
+ ProjectSourceExportState:
type: object
- description: Custom email template
+ description: The project's source of truth and any pending Git transition.
properties:
- id:
+ mode:
type: string
- format: uuid
- project_id:
+ enum:
+ - platform
+ - git_exporting
+ - git_pending
+ - git
+ transition_started_at:
type: string
- format: uuid
- template_type:
+ format: date-time
+ nullable: true
+ description: When source export started, cleared if an incomplete transition is canceled.
+ exported_at:
type: string
- enum:
- - welcome
- - confirmation
- - password_reset
- - password_changed
- subject:
+ format: date-time
+ nullable: true
+ description: When the initial export push entered deployment, or when a transition was canceled after its commit was reserved. Once set, the one-time export is consumed.
+ handed_over_at:
type: string
- example: Confirm your email address
- html_body:
+ format: date-time
+ nullable: true
+ description: When a complete production-branch deployment first proved the repository could drive the project, null until then. Once set, the repository is the project's source of truth.
+ required:
+ - mode
+ - transition_started_at
+ - exported_at
+ - handed_over_at
+ ProjectSourceExport:
+ type: object
+ description: The initial production-branch commit, and everything export could not carry.
+ properties:
+ repo_full_name:
type: string
- description: HTML template with placeholders
- text_body:
+ branch:
type: string
- description: Plain text template with placeholders
- created_at:
+ description: The production branch that was created.
+ commit_sha:
type: string
- format: date-time
- updated_at:
+ file_count:
+ type: integer
+ skipped:
+ type: array
+ description: Resources whose source could not be taken, with the reason. Most often a resource that has never deployed successfully.
+ items:
+ $ref: '#/components/schemas/ProjectSourceExportSkip'
+ omitted:
+ type: array
+ description: Things deliberately left out of the branch.
+ items:
+ $ref: '#/components/schemas/ProjectSourceExportOmission'
+ required:
+ - repo_full_name
+ - branch
+ - commit_sha
+ - file_count
+ - skipped
+ - omitted
+ ExportProjectSourceRequest:
+ type: object
+ additionalProperties: false
+ properties:
+ production_branch:
type: string
- format: date-time
+ minLength: 1
+ description: The currently configured production branch the user confirmed for export.
+ repo_id:
+ type: integer
+ format: int64
+ description: |
+ The `repo_id` of the connected repository the user confirmed for
+ export, as the git connection reports it. When set, export answers
+ `409` if the project is now connected to a different repository, so
+ source is written only to the repository the user was shown.
required:
- - template_type
- - subject
- - html_body
- - text_body
- Error:
+ - production_branch
+ ProjectSourceExportSkip:
type: object
properties:
- error:
+ kind:
type: string
- code:
+ description: 'The kind of resource, "function" or "frontend". Deliberately not an enum: the generated constants would collide with an existing resource-type enum and rename its members.'
+ name:
+ type: string
+ reason:
type: string
- description: Stable machine-readable error code when a specific recovery path is available.
required:
- - error
- ImportProvider:
- type: string
- enum:
- - vercel
- default: vercel
- x-enum-varnames:
- - ImportProviderVercel
- ImportConnectStartResponse:
+ - kind
+ - name
+ - reason
+ ProjectSourceExportOmission:
type: object
properties:
- authorization_url:
+ kind:
+ type: string
+ description: 'What was left out: migrations Volcano stores no copy of, variable values, a credential-shaped file, installed dependencies, or an archive entry a repository cannot carry.'
+ resource:
+ type: string
+ description: The resource it came from, empty when project-wide.
+ path:
+ type: string
+ required:
+ - kind
+ - resource
+ - path
+ SetProjectGitProductionBranchRequest:
+ type: object
+ properties:
+ production_branch:
+ type: string
+ maxLength: 255
+ description: The branch a push must land on to deploy. Validated as a Git branch name only — it does not have to exist yet. An empty string follows the repository's default branch, including later renames.
+ required:
+ - production_branch
+ SetProjectGitRootDirectoryRequest:
+ type: object
+ properties:
+ root_directory:
type: string
+ maxLength: 1024
+ description: Monorepo subdirectory the project builds from, relative to the repository root. An empty string means the repository root.
required:
- - authorization_url
- ImportConnection:
+ - root_directory
+ ConnectProjectGitRequest:
type: object
properties:
- id:
+ connection_id:
type: string
format: uuid
- provider:
- $ref: '#/components/schemas/ImportProvider'
- account_id:
- type: string
- account_name:
- type: string
- configuration_id:
- type: string
- granted_scopes:
- type: array
- items:
- type: string
- status:
- type: string
- expires_at:
- type: string
- format: date-time
- nullable: true
- last_authenticated_at:
+ description: The caller's user_git_connections row (see /user/git/connections).
+ installation_id:
+ type: integer
+ format: int64
+ repository_id:
+ type: integer
+ format: int64
+ description: Stable GitHub repository id (repository.id), the preferred selector. Either repository_id or repo_full_name is required; when both are given they must identify the same live repository.
+ repo_full_name:
type: string
- format: date-time
- created_at:
+ deprecated: true
+ description: Deprecated selector kept for a compatibility window; prefer repository_id. Either repository_id or repo_full_name is required.
+ root_directory:
type: string
- format: date-time
- updated_at:
+ description: Monorepo subdirectory the project builds from. Omit for the repo root.
+ production_branch:
type: string
- format: date-time
+ maxLength: 255
+ description: 'The branch a push must land on to deploy, with three cases, because this is a full replace and a read-modify-write client sends back whatever it read. Omit it to follow the repository''s GitHub default branch, which also discards a branch set earlier. Send back the branch the project already deploys from, when that is the repository''s default, and nothing changes either way — a project pinned to that branch stays pinned. Sending the default branch when the project deploys from something else returns it to following the default, including on a rebind, where a pin describes a branch chosen for the repository being left. Any other branch becomes the project''s own choice, exempt from later default-branch renames. Validated as a Git branch name only: it does not have to exist yet, so a project can be pointed at a branch about to be pushed. Changing repository and naming a branch other than the new repository''s default in one request is refused with 400, because the branch named is almost always the previous repository''s, echoed back — connect first, then set the branch. A repository that reports no default branch, as one with no commits can, is connected only by naming a branch, and any branch is accepted for it, including on a rebind. An empty repository that still reports a default follows the rule above.'
required:
- - id
- - provider
- - account_id
- - account_name
- - configuration_id
- - granted_scopes
- - status
- - last_authenticated_at
- - created_at
- - updated_at
- ImportConnectionsResponse:
+ - connection_id
+ - installation_id
+ Frontend:
type: object
properties:
- connections:
+ variable_scope:
+ type: string
+ enum:
+ - all
+ - shared
+ - scoped
+ description: All preserves access to all project variables. Shared includes the project frontend shared-variable list. Scoped includes only explicitly declared variables in builds and runtime. Omission preserves the stored selection.
+ declared_variables:
type: array
+ uniqueItems: true
items:
- $ref: '#/components/schemas/ImportConnection'
- required:
- - connections
- ImportSource:
- type: object
- properties:
+ type: string
+ pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
+ description: Names selected when variable_scope is scoped. Missing declared values reject deployment. Omission preserves the stored list; an empty list clears it.
id:
type: string
- name:
+ format: uuid
+ project_id:
type: string
- account_id:
+ format: uuid
+ name:
type: string
+ maxLength: 63
+ pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$
framework:
type: string
- required:
- - id
- - name
- - account_id
- - framework
- ImportSourcesResponse:
- type: object
- properties:
- sources:
+ enum:
+ - nextjs
+ app_root:
+ type: string
+ maxLength: 1024
+ description: Optional relative POSIX path from the uploaded archive root to the Next.js app that is deployed.
+ status:
+ type: string
+ description: |
+ Frontend lifecycle status. `degraded` means the regional runtime remains
+ available but edge synchronization exhausted its immediate retries; Volcano
+ retries edge recovery without rebuilding the frontend, and stops once a new
+ deployment is queued or the retry budget runs out, leaving the frontend
+ `degraded` until the next redeploy. A redeploy that fails over a serving
+ frontend stays `active` on the previous deployment, so `failed` means no
+ deployment is serving.
+ enum:
+ - provisioning
+ - active
+ - degraded
+ - failed
+ - deleting
+ provisioning_started_at:
+ type: string
+ format: date-time
+ description: Timestamp when the current provisioning phase started
+ deployed_regions:
type: array
items:
- $ref: '#/components/schemas/ImportSource'
- required:
- - sources
- ProjectImportTarget:
- type: string
- enum:
- - production
- x-enum-varnames:
- - ProjectImportTargetProduction
- ProjectImportDestinationMode:
- type: string
- enum:
- - create
- x-enum-varnames:
- - ProjectImportDestinationCreate
- ProjectImportDisposition:
- type: string
- enum:
- - automatic
- - manual
- - deferred
- - unsupported
- x-enum-varnames:
- - ProjectImportDispositionAutomatic
- - ProjectImportDispositionManual
- - ProjectImportDispositionDeferred
- - ProjectImportDispositionUnsupported
- ProjectImportImpact:
- type: string
- enum:
- - none
- - warning
- - blocking
- x-enum-varnames:
- - ProjectImportImpactNone
- - ProjectImportImpactWarning
- - ProjectImportImpactBlocking
- ProjectImportReadiness:
- type: string
- enum:
- - importable
- - needs_input
- - blocked
- x-enum-varnames:
- - ProjectImportReadinessImportable
- - ProjectImportReadinessNeedsInput
- - ProjectImportReadinessBlocked
- ProjectImportActionCode:
- type: string
- enum:
- - project.create
- - git.connect
- - frontend.configure
- - variable.set
- x-enum-varnames:
- - ProjectImportActionProjectCreate
- - ProjectImportActionGitConnect
- - ProjectImportActionFrontendConfigure
- - ProjectImportActionVariableSet
- ProjectImportResourceKind:
- type: string
- enum:
- - project
- - git_repository
- - frontend
- - variable
- - domain
- x-enum-varnames:
- - ProjectImportResourceProject
- - ProjectImportResourceGitRepository
- - ProjectImportResourceFrontend
- - ProjectImportResourceVariable
- - ProjectImportResourceDomain
- ProjectImportPreflightRequest:
- type: object
- properties:
- connection_id:
+ type: string
+ current_deployment_id:
type: string
format: uuid
- source_id:
+ description: Identifier of the latest frontend deployment operation
+ pending_deployment_id:
type: string
- minLength: 1
- project_name:
+ format: uuid
+ description: Newest queued deployment that will run after the current operation
+ serving_candidate_id:
type: string
- maxLength: 255
- pattern: ^[A-Za-z0-9_-]+$
- target:
- $ref: '#/components/schemas/ProjectImportTarget'
- confirm_environment_variable_read:
- type: boolean
- default: false
- description: Set to true only after the user confirms an immediately preceding disclosure that the Vercel Integration grant permits reads and writes, while this preflight reads production variable values only. When false or omitted, preflight reads variable metadata only and reports readable values as manual input.
- required:
- - connection_id
- - source_id
- - project_name
- - target
- ProjectImportStartRequest:
- type: object
- properties:
- connection_id:
+ format: uuid
+ nullable: true
+ readOnly: true
+ description: |
+ The promoted Candidate whose runtime receives this frontend's traffic, the same as
+ `candidate_id` in `serving`. Null when the frontend serves its own runtime. While it is
+ set, `current_deployment_id` and `status` describe a deployment that receives no traffic,
+ and deploying the frontend is refused until it is rolled back.
+ site_url:
+ type: string
+ custom_domain:
+ type: string
+ description: Active custom domain hostname when configured
+ custom_domain_status:
+ type: string
+ description: Current custom domain lifecycle status
+ enum:
+ - pending_verification
+ - provisioning
+ - active
+ - detaching
+ - failed
+ - deleted
+ function_routes:
+ type: array
+ maxItems: 64
+ items:
+ $ref: '#/components/schemas/FrontendFunctionRoute'
+ description: |
+ Paths on this frontend that forward to a public function, ordered
+ from most to least specific. Anyone who can load the frontend can
+ reach the target function at these paths without a credential.
+ frontend_routes:
+ type: array
+ maxItems: 64
+ items:
+ $ref: '#/components/schemas/FrontendRoute'
+ description: |
+ Paths on this frontend served by another frontend in the project,
+ ordered from most to least specific. Function and Frontend routes
+ share one path namespace and the 64-route limit.
+ last_deployed_at:
type: string
- format: uuid
- source_id:
+ format: date-time
+ description: Recorded completion time of the most recent deploy or redeploy with status active. Omitted when no such deployment has a recorded completion time. Site traffic, pending deployments, degraded deployments, failed deployments, and deletion do not change this value.
+ last_invoked_at:
type: string
- minLength: 1
- maxLength: 255
- project_name:
+ format: date-time
+ created_at:
type: string
- maxLength: 255
- pattern: ^[A-Za-z0-9_-]+$
- target:
- $ref: '#/components/schemas/ProjectImportTarget'
- confirm_environment_variable_read:
- type: boolean
- enum:
- - true
- preflight_fingerprint:
+ format: date-time
+ updated_at:
type: string
- pattern: ^sha256:[0-9a-f]{64}$
+ format: date-time
required:
- - connection_id
- - source_id
- - project_name
- - target
- - confirm_environment_variable_read
- - preflight_fingerprint
- ProjectImportRunStatus:
- type: string
- enum:
- - pending
- - running
- - succeeded
- - failed
- - superseded
- x-enum-varnames:
- - ProjectImportRunStatusPending
- - ProjectImportRunStatusRunning
- - ProjectImportRunStatusSucceeded
- - ProjectImportRunStatusFailed
- - ProjectImportRunStatusSuperseded
- ProjectImportRun:
+ - id
+ - project_id
+ - name
+ - framework
+ - status
+ - deployed_regions
+ - serving_candidate_id
+ - function_routes
+ - frontend_routes
+ - created_at
+ - updated_at
+ FrontendCandidate:
type: object
+ additionalProperties: false
+ description: |
+ A copy of a frontend built from an uploaded archive with the frontend's own configuration, so
+ it can be checked before anything is promoted. A Candidate is reachable by anyone who holds its
+ URL and is not indexed or listed; it is never public, and it does not claim to be private.
properties:
id:
type: string
- provider:
- $ref: '#/components/schemas/ImportProvider'
- source_id:
+ format: uuid
+ frontend_id:
type: string
- destination_project_name:
+ format: uuid
+ name:
type: string
- resource:
- $ref: '#/components/schemas/ResourceReference'
- deployment:
- $ref: '#/components/schemas/DeploymentReference'
+ maxLength: 128
status:
- $ref: '#/components/schemas/ProjectImportRunStatus'
- error_code:
type: string
- error_message:
+ enum:
+ - creating
+ - ready
+ - deleting
+ - error
+ description: |
+ `creating` until its first deployment succeeds, `ready` while it serves, `deleting` while
+ its runtime is removed, and `error` when its deletion gave up and needs an operator.
+ url:
type: string
+ format: uri
+ description: Where the Candidate is served. Absent until its first deployment succeeds.
+ expires_at:
+ type: string
+ format: date-time
+ description: When the Candidate is deleted on its own. Absent when it is kept until deleted.
+ current_deployment_id:
+ type: string
+ format: uuid
+ description: |
+ The deployment the Candidate serves. Absent until its first
+ deployment succeeds. It differs from `deployment` while a redeploy runs or after one failed.
+ deployment:
+ $ref: '#/components/schemas/FrontendCandidateDeployment'
+ configuration_status:
+ type: string
+ enum:
+ - current
+ - changed
+ description: |
+ Present while the Candidate serves a deployment. `current` means that deployment was built
+ with the variables the frontend selects now; `changed` means they differ, or can no longer
+ be resolved. Promotion refuses a Candidate whose status is `changed`.
created_at:
type: string
format: date-time
@@ -20110,171 +28543,109 @@ components:
format: date-time
required:
- id
- - provider
- - source_id
- - destination_project_name
- - resource
- - deployment
+ - frontend_id
+ - name
- status
- created_at
- updated_at
- ProjectImportDestination:
- type: object
- properties:
- mode:
- $ref: '#/components/schemas/ProjectImportDestinationMode'
- project_name:
- type: string
- target:
- $ref: '#/components/schemas/ProjectImportTarget'
- required:
- - mode
- - project_name
- - target
- ProjectImportResource:
+ FrontendCandidateDeployment:
type: object
+ additionalProperties: false
properties:
- kind:
- $ref: '#/components/schemas/ProjectImportResourceKind'
- name:
+ id:
type: string
- source_id:
+ format: uuid
+ status:
type: string
- minLength: 1
- description: Stable provider identifier for a scoped source resource.
- scope:
+ enum:
+ - provisioning
+ - active
+ - failed
+ description: |
+ `provisioning` while the build and deploy run, `active` once the Candidate serves this
+ deployment, and `failed` when it could not be built or deployed. A failed deployment of a
+ Candidate that already served keeps the previous deployment serving.
+ configuration_digest:
type: string
- minLength: 1
- description: URL-encoded source scope, including target, branch, and custom environment identifiers.
- required:
- - kind
- - name
- ProjectImportAction:
- type: object
- properties:
- code:
- $ref: '#/components/schemas/ProjectImportActionCode'
- resource:
- $ref: '#/components/schemas/ProjectImportResource'
- disposition:
- $ref: '#/components/schemas/ProjectImportDisposition'
- required:
- - code
- - resource
- - disposition
- ProjectImportFinding:
- type: object
- properties:
- code:
+ pattern: ^sha256:[0-9a-f]{64}$
+ description: Identifies the resolved configuration the deployment was built with. It carries no value.
+ error_message:
type: string
- pattern: ^(vercel|volcano|import)\.[a-z0-9_]+$
- resource:
- $ref: '#/components/schemas/ProjectImportResource'
- disposition:
- $ref: '#/components/schemas/ProjectImportDisposition'
- impact:
- $ref: '#/components/schemas/ProjectImportImpact'
- message:
+ description: Why a failed deployment failed.
+ created_at:
type: string
- remediation:
+ format: date-time
+ completed_at:
type: string
+ format: date-time
+ description: Set once the deployment is no longer provisioning.
required:
- - code
- - resource
- - disposition
- - impact
- - message
- - remediation
- ProjectImportSummary:
+ - id
+ - status
+ - configuration_digest
+ - created_at
+ FrontendServing:
type: object
+ additionalProperties: false
+ description: |
+ What a frontend serves. Until a Candidate is promoted it serves its own runtime and
+ `candidate_id` is null. After a promotion, the frontend's traffic is routed to that
+ Candidate's runtime, nothing is rebuilt or copied, and `previous_candidate_id` is the runtime a
+ rollback returns to (null when that is the frontend's own). A Candidate that serves cannot be
+ deleted and does not expire. One kept only as the runtime a rollback returns to does not
+ expire either, but it can be deleted, which gives up that rollback; the frontend's own
+ runtime stays one `to_production` rollback away.
properties:
- automatic:
- type: integer
- minimum: 0
- manual:
- type: integer
- minimum: 0
- deferred:
- type: integer
- minimum: 0
- unsupported:
- type: integer
- minimum: 0
- warnings:
- type: integer
- minimum: 0
- blocking:
+ revision:
type: integer
+ format: int64
minimum: 0
+ description: Counts changes to what the frontend serves or can roll back to — promotions, rollbacks, and deleting the Candidate kept for a rollback. A promotion or rollback names the revision it read, so one that read before such a change fails with `409` instead of overwriting it; read the serving state again and retry.
+ candidate_id:
+ type: string
+ format: uuid
+ nullable: true
+ previous_candidate_id:
+ type: string
+ format: uuid
+ nullable: true
required:
- - automatic
- - manual
- - deferred
- - unsupported
- - warnings
- - blocking
- ProjectImportReport:
+ - revision
+ - candidate_id
+ - previous_candidate_id
+ FrontendCandidateList:
type: object
+ additionalProperties: false
properties:
- schema_version:
- type: string
- provider:
- $ref: '#/components/schemas/ImportProvider'
- source:
- $ref: '#/components/schemas/ImportSource'
- destination:
- $ref: '#/components/schemas/ProjectImportDestination'
- actions:
- type: array
- items:
- $ref: '#/components/schemas/ProjectImportAction'
- findings:
+ data:
type: array
items:
- $ref: '#/components/schemas/ProjectImportFinding'
- summary:
- $ref: '#/components/schemas/ProjectImportSummary'
- readiness:
- $ref: '#/components/schemas/ProjectImportReadiness'
- source_fingerprint:
- type: string
- capability_fingerprint:
- type: string
- fingerprint:
- type: string
- generated_at:
- type: string
- format: date-time
+ $ref: '#/components/schemas/FrontendCandidate'
required:
- - schema_version
- - provider
- - source
- - destination
- - actions
- - findings
- - summary
- - readiness
- - source_fingerprint
- - capability_fingerprint
- - fingerprint
- - generated_at
- GitConnection:
+ - data
+ FrontendFunctionRoute:
type: object
+ additionalProperties: false
properties:
id:
type: string
- format: uuid
- provider:
- type: string
- provider_user_id:
+ format: uuid
+ project_id:
type: string
- provider_login:
+ format: uuid
+ frontend_id:
type: string
- status:
+ format: uuid
+ function_id:
type: string
- last_authenticated_at:
+ format: uuid
+ path_prefix:
type: string
- format: date-time
+ minLength: 2
+ maxLength: 512
+ pattern: ^/[^?#\\]*[^/?#\\]$
+ strip_prefix:
+ type: boolean
created_at:
type: string
format: date-time
@@ -20283,396 +28654,510 @@ components:
format: date-time
required:
- id
- - provider
- - provider_user_id
- - provider_login
- - status
- - last_authenticated_at
+ - project_id
+ - frontend_id
+ - function_id
+ - path_prefix
+ - strip_prefix
- created_at
- updated_at
- GitConnectStartResponse:
- type: object
- properties:
- authorization_url:
- type: string
- required:
- - authorization_url
- VerifiedDomain:
- type: object
- description: A domain the account owns, along with every name below it.
- properties:
- domain:
- type: string
- example: example.com
- verified_at:
- type: string
- format: date-time
- description: When the account last proved ownership.
- required:
- - domain
- - verified_at
- VerifiedDomainsResponse:
+ FrontendFunctionRouteList:
type: object
+ additionalProperties: false
properties:
- domains:
+ data:
type: array
items:
- $ref: '#/components/schemas/VerifiedDomain'
+ $ref: '#/components/schemas/FrontendFunctionRoute'
required:
- - domains
- VerifyDomainRequest:
+ - data
+ CreateFrontendFunctionRouteRequest:
type: object
+ additionalProperties: false
properties:
- domain:
+ function_id:
type: string
- minLength: 1
- maxLength: 253
- description: The domain to verify, such as `example.com`.
- required:
- - domain
- GitConnectionsResponse:
- type: object
- properties:
- connections:
- type: array
- items:
- $ref: '#/components/schemas/GitConnection'
+ format: uuid
+ path_prefix:
+ type: string
+ minLength: 2
+ maxLength: 512
+ pattern: ^/[^?#\\]*[^/?#\\]$
+ strip_prefix:
+ type: boolean
+ default: false
required:
- - connections
- GitInstallation:
+ - function_id
+ - path_prefix
+ FrontendRoute:
type: object
+ additionalProperties: false
+ description: |
+ A path prefix on this Frontend's hostnames served by another Frontend in the Project, the
+ mounted Frontend. Paths are forwarded unchanged, so the mounted Frontend serves its prefix
+ as real pages (page directories or a matching `basePath`).
properties:
id:
- type: integer
- format: int64
- account_login:
type: string
- account_type:
+ format: uuid
+ project_id:
type: string
- repository_selection:
+ format: uuid
+ frontend_id:
+ type: string
+ format: uuid
+ description: The Frontend whose hostnames serve the route
+ target_frontend_id:
+ type: string
+ format: uuid
+ description: The mounted Frontend
+ path_prefix:
+ type: string
+ minLength: 2
+ maxLength: 512
+ pattern: ^/[^?#\\]*[^/?#\\]$
+ created_at:
+ type: string
+ format: date-time
+ updated_at:
type: string
+ format: date-time
required:
- id
- - account_login
- - account_type
- - repository_selection
- GitInstallationsResponse:
+ - project_id
+ - frontend_id
+ - target_frontend_id
+ - path_prefix
+ - created_at
+ - updated_at
+ FrontendRouteList:
type: object
+ additionalProperties: false
properties:
- installations:
+ data:
type: array
items:
- $ref: '#/components/schemas/GitInstallation'
+ $ref: '#/components/schemas/FrontendRoute'
required:
- - installations
- GitRepository:
+ - data
+ CreateFrontendRouteRequest:
type: object
+ additionalProperties: false
properties:
- id:
- type: integer
- format: int64
- description: Stable GitHub repository id (repository.id), unchanged by renames.
- full_name:
+ target_frontend_id:
type: string
- default_branch:
+ format: uuid
+ description: The Frontend to mount. It must be another Frontend in the Project.
+ path_prefix:
type: string
- private:
- type: boolean
- is_empty:
- type: boolean
- description: Whether the repository has no commits and can receive an initial source export.
+ minLength: 2
+ maxLength: 512
+ pattern: ^/[^?#\\]*[^/?#\\]$
required:
- - id
- - full_name
- - default_branch
- - private
- - is_empty
- GitRepositoriesResponse:
+ - target_frontend_id
+ - path_prefix
+ CreateFrontendDeploymentRequest:
type: object
+ additionalProperties: false
+ description: Deploys the build of an existing deployment instead of compiling the frontend's source.
properties:
- repositories:
- type: array
- items:
- $ref: '#/components/schemas/GitRepository'
+ source_deployment_id:
+ type: string
+ format: uuid
+ description: An `active` or `degraded` deployment of another frontend in the same project. Its build is copied to this frontend and published without compiling it again.
required:
- - repositories
- ProjectGitConnection:
+ - source_deployment_id
+ FrontendCustomDomainTLSConfig:
type: object
+ description: 'TLS for a new custom domain. With `mode: managed`, Volcano issues and renews the certificate; omit every PEM field. With `mode: byoc`, send both `certificate_pem` and `private_key_pem`, plus an optional `certificate_chain_pem`.'
+ additionalProperties: false
+ not:
+ anyOf:
+ - allOf:
+ - properties:
+ mode:
+ enum:
+ - managed
+ required:
+ - mode
+ - anyOf:
+ - required:
+ - certificate_pem
+ - required:
+ - private_key_pem
+ - required:
+ - certificate_chain_pem
+ - allOf:
+ - properties:
+ mode:
+ enum:
+ - byoc
+ required:
+ - mode
+ - anyOf:
+ - not:
+ required:
+ - certificate_pem
+ - not:
+ required:
+ - private_key_pem
properties:
- repo_installation_id:
- type: integer
- format: int64
- repo_id:
- type: integer
- format: int64
- description: Stable GitHub repository id (repository.id), the authoritative binding.
- repo_full_name:
+ mode:
type: string
- root_directory:
+ enum:
+ - managed
+ - byoc
+ default: byoc
+ description: managed for a Volcano-issued certificate; byoc to supply your own.
+ certificate_pem:
type: string
- production_branch:
+ maxLength: 65536
+ description: PEM-encoded certificate. Required when mode is byoc; not allowed when mode is managed.
+ private_key_pem:
+ type: string
+ maxLength: 65536
+ description: PEM-encoded private key. Required when mode is byoc; not allowed when mode is managed.
+ certificate_chain_pem:
+ type: string
+ maxLength: 65536
+ description: Optional PEM-encoded certificate chain when mode is byoc; not allowed when mode is managed.
+ required:
+ - mode
+ FrontendCustomDomainResponse:
+ type: object
+ properties:
+ domain:
+ type: string
+ tls_mode:
+ type: string
+ enum:
+ - managed
+ - byoc
+ domain_status:
+ type: string
+ enum:
+ - pending_verification
+ - provisioning
+ - active
+ - detaching
+ - failed
+ - deleted
+ verification_status:
+ type: string
+ enum:
+ - pending
+ - verified
+ - failed
+ description: '`verified`: the domain is served by a validated certificate. `pending`: it is not served yet, is being re-validated after its certificate material was withdrawn, or Volcano is retrying after a failure. `failed`: a failure left the domain unserved, alongside `domain_status: failed`; managed domains report the cause in `failure_reason`.'
+ serving_certificate:
+ type: string
+ enum:
+ - uploaded
+ - managed
+ description: 'Certificate the domain serves, present only while it is active. `uploaded`: the BYOC certificate, including after the domain switched to managed TLS and until Volcano issues the managed one; `failure_reason` then reports an issuance failure. `managed`: a certificate Volcano issued.'
+ failure_reason:
+ type: string
+ description: Failure category, present when managed TLS setup has failed, or when issuance is failing for a domain that switched to managed TLS and still serves its uploaded certificate. Current values are provider, certificate, ownership, and internal; ownership means another account has already claimed the hostname through ownership verification. Treat unrecognized values as internal.
+ verification_records:
+ type: array
+ description: DNS records to publish now. For a managed domain whose hostname the account already owns, the create response names the `_acme-challenge` CNAME that authorizes certificate issuance and renewal. Otherwise it names the `_volcano` TXT record that proves ownership of the hostname's registrable domain, and reads return the CNAME once Volcano sees that record. Usually empty for BYOC.
+ items:
+ $ref: '#/components/schemas/FrontendDomainVerificationRecord'
+ required_routing_record:
+ allOf:
+ - $ref: '#/components/schemas/FrontendDomainRoutingRecord'
+ deprecated: true
+ description: Deprecated and no longer returned. Use routing_target_hostname as the DNS routing target.
+ routing_target_hostname:
type: string
- description: The branch a push must land on to deploy. Follows the repository's GitHub default branch unless the project set its own, which a default-branch rename on GitHub then leaves alone.
- updated_at:
+ description: DNS routing target hostname for this frontend. The DNS record type depends on whether the custom domain is a zone apex.
+ effective_urls:
+ type: array
+ items:
+ type: string
+ redirect:
+ allOf:
+ - $ref: '#/components/schemas/FrontendCustomDomainRedirect'
+ nullable: true
+ description: Where the domain redirects every request, or null when it serves the frontend.
+ created_at:
type: string
format: date-time
- required:
- - repo_installation_id
- - repo_id
- - repo_full_name
- - root_directory
- - production_branch
- - updated_at
- ProjectGitDeploySettings:
- type: object
- description: 'A project''s GitHub auto-deploy settings: what a push to the connected repo''s production branch deploys. All settings are default-off.'
- properties:
- auto_deploy_enabled:
- type: boolean
- description: Whether a production-branch push triggers a deployment.
- deploy_functions:
- type: boolean
- description: Whether the repo's functions are deployed on push.
- frontend_name:
- type: string
- description: Name of the frontend to build and deploy on push. Omitted when no frontend is deployed. Resolved at deploy time; need not exist yet.
- frontend_app_root:
- type: string
- description: App root (subdirectory) the frontend builds from. Omitted for the repo root.
updated_at:
type: string
format: date-time
required:
- - auto_deploy_enabled
- - deploy_functions
+ - domain
+ - tls_mode
+ - domain_status
+ - verification_status
+ - effective_urls
+ - redirect
+ - created_at
- updated_at
- UpdateProjectGitDeploySettingsRequest:
+ FrontendCustomDomainList:
type: object
- description: Full replace of a project's Git auto-deploy settings.
properties:
- auto_deploy_enabled:
- type: boolean
- deploy_functions:
- type: boolean
- frontend_name:
- type: string
- description: Frontend to deploy on push. Omit or empty to deploy no frontend.
- frontend_app_root:
- type: string
- description: App root the frontend builds from. Requires frontend_name; omit for the repo root.
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/FrontendCustomDomainResponse'
required:
- - auto_deploy_enabled
- - deploy_functions
- ProjectLockLeaseRequest:
+ - data
+ FrontendCustomDomainRedirect:
type: object
- additionalProperties: false
properties:
- ttl_seconds:
+ to:
+ type: string
+ description: Hostname the domain redirects to.
+ status:
type: integer
- minimum: 5
- maximum: 7776000
- description: |
- Lease duration in seconds, from 5 seconds through 90 days, measured
- from when the request is served. Renew before it elapses. A renewal
- sets the new expiry outright, so a shorter TTL shortens the lease.
- Renewals cannot extend an acquisition beyond its absolute 90-day
- deadline.
+ enum:
+ - 301
+ - 302
+ - 307
+ - 308
required:
- - ttl_seconds
- ProjectLockLease:
+ - to
+ - status
+ FrontendCustomDomainRedirectRequest:
type: object
additionalProperties: false
+ description: Redirects every request for the domain to `to`, another active domain of the same frontend that serves it, keeping the path and query string.
properties:
- expires_at:
+ to:
type: string
- format: date-time
- description: Advisory lease expiry timestamp in UTC.
- fencing_token:
+ minLength: 1
+ maxLength: 253
+ description: Hostname of an active domain of the same frontend that serves it.
+ example: www.example.com
+ status:
type: integer
- format: int64
- description: |
- Monotonically increasing token for this acquisition. It rises whenever the
- lock changes hands and stays the same across renewals of one lease. Pass it
- to the resource you are protecting and reject any write carrying a token
- lower than the highest already seen; that is what stops a displaced holder
- from writing after its lease lapsed.
+ enum:
+ - 301
+ - 302
+ - 307
+ - 308
+ default: 308
+ description: Redirect status. 301 and 308 are permanent, 302 and 307 temporary; 307 and 308 keep the request method and body.
required:
- - expires_at
- - fencing_token
- ProjectLockState:
+ - to
+ UpdateFrontendCustomDomainRequest:
type: object
additionalProperties: false
properties:
- held:
- type: boolean
- description: |
- Whether the lock is unavailable right now. False means an acquire would
- succeed. It remains true during the brief grace window after expiry.
- expires_at:
- type: string
- format: date-time
- description: Advisory lease expiry timestamp in UTC. Present only when held.
- fencing_token:
- type: integer
- format: int64
- description: Current holder's fencing token. Present only when held.
+ redirect:
+ allOf:
+ - $ref: '#/components/schemas/FrontendCustomDomainRedirectRequest'
+ nullable: true
+ description: The redirect to set, or null to make the domain serve the frontend.
required:
- - held
- ProjectSourceExportState:
+ - redirect
+ FrontendDeployment:
type: object
- description: The project's source of truth and any pending Git transition.
properties:
- mode:
+ id:
+ type: string
+ format: uuid
+ frontend_id:
+ type: string
+ format: uuid
+ project_id:
+ type: string
+ format: uuid
+ operation:
+ type: string
+ enum:
+ - deploy
+ - redeploy
+ - delete
+ status:
+ type: string
+ description: |
+ Deployment lifecycle status. A `degraded` redeploy remains available while
+ edge-only recovery is retried. A `failed` redeploy is recorded here while the
+ frontend keeps serving its previous deployment.
+ enum:
+ - queued
+ - provisioning
+ - active
+ - degraded
+ - failed
+ - superseded
+ - deleting
+ - deleted
+ deploy_source:
type: string
enum:
- - platform
- - git_exporting
- - git_pending
- git
- transition_started_at:
+ - cli
+ - web
+ - api
+ - system
+ - unknown
+ description: What initiated this deployment.
+ initiated_by:
+ type: string
+ description: Platform user that triggered a request-initiated deployment; absent for git and system deployments.
+ commit:
+ $ref: '#/components/schemas/DeploymentCommit'
+ source_deployment_id:
+ type: string
+ format: uuid
+ description: The deployment whose build this deployment published instead of compiling its own source. Absent when the deployment compiled.
+ site_url:
+ type: string
+ build_duration_seconds:
+ type: integer
+ format: int64
+ description: Total build time recorded for this deployment, in seconds.
+ build_count:
+ type: integer
+ description: Number of completed builds included in build_duration_seconds.
+ build_duration_recorded_at:
type: string
format: date-time
- nullable: true
- description: When source export started, cleared if an incomplete transition is canceled.
- exported_at:
+ description: When the build time was last recorded.
+ progress:
+ $ref: '#/components/schemas/DeploymentProgress'
+ error_message:
+ type: string
+ created_at:
type: string
format: date-time
- nullable: true
- description: When the initial export push entered deployment, or when a transition was canceled after its commit was reserved. Once set, the one-time export is consumed.
- handed_over_at:
+ updated_at:
type: string
format: date-time
- nullable: true
- description: When a complete production-branch deployment first proved the repository could drive the project, null until then. Once set, the repository is the project's source of truth.
required:
- - mode
- - transition_started_at
- - exported_at
- - handed_over_at
- ProjectSourceExport:
+ - id
+ - frontend_id
+ - project_id
+ - operation
+ - status
+ - deploy_source
+ - created_at
+ - updated_at
+ FrontendDomainRoutingRecord:
type: object
- description: The initial production-branch commit, and everything export could not carry.
properties:
- repo_full_name:
- type: string
- branch:
+ record_type:
type: string
- description: The production branch that was created.
- commit_sha:
+ enum:
+ - CNAME
+ name:
type: string
- file_count:
- type: integer
- skipped:
- type: array
- description: Resources whose source could not be taken, with the reason. Most often a resource that has never deployed successfully.
- items:
- $ref: '#/components/schemas/ProjectSourceExportSkip'
- omitted:
- type: array
- description: Things deliberately left out of the branch.
- items:
- $ref: '#/components/schemas/ProjectSourceExportOmission'
- required:
- - repo_full_name
- - branch
- - commit_sha
- - file_count
- - skipped
- - omitted
- ExportProjectSourceRequest:
- type: object
- additionalProperties: false
- properties:
- production_branch:
+ value:
type: string
- minLength: 1
- description: The currently configured production branch the user confirmed for export.
required:
- - production_branch
- ProjectSourceExportSkip:
+ - record_type
+ - name
+ - value
+ FrontendDomainVerificationRecord:
type: object
- properties:
- kind:
- type: string
- description: 'The kind of resource, "function" or "frontend". Deliberately not an enum: the generated constants would collide with an existing resource-type enum and rename its members.'
+ description: The DNS records currently required. Volcano may require an account-specific TXT ownership record for the hostname's domain before returning a CNAME that authorizes managed certificate issuance and renewal. Clients must follow the records returned for the current lifecycle state instead of assuming a fixed sequence.
+ properties:
name:
type: string
- reason:
+ type:
+ type: string
+ value:
type: string
required:
- - kind
- name
- - reason
- ProjectSourceExportOmission:
+ - type
+ - value
+ FrontendCustomDomainConflictError:
+ description: 'Domain ownership conflict. With `code: ownership_verification_required`, the account has not proven it owns the domain: publish `required_record` in DNS and send the same request again. The retry succeeds once Volcano can see the record. With `code: custom_domain_releasing`, a removed domain still holds the hostname or the frontend while Volcano releases it: send the same request again after the response''s `Retry-After` seconds. A release that will not finish within a few minutes is a plain conflict. Other conflicts omit both fields.'
+ allOf:
+ - $ref: '#/components/schemas/Error'
+ - type: object
+ properties:
+ required_record:
+ $ref: '#/components/schemas/FrontendDomainVerificationRecord'
+ FrontendUsageDailyEntry:
type: object
+ description: One day of request and error counts for a single frontend.
properties:
- kind:
- type: string
- description: 'What was left out: migrations Volcano stores no copy of, variable values, a credential-shaped file, installed dependencies, or an archive entry a repository cannot carry.'
- resource:
- type: string
- description: The resource it came from, empty when project-wide.
- path:
+ day:
type: string
+ format: date
+ description: UTC date (YYYY-MM-DD) the counts cover.
+ requests:
+ type: integer
+ format: int64
+ description: Total requests served on this day.
+ errors:
+ type: integer
+ format: int64
+ description: 5xx responses served on this day.
+ page_views:
+ type: integer
+ format: int64
+ description: Navigable-document responses served on this day (text/html or Sec-Fetch-Dest=document) — strict subset of `requests`.
required:
- - kind
- - resource
- - path
- SetProjectGitProductionBranchRequest:
+ - day
+ - requests
+ - errors
+ - page_views
+ FrontendUsageData:
type: object
+ description: Monthly frontend request totals grouped by frontend.
properties:
- production_branch:
+ frontend_id:
type: string
- minLength: 1
- maxLength: 255
- description: The branch a push must land on to deploy. Validated as a Git branch name only — it does not have to exist yet.
+ format: uuid
+ description: Frontend ID
+ frontend_name:
+ type: string
+ description: Frontend name at the time usage was fetched
+ nullable: true
+ requests:
+ type: integer
+ format: int64
+ description: Total requests for this frontend in the current usage month
required:
- - production_branch
- ConnectProjectGitRequest:
+ - frontend_id
+ - requests
+ FrontendUsageHistoryResponse:
type: object
+ description: Zero-filled daily series of request + error counts for a single frontend, oldest first.
properties:
- connection_id:
+ frontend_id:
type: string
format: uuid
- description: The caller's user_git_connections row (see /user/git/connections).
- installation_id:
+ days:
+ type: integer
+ description: Number of daily entries returned (always equal to the `days` query param after clamping).
+ daily:
+ type: array
+ items:
+ $ref: '#/components/schemas/FrontendUsageDailyEntry'
+ total_requests:
type: integer
format: int64
- repository_id:
+ total_errors:
+ type: integer
+ format: int64
+ total_page_views:
type: integer
format: int64
- description: Stable GitHub repository id (repository.id), the preferred selector. Either repository_id or repo_full_name is required; when both are given they must identify the same live repository.
- repo_full_name:
- type: string
- deprecated: true
- description: Deprecated selector kept for a compatibility window; prefer repository_id. Either repository_id or repo_full_name is required.
- root_directory:
- type: string
- description: Monorepo subdirectory the project builds from. Omit for the repo root.
- production_branch:
- type: string
- maxLength: 255
- description: 'The branch a push must land on to deploy, with three cases, because this is a full replace and a read-modify-write client sends back whatever it read. Omit it to follow the repository''s GitHub default branch, which also discards a branch set earlier. Send back the branch the project already deploys from, when that is the repository''s default, and nothing changes either way — a project pinned to that branch stays pinned. Sending the default branch when the project deploys from something else returns it to following the default, including on a rebind, where a pin describes a branch chosen for the repository being left. Any other branch becomes the project''s own choice, exempt from later default-branch renames. Validated as a Git branch name only: it does not have to exist yet, so a project can be pointed at a branch about to be pushed. Changing repository and naming a branch other than the new repository''s default in one request is refused with 400, because the branch named is almost always the previous repository''s, echoed back — connect first, then set the branch.'
required:
- - connection_id
- - installation_id
- Frontend:
+ - frontend_id
+ - days
+ - daily
+ - total_requests
+ - total_errors
+ - total_page_views
+ ProjectAccessToken:
type: object
+ description: |
+ A project access token: a control-plane credential bound to a single
+ project. Unlike a platform token, which acts on every project its owner
+ has, this one is limited to the project it was created in.
+
+ The secret itself is never returned here. Only its hash is stored, so
+ the plaintext exists solely in the response to the create call.
properties:
- variable_scope:
- type: string
- enum:
- - all
- - shared
- - scoped
- description: All preserves access to all project variables. Shared includes the project frontend shared-variable list. Scoped includes only explicitly declared variables in builds and runtime. Omission preserves the stored selection.
- declared_variables:
- type: array
- uniqueItems: true
- items:
- type: string
- pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
- description: Names selected when variable_scope is scoped. Missing declared values reject deployment. Omission preserves the stored list; an empty list clears it.
id:
type: string
format: uuid
@@ -20681,346 +29166,265 @@ components:
format: uuid
name:
type: string
- maxLength: 63
- pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$
- framework:
- type: string
- enum:
- - nextjs
- app_root:
+ description: Unique per project.
+ token_prefix:
type: string
- maxLength: 1024
- description: Optional relative POSIX path from the uploaded archive root to the Next.js app that is deployed.
+ description: First 12 characters of the secret, for recognising a token in a list.
+ scope:
+ $ref: '#/components/schemas/ProjectAccessTokenScope'
status:
type: string
- description: |
- Frontend lifecycle status. `degraded` means the regional runtime remains
- available but edge synchronization exhausted its immediate retries; Volcano
- retries edge recovery without rebuilding the frontend, and stops once a new
- deployment is queued or the retry budget runs out, leaving the frontend
- `degraded` until the next redeploy. A redeploy that fails over a serving
- frontend stays `active` on the previous deployment, so `failed` means no
- deployment is serving.
enum:
- - provisioning
- active
- - degraded
- - failed
- - deleting
- provisioning_started_at:
- type: string
- format: date-time
- description: Timestamp when the current provisioning phase started
- deployed_regions:
- type: array
- items:
- type: string
- current_deployment_id:
- type: string
- format: uuid
- description: Identifier of the latest frontend deployment operation
- pending_deployment_id:
- type: string
- format: uuid
- description: Newest queued deployment that will run after the current operation
- site_url:
- type: string
- custom_domain:
- type: string
- description: Active custom domain hostname when configured
- custom_domain_status:
+ - revoked
+ - expired
+ description: |
+ `revoked` means the token was deliberately revoked, by you or by the
+ deletion of its project. `expired` means it simply reached
+ `expires_at`; nothing was taken away. Both are refused, and both keep
+ their record so a token's name, prefix, last use, and request history
+ remain available after a leak.
+
+ A token revoked before its expiry passed stays `revoked`, because
+ that is the fact worth keeping.
+ token_source:
type: string
- description: Current custom domain lifecycle status
enum:
- - pending_verification
- - provisioning
- - active
- - detaching
- - failed
- - deleted
- function_routes:
- type: array
- maxItems: 64
- items:
- $ref: '#/components/schemas/FrontendFunctionRoute'
- description: |
- Paths on this frontend that forward to a public function, ordered
- from most to least specific. Anyone who can load the frontend can
- reach the target function at these paths without a credential.
- last_deployed_at:
+ - api
+ - cli
+ - dashboard
+ description: What created the token.
+ expires_at:
type: string
format: date-time
- description: Recorded completion time of the most recent deploy or redeploy with status active. Omitted when no such deployment has a recorded completion time. Site traffic, pending deployments, degraded deployments, failed deployments, and deletion do not change this value.
- last_invoked_at:
+ nullable: true
+ description: Absent for a token that does not expire.
+ last_used_at:
type: string
format: date-time
+ nullable: true
+ description: Updated at most once every few minutes, so it may lag slightly.
created_at:
type: string
format: date-time
- updated_at:
- type: string
- format: date-time
+ all_time_requests:
+ type: integer
+ format: int64
+ description: Requests authenticated with this token since it was created.
required:
- id
- project_id
- name
- - framework
+ - token_prefix
+ - scope
- status
- - deployed_regions
- - function_routes
+ - token_source
- created_at
- - updated_at
- FrontendFunctionRoute:
+ - all_time_requests
+ ProjectAccessTokenScope:
+ type: string
+ description: |
+ What a project access token may do within its project.
+
+ `full` is everything you can do to that one project, up to and including
+ deleting it. It cannot manage access tokens, so a leaked token cannot
+ mint a replacement or erase the record of its own use, but for a CI or
+ agent credential that only deploys, prefer `read_only` where the job
+ allows it.
+
+ `read_only` refuses mutations. It is enforced by route classification
+ rather than HTTP method, so the log and metrics query endpoints remain
+ available even though they are POST requests that carry body filters.
+
+ `read_only` also refuses the reads that return a credential — service
+ keys, anon keys, variable values, and database connection strings. Those
+ grant write access over the project's data and keep working after the
+ token that fetched them is revoked, so returning one to a read-only
+ credential would make the scope a formality. An anon key is included
+ because its permissions are chosen per key and may include uploading,
+ deleting, and publishing.
+ enum:
+ - full
+ - read_only
+ x-enum-varnames:
+ - ProjectAccessTokenScopeFull
+ - ProjectAccessTokenScopeReadOnly
+ CreateProjectAccessTokenRequest:
type: object
- additionalProperties: false
properties:
- id:
- type: string
- format: uuid
- project_id:
- type: string
- format: uuid
- frontend_id:
- type: string
- format: uuid
- function_id:
- type: string
- format: uuid
- path_prefix:
- type: string
- minLength: 2
- maxLength: 512
- pattern: ^/[^?#\\]*[^/?#\\]$
- strip_prefix:
- type: boolean
- created_at:
+ name:
type: string
- format: date-time
- updated_at:
+ minLength: 1
+ maxLength: 100
+ description: |
+ Held by any of the project's tokens you have not revoked, including
+ one that has expired. Creating a duplicate returns 409 with code
+ `access_token_name_exists`; revoking the holder frees the name, so a
+ rotation can keep the name its caller already references.
+ scope:
+ $ref: '#/components/schemas/ProjectAccessTokenScope'
+ expires_at:
type: string
format: date-time
+ description: Omit for a token that does not expire.
required:
- - id
- - project_id
- - frontend_id
- - function_id
- - path_prefix
- - strip_prefix
- - created_at
- - updated_at
- FrontendFunctionRouteList:
+ - name
+ - scope
+ CreatedProjectAccessToken:
+ allOf:
+ - $ref: '#/components/schemas/ProjectAccessToken'
+ - type: object
+ properties:
+ token:
+ type: string
+ description: |
+ The secret. Returned only here, and not recoverable afterwards:
+ the server stores a hash rather than the value. Save it now.
+ required:
+ - token
+ PaginatedProjectAccessTokens:
type: object
- additionalProperties: false
properties:
data:
type: array
items:
- $ref: '#/components/schemas/FrontendFunctionRoute'
+ $ref: '#/components/schemas/ProjectAccessToken'
+ page:
+ type: integer
+ limit:
+ type: integer
+ total:
+ type: integer
+ has_more:
+ type: boolean
+ next:
+ type: string
required:
- data
- CreateFrontendFunctionRouteRequest:
+ - page
+ - limit
+ - total
+ - has_more
+ ProjectAccessTokenUsage:
type: object
- additionalProperties: false
+ description: |
+ Zero-filled daily request counts for a single token, oldest first. Every
+ day in the window is present, so a gap reads as zero rather than missing.
+
+ Counts every request the token authenticated, including ones then
+ refused — a read-only token attempting a write, or a token presented on
+ another project's route. That is deliberate: after a leak, the probing
+ is the part you want to see, and a counter that hid it would make a
+ token look idle while it was being tried.
properties:
- function_id:
+ token_id:
type: string
format: uuid
- path_prefix:
- type: string
- minLength: 2
- maxLength: 512
- pattern: ^/[^?#\\]*[^/?#\\]$
- strip_prefix:
- type: boolean
- default: false
- required:
- - function_id
- - path_prefix
- FrontendCustomDomainTLSConfig:
- type: object
- description: 'TLS for a new custom domain. With `mode: managed`, Volcano issues and renews the certificate; omit every PEM field. With `mode: byoc`, send both `certificate_pem` and `private_key_pem`, plus an optional `certificate_chain_pem`.'
- additionalProperties: false
- not:
- anyOf:
- - allOf:
- - properties:
- mode:
- enum:
- - managed
- required:
- - mode
- - anyOf:
- - required:
- - certificate_pem
- - required:
- - private_key_pem
- - required:
- - certificate_chain_pem
- - allOf:
- - properties:
- mode:
- enum:
- - byoc
- required:
- - mode
- - anyOf:
- - not:
- required:
- - certificate_pem
- - not:
- required:
- - private_key_pem
- properties:
- mode:
- type: string
- enum:
- - managed
- - byoc
- default: byoc
- description: managed for a Volcano-issued certificate; byoc to supply your own.
- certificate_pem:
- type: string
- maxLength: 65536
- description: PEM-encoded certificate. Required when mode is byoc; not allowed when mode is managed.
- private_key_pem:
+ name:
type: string
- maxLength: 65536
- description: PEM-encoded private key. Required when mode is byoc; not allowed when mode is managed.
- certificate_chain_pem:
+ token_prefix:
type: string
- maxLength: 65536
- description: Optional PEM-encoded certificate chain when mode is byoc; not allowed when mode is managed.
+ description: |
+ The token's display prefix, which identifies the credential when its
+ name does not. Revoking frees a name, so a project that rotated
+ `ci-deploy` has two entries here both called `ci-deploy`. Not usable
+ as a credential.
+ days:
+ type: integer
+ description: Number of daily entries returned, always equal to the requested window.
+ daily:
+ type: array
+ items:
+ $ref: '#/components/schemas/ProjectAccessTokenUsageDailyEntry'
+ total_requests:
+ type: integer
+ format: int64
required:
- - mode
- FrontendCustomDomainResponse:
+ - token_id
+ - name
+ - token_prefix
+ - days
+ - daily
+ - total_requests
+ ProjectAccessTokenUsageDailyEntry:
type: object
properties:
- domain:
- type: string
- tls_mode:
- type: string
- enum:
- - managed
- - byoc
- domain_status:
- type: string
- enum:
- - pending_verification
- - provisioning
- - active
- - detaching
- - failed
- - deleted
- verification_status:
- type: string
- enum:
- - pending
- - verified
- - failed
- description: '`verified`: the domain is served by a validated certificate. `pending`: it is not served yet, is being re-validated after its certificate material was withdrawn, or Volcano is retrying after a failure. `failed`: a failure left the domain unserved, alongside `domain_status: failed`; managed domains report the cause in `failure_reason`.'
- serving_certificate:
- type: string
- enum:
- - uploaded
- - managed
- description: 'Certificate the domain serves, present only while it is active. `uploaded`: the BYOC certificate, including after the domain switched to managed TLS and until Volcano issues the managed one; `failure_reason` then reports an issuance failure. `managed`: a certificate Volcano issued.'
- failure_reason:
- type: string
- description: Failure category, present when managed TLS setup has failed, or when issuance is failing for a domain that switched to managed TLS and still serves its uploaded certificate. Current values are provider, certificate, ownership, and internal; ownership means another account has already claimed the hostname through ownership verification. Treat unrecognized values as internal.
- verification_records:
- type: array
- description: DNS records to publish now. For a managed domain whose hostname the account already owns, the create response names the `_acme-challenge` CNAME that authorizes certificate issuance and renewal. Otherwise it names the `_volcano` TXT record that proves ownership of the hostname's registrable domain, and reads return the CNAME once Volcano sees that record. Usually empty for BYOC.
- items:
- $ref: '#/components/schemas/FrontendDomainVerificationRecord'
- required_routing_record:
- allOf:
- - $ref: '#/components/schemas/FrontendDomainRoutingRecord'
- deprecated: true
- description: Deprecated and no longer returned. Use routing_target_hostname as the DNS routing target.
- routing_target_hostname:
- type: string
- description: DNS routing target hostname for this frontend. The DNS record type depends on whether the custom domain is a zone apex.
- effective_urls:
- type: array
- items:
- type: string
- created_at:
- type: string
- format: date-time
- updated_at:
+ day:
type: string
- format: date-time
+ format: date
+ description: UTC day.
+ requests:
+ type: integer
+ format: int64
required:
- - domain
- - tls_mode
- - domain_status
- - verification_status
- - effective_urls
- - created_at
- - updated_at
- FrontendDeployment:
+ - day
+ - requests
+ Function:
type: object
properties:
id:
type: string
format: uuid
- frontend_id:
- type: string
- format: uuid
project_id:
type: string
format: uuid
- operation:
+ name:
type: string
- enum:
- - deploy
- - redeploy
- - delete
+ maxLength: 63
+ pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$
status:
type: string
- description: |
- Deployment lifecycle status. A `degraded` redeploy remains available while
- edge-only recovery is retried. A `failed` redeploy is recorded here while the
- frontend keeps serving its previous deployment.
enum:
- - queued
- provisioning
- active
- - degraded
- failed
- - superseded
- deleting
- - deleted
- deploy_source:
+ provisioning_started_at:
type: string
- enum:
- - git
- - cli
- - web
- - api
- - system
- - unknown
- description: What initiated this deployment.
- initiated_by:
+ format: date-time
+ description: Timestamp when the current provisioning phase started
+ visibility:
+ $ref: '#/components/schemas/FunctionVisibility'
+ is_public:
+ type: boolean
+ deprecated: true
+ description: Deprecated. `true` exactly when `visibility` is `public`.
+ invocation_mode:
+ $ref: '#/components/schemas/FunctionInvocationMode'
+ http_auth_mode:
+ $ref: '#/components/schemas/FunctionHTTPAuthMode'
+ openapi_spec:
+ type: object
+ nullable: true
+ additionalProperties: true
+ description: Optional OpenAPI 3.0 or 3.1 document describing an HTTP-mode function.
+ has_openapi_spec:
+ type: boolean
+ description: Whether OpenAPI metadata is configured; list responses omit the document itself.
+ invoke_url:
type: string
- description: Platform user that triggered a request-initiated deployment; absent for git and system deployments.
- site_url:
+ description: 'Canonical geo-routed HTTPS endpoint for invoking this function. Use it as-is: it does not share a domain with the API, so a host derived from the API URL will not reach the function. In local development it is `http://{id}.functions.localhost:8000/`, served by the local API. Omitted when the deployment serves no function invocation domain, so a client testing for an empty string never matches.'
+ deployed_regions:
+ type: array
+ items:
+ type: string
+ description: Regions where this function is currently deployed
+ runtime:
type: string
- build_duration_seconds:
- type: integer
- format: int64
- description: Total build time recorded for this deployment, in seconds.
- build_count:
- type: integer
- description: Number of completed builds included in build_duration_seconds.
- build_duration_recorded_at:
+ handler:
type: string
- format: date-time
- description: When the build time was last recorded.
- progress:
- $ref: '#/components/schemas/DeploymentProgress'
- error_message:
+ current_deployment_id:
+ type: string
+ format: uuid
+ description: Identifier of the latest function deployment operation
+ pending_deployment_id:
+ type: string
+ format: uuid
+ description: Newest queued deployment that will run after the current operation
+ last_invoked_at:
type: string
+ format: date-time
+ description: Most recent successful invocation timestamp
created_at:
type: string
format: date-time
@@ -21029,401 +29433,530 @@ components:
format: date-time
required:
- id
- - frontend_id
- project_id
- - operation
+ - name
- status
- - deploy_source
+ - visibility
+ - is_public
+ - invocation_mode
+ - http_auth_mode
+ - openapi_spec
+ - has_openapi_spec
+ - deployed_regions
- created_at
- updated_at
- FrontendDomainRoutingRecord:
+ DurableFunction:
type: object
+ description: |
+ A durable function. Separate from `Function` because a durable function
+ is invoked only through its own execution endpoints, so it has no
+ invocation mode, HTTP auth mode, OpenAPI document or invoke URL, and it
+ carries a `durable` configuration that a standard function has no field
+ for.
properties:
- record_type:
+ id:
type: string
- enum:
- - CNAME
+ format: uuid
+ project_id:
+ type: string
+ format: uuid
name:
type: string
- value:
+ maxLength: 63
+ pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$
+ status:
type: string
- required:
- - record_type
- - name
- - value
- FrontendDomainVerificationRecord:
- type: object
- description: The DNS records currently required. Volcano may require an account-specific TXT ownership record for the hostname's domain before returning a CNAME that authorizes managed certificate issuance and renewal. Clients must follow the records returned for the current lifecycle state instead of assuming a fixed sequence.
- properties:
- name:
+ enum:
+ - provisioning
+ - active
+ - failed
+ - deleting
+ provisioning_started_at:
type: string
- type:
+ format: date-time
+ description: Timestamp when the current provisioning phase started
+ visibility:
+ allOf:
+ - $ref: '#/components/schemas/FunctionVisibility'
+ description: |
+ Who may start executions of this function through
+ `POST /durable-functions/{functionId}/executions`, and read and stop
+ them through `GET /durable-functions/{functionId}/executions/{executionId}`
+ and its `/stop`: service keys at every level (a scoped key needs
+ `functions.invoke`), signed-in users of the project from
+ `authenticated`, and anon keys holding `functions.invoke` only at
+ `public`. On the read and stop routes a service key holding `*`,
+ the default, reaches every execution. A service key scoped to a
+ list without `*` and an anon key reach the ones whose client token
+ they send, which the start returns, and a signed-in user also the
+ ones they started. The project-scoped routes under
+ `/projects/{id}/durable-functions` take the project owner's token or
+ a project access token, whatever this is set to.
+
+ Set it when the function is deployed. Durable functions have no
+ update endpoint, so changing visibility later means redeploying.
+
+ A durable function is startable, never invocable: it is not
+ reachable through `POST /functions/{functionId}/invoke` or a
+ function URL, which answer `404` at every level.
+ is_public:
+ type: boolean
+ deprecated: true
+ description: Deprecated. `true` exactly when `visibility` is `public`.
+ durable:
+ $ref: '#/components/schemas/DurableFunctionConfig'
+ deployed_regions:
+ type: array
+ items:
+ type: string
+ description: Regions where this function is currently deployed
+ runtime:
type: string
- value:
+ handler:
type: string
- required:
- - name
- - type
- - value
- FrontendCustomDomainConflictError:
- description: 'Domain ownership conflict. With `code: ownership_verification_required`, the account has not proven it owns the domain: publish `required_record` in DNS and send the same request again. The retry succeeds once Volcano can see the record. With `code: custom_domain_releasing`, a removed domain still holds the hostname or the frontend while Volcano releases it: send the same request again after the response''s `Retry-After` seconds. A release that will not finish within a few minutes is a plain conflict. Other conflicts omit both fields.'
- allOf:
- - $ref: '#/components/schemas/Error'
- - type: object
- properties:
- required_record:
- $ref: '#/components/schemas/FrontendDomainVerificationRecord'
- FrontendUsageDailyEntry:
- type: object
- description: One day of request and error counts for a single frontend.
- properties:
- day:
+ current_deployment_id:
type: string
- format: date
- description: UTC date (YYYY-MM-DD) the counts cover.
- requests:
- type: integer
- format: int64
- description: Total requests served on this day.
- errors:
- type: integer
- format: int64
- description: 5xx responses served on this day.
- page_views:
- type: integer
- format: int64
- description: Navigable-document responses served on this day (text/html or Sec-Fetch-Dest=document) — strict subset of `requests`.
- required:
- - day
- - requests
- - errors
- - page_views
- FrontendUsageData:
- type: object
- description: Monthly frontend request totals grouped by frontend.
- properties:
- frontend_id:
+ format: uuid
+ description: Identifier of the latest deployment operation
+ pending_deployment_id:
type: string
format: uuid
- description: Frontend ID
- frontend_name:
+ description: Newest queued deployment that will run after the current operation
+ last_invoked_at:
type: string
- description: Frontend name at the time usage was fetched
- nullable: true
- requests:
- type: integer
- format: int64
- description: Total requests for this frontend in the current usage month
+ format: date-time
+ description: Most recent successful invocation timestamp
+ created_at:
+ type: string
+ format: date-time
+ updated_at:
+ type: string
+ format: date-time
required:
- - frontend_id
- - requests
- FrontendUsageHistoryResponse:
+ - id
+ - project_id
+ - name
+ - status
+ - visibility
+ - is_public
+ - durable
+ - deployed_regions
+ - created_at
+ - updated_at
+ DurableFunctionConfig:
type: object
- description: Zero-filled daily series of request + error counts for a single frontend, oldest first.
- properties:
- frontend_id:
- type: string
- format: uuid
- days:
- type: integer
- description: Number of daily entries returned (always equal to the `days` query param after clamping).
- daily:
- type: array
- items:
- $ref: '#/components/schemas/FrontendUsageDailyEntry'
- total_requests:
- type: integer
- format: int64
- total_errors:
+ description: |
+ Execution limits the function was created with, derived from the
+ project's plan. Fixed for the life of the function: changing them means
+ creating a new one.
+
+ The memory the function runs at, and the timeout on one attempt within
+ an execution, also come from the plan but are not reported here: they
+ are applied to the deployed function rather than recorded on it. Both
+ are published per plan in the plans and limits guide.
+ properties:
+ execution_timeout_seconds:
type: integer
format: int64
- total_page_views:
+ description: |
+ How long a whole execution may run, including time suspended in a
+ wait. This is not a limit on one attempt: an execution outlives any
+ single attempt by checkpointing and resuming, and the per-attempt
+ timeout is the plan's own, smaller number.
+ retention_days:
type: integer
format: int64
+ description: |
+ How long a finished execution's result and history are retained, for
+ as long as the function exists. Deleting the function, or its
+ project, ends retention early and takes the history with it. A
+ result or error Volcano has just read is kept in memory for up to
+ five minutes, so a read can still return it for up to five minutes
+ after retention ends.
required:
- - frontend_id
- - days
- - daily
- - total_requests
- - total_errors
- - total_page_views
- ProjectAccessToken:
+ - execution_timeout_seconds
+ - retention_days
+ DurableExecution:
type: object
- description: |
- A project access token: a control-plane credential bound to a single
- project. Unlike a platform token, which acts on every project its owner
- has, this one is limited to the project it was created in.
-
- The secret itself is never returned here. Only its hash is stored, so
- the plaintext exists solely in the response to the create call.
properties:
id:
type: string
format: uuid
- project_id:
+ function_id:
type: string
format: uuid
name:
type: string
- description: Unique per project.
- token_prefix:
- type: string
- description: First 12 characters of the secret, for recognising a token in a list.
- scope:
- $ref: '#/components/schemas/ProjectAccessTokenScope'
+ description: |
+ Idempotency key for the execution. Supplied by the client through
+ `X-Volcano-Execution-Name`, otherwise generated.
status:
+ $ref: '#/components/schemas/DurableExecutionStatus'
+ region:
type: string
- enum:
- - active
- - revoked
- - expired
description: |
- `revoked` means the token was deliberately revoked, by you or by the
- deletion of its project. `expired` means it simply reached
- `expires_at`; nothing was taken away. Both are refused, and both keep
- their record so a token's name, prefix, last use, and request history
- remain available after a leak.
+ Region the execution runs in. An execution is pinned to one region
+ for its whole life because its checkpoints live there.
+ result:
+ description: |
+ Whatever the function returned, verbatim. Absent while the execution
+ is still running, absent when the result was too large to return and
+ was checkpointed instead, and absent once the retention period has
+ lapsed. A result Volcano has just read can still be returned for up
+ to five minutes after that.
+ result_expired:
+ type: boolean
+ description: |
+ `true` when the execution is terminal but its result is no longer
+ retained, which distinguishes a discarded result from an empty one.
+ Shortly after that the execution itself is dropped and reads answer
+ `404`.
- A token revoked before its expiry passed stays `revoked`, because
- that is the fact worth keeping.
- token_source:
- type: string
- enum:
- - api
- - cli
- - dashboard
- description: What created the token.
- expires_at:
+ A result that was checkpointed rather than returned leaves this
+ unset, so it reads like a function that returned nothing.
+ error:
+ $ref: '#/components/schemas/DurableExecutionError'
+ created_at:
type: string
format: date-time
- nullable: true
- description: Absent for a token that does not expire.
- last_used_at:
+ completed_at:
type: string
format: date-time
- nullable: true
- description: Updated at most once every few minutes, so it may lag slightly.
- created_at:
+ description: Present once the execution has reached a terminal status.
+ client_token:
type: string
- format: date-time
- all_time_requests:
- type: integer
- format: int64
- description: Requests authenticated with this token since it was created.
+ description: |
+ Lets a browser read the execution, stop it, and read and send its
+ messages, and a service key scoped to a list without `*` do the
+ same. Returned only by the start whose input the execution runs,
+ never by a repeat under the same name or by a read. Send it as
+ `X-Volcano-Client-Token`.
required:
- id
- - project_id
+ - function_id
- name
- - token_prefix
- - scope
- status
- - token_source
+ - region
- created_at
- - all_time_requests
- ProjectAccessTokenScope:
+ DurableExecutionStatus:
type: string
+ enum:
+ - pending
+ - running
+ - succeeded
+ - failed
+ - timed_out
+ - stopped
+ - unknown
description: |
- What a project access token may do within its project.
-
- `full` is everything you can do to that one project, up to and including
- deleting it. It cannot manage access tokens, so a leaked token cannot
- mint a replacement or erase the record of its own use, but for a CI or
- agent credential that only deploys, prefer `read_only` where the job
- allows it.
-
- `read_only` refuses mutations. It is enforced by route classification
- rather than HTTP method, so the log and metrics query endpoints remain
- available even though they are POST requests that carry body filters.
+ Lifecycle state of an execution. `pending` covers the window between the
+ platform reserving the execution name and the function accepting the
+ start, and has no counterpart once the execution is under way.
+ `succeeded`, `failed`, `timed_out`, `stopped` and `unknown` are
+ terminal.
- `read_only` also refuses the reads that return a credential — service
- keys, anon keys, variable values, and database connection strings. Those
- grant write access over the project's data and keep working after the
- token that fetched them is revoked, so returning one to a read-only
- credential would make the scope a formality. An anon key is included
- because its permissions are chosen per key and may include uploading,
- deleting, and publishing.
- enum:
- - full
- - read_only
- x-enum-varnames:
- - ProjectAccessTokenScopeFull
- - ProjectAccessTokenScopeReadOnly
- CreateProjectAccessTokenRequest:
+ `unknown` means the execution's outcome cannot be established, so no
+ result or error can be given for it. Either it was under way and was
+ never seen to finish, or its start failed with a `500` without the
+ platform establishing whether the execution began — which is why a
+ name whose start returned an error can later read as `unknown` rather
+ than not being found. It is terminal because nothing can settle it
+ later, and it is rare — treat it as an outcome to retry rather than a
+ state to wait on. A retry under the same name picks this execution back
+ up instead of starting a second one, and needs a free concurrency slot
+ because an `unknown` execution has given its own up. `completed_at` on
+ an `unknown` execution is when the platform gave up, not when the work
+ ended.
+ DurableExecutionError:
+ type: object
+ description: Why a failed or timed-out execution ended.
+ properties:
+ type:
+ type: string
+ message:
+ type: string
+ DurableExecutionOperationList:
+ type: object
+ description: A durable execution's trace.
+ properties:
+ data:
+ type: array
+ description: |
+ Every operation the execution began. The execution itself comes
+ first and is the only operation without a `parent_id`; the rest
+ follow in the order they started.
+ items:
+ $ref: '#/components/schemas/DurableExecutionOperation'
+ invocations:
+ type: array
+ description: |
+ When the function's code was running, oldest first. An execution
+ suspended in a wait holds no runtime, so the gaps between these are
+ not charged as compute.
+ items:
+ $ref: '#/components/schemas/DurableExecutionInvocation'
+ complete:
+ type: boolean
+ description: |
+ `true` once the execution has finished and nothing more will be
+ recorded. Its operations no longer change, and it is no longer
+ refreshed on read; a final invocation window can still be added
+ shortly after.
+ synced_at:
+ type: string
+ format: date-time
+ description: |
+ When the trace was last refreshed. Absent before it has been
+ refreshed at all. A running execution's trace is usually within
+ about ten seconds of the execution, and further behind when many
+ executions are being watched at once.
+ required:
+ - data
+ - invocations
+ - complete
+ DurableExecutionOperation:
type: object
+ description: One operation on an execution's timeline.
properties:
+ id:
+ type: string
+ description: Identifies the operation within its execution.
+ parent_id:
+ type: string
+ description: |
+ The operation this one ran inside: a child context, map item or
+ parallel branch, or the execution itself for top-level work. Absent
+ only on the execution.
name:
type: string
- minLength: 1
- maxLength: 100
description: |
- Held by any of the project's tokens you have not revoked, including
- one that has expired. Creating a duplicate returns 409 with code
- `access_token_name_exists`; revoking the holder frees the name, so a
- rotation can keep the name its caller already references.
- scope:
- $ref: '#/components/schemas/ProjectAccessTokenScope'
- expires_at:
+ The name the handler gave the operation. Map items and parallel
+ branches the handler did not name carry the SDK's positional name,
+ such as `map-item-0`. Absent for an unnamed operation.
+ type:
+ type: string
+ enum:
+ - execution
+ - step
+ - wait
+ - callback
+ - context
+ - chained_invoke
+ description: The kind of checkpointed operation Volcano recorded.
+ kind:
+ type: string
+ enum:
+ - execution
+ - step
+ - wait
+ - wait_until
+ - callback
+ - child
+ - map
+ - map_item
+ - parallel
+ - parallel_branch
+ - invoke
+ description: |
+ The operation as the handler wrote it: `ctx.step` is `step`,
+ `ctx.wait` is `wait`, `ctx.waitUntil` is `wait_until`, `ctx.child`
+ is `child`, `ctx.map` is `map` with one `map_item` per item, and
+ `ctx.parallel` is `parallel` with one `parallel_branch` per branch.
+ status:
+ type: string
+ enum:
+ - running
+ - waiting
+ - retrying
+ - succeeded
+ - failed
+ - cancelled
+ - timed_out
+ - stopped
+ - unknown
+ description: |
+ Where the operation stands. `waiting` holds no runtime: a wait that
+ has not elapsed, or a `waitUntil` between checks. `retrying` is a step whose last attempt failed and
+ whose next one is scheduled at `next_attempt_at`. Work still open
+ when the execution ended is `cancelled` at the moment it ended.
+ `unknown` is only ever the execution itself, when its outcome was
+ lost with its history, as in the execution's own `unknown` status.
+ started_at:
type: string
format: date-time
- description: Omit for a token that does not expire.
- required:
- - name
- - scope
- CreatedProjectAccessToken:
- allOf:
- - $ref: '#/components/schemas/ProjectAccessToken'
- - type: object
- properties:
- token:
- type: string
- description: |
- The secret. Returned only here, and not recoverable afterwards:
- the server stores a hash rather than the value. Save it now.
- required:
- - token
- PaginatedProjectAccessTokens:
- type: object
- properties:
- data:
+ ended_at:
+ type: string
+ format: date-time
+ description: Present once the operation has ended.
+ scheduled_end_at:
+ type: string
+ format: date-time
+ description: When a wait is due to elapse.
+ next_attempt_at:
+ type: string
+ format: date-time
+ description: |
+ When a step's next attempt, or a `waitUntil`'s next check, is due.
+ Present only while one is scheduled.
+ attempts:
type: array
+ description: |
+ Each run of a step's body, in order. Present on steps and
+ `waitUntil` polls, where each check is an attempt.
items:
- $ref: '#/components/schemas/ProjectAccessToken'
- page:
- type: integer
- limit:
- type: integer
- total:
- type: integer
- has_more:
- type: boolean
- next:
- type: string
+ $ref: '#/components/schemas/DurableExecutionOperationAttempt'
+ error:
+ $ref: '#/components/schemas/DurableExecutionError'
required:
- - data
- - page
- - limit
- - total
- - has_more
- ProjectAccessTokenUsage:
+ - id
+ - type
+ - kind
+ - status
+ - started_at
+ DurableExecutionOperationAttempt:
type: object
- description: |
- Zero-filled daily request counts for a single token, oldest first. Every
- day in the window is present, so a gap reads as zero rather than missing.
-
- Counts every request the token authenticated, including ones then
- refused — a read-only token attempting a write, or a token presented on
- another project's route. That is deliberate: after a leak, the probing
- is the part you want to see, and a counter that hid it would make a
- token look idle while it was being tried.
+ description: One run of a step's body.
properties:
- token_id:
+ attempt:
+ type: integer
+ minimum: 1
+ description: The attempt's number, starting at 1.
+ status:
type: string
- format: uuid
- name:
+ enum:
+ - running
+ - succeeded
+ - failed
+ description: |
+ How the attempt ended. A `waitUntil` check whose condition did not
+ hold yet is `succeeded`: the check ran, and the poll continues.
+ started_at:
type: string
- token_prefix:
+ format: date-time
+ ended_at:
type: string
- description: |
- The token's display prefix, which identifies the credential when its
- name does not. Revoking frees a name, so a project that rotated
- `ci-deploy` has two entries here both called `ci-deploy`. Not usable
- as a credential.
- days:
- type: integer
- description: Number of daily entries returned, always equal to the requested window.
- daily:
- type: array
- items:
- $ref: '#/components/schemas/ProjectAccessTokenUsageDailyEntry'
- total_requests:
- type: integer
- format: int64
+ format: date-time
+ description: Present once the attempt has ended.
+ error:
+ $ref: '#/components/schemas/DurableExecutionError'
required:
- - token_id
- - name
- - token_prefix
- - days
- - daily
- - total_requests
- ProjectAccessTokenUsageDailyEntry:
+ - attempt
+ - status
+ - started_at
+ DurableExecutionInvocation:
type: object
+ description: A window in which the function's code was running.
properties:
- day:
+ started_at:
type: string
- format: date
- description: UTC day.
- requests:
- type: integer
- format: int64
+ format: date-time
+ ended_at:
+ type: string
+ format: date-time
required:
- - day
- - requests
- Function:
+ - started_at
+ - ended_at
+ FunctionInvocationMode:
+ type: string
+ enum:
+ - rpc
+ - http
+ description: |
+ Invocation contract. `rpc` preserves the existing POST `{payload: ...}` contract;
+ `http` forwards HTTP request semantics to the function runtime.
+ FunctionHTTPAuthMode:
+ type: string
+ enum:
+ - volcano
+ - none
+ description: |
+ Authentication applied by the HTTP ingress. `none` is valid only for
+ HTTP-mode functions with `visibility: public` and is intended for
+ externally signed webhooks.
+ FunctionVisibility:
+ type: string
+ enum:
+ - private
+ - authenticated
+ - public
+ x-enum-varnames:
+ - FunctionVisibilityPrivate
+ - FunctionVisibilityAuthenticated
+ - FunctionVisibilityPublic
+ description: |
+ Who can invoke the function. Each level admits everything the one
+ before it does.
+ - `private`: service keys and the project's schedulers only. The
+ default for a new function. To any other credential the function
+ does not exist: it answers 404, like a missing one.
+ - `authenticated`: also any signed-in user of the project, including
+ anonymous sign-ins. The function receives their auth context.
+ - `public`: also anon keys holding `functions.invoke`, and Frontend
+ Function routes, which forward requests without a credential.
+ FunctionDeployment:
type: object
properties:
id:
type: string
format: uuid
+ function_id:
+ type: string
+ format: uuid
project_id:
type: string
format: uuid
- name:
+ batch_id:
type: string
- maxLength: 63
- pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$
+ format: uuid
+ operation:
+ type: string
+ enum:
+ - deploy
+ - update
+ - delete
status:
type: string
enum:
+ - queued
- provisioning
- active
- failed
+ - superseded
- deleting
- provisioning_started_at:
- type: string
- format: date-time
- description: Timestamp when the current provisioning phase started
- visibility:
- $ref: '#/components/schemas/FunctionVisibility'
- is_public:
- type: boolean
- deprecated: true
- description: Deprecated. `true` exactly when `visibility` is `public`.
- invocation_mode:
- $ref: '#/components/schemas/FunctionInvocationMode'
- http_auth_mode:
- $ref: '#/components/schemas/FunctionHTTPAuthMode'
- openapi_spec:
- type: object
- nullable: true
- additionalProperties: true
- description: Optional OpenAPI 3.0 or 3.1 document describing an HTTP-mode function.
- has_openapi_spec:
- type: boolean
- description: Whether OpenAPI metadata is configured; list responses omit the document itself.
- invoke_url:
- type: string
- description: 'Canonical geo-routed HTTPS endpoint for invoking this function. Use it as-is: it does not share a domain with the API, so a host derived from the API URL will not reach the function. Omitted when the deployment serves no public invocation domain, as in local development, so a client testing for an empty string never matches.'
- deployed_regions:
- type: array
- items:
- type: string
- description: Regions where this function is currently deployed
- runtime:
+ - deleted
+ deploy_source:
type: string
- handler:
+ enum:
+ - git
+ - cli
+ - web
+ - api
+ - system
+ - unknown
+ description: What initiated this deployment.
+ initiated_by:
type: string
- current_deployment_id:
+ description: Platform user that triggered a request-initiated deployment; absent for git and system deployments.
+ commit:
+ $ref: '#/components/schemas/DeploymentCommit'
+ build_duration_seconds:
+ type: integer
+ format: int64
+ description: Total build time recorded for this deployment, in seconds.
+ build_count:
+ type: integer
+ description: Number of completed builds included in build_duration_seconds.
+ build_duration_recorded_at:
type: string
- format: uuid
- description: Identifier of the latest function deployment operation
- pending_deployment_id:
+ format: date-time
+ description: When the build time was last recorded.
+ progress:
+ $ref: '#/components/schemas/DeploymentProgress'
+ error_message:
type: string
- format: uuid
- description: Newest queued deployment that will run after the current operation
- last_invoked_at:
+ completed_at:
type: string
format: date-time
- description: Most recent successful invocation timestamp
created_at:
type: string
format: date-time
@@ -21432,1841 +29965,2668 @@ components:
format: date-time
required:
- id
+ - function_id
- project_id
- - name
+ - operation
- status
- - visibility
- - is_public
- - invocation_mode
- - http_auth_mode
- - openapi_spec
- - has_openapi_spec
- - deployed_regions
+ - deploy_source
- created_at
- updated_at
- DurableFunction:
+ FunctionInvocationRequest:
type: object
- description: |
- A durable function. Separate from `Function` because a durable function
- is invoked only through its own execution endpoints, so it has no
- invocation mode, HTTP auth mode, OpenAPI document or invoke URL, and it
- carries a `durable` configuration that a standard function has no field
- for.
properties:
- id:
+ payload:
+ type: object
+ additionalProperties: true
+ description: |
+ Payload to send to the function.
+
+ If invoked with auth user token, Volcano automatically injects `__volcano_auth` context:
+ ```javascript
+ {
+ ...yourPayload,
+ __volcano_auth: {
+ user_id: "uuid",
+ email: "user@example.com",
+ project_id: "uuid",
+ role: "authenticated" | "anonymous"
+ }
+ }
+ ```
+
+ The top-level `__volcano_auth` and `__volcano_http` keys are reserved;
+ Volcano removes caller-supplied values for both.
+ FunctionInvocationResponse:
+ type: object
+ description: Raw function response body returned by the invoked function.
+ additionalProperties: true
+ LogActivityBucket:
+ type: object
+ description: Log-event counts for one activity time bucket. The first and last buckets can extend past the requested window; they count only events inside it.
+ properties:
+ start_time:
type: string
- format: uuid
- project_id:
+ format: date-time
+ description: Bucket start time, inclusive.
+ end_time:
type: string
- format: uuid
- name:
+ format: date-time
+ description: Bucket end time, exclusive.
+ counts:
+ type: object
+ description: Counts grouped by activity dimension.
+ properties:
+ levels:
+ type: object
+ additionalProperties:
+ type: integer
+ description: Counts by normalized log level.
+ regions:
+ type: object
+ additionalProperties:
+ type: integer
+ description: Counts by event region.
+ resource_ids:
+ type: object
+ additionalProperties:
+ type: integer
+ description: Counts by resource ID.
+ required:
+ - levels
+ - regions
+ - resource_ids
+ total:
+ type: integer
+ description: Total events in this bucket.
+ required:
+ - start_time
+ - end_time
+ - counts
+ - total
+ LogActivityRequest:
+ type: object
+ description: Activity request for bucketed log counts.
+ additionalProperties: false
+ properties:
+ resource:
+ $ref: '#/components/schemas/LogRequestResource'
+ q:
type: string
- maxLength: 63
- pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$
- status:
+ maxLength: 512
+ description: Optional activity query. Supports quoted text, implicit AND, AND/OR/NOT, parentheses, and fields such as `level`, `region`, `invocation.id`, `resource.id`, `resource.name`, `function`, `frontend`, `database`, and `body`.
+ start_time:
type: string
- enum:
- - provisioning
- - active
- - failed
- - deleting
- provisioning_started_at:
+ format: date-time
+ description: Start of the window, inclusive. Defaults to 24 hours before `end_time`.
+ end_time:
type: string
format: date-time
- description: Timestamp when the current provisioning phase started
- visibility:
- allOf:
- - $ref: '#/components/schemas/FunctionVisibility'
- description: |
- Who may start executions of this function through
- `POST /durable-functions/{functionId}/executions`: service keys at
- every level, signed-in users of the project from `authenticated`,
- and anon keys holding `functions.invoke` only at `public`. Reading
- and stopping an execution always require the project owner's
- token, whatever this is set to.
-
- Set it when the function is deployed. Durable functions have no
- update endpoint, so changing visibility later means redeploying.
-
- A durable function is startable, never invocable: it is not
- reachable through `POST /functions/{functionId}/invoke` or a
- function URL, which answer `404` at every level.
- is_public:
- type: boolean
- deprecated: true
- description: Deprecated. `true` exactly when `visibility` is `public`.
- durable:
- $ref: '#/components/schemas/DurableFunctionConfig'
- deployed_regions:
+ description: End of the window, exclusive. Defaults to now.
+ bucket_count:
+ type: integer
+ minimum: 1
+ maximum: 96
+ description: Maximum number of buckets. Defaults to 24. Volcano picks the smallest bucket width from 1s, 2s, 5s, 10s, 15s, 30s, 1m, 2m, 5m, 10m, 15m, 30m, 1h, 2h, 3h, 6h, 12h, 1d, or a whole number of days that covers the window in at most this many buckets. Bucket edges fall on UTC multiples of the width, so they stay fixed as the window moves, and the response can contain fewer buckets. `1` returns one bucket that spans exactly the window.
+ required:
+ - resource
+ LogActivityResponse:
+ type: object
+ description: Bucketed runtime log activity.
+ properties:
+ data:
type: array
items:
- type: string
- description: Regions where this function is currently deployed
- runtime:
+ $ref: '#/components/schemas/LogActivityBucket'
+ total:
+ type: integer
+ description: Total events counted across all buckets.
+ required:
+ - data
+ - total
+ LogSearchRequest:
+ type: object
+ description: Search request for project logs.
+ additionalProperties: false
+ properties:
+ resource:
+ $ref: '#/components/schemas/LogRequestResource'
+ q:
+ type: string
+ maxLength: 512
+ description: Optional log query. Supports quoted text, implicit AND, AND/OR/NOT, parentheses, and fields such as `level`, `region`, `invocation.id`, `resource.id`, `resource.name`, `function`, `frontend`, `database`, and `body`.
+ start_time:
+ type: string
+ format: date-time
+ description: Start time.
+ end_time:
+ type: string
+ format: date-time
+ description: End time.
+ limit:
+ type: integer
+ minimum: 1
+ maximum: 1000
+ default: 100
+ description: Maximum number of records to return.
+ cursor:
+ type: string
+ description: Opaque pagination cursor from the previous response's `next_cursor`.
+ required:
+ - resource
+ LogStreamRequest:
+ type: object
+ description: Stream request for live project logs. Pagination cursors and fixed end times are not supported.
+ additionalProperties: false
+ properties:
+ resource:
+ $ref: '#/components/schemas/LogRequestResource'
+ q:
+ type: string
+ maxLength: 512
+ description: Optional log query using the same syntax as search and activity requests.
+ start_time:
+ type: string
+ format: date-time
+ description: Start time.
+ limit:
+ type: integer
+ minimum: 1
+ maximum: 1000
+ default: 100
+ description: Maximum number of records to deliver on connect or reconnect before following new events.
+ required:
+ - resource
+ LogSearchEvent:
+ allOf:
+ - $ref: '#/components/schemas/LogEvent'
+ - type: object
+ description: Runtime log event returned by project log search. Search results always include a stable event ID and owning resource.
+ properties:
+ id:
+ type: string
+ description: Opaque stable log event ID for pagination, deduplication, and display.
+ resource:
+ $ref: '#/components/schemas/LogResource'
+ required:
+ - id
+ - resource
+ LogSearchResponse:
+ type: object
+ description: Paginated project runtime log search response.
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/LogSearchEvent'
+ description: Array of log events sorted by timestamp, newest first.
+ limit:
+ type: integer
+ description: Number of items requested per page.
+ has_more:
+ type: boolean
+ description: Whether the search may have more matching log events. A page can hold fewer than `limit` events, or none, while this is true; keep paging until it is false.
+ next_cursor:
type: string
- handler:
+ description: Opaque cursor for the next page, present while `has_more` is true. Send this value as `cursor` on the next request, even when `data` is empty.
+ required:
+ - data
+ - limit
+ - has_more
+ FunctionRegion:
+ type: object
+ required:
+ - code
+ - label
+ - flag
+ properties:
+ code:
type: string
- current_deployment_id:
+ example: us-east-1
+ description: Region identifier accepted by function APIs.
+ label:
type: string
- format: uuid
- description: Identifier of the latest deployment operation
- pending_deployment_id:
+ example: NA-East
+ description: Human-readable region label suitable for display in pickers.
+ flag:
type: string
- format: uuid
- description: Newest queued deployment that will run after the current operation
- last_invoked_at:
+ example: 🇺🇸
+ description: Country flag emoji associated with the region's geography.
+ FunctionRuntimeOption:
+ type: object
+ required:
+ - name
+ - label
+ - language
+ - default
+ - durable_capable
+ - deployment
+ properties:
+ name:
type: string
- format: date-time
- description: Most recent successful invocation timestamp
- created_at:
+ example: nodejs24.x
+ description: Runtime identifier accepted by function APIs.
+ label:
type: string
- format: date-time
- updated_at:
+ example: Node.js 24
+ description: Human-readable runtime label suitable for display in pickers.
+ language:
type: string
- format: date-time
+ example: nodejs
+ description: Runtime language family used by the CLI to choose defaults from source files.
+ default:
+ type: boolean
+ description: Whether this runtime is the CLI default for its language.
+ durable_capable:
+ type: boolean
+ description: Whether a durable function can be authored on this runtime. Only runtimes with a durable authoring API report true, and a durable deploy naming any other runtime is rejected.
+ deployment:
+ $ref: '#/components/schemas/FunctionRuntimeDeployment'
+ FunctionRuntimesResponse:
+ type: object
required:
- - id
- - project_id
- - name
- - status
- - visibility
- - is_public
+ - runtimes
+ properties:
+ runtimes:
+ type: array
+ items:
+ $ref: '#/components/schemas/FunctionRuntimeOption'
+ FunctionKindFilter:
+ type: string
+ enum:
+ - standard
- durable
- - deployed_regions
- - created_at
- - updated_at
- DurableFunctionConfig:
- type: object
description: |
- Execution limits the function was created with, derived from the
- project's plan. Fixed for the life of the function: changing them means
- creating a new one.
-
- The memory the function runs at, and the timeout on one attempt within
- an execution, also come from the plan but are not reported here: they
- are applied to the deployed function rather than recorded on it. Both
- are published per plan in the plans and limits guide.
- properties:
- execution_timeout_seconds:
- type: integer
- format: int64
- description: |
- How long a whole execution may run, including time suspended in a
- wait. This is not a limit on one attempt: an execution outlives any
- single attempt by checkpointing and resuming, and the per-attempt
- timeout is the plan's own, smaller number.
- retention_days:
- type: integer
- format: int64
- description: |
- How long a finished execution's result and history are retained, for
- as long as the function exists. Deleting the function, or its
- project, ends retention early and takes the history with it.
- required:
- - execution_timeout_seconds
- - retention_days
- DurableExecution:
+ A function kind to filter a list by. Unlike `FunctionKind` it has no
+ default: omitting the filter includes both kinds.
+ x-enum-varnames:
+ - FunctionKindFilterStandard
+ - FunctionKindFilterDurable
+ FunctionScheduler:
type: object
properties:
id:
type: string
format: uuid
- function_id:
+ project_id:
type: string
format: uuid
- name:
+ function_id:
type: string
+ format: uuid
+ function_kind:
+ allOf:
+ - $ref: '#/components/schemas/FunctionKind'
description: |
- Idempotency key for the execution. Supplied by the client through
- `X-Volcano-Execution-Name`, otherwise generated.
- status:
- $ref: '#/components/schemas/DurableExecutionStatus'
- region:
+ Which collection the scheduled function belongs to. A project-wide
+ scheduler list mixes both kinds, and this is what says whether the
+ function is read back from `/projects/{id}/functions` or
+ `/projects/{id}/durable-functions` — and whether a tick invokes it
+ or starts a durable execution.
+ name:
type: string
- description: |
- Region the execution runs in. An execution is pinned to one region
- for its whole life because its checkpoints live there.
- result:
- description: |
- Whatever the function returned, verbatim. Absent while the execution
- is still running, absent when the result was too large to return and
- was checkpointed instead, and absent once the retention period has
- lapsed.
- result_expired:
+ enabled:
type: boolean
- description: |
- `true` when the execution is terminal but its result is no longer
- retained, which distinguishes a discarded result from an empty one.
- Shortly after that the execution itself is dropped and reads answer
- `404`.
-
- A result that was checkpointed rather than returned leaves this
- unset, so it reads like a function that returned nothing.
- error:
- $ref: '#/components/schemas/DurableExecutionError'
- created_at:
- type: string
- format: date-time
- completed_at:
- type: string
- format: date-time
- description: Present once the execution has reached a terminal status.
- client_token:
- type: string
- description: |
- Lets a browser read and send the execution's messages. Returned only
- by the start whose input the execution runs, never by a repeat under
- the same name or by a read. Send it as `X-Volcano-Client-Token`.
- required:
- - id
- - function_id
- - name
- - status
- - region
- - created_at
- DurableExecutionStatus:
- type: string
- enum:
- - pending
- - running
- - succeeded
- - failed
- - timed_out
- - stopped
- - unknown
- description: |
- Lifecycle state of an execution. `pending` covers the window between the
- platform reserving the execution name and the function accepting the
- start, and has no counterpart once the execution is under way.
- `succeeded`, `failed`, `timed_out`, `stopped` and `unknown` are
- terminal.
-
- `unknown` means the execution's outcome cannot be established, so no
- result or error can be given for it. Either it was under way and was
- never seen to finish, or its start failed with a `500` without the
- platform establishing whether the execution began — which is why a
- name whose start returned an error can later read as `unknown` rather
- than not being found. It is terminal because nothing can settle it
- later, and it is rare — treat it as an outcome to retry rather than a
- state to wait on. A retry under the same name picks this execution back
- up instead of starting a second one, and needs a free concurrency slot
- because an `unknown` execution has given its own up. `completed_at` on
- an `unknown` execution is when the platform gave up, not when the work
- ended.
- DurableExecutionError:
- type: object
- description: Why a failed or timed-out execution ended.
- properties:
- type:
+ schedule_kind:
type: string
- message:
+ enum:
+ - cron
+ cron_expression:
type: string
- DurableExecutionOperationList:
- type: object
- description: A durable execution's trace.
- properties:
- data:
- type: array
- description: |
- Every operation the execution began. The execution itself comes
- first and is the only operation without a `parent_id`; the rest
- follow in the order they started.
- items:
- $ref: '#/components/schemas/DurableExecutionOperation'
- invocations:
+ payload:
+ type: object
+ additionalProperties: true
+ regions:
type: array
- description: |
- When the function's code was running, oldest first. An execution
- suspended in a wait holds no runtime, so the gaps between these are
- not charged as compute.
items:
- $ref: '#/components/schemas/DurableExecutionInvocation'
- complete:
+ type: string
+ regions_explicit:
type: boolean
- description: |
- `true` once the execution has finished and nothing more will be
- recorded. Its operations no longer change, and it is no longer
- refreshed on read; a final invocation window can still be added
- shortly after.
- synced_at:
+ next_run_at:
type: string
format: date-time
- description: |
- When the trace was last refreshed. Absent before it has been
- refreshed at all. A running execution's trace is usually within
- about ten seconds of the execution, and further behind when many
- executions are being watched at once.
- required:
- - data
- - invocations
- - complete
- DurableExecutionOperation:
- type: object
- description: One operation on an execution's timeline.
- properties:
- id:
- type: string
- description: Identifies the operation within its execution.
- parent_id:
+ last_started_at:
type: string
- description: |
- The operation this one ran inside: a child context, map item or
- parallel branch, or the execution itself for top-level work. Absent
- only on the execution.
- name:
+ format: date-time
+ last_completed_at:
type: string
- description: |
- The name the handler gave the operation. Map items and parallel
- branches the handler did not name carry the SDK's positional name,
- such as `map-item-0`. Absent for an unnamed operation.
- type:
+ format: date-time
+ last_error:
type: string
- enum:
- - execution
- - step
- - wait
- - callback
- - context
- - chained_invoke
- description: The kind of checkpointed operation Volcano recorded.
- kind:
+ run_count:
+ type: integer
+ format: int64
+ description: Total number of times this scheduler has executed. 0 for a scheduler that has never run.
+ health:
type: string
enum:
- - execution
- - step
- - wait
- - wait_until
- - callback
- - child
- - map
- - map_item
- - parallel
- - parallel_branch
- - invoke
- description: |
- The operation as the handler wrote it: `ctx.step` is `step`,
- `ctx.wait` is `wait`, `ctx.waitUntil` is `wait_until`, `ctx.child`
- is `child`, `ctx.map` is `map` with one `map_item` per item, and
- `ctx.parallel` is `parallel` with one `parallel_branch` per branch.
- status:
+ - healthy
+ - failing
+ description: '`failing` while `consecutive_failures` is above 0; `healthy` otherwise, including before its first run in the region the scheduler runs in now. A run from a region it moved away from does not count. For a durable function a run finishes when its execution does, so a run that starts but then fails counts as failed.'
+ consecutive_failures:
+ type: integer
+ format: int64
+ minimum: 0
+ description: How many runs in a row have failed in the region the scheduler runs in now. Resets to 0 when a run succeeds, and starts at 0 in a region it moves to.
+ last_run_status:
type: string
enum:
- - running
- - waiting
- - retrying
- succeeded
- failed
- - cancelled
- - timed_out
- - stopped
- - unknown
- description: |
- Where the operation stands. `waiting` holds no runtime: a wait that
- has not elapsed, or a `waitUntil` between checks. `retrying` is a step whose last attempt failed and
- whose next one is scheduled at `next_attempt_at`. Work still open
- when the execution ended is `cancelled` at the moment it ended.
- `unknown` is only ever the execution itself, when its outcome was
- lost with its history, as in the execution's own `unknown` status.
- started_at:
+ description: Outcome of the most recent finished run. Absent before the first.
+ last_success_at:
type: string
format: date-time
- ended_at:
+ description: When the most recent successful run finished.
+ last_failure_at:
type: string
format: date-time
- description: Present once the operation has ended.
- scheduled_end_at:
+ description: When the most recent failed run finished.
+ created_at:
type: string
format: date-time
- description: When a wait is due to elapse.
- next_attempt_at:
+ updated_at:
type: string
format: date-time
- description: |
- When a step's next attempt, or a `waitUntil`'s next check, is due.
- Present only while one is scheduled.
- attempts:
+ FunctionSchedulerListResponse:
+ type: object
+ properties:
+ data:
type: array
- description: |
- Each run of a step's body, in order. Present on steps and
- `waitUntil` polls, where each check is an attempt.
items:
- $ref: '#/components/schemas/DurableExecutionOperationAttempt'
- error:
- $ref: '#/components/schemas/DurableExecutionError'
+ $ref: '#/components/schemas/FunctionScheduler'
+ page:
+ type: integer
+ limit:
+ type: integer
+ total:
+ type: integer
+ has_more:
+ type: boolean
+ next_cursor:
+ type: string
+ description: Opaque cursor for the next page (cursor pagination only; present if has_more is true)
+ prev_cursor:
+ type: string
+ description: Opaque cursor for the previous page (cursor pagination only; present when a previous page exists). Send as `ending_before`.
required:
- - id
- - type
- - kind
- - status
- - started_at
- DurableExecutionOperationAttempt:
+ - data
+ - page
+ - limit
+ - total
+ - has_more
+ HostedAuthPageType:
+ type: string
+ enum:
+ - login
+ - signup
+ - forgot-password
+ - device
+ - verify-email
+ - reset-password
+ HostedLoginEmailCheckRequest:
type: object
- description: One run of a step's body.
+ required:
+ - email
properties:
- attempt:
- type: integer
- minimum: 1
- description: The attempt's number, starting at 1.
- status:
+ email:
type: string
- enum:
- - running
- - succeeded
- - failed
- description: |
- How the attempt ended. A `waitUntil` check whose condition did not
- hold yet is `succeeded`: the check ran, and the poll continues.
- started_at:
+ format: email
+ HostedLoginEmailCheckResponse:
+ type: object
+ properties:
+ exists:
+ type: boolean
+ HostedLoginOptionsResponse:
+ type: object
+ properties:
+ require_email_confirmation:
+ type: boolean
+ email_password_enabled:
+ type: boolean
+ enable_signup:
+ type: boolean
+ post_auth_redirect_url:
type: string
- format: date-time
- ended_at:
+ oauth_providers:
+ type: array
+ items:
+ type: string
+ HostedRenderablePageType:
+ type: string
+ enum:
+ - signup
+ - forgot-password
+ - device
+ - verify-email
+ - reset-password
+ LogEvent:
+ type: object
+ description: Historical log event returned by log APIs.
+ properties:
+ id:
+ type: string
+ description: Opaque stable log event ID for pagination, deduplication, and display.
+ timestamp:
type: string
format: date-time
- description: Present once the attempt has ended.
- error:
- $ref: '#/components/schemas/DurableExecutionError'
+ description: Event timestamp.
+ level:
+ $ref: '#/components/schemas/LiveLogLevel'
+ body:
+ description: Application log value. JSON arguments retain their JSON type. Strings containing a serialized JSON object or array are normalized to that object or array; all other strings remain strings.
+ nullable: true
+ oneOf:
+ - type: string
+ - type: object
+ additionalProperties: true
+ - type: array
+ items: {}
+ - type: number
+ format: double
+ - type: boolean
+ region:
+ type: string
+ description: Region where this log event originated.
+ resource:
+ $ref: '#/components/schemas/LogResource'
+ deployment:
+ $ref: '#/components/schemas/LogDeployment'
+ invocation_id:
+ type: string
+ description: Function invocation ID associated with this log event, when available.
required:
- - attempt
- - status
- - started_at
- DurableExecutionInvocation:
+ - timestamp
+ - body
+ LiveLogLevel:
+ type: string
+ enum:
+ - trace
+ - debug
+ - info
+ - warn
+ - error
+ - fatal
+ description: Canonical lowercase function runtime log level.
+ MetricUsageData:
type: object
- description: A window in which the function's code was running.
+ description: Usage data for one metric across totals, daily, and hourly windows.
properties:
- started_at:
- type: string
- format: date-time
- ended_at:
+ metric:
type: string
- format: date-time
+ description: |
+ Metric name (for example, "Function & Frontend Invocations", "Frontend Requests",
+ "Durable Executions", "Durable Operations", "Durable Compute (MB-Seconds)",
+ "Build Seconds",
+ "Bandwidth Ingress (Bytes)", "Bandwidth Egress (Bytes)",
+ "Bandwidth Total (Bytes)", or "Database Storage (Bytes)"). Byte-based metrics are
+ reported in bytes. "Bandwidth Total (Bytes)" is derived (ingress + egress) and
+ is not billed separately. The three durable metrics are
+ counted separately from "Function & Frontend Invocations", which covers standard
+ invocations only. Operations and compute are counted when an execution finishes,
+ so they appear in the window the execution completed in rather than the one it
+ started in. "Durable Compute (MB-Seconds)" reports the memory the execution ran
+ at times the time it spent running, in megabyte-seconds; the allowance for it is
+ published in gigabyte-seconds, which is 1024 of these.
+ "Sandbox Running (MiB-Seconds)", "Sandbox Suspended (Seconds)", and
+ "Sandbox Uncertain (MiB-Seconds)" report cloud Sandbox usage. Running
+ reports configured baseline memory times confirmed runtime, not measured
+ CPU or elastic memory consumption. For sessions admitted after the pricing
+ release, confirmed running time consumes the account's runtime allowance;
+ SUPERAGENT overage debits credits according to the account's pricing terms.
+ Suspended time and uncertain usage do not consume runtime allowance or
+ debit credits. Uncertain includes observation gaps and unconfirmed state
+ transitions. Suspended reports duration, not snapshot size; snapshot costs
+ are included in runtime pricing. Local and platform image-validation
+ sessions do not contribute. Existing preview sessions remain unbilled,
+ and preview history is never charged retroactively. Displayed totals are
+ rounded down after aggregating millisecond measurements; billing uses
+ unrounded measurements in the monthly account billing cycle.
+ "Database Storage (Bytes)" is a current observed gauge,
+ not a cumulative counter. It is the sum of the latest samples exposed as
+ `storage_bytes` by the project's database list, so it includes what each
+ database's branches and backups hold, and it inherits that field's lag
+ behind a live measurement.
+ total:
+ type: integer
+ format: int64
+ description: Total usage for the current usage month
+ all_time:
+ type: integer
+ format: int64
+ description: Lifetime cumulative usage across every month for this metric
+ daily:
+ type: array
+ description: Last 30 days of daily usage points
+ items:
+ $ref: '#/components/schemas/UsageDataPoint'
+ hourly:
+ type: array
+ description: Last 24 hours of hourly usage points
+ items:
+ $ref: '#/components/schemas/UsageDataPoint'
required:
- - started_at
- - ended_at
- FunctionInvocationMode:
- type: string
- enum:
- - rpc
- - http
- description: |
- Invocation contract. `rpc` preserves the existing POST `{payload: ...}` contract;
- `http` forwards HTTP request semantics to the function runtime.
- FunctionHTTPAuthMode:
- type: string
- enum:
- - volcano
- - none
- description: |
- Authentication applied by the HTTP ingress. `none` is valid only for
- HTTP-mode functions with `visibility: public` and is intended for
- externally signed webhooks.
- FunctionVisibility:
- type: string
- enum:
- - private
- - authenticated
- - public
- x-enum-varnames:
- - FunctionVisibilityPrivate
- - FunctionVisibilityAuthenticated
- - FunctionVisibilityPublic
- description: |
- Who can invoke the function. Each level admits everything the one
- before it does.
- - `private`: service keys and the project's schedulers only. The
- default for a new function. To any other credential the function
- does not exist: it answers 404, like a missing one.
- - `authenticated`: also any signed-in user of the project, including
- anonymous sign-ins. The function receives their auth context.
- - `public`: also anon keys holding `functions.invoke`, and Frontend
- Function routes, which forward requests without a credential.
- FunctionDeployment:
+ - metric
+ - total
+ - all_time
+ - daily
+ - hourly
+ OAuthConfig:
type: object
properties:
id:
type: string
format: uuid
- function_id:
- type: string
- format: uuid
- project_id:
- type: string
- format: uuid
- batch_id:
- type: string
- format: uuid
- operation:
- type: string
- enum:
- - deploy
- - update
- - delete
- status:
- type: string
- enum:
- - queued
- - provisioning
- - active
- - failed
- - superseded
- - deleting
- - deleted
- deploy_source:
+ provider:
type: string
enum:
- - git
- - cli
- - web
- - api
- - system
- - unknown
- description: What initiated this deployment.
- initiated_by:
- type: string
- description: Platform user that triggered a request-initiated deployment; absent for git and system deployments.
- build_duration_seconds:
- type: integer
- format: int64
- description: Total build time recorded for this deployment, in seconds.
- build_count:
- type: integer
- description: Number of completed builds included in build_duration_seconds.
- build_duration_recorded_at:
+ - google
+ - github
+ - microsoft
+ - apple
+ - device
+ client_id:
type: string
- format: date-time
- description: When the build time was last recorded.
- progress:
- $ref: '#/components/schemas/DeploymentProgress'
- error_message:
+ example: 123456789.apps.googleusercontent.com
+ client_secret:
type: string
- completed_at:
+ description: Masked in responses (shows only first/last 4 chars)
+ example: GOCS...****
+ enabled:
+ type: boolean
+ redirect_url:
type: string
- format: date-time
+ format: uri
+ example: https://yourapp.com/auth/callback
+ scopes:
+ type: array
+ items:
+ type: string
+ example:
+ - openid
+ - email
+ - profile
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
- required:
- - id
- - function_id
- - project_id
- - operation
- - status
- - deploy_source
- - created_at
- - updated_at
- FunctionInvocationRequest:
- type: object
- properties:
- payload:
- type: object
- additionalProperties: true
- description: |
- Payload to send to the function.
-
- If invoked with auth user token, Volcano automatically injects `__volcano_auth` context:
- ```javascript
- {
- ...yourPayload,
- __volcano_auth: {
- user_id: "uuid",
- email: "user@example.com",
- project_id: "uuid",
- role: "authenticated" | "anonymous"
- }
- }
- ```
-
- The top-level `__volcano_auth` and `__volcano_http` keys are reserved;
- Volcano removes caller-supplied values for both.
- FunctionInvocationResponse:
- type: object
- description: Raw function response body returned by the invoked function.
- additionalProperties: true
- LogActivityBucket:
+ OAuthErrorResponse:
type: object
- description: Log-event counts for one activity time bucket. The first and last buckets can extend past the requested window; they count only events inside it.
properties:
- start_time:
+ error:
type: string
- format: date-time
- description: Bucket start time, inclusive.
- end_time:
+ error_description:
type: string
- format: date-time
- description: Bucket end time, exclusive.
- counts:
- type: object
- description: Counts grouped by activity dimension.
- properties:
- levels:
- type: object
- additionalProperties:
- type: integer
- description: Counts by normalized log level.
- regions:
- type: object
- additionalProperties:
- type: integer
- description: Counts by event region.
- resource_ids:
- type: object
- additionalProperties:
- type: integer
- description: Counts by resource ID.
- required:
- - levels
- - regions
- - resource_ids
+ required:
+ - error
+ PaginatedAuthUsers:
+ type: object
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/AuthUser'
+ page:
+ type: integer
+ description: Current page number (1-indexed)
+ limit:
+ type: integer
+ description: Number of items per page
total:
type: integer
- description: Total events in this bucket.
+ description: Total number of items across all pages
+ has_more:
+ type: boolean
+ description: Whether there are more pages available
+ next:
+ type: string
+ description: URL path to next page (only present if has_more is true)
required:
- - start_time
- - end_time
- - counts
+ - data
+ - page
+ - limit
- total
- LogActivityRequest:
+ - has_more
+ PaginatedDatabases:
type: object
- description: Activity request for bucketed log counts.
- additionalProperties: false
properties:
- resource:
- $ref: '#/components/schemas/LogRequestResource'
- q:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/Database'
+ page:
+ type: integer
+ description: Current page number (1-indexed)
+ limit:
+ type: integer
+ description: Number of items per page
+ total:
+ type: integer
+ description: Total number of items across all pages
+ has_more:
+ type: boolean
+ description: Whether there are more pages available
+ next:
type: string
- maxLength: 512
- description: Optional activity query. Supports quoted text, implicit AND, AND/OR/NOT, parentheses, and fields such as `level`, `region`, `invocation.id`, `resource.id`, `resource.name`, `function`, `frontend`, `database`, and `body`.
- start_time:
+ description: URL path to next page (only present if has_more is true)
+ next_cursor:
type: string
- format: date-time
- description: Start of the window, inclusive. Defaults to 24 hours before `end_time`.
- end_time:
+ description: Opaque cursor for the next page (cursor pagination only; present if has_more is true)
+ prev_cursor:
type: string
- format: date-time
- description: End of the window, exclusive. Defaults to now.
- bucket_count:
- type: integer
- minimum: 1
- maximum: 96
- description: Maximum number of buckets. Defaults to 24. Volcano picks the smallest bucket width from 1s, 2s, 5s, 10s, 15s, 30s, 1m, 2m, 5m, 10m, 15m, 30m, 1h, 2h, 3h, 6h, 12h, 1d, or a whole number of days that covers the window in at most this many buckets. Bucket edges fall on UTC multiples of the width, so they stay fixed as the window moves, and the response can contain fewer buckets. `1` returns one bucket that spans exactly the window.
+ description: Opaque cursor for the previous page (cursor pagination only; present when a previous page exists). Send as `ending_before`.
required:
- - resource
- LogActivityResponse:
+ - data
+ - page
+ - limit
+ - total
+ - has_more
+ PaginatedFrontendDeployments:
type: object
- description: Bucketed runtime log activity.
properties:
data:
type: array
items:
- $ref: '#/components/schemas/LogActivityBucket'
+ $ref: '#/components/schemas/FrontendDeployment'
+ page:
+ type: integer
+ description: Current page number (1-indexed)
+ limit:
+ type: integer
+ description: Number of items per page
total:
type: integer
- description: Total events counted across all buckets.
+ description: Total number of items across all pages
+ has_more:
+ type: boolean
+ description: Whether there are more pages available
+ next:
+ type: string
+ description: URL path to next page (only present if has_more is true)
required:
- data
+ - page
+ - limit
- total
- LogSearchRequest:
+ - has_more
+ PaginatedFrontends:
type: object
- description: Search request for project logs.
- additionalProperties: false
properties:
- resource:
- $ref: '#/components/schemas/LogRequestResource'
- q:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/Frontend'
+ page:
+ type: integer
+ description: Current page number (1-indexed)
+ limit:
+ type: integer
+ description: Number of items per page
+ total:
+ type: integer
+ description: Total number of items across all pages
+ has_more:
+ type: boolean
+ description: Whether there are more pages available
+ next:
type: string
- maxLength: 512
- description: Optional log query. Supports quoted text, implicit AND, AND/OR/NOT, parentheses, and fields such as `level`, `region`, `invocation.id`, `resource.id`, `resource.name`, `function`, `frontend`, `database`, and `body`.
- start_time:
+ description: URL path to next page (offset pagination only; present if has_more is true)
+ next_cursor:
type: string
- format: date-time
- description: Start time.
- end_time:
+ description: Opaque cursor for the next page (cursor pagination only; present if has_more is true)
+ prev_cursor:
type: string
- format: date-time
- description: End time.
+ description: Opaque cursor for the previous page (cursor pagination only; present when a previous page exists). Send as `ending_before`.
+ required:
+ - data
+ - page
+ - limit
+ - total
+ - has_more
+ PaginatedFunctionDeployments:
+ type: object
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/FunctionDeployment'
+ page:
+ type: integer
+ description: Current page number (1-indexed)
limit:
type: integer
- minimum: 1
- maximum: 1000
- default: 100
- description: Maximum number of records to return.
- cursor:
+ description: Number of items per page
+ total:
+ type: integer
+ description: Total number of items across all pages
+ has_more:
+ type: boolean
+ description: Whether there are more pages available
+ next:
type: string
- description: Opaque pagination cursor from the previous response's `next_cursor`.
+ description: URL path to next page (only present if has_more is true)
required:
- - resource
- LogStreamRequest:
+ - data
+ - page
+ - limit
+ - total
+ - has_more
+ PaginatedFunctions:
type: object
- description: Stream request for live project logs. Pagination cursors and fixed end times are not supported.
- additionalProperties: false
properties:
- resource:
- $ref: '#/components/schemas/LogRequestResource'
- q:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/Function'
+ page:
+ type: integer
+ description: Current page number (1-indexed)
+ limit:
+ type: integer
+ description: Number of items per page
+ total:
+ type: integer
+ description: Total number of items across all pages
+ has_more:
+ type: boolean
+ description: Whether there are more pages available
+ next:
type: string
- maxLength: 512
- description: Optional log query using the same syntax as search and activity requests.
- start_time:
+ description: URL path to next page (only present if has_more is true)
+ next_cursor:
type: string
- format: date-time
- description: Start time.
+ description: Opaque cursor for the next page (cursor pagination only; present if has_more is true)
+ prev_cursor:
+ type: string
+ description: Opaque cursor for the previous page (cursor pagination only; present when a previous page exists). Send as `ending_before`.
+ required:
+ - data
+ - page
+ - limit
+ - total
+ - has_more
+ PaginatedDurableFunctions:
+ type: object
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/DurableFunction'
+ page:
+ type: integer
+ description: Current page number (1-indexed)
limit:
type: integer
- minimum: 1
- maximum: 1000
- default: 100
- description: Maximum number of records to deliver on connect or reconnect before following new events.
+ description: Number of items per page
+ total:
+ type: integer
+ description: Total number of items across all pages
+ has_more:
+ type: boolean
+ description: Whether there are more pages available
required:
- - resource
- LogSearchEvent:
- allOf:
- - $ref: '#/components/schemas/LogEvent'
- - type: object
- description: Runtime log event returned by project log search. Search results always include a stable event ID and owning resource.
- properties:
- id:
- type: string
- description: Opaque stable log event ID for pagination, deduplication, and display.
- resource:
- $ref: '#/components/schemas/LogResource'
- required:
- - id
- - resource
- LogSearchResponse:
+ - data
+ - page
+ - limit
+ - total
+ - has_more
+ PaginatedDurableExecutions:
type: object
- description: Paginated project runtime log search response.
properties:
data:
type: array
items:
- $ref: '#/components/schemas/LogSearchEvent'
- description: Array of log events sorted by timestamp, newest first.
+ $ref: '#/components/schemas/DurableExecution'
+ page:
+ type: integer
+ description: Current page number (1-indexed)
limit:
type: integer
- description: Number of items requested per page.
+ description: Number of items per page
+ total:
+ type: integer
+ description: Total number of items across all pages
has_more:
type: boolean
- description: Whether the search may have more matching log events. A page can hold fewer than `limit` events, or none, while this is true; keep paging until it is false.
- next_cursor:
- type: string
- description: Opaque cursor for the next page, present while `has_more` is true. Send this value as `cursor` on the next request, even when `data` is empty.
+ description: Whether there are more pages available
required:
- data
+ - page
- limit
+ - total
- has_more
- FunctionRegion:
+ DurableApproval:
type: object
- required:
- - code
- - label
- - flag
+ description: An approval a durable workflow requested.
properties:
- code:
+ id:
type: string
- example: us-east-1
- description: Region identifier accepted by function APIs.
- label:
+ format: uuid
+ status:
+ $ref: '#/components/schemas/DurableApprovalStatus'
+ name:
type: string
- example: NA-East
- description: Human-readable region label suitable for display in pickers.
- flag:
+ description: |
+ The name the workflow gave the approval in `ctx.waitForApproval`.
+ title:
type: string
- example: 🇺🇸
- description: Country flag emoji associated with the region's geography.
- FunctionRuntimeOption:
- type: object
- required:
- - name
- - label
- - language
- - default
- - durable_capable
- - deployment
- properties:
- name:
+ description:
type: string
- example: nodejs24.x
- description: Runtime identifier accepted by function APIs.
- label:
+ details:
+ description: |
+ The JSON value the workflow attached for the person deciding, as
+ given.
+ function:
+ $ref: '#/components/schemas/DurableApprovalFunction'
+ execution:
+ $ref: '#/components/schemas/DurableApprovalExecution'
+ requested_at:
type: string
- example: Node.js 24
- description: Human-readable runtime label suitable for display in pickers.
- language:
+ format: date-time
+ expires_at:
type: string
- example: nodejs
- description: Runtime language family used by the CLI to choose defaults from source files.
- default:
- type: boolean
- description: Whether this runtime is the CLI default for its language.
- durable_capable:
- type: boolean
- description: Whether a durable function can be authored on this runtime. Only runtimes with a durable authoring API report true, and a durable deploy naming any other runtime is rejected.
- deployment:
- $ref: '#/components/schemas/FunctionRuntimeDeployment'
- FunctionRuntimesResponse:
- type: object
+ format: date-time
+ nullable: true
+ description: |
+ When the approval expires if nobody decides. Null when the
+ workflow set no timeout; the approval then lasts as long as its
+ execution.
+ decision:
+ $ref: '#/components/schemas/DurableApprovalDecision'
required:
- - runtimes
- properties:
- runtimes:
- type: array
- items:
- $ref: '#/components/schemas/FunctionRuntimeOption'
- FunctionKindFilter:
+ - id
+ - status
+ - name
+ - title
+ - description
+ - function
+ - execution
+ - requested_at
+ - expires_at
+ - decision
+ DurableApprovalStatus:
type: string
enum:
- - standard
- - durable
+ - pending
+ - approved
+ - denied
+ - expired
+ - cancelled
description: |
- A function kind to filter a list by. Unlike `FunctionKind` it has no
- default: omitting the filter includes both kinds.
- x-enum-varnames:
- - FunctionKindFilterStandard
- - FunctionKindFilterDurable
- FunctionScheduler:
+ `pending` means the workflow is waiting for a decision. `approved` and
+ `denied` are decisions a person made. `expired` means the workflow's
+ approval timeout passed first, and `cancelled` means the execution
+ ended while the approval was still pending. Every status but `pending`
+ is final.
+ DurableApprovalRegistration:
type: object
+ description: The registered approval, as the requesting workflow sees it.
properties:
id:
type: string
format: uuid
- project_id:
- type: string
- format: uuid
- function_id:
- type: string
- format: uuid
- function_kind:
- allOf:
- - $ref: '#/components/schemas/FunctionKind'
- description: |
- Which collection the scheduled function belongs to. A project-wide
- scheduler list mixes both kinds, and this is what says whether the
- function is read back from `/projects/{id}/functions` or
- `/projects/{id}/durable-functions` — and whether a tick invokes it
- or starts a durable execution.
- name:
+ status:
+ $ref: '#/components/schemas/DurableApprovalStatus'
+ expires_at:
type: string
- enabled:
- type: boolean
- schedule_kind:
+ format: date-time
+ nullable: true
+ required:
+ - id
+ - status
+ - expires_at
+ DurableApprovalStats:
+ type: object
+ properties:
+ from:
type: string
- enum:
- - cron
- cron_expression:
+ format: date-time
+ to:
type: string
- payload:
- type: object
- additionalProperties: true
- regions:
+ format: date-time
+ counts:
+ $ref: '#/components/schemas/DurableApprovalCounts'
+ approval_rate:
+ type: number
+ format: double
+ nullable: true
+ description: |
+ `approved / (approved + denied)`, from 0 to 1. Null when nothing in
+ the window was decided.
+ median_seconds_to_decision:
+ type: number
+ format: double
+ nullable: true
+ description: Median time from request to decision. Null when nothing was decided.
+ p90_seconds_to_decision:
+ type: number
+ format: double
+ nullable: true
+ description: 90th percentile time from request to decision. Null when nothing was decided.
+ functions:
type: array
+ description: |
+ The ten workflows that requested the most approvals, most first.
+ The rest are summed in `other_functions`.
items:
- type: string
- regions_explicit:
- type: boolean
- next_run_at:
+ $ref: '#/components/schemas/DurableApprovalFunctionCounts'
+ other_functions:
+ $ref: '#/components/schemas/DurableApprovalCounts'
+ daily:
+ type: array
+ description: |
+ One entry per UTC day in the window that has approvals, oldest
+ first. Days with none are omitted.
+ items:
+ $ref: '#/components/schemas/DurableApprovalDailyCounts'
+ required:
+ - from
+ - to
+ - counts
+ - approval_rate
+ - median_seconds_to_decision
+ - p90_seconds_to_decision
+ - functions
+ - other_functions
+ - daily
+ DurableApprovalDecisionRequest:
+ type: object
+ properties:
+ comment:
type: string
- format: date-time
- last_started_at:
+ maxLength: 2000
+ description: A note for the workflow and the approval's history.
+ additionalProperties: false
+ RequestDurableApprovalRequest:
+ type: object
+ properties:
+ execution_ref:
type: string
- format: date-time
- last_completed_at:
+ minLength: 1
+ maxLength: 2048
+ description: Opaque reference to the running execution, supplied by the SDK.
+ callback_id:
type: string
- format: date-time
- last_error:
+ minLength: 1
+ maxLength: 1024
+ description: Opaque approval reference, supplied by the SDK.
+ name:
type: string
- run_count:
- type: integer
- format: int64
- description: Total number of times this scheduler has executed. 0 for a scheduler that has never run.
- created_at:
+ minLength: 1
+ maxLength: 255
+ title:
type: string
- format: date-time
- updated_at:
+ minLength: 1
+ maxLength: 200
+ description:
type: string
- format: date-time
- FunctionSchedulerListResponse:
+ maxLength: 4000
+ details:
+ x-go-type: json.RawMessage
+ x-go-type-skip-optional-pointer: true
+ description: |
+ Any JSON value to show the person deciding. A number's exponent must
+ be between -324 and 324, and a number too large or too precise to
+ store is refused with `400`. Numbers are read back written out in
+ full, so the exponents' absolute values may total at most 65,536.
+ The whole request is limited to 64 KiB.
+ required:
+ - execution_ref
+ - callback_id
+ - name
+ - title
+ additionalProperties: false
+ PaginatedDurableApprovals:
type: object
properties:
data:
type: array
items:
- $ref: '#/components/schemas/FunctionScheduler'
+ $ref: '#/components/schemas/DurableApproval'
page:
type: integer
+ description: Current page number (1-indexed)
limit:
type: integer
+ description: Number of items per page
total:
type: integer
+ description: Total number of items across all pages
has_more:
type: boolean
- next_cursor:
- type: string
- description: Opaque cursor for the next page (cursor pagination only; present if has_more is true)
- prev_cursor:
- type: string
- description: Opaque cursor for the previous page (cursor pagination only; present when a previous page exists). Send as `ending_before`.
+ description: Whether there are more pages available
required:
- data
- page
- limit
- total
- has_more
- HostedAuthPageType:
+ DurableMessageName:
+ type: string
+ minLength: 1
+ maxLength: 237
+ pattern: ^[ -~]+$
+ description: |
+ The name a workflow waits on or publishes under: up to 237 printable
+ ASCII characters.
+ DurableMessageDirection:
type: string
enum:
- - login
- - signup
- - forgot-password
- - device
- - verify-email
- - reset-password
- HostedLoginEmailCheckRequest:
+ - in
+ - out
+ x-enum-varnames:
+ - DurableMessageDirectionIn
+ - DurableMessageDirectionOut
+ description: |
+ `in` is a message sent to the execution. `out` is one the execution
+ published.
+ DurableMessage:
type: object
- required:
- - email
+ description: A message sent to, or published by, a durable execution.
properties:
- email:
+ id:
type: string
- format: email
- HostedLoginEmailCheckResponse:
- type: object
- properties:
- exists:
- type: boolean
- HostedLoginOptionsResponse:
+ format: uuid
+ execution_id:
+ type: string
+ format: uuid
+ direction:
+ $ref: '#/components/schemas/DurableMessageDirection'
+ seq:
+ type: integer
+ format: int64
+ description: |
+ Orders the execution's messages in both directions. It increases
+ with every message but can skip numbers. Pass the last one you read
+ as `after` to read what came next.
+ name:
+ type: string
+ data:
+ x-go-type: json.RawMessage
+ x-go-type-skip-optional-pointer: true
+ nullable: true
+ description: The JSON value sent or published, or null.
+ sender:
+ $ref: '#/components/schemas/DurableMessageSender'
+ status:
+ $ref: '#/components/schemas/DurableMessageStatus'
+ delivered_at:
+ type: string
+ format: date-time
+ nullable: true
+ description: When the execution received the message. Null until then, and for `out` messages.
+ sent_at:
+ type: string
+ format: date-time
+ required:
+ - id
+ - execution_id
+ - direction
+ - seq
+ - name
+ - data
+ - sender
+ - status
+ - delivered_at
+ - sent_at
+ DurableMessageList:
type: object
properties:
- require_email_confirmation:
- type: boolean
- email_password_enabled:
- type: boolean
- enable_signup:
- type: boolean
- post_auth_redirect_url:
- type: string
- oauth_providers:
+ data:
type: array
+ description: Messages after `after`, oldest first.
items:
- type: string
- HostedRenderablePageType:
- type: string
- enum:
- - signup
- - forgot-password
- - device
- - verify-email
- - reset-password
- LogEvent:
+ $ref: '#/components/schemas/DurableMessage'
+ has_more:
+ type: boolean
+ description: |
+ Whether more messages follow. Read them with `after` set to the
+ last message's `seq`.
+ required:
+ - data
+ - has_more
+ DurableMessageWait:
type: object
- description: Historical log event returned by log APIs.
+ description: A wait an execution has open for a message.
properties:
id:
type: string
- description: Opaque stable log event ID for pagination, deduplication, and display.
- timestamp:
+ format: uuid
+ name:
+ type: string
+ status:
+ $ref: '#/components/schemas/DurableMessageWaitStatus'
+ expires_at:
type: string
format: date-time
- description: Event timestamp.
- level:
- $ref: '#/components/schemas/LiveLogLevel'
- body:
- description: Application log value. JSON arguments retain their JSON type. Strings containing a serialized JSON object or array are normalized to that object or array; all other strings remain strings.
nullable: true
- oneOf:
- - type: string
- - type: object
- additionalProperties: true
- - type: array
- items: {}
- - type: number
- format: double
- - type: boolean
- region:
- type: string
- description: Region where this log event originated.
- resource:
- $ref: '#/components/schemas/LogResource'
- deployment:
- $ref: '#/components/schemas/LogDeployment'
- invocation_id:
+ description: When the wait times out. Null when the workflow set no timeout.
+ created_at:
type: string
- description: Function invocation ID associated with this log event, when available.
+ format: date-time
required:
- - timestamp
- - body
- LiveLogLevel:
- type: string
- enum:
- - trace
- - debug
- - info
- - warn
- - error
- - fatal
- description: Canonical lowercase function runtime log level.
- MetricUsageData:
+ - id
+ - name
+ - status
+ - expires_at
+ - created_at
+ DurableMessageWaitList:
type: object
- description: Usage data for one metric across totals, daily, and hourly windows.
properties:
- metric:
- type: string
- description: |
- Metric name (for example, "Function & Frontend Invocations", "Frontend Requests",
- "Durable Executions", "Durable Operations", "Durable Compute (MB-Seconds)",
- "Build Seconds",
- "Bandwidth Ingress (Bytes)", "Bandwidth Egress (Bytes)",
- "Bandwidth Total (Bytes)", or "Database Storage (Bytes)"). Byte-based metrics are
- reported in bytes. "Bandwidth Total (Bytes)" is derived (ingress + egress) and
- is not billed separately. The three durable metrics are
- counted separately from "Function & Frontend Invocations", which covers standard
- invocations only. Operations and compute are counted when an execution finishes,
- so they appear in the window the execution completed in rather than the one it
- started in. "Durable Compute (MB-Seconds)" reports the memory the execution ran
- at times the time it spent running, in megabyte-seconds; the allowance for it is
- published in gigabyte-seconds, which is 1024 of these.
- "Sandbox Running (MiB-Seconds)", "Sandbox Suspended (Seconds)", and
- "Sandbox Uncertain (MiB-Seconds)" report cloud Sandbox usage. Running
- reports configured baseline memory times confirmed runtime, not measured
- CPU or elastic memory consumption. For sessions admitted after the pricing
- release, confirmed running time consumes the account's runtime allowance;
- SUPERAGENT overage debits credits according to the account's pricing terms.
- Suspended time and uncertain usage do not consume runtime allowance or
- debit credits. Uncertain includes observation gaps and unconfirmed state
- transitions. Suspended reports duration, not snapshot size; snapshot costs
- are included in runtime pricing. Local and platform image-validation
- sessions do not contribute. Existing preview sessions remain unbilled,
- and preview history is never charged retroactively. Displayed totals are
- rounded down after aggregating millisecond measurements; billing uses
- unrounded measurements in the monthly account billing cycle.
- "Database Storage (Bytes)" is a current observed gauge,
- not a cumulative counter. It is the sum of the latest samples exposed as
- `storage_bytes` by the project's database list, so it includes what each
- database's branches and backups hold, and it inherits that field's lag
- behind a live measurement.
- total:
- type: integer
- format: int64
- description: Total usage for the current usage month
- all_time:
- type: integer
- format: int64
- description: Lifetime cumulative usage across every month for this metric
- daily:
- type: array
- description: Last 30 days of daily usage points
- items:
- $ref: '#/components/schemas/UsageDataPoint'
- hourly:
+ data:
type: array
- description: Last 24 hours of hourly usage points
+ description: Open waits, oldest first.
items:
- $ref: '#/components/schemas/UsageDataPoint'
+ $ref: '#/components/schemas/DurableMessageWait'
+ required:
+ - data
+ SendDurableMessageRequest:
+ type: object
+ properties:
+ name:
+ $ref: '#/components/schemas/DurableMessageName'
+ data:
+ x-go-type: json.RawMessage
+ x-go-type-skip-optional-pointer: true
+ nullable: true
+ description: Any JSON value, up to 64 KiB. Omitted means null.
+ required:
+ - name
+ additionalProperties: false
+ RegisterDurableMessageWaitRequest:
+ type: object
+ properties:
+ execution_ref:
+ type: string
+ minLength: 1
+ maxLength: 2048
+ description: Opaque reference to the running execution, supplied by the SDK.
+ callback_id:
+ type: string
+ minLength: 1
+ maxLength: 1024
+ description: Opaque wait reference, supplied by the SDK.
+ name:
+ $ref: '#/components/schemas/DurableMessageName'
required:
- - metric
- - total
- - all_time
- - daily
- - hourly
- OAuthConfig:
+ - execution_ref
+ - callback_id
+ - name
+ additionalProperties: false
+ DurableMessageWaitRegistration:
type: object
+ description: The registered wait, as the waiting workflow sees it.
properties:
id:
type: string
format: uuid
- provider:
+ status:
+ $ref: '#/components/schemas/DurableMessageWaitStatus'
+ expires_at:
type: string
- enum:
- - google
- - github
- - microsoft
- - apple
- - device
- client_id:
+ format: date-time
+ nullable: true
+ required:
+ - id
+ - status
+ - expires_at
+ OpenDurableMessageSessionRequest:
+ type: object
+ properties:
+ execution_ref:
type: string
- example: 123456789.apps.googleusercontent.com
- client_secret:
+ minLength: 1
+ maxLength: 2048
+ description: Opaque reference to the running execution, supplied by the SDK.
+ callback_id:
type: string
- description: Masked in responses (shows only first/last 4 chars)
- example: GOCS...****
- enabled:
- type: boolean
- redirect_url:
+ minLength: 1
+ maxLength: 1024
+ description: Opaque session reference, supplied by the SDK.
+ required:
+ - execution_ref
+ - callback_id
+ additionalProperties: false
+ DurableMessageSessionRegistration:
+ type: object
+ description: |
+ The registered session. Its token reaches the workflow through the
+ workflow itself, never in this response.
+ properties:
+ id:
type: string
- format: uri
- example: https://yourapp.com/auth/callback
- scopes:
- type: array
- items:
- type: string
- example:
- - openid
- - email
- - profile
- created_at:
+ format: uuid
+ required:
+ - id
+ PublishDurableMessageRequest:
+ type: object
+ properties:
+ name:
+ $ref: '#/components/schemas/DurableMessageName'
+ data:
+ x-go-type: json.RawMessage
+ x-go-type-skip-optional-pointer: true
+ nullable: true
+ description: Any JSON value, up to 64 KiB. Omitted means null.
+ required:
+ - name
+ additionalProperties: false
+ RegisterDurableCallbackRequest:
+ type: object
+ properties:
+ execution_ref:
type: string
- format: date-time
- updated_at:
+ minLength: 1
+ maxLength: 2048
+ description: Opaque reference to the running execution, supplied by the SDK.
+ callback_id:
+ type: string
+ minLength: 1
+ maxLength: 1024
+ description: Opaque reference to the waiting step, supplied by the SDK.
+ name:
+ type: string
+ minLength: 1
+ maxLength: 237
+ pattern: ^[ -~]+$
+ description: The waiting step's name, up to 237 printable ASCII characters.
+ operation_id:
+ type: string
+ minLength: 1
+ maxLength: 64
+ pattern: ^[0-9a-f]+$
+ description: |
+ The operation an earlier run of the workflow opened the waiting step
+ under, supplied by the SDK when a replay registers it. Volcano then
+ looks for the step further back in the execution's history than a
+ first registration reads.
+ required:
+ - execution_ref
+ - callback_id
+ - name
+ additionalProperties: false
+ DurableCallbackRegistration:
+ type: object
+ description: The token for the waiting step, as the workflow receives it.
+ properties:
+ token:
+ $ref: '#/components/schemas/DurableCallbackToken'
+ expires_at:
type: string
format: date-time
- OAuthErrorResponse:
+ nullable: true
+ description: |
+ When the waiting step's `timeout` passes and the token stops
+ working. Null when the workflow set no `timeout`. A step with a
+ heartbeat timeout also ends once that long passes without a
+ heartbeat, which can be before this time.
+ required:
+ - token
+ - expires_at
+ SucceedDurableCallbackRequest:
+ type: object
+ properties:
+ token:
+ $ref: '#/components/schemas/DurableCallbackToken'
+ result:
+ x-go-type: json.RawMessage
+ x-go-type-skip-optional-pointer: true
+ description: |
+ Any JSON value other than null, up to 64 KiB. The waiting step
+ resolves with it. Null is refused because a timeout resolves the
+ step with null.
+ required:
+ - token
+ - result
+ additionalProperties: false
+ FailDurableCallbackRequest:
type: object
properties:
+ token:
+ $ref: '#/components/schemas/DurableCallbackToken'
error:
- type: string
- error_description:
- type: string
+ $ref: '#/components/schemas/DurableCallbackError'
required:
+ - token
- error
- PaginatedAuthUsers:
+ additionalProperties: false
+ HeartbeatDurableCallbackRequest:
type: object
properties:
- data:
- type: array
- items:
- $ref: '#/components/schemas/AuthUser'
- page:
- type: integer
- description: Current page number (1-indexed)
- limit:
- type: integer
- description: Number of items per page
- total:
- type: integer
- description: Total number of items across all pages
- has_more:
- type: boolean
- description: Whether there are more pages available
- next:
- type: string
- description: URL path to next page (only present if has_more is true)
+ token:
+ $ref: '#/components/schemas/DurableCallbackToken'
required:
- - data
- - page
- - limit
- - total
- - has_more
- PaginatedDatabases:
+ - token
+ additionalProperties: false
+ DurableCallbackOutcome:
type: object
properties:
- data:
- type: array
- items:
- $ref: '#/components/schemas/Database'
- page:
- type: integer
- description: Current page number (1-indexed)
- limit:
- type: integer
- description: Number of items per page
- total:
- type: integer
- description: Total number of items across all pages
- has_more:
+ status:
+ $ref: '#/components/schemas/DurableCallbackStatus'
+ required:
+ - status
+ Issue:
+ type: object
+ description: Runtime errors from one function or frontend, grouped by error type and stack, one LavaFlow Code Quality finding, or a user-reported project problem. A report has a project resource, zero runtime occurrences, and report times as its first and last seen times.
+ properties:
+ id:
+ type: string
+ format: uuid
+ project_id:
+ type: string
+ format: uuid
+ resource:
+ $ref: '#/components/schemas/ResourceReference'
+ title:
+ type: string
+ description: |
+ The error type and message, with values such as IDs, numbers, and
+ URLs replaced by placeholders like `` and ``.
+ error_type:
+ type: string
+ description: The exception class, such as `TypeError`. Omitted when the error has none.
+ culprit:
+ type: string
+ description: The innermost frame of your code in the stack, as `function (file)`. For a frontend's Next.js build output, the outermost route or page file of the build in the stack, such as `.next/server/app/checkout/route.js`, or without one, the outermost file of the build. For a minified file of a function's own bundle, the file alone. Omitted without a stack.
+ status:
+ $ref: '#/components/schemas/IssueStatus'
+ source:
+ type: string
+ enum:
+ - runtime
+ - code_quality
+ - report
+ description: 'Where the issue came from: `runtime` for errors your code logged, `code_quality` for a LavaFlow Code Quality finding in code a deploy changed, or `report` for a problem reported for the project, such as through Slack. A `code_quality` issue''s `error_type` is the finding''s rule, its `culprit` the enclosing function and file, and its `event_count` the scans that found it.'
+ finding:
+ allOf:
+ - $ref: '#/components/schemas/IssueFinding'
+ description: The finding behind a `code_quality` issue. Absent on a `runtime` issue.
+ exception:
type: boolean
- description: Whether there are more pages available
- next:
+ description: |
+ Whether the issue holds an exception: one your code threw, or one it
+ logged with `console.error(err)` or Python's `logger.exception()`.
+ `false` for an error logged any other way, such as a structured log
+ line, a logger's error line, or a printed traceback, and for every
+ `code_quality` issue. Once `true`, it stays `true`.
+ event_count:
+ type: integer
+ format: int64
+ description: Errors counted in this issue. A retried delivery can count an error twice.
+ first_seen_at:
+ type: string
+ format: date-time
+ last_seen_at:
+ type: string
+ format: date-time
+ last_region:
type: string
- description: URL path to next page (only present if has_more is true)
- next_cursor:
+ description: The region that served the latest error, such as `us-east-1`.
+ sample_event_id:
type: string
- description: Opaque cursor for the next page (cursor pagination only; present if has_more is true)
- prev_cursor:
+ description: The ID of the latest error's log event, while logs retain it.
+ sample_event_at:
type: string
- description: Opaque cursor for the previous page (cursor pagination only; present when a previous page exists). Send as `ending_before`.
- required:
- - data
- - page
- - limit
- - total
- - has_more
- PaginatedFrontendDeployments:
- type: object
- properties:
- data:
- type: array
- items:
- $ref: '#/components/schemas/FrontendDeployment'
- page:
- type: integer
- description: Current page number (1-indexed)
- limit:
- type: integer
- description: Number of items per page
- total:
- type: integer
- description: Total number of items across all pages
- has_more:
- type: boolean
- description: Whether there are more pages available
- next:
+ format: date-time
+ description: When the latest error's log event was written.
+ resolved_at:
type: string
- description: URL path to next page (only present if has_more is true)
+ format: date-time
+ description: When the issue was resolved. Present only while it is resolved.
+ regressed_at:
+ type: string
+ format: date-time
+ description: When a resolved issue was last seen again and reopened.
+ created_at:
+ type: string
+ format: date-time
+ updated_at:
+ type: string
+ format: date-time
required:
- - data
- - page
- - limit
- - total
- - has_more
- PaginatedFrontends:
+ - id
+ - project_id
+ - resource
+ - title
+ - status
+ - source
+ - exception
+ - event_count
+ - first_seen_at
+ - last_seen_at
+ - created_at
+ - updated_at
+ IssueStatus:
+ type: string
+ enum:
+ - open
+ - resolved
+ - ignored
+ description: |
+ `open` until someone resolves or ignores the issue. A resolved issue
+ seen again reopens. A reported problem resolves when its LavaFlow fix
+ merges. Volcano ignores one whose report it deleted before any fix
+ merged, so it no longer counts toward the project's open issues.
+ PaginatedIssues:
type: object
properties:
data:
type: array
items:
- $ref: '#/components/schemas/Frontend'
- page:
- type: integer
- description: Current page number (1-indexed)
+ $ref: '#/components/schemas/Issue'
limit:
type: integer
description: Number of items per page
- total:
- type: integer
- description: Total number of items across all pages
has_more:
type: boolean
- description: Whether there are more pages available
- next:
- type: string
- description: URL path to next page (offset pagination only; present if has_more is true)
+ description: Whether a next page exists
next_cursor:
type: string
- description: Opaque cursor for the next page (cursor pagination only; present if has_more is true)
- prev_cursor:
- type: string
- description: Opaque cursor for the previous page (cursor pagination only; present when a previous page exists). Send as `ending_before`.
+ description: Opaque cursor for the next page (present if has_more is true)
required:
- data
- - page
- limit
- - total
- has_more
- PaginatedFunctionDeployments:
+ UpdateIssueRequest:
type: object
+ additionalProperties: false
properties:
- data:
- type: array
- items:
- $ref: '#/components/schemas/FunctionDeployment'
- page:
- type: integer
- description: Current page number (1-indexed)
- limit:
- type: integer
- description: Number of items per page
- total:
- type: integer
- description: Total number of items across all pages
- has_more:
- type: boolean
- description: Whether there are more pages available
- next:
- type: string
- description: URL path to next page (only present if has_more is true)
+ status:
+ $ref: '#/components/schemas/IssueStatus'
required:
- - data
- - page
- - limit
- - total
- - has_more
- PaginatedFunctions:
+ - status
+ LavaflowAutonomy:
+ type: string
+ enum:
+ - diagnose_only
+ - open_pr
+ - merge
+ description: How far LavaFlow goes on its own. `diagnose_only` stops at a diagnosis. `open_pr` also opens a pull request with a fix, and never merges it. `merge` also merges the fix once LavaFlow's reviewers pass it, its required checks pass, and nothing holds it; a held fix is handed to you for good. LavaFlow merges only into a base branch that requires at least one status check, through branch protection or a ruleset; on any other branch it holds every fix with `no_required_checks`. Turning on merge lets LavaFlow's fixes, including those from runs it starts on its own, run your CI with the secrets your pull request workflows get. Choosing `merge` needs the project's `lavaflow.merge` capability.
+ LavaflowMergePolicy:
type: object
+ description: 'Your rules for fixes LavaFlow must never merge. They apply with `autonomy: merge`; at another autonomy they are saved and do nothing.'
properties:
- data:
+ human_review_paths:
type: array
+ maxItems: 50
items:
- $ref: '#/components/schemas/Function'
- page:
- type: integer
- description: Current page number (1-indexed)
- limit:
- type: integer
- description: Number of items per page
- total:
- type: integer
- description: Total number of items across all pages
- has_more:
- type: boolean
- description: Whether there are more pages available
- next:
- type: string
- description: URL path to next page (only present if has_more is true)
- next_cursor:
- type: string
- description: Opaque cursor for the next page (cursor pagination only; present if has_more is true)
- prev_cursor:
- type: string
- description: Opaque cursor for the previous page (cursor pagination only; present when a previous page exists). Send as `ending_before`.
+ type: string
+ minLength: 1
+ maxLength: 200
+ description: 'Globs of paths whose change LavaFlow never merges: a fix that changes one is held and handed to you. Paths are relative to the repository root, such as `db/migrations/**`. `*` and `?` match within one directory, `**/` spans any number of directories, and a final `**` matches the rest. A pattern that starts with `/`, `./` or `../`, ends with `/`, holds an empty, `.` or `..` segment, or holds a NUL character answers `400`. Volcano''s own held paths, such as deploy configuration and authentication code, are always held too. Defaults to none.'
required:
- - data
- - page
- - limit
- - total
- - has_more
- PaginatedDurableFunctions:
+ - human_review_paths
+ LavaflowMergePolicyUpdate:
type: object
+ additionalProperties: false
+ minProperties: 1
+ description: 'The merge policy fields to change. An omitted field keeps its saved value. Send `human_review_paths: []` to clear the paths.'
properties:
- data:
+ human_review_paths:
type: array
+ maxItems: 50
items:
- $ref: '#/components/schemas/DurableFunction'
- page:
- type: integer
- description: Current page number (1-indexed)
- limit:
- type: integer
- description: Number of items per page
- total:
- type: integer
- description: Total number of items across all pages
- has_more:
- type: boolean
- description: Whether there are more pages available
- required:
- - data
- - page
- - limit
- - total
- - has_more
- PaginatedDurableExecutions:
+ type: string
+ minLength: 1
+ maxLength: 200
+ LavaflowMergeStatus:
+ type: string
+ enum:
+ - waiting_for_checks
+ - queued
+ - merged
+ - held
+ - stopped
+ description: '`waiting_for_checks`: LavaFlow waits for the checks on the fix''s commit. `queued`: the fix is in the repository''s merge queue. `merged`: the pull request merged. `held`: something in `hold_reasons` needs a person. LavaFlow commented on the pull request once and never merges, pushes to, rebases or dequeues it again; review it and merge it yourself if you want it. `stopped`: LavaFlow left the pull request open for you, for `reason`.'
+ LavaflowMergeReason:
+ type: string
+ description: 'Why the merge stopped, or what a waiting merge is paused for. A stopped merge leaves the pull request open for you, and LavaFlow never merges, pushes to, rebases or dequeues it again; unless a reason says otherwise, review the change, then merge or close the pull request yourself. `review_unresolved`: LavaFlow''s review didn''t pass the fix; the run''s `review` says why. `checks_failed`: a check on the fix failed. `checks_timed_out`: the checks didn''t all finish within 24 hours. `blocked_by_rules`: a rule of the repository that LavaFlow can''t satisfy blocks the merge. `not_mergeable`: GitHub can''t merge the pull request, for example because it conflicts with its base branch; resolve the conflict first. `branch_behind`: the base branch requires the fix to be up to date with it, and LavaFlow doesn''t update fix branches; update the branch first. `removed_from_queue`: the fix isn''t in the merge queue, and LavaFlow can''t tell why, for example because its checks failed there or someone removed it. `reads_failed`: LavaFlow failed to read the pull request for about an hour while the fix may have been queued, so it took the fix out of the merge queue, when it could still reach it, and stopped, or failed to read the project''s settings or repository for about a day while merging was paused. `handed_off`: someone drafted or closed the pull request, or moved it to another branch, so LavaFlow stopped; nothing to do. `unreadable`: the pull request has more checks, reviews, labels or commits than LavaFlow reads, so it can''t judge the fix. `permission_missing`: the Volcano GitHub App, or the project owner''s GitHub account, lacks a permission the merge needs; grant the App''s requested permissions and make sure the owner can push. `repository_changed`: the project now deploys from another repository. `settings_changed`: the project''s settings no longer let LavaFlow merge: LavaFlow was turned off, `autonomy` is no longer `merge`, the owner''s plan no longer includes LavaFlow, or the project is being deleted. `request_rejected`: GitHub refused LavaFlow''s request to start the checks on the fix. `ci_start_commit_mismatch`: GitHub reports a different commit from the one LavaFlow made to start the checks. `branch_refused`: LavaFlow didn''t start the fix''s checks because the pull request was no longer open, or its branch isn''t a LavaFlow branch of a pull request LavaFlow opened; LavaFlow never starts checks on the default or production branch. `head_unverified`: GitHub doesn''t report the fix''s head as the signed commit LavaFlow pushed, so LavaFlow didn''t start its checks. `checks_not_started`: LavaFlow couldn''t give the fix a commit message that runs CI. `queue_carries_ci_skip`: the repository''s merge queue could carry an instruction to skip checks, from the fix''s commits or its pull request''s title or description, into the base branch; reword LavaFlow''s commit to drop it and force-push, and take any such instruction out of the title and description, before you queue the fix. `merge_carries_ci_skip`: merging would carry an instruction to skip checks into the base branch, for example because the repository allows no squash merge; reword LavaFlow''s commit to drop it and force-push before you merge. After `request_rejected`, `ci_start_commit_mismatch` or `checks_not_started`, the fix''s CI didn''t start: push a commit to its branch to run it. `paused_too_long`: merging stayed paused for more than 7 days. `cancelled`: the project is being deleted, so LavaFlow stopped waiting on the merge; nothing to do. `manual_deploy`: the fix merged and waits for you to deploy it. `paused`: merging is paused, and the merge waits. LavaFlow takes a queued fix out of the merge queue, so it shows `waiting_for_checks`, and queues it again when merging resumes. New reasons may appear.'
+ LavaflowHoldReason:
type: object
+ description: One reason LavaFlow holds the fix for a person.
properties:
- data:
+ code:
+ type: string
+ description: 'Why the fix is held. `client_reported_commit`: the fix is built on a commit Volcano can''t tie to a push. `path`: it changes a path in `human_review_paths`, or deploy or infrastructure configuration Volcano always holds, such as `volcano-config.yaml`, Terraform files, a YAML or JSON file that declares a resource, a YAML template that mentions `apiVersion` or `kind`, a file in a Helm chart or Kustomize directory, or, in a repository too large to read in full, any file no other path reason holds. `sensitive_path`: it changes another path Volcano always holds: authentication or authorization code, Next.js middleware included; secret, key, certificate or cryptography files; a coding agent''s instructions or settings, or Git hook configuration; CI configuration; a dependency manifest or lockfile, or a `package.json` change to what installs or its install scripts; or runtime, container or other configuration files. `label`: the pull request has the `needs-human-review` label. `no_checks`: no CI ran on it. `required_check_skipped`: a required check was skipped. `no_required_checks`: the base branch requires no check, so passing checks alone don''t vouch for the fix. `changes_requested`: a reviewer requested changes. `repository_requires_approval`: the repository requires an approving review. `person_commits`: someone other than LavaFlow pushed to the fix''s branch. `rules_bypass`: the Volcano GitHub App can bypass a ruleset on the base branch. `unchecked_rules`: the base branch has a rule LavaFlow doesn''t check, such as required signatures. `commit_convention`: no title can meet the repository''s commit convention. `ungated_workflows`: the fix opened past workflows that can run it with the repository''s secrets before a person approves it, as the project''s owner allowed, or LavaFlow couldn''t check its workflows, or, when LavaFlow was about to start its CI or add it to a merge queue, a workflow could run it with those secrets before a person approves it or couldn''t be read, so LavaFlow takes it no further and never merges it. A fix held for another reason before its CI starts lists it too when that check, run without starting CI, finds such a workflow or can''t finish. `ci_outside_actions`: when LavaFlow was about to start the fix''s CI, the repository could run CI, a build or a preview outside GitHub Actions: the root of the fix''s tree or its base branch''s holds another service''s configuration, such as `.travis.yml`, `.circleci/` or `netlify.toml`, which `paths` names, another app reported checks or statuses on the base branch, or LavaFlow couldn''t read them in full. LavaFlow starts CI only when it finds no sign of CI outside GitHub Actions, so it never starts this fix''s CI or merges it. `lineage_undoes_parent`: the fix follows up an earlier LavaFlow fix and deletes or changes lines that fix added, which could undo it. `lineage_cap`: the fix''s lineage opened as many pull requests as it may. `lineage_held`: an earlier pull request in the fix''s lineage was held, stopped or closed. `recent_regressions`: fixes LavaFlow merged in the project recently caused new errors. `no_test`: the fix changes code the repository tests and adds no test, because testing it needs test infrastructure the repository doesn''t have or the change has no effect a test can observe. Other codes name a concern LavaFlow''s reviewers raised. New codes may appear.'
+ question:
+ type: string
+ description: Why LavaFlow holds the fix and what to check before you merge it, in one or two sentences to show as given. A reviewer's reason is a question for you to answer. Reads `LavaFlow left this question out because it may contain a credential` when it holds one of the project's secret values, a value shaped like a credential, or a path `paths` leaves out, or is over 4,000 characters, and, for a question LavaFlow's reviewers wrote, when it may contain a credential. Every question reads so, LavaFlow's fixed sentences too, on a run whose `pull_request_skipped` is `possible_credential`.
+ paths:
type: array
items:
- $ref: '#/components/schemas/DurableExecution'
- page:
- type: integer
- description: Current page number (1-indexed)
- limit:
- type: integer
- description: Number of items per page
- total:
- type: integer
- description: Total number of items across all pages
- has_more:
- type: boolean
- description: Whether there are more pages available
+ type: string
+ description: The changed paths that matched, for a path code. For `ci_outside_actions`, the entries at the repository's root that another CI or preview service reads, whether or not the fix changes them. `""` for a path that may contain a credential, holds one of the project's secret values, or is over 4,000 characters.
required:
- - data
- - page
- - limit
- - total
- - has_more
- DurableApproval:
+ - code
+ - question
+ - paths
+ LavaflowMerge:
type: object
- description: An approval a durable workflow requested.
+ description: Where the run's merge stands. Present for a run that may merge its fix, once its pull request opens.
properties:
- id:
- type: string
- format: uuid
status:
- $ref: '#/components/schemas/DurableApprovalStatus'
- name:
- type: string
- description: |
- The name the workflow gave the approval in `ctx.waitForApproval`.
- title:
- type: string
- description:
- type: string
- details:
- description: |
- The JSON value the workflow attached for the person deciding, as
- given.
- function:
- $ref: '#/components/schemas/DurableApprovalFunction'
- execution:
- $ref: '#/components/schemas/DurableApprovalExecution'
- requested_at:
- type: string
- format: date-time
- expires_at:
- type: string
- format: date-time
+ $ref: '#/components/schemas/LavaflowMergeStatus'
+ reason:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowMergeReason'
nullable: true
- description: |
- When the approval expires if nobody decides. Null when the
- workflow set no timeout; the approval then lasts as long as its
- execution.
- decision:
- $ref: '#/components/schemas/DurableApprovalDecision'
+ hold_reasons:
+ type: array
+ items:
+ $ref: '#/components/schemas/LavaflowHoldReason'
+ description: Why LavaFlow holds the fix. Empty unless `status` is `held`.
+ merged_by_lavaflow:
+ type: boolean
+ nullable: true
+ description: 'Whether LavaFlow made the merge: `true` when it merged the fix''s commit itself or through the merge queue, `false` when someone else merged the pull request while LavaFlow waited. `null` unless `status` is `merged`.'
required:
- - id
- status
- - name
- - title
- - description
- - function
- - execution
- - requested_at
- - expires_at
- - decision
- DurableApprovalStatus:
- type: string
- enum:
- - pending
- - approved
- - denied
- - expired
- - cancelled
- description: |
- `pending` means the workflow is waiting for a decision. `approved` and
- `denied` are decisions a person made. `expired` means the workflow's
- approval timeout passed first, and `cancelled` means the execution
- ended while the approval was still pending. Every status but `pending`
- is final.
- DurableApprovalRegistration:
+ - reason
+ - hold_reasons
+ - merged_by_lavaflow
+ LavaflowInvolvedResource:
type: object
- description: The registered approval, as the requesting workflow sees it.
+ description: A resource a run involves, and how.
+ properties:
+ resource:
+ $ref: '#/components/schemas/LavaflowResourceReference'
+ roles:
+ type: array
+ minItems: 1
+ items:
+ type: string
+ enum:
+ - issue
+ - cause
+ - fix
+ description: '`issue`: the issue came from it. `cause`: the issue came from it, or code the diagnosis cites as evidence is in its source. `fix`: the diagnosis proposes changing its source, or the fix changes it; a change to code that every function shares involves every function.'
+ required:
+ - resource
+ - roles
+ LavaflowIssueSummary:
+ type: object
+ description: The project issue a run works on.
properties:
id:
type: string
format: uuid
+ title:
+ type: string
+ description: 'The issue''s title: the error type and message, a Code Quality finding''s title, or a reported problem''s title.'
+ culprit:
+ type: string
+ nullable: true
+ description: The innermost frame of your code, as `function (file)`; for a Code Quality finding, the symbol and file it is in, as `symbol (file)`, or the file alone. Null for an error without a stack and for a reported problem.
status:
- $ref: '#/components/schemas/DurableApprovalStatus'
- expires_at:
+ $ref: '#/components/schemas/IssueStatus'
+ severity:
+ type: string
+ enum:
+ - nit
+ - minor
+ - major
+ - critical
+ x-enum-varnames:
+ - LavaflowIssueSeverityNit
+ - LavaflowIssueSeverityMinor
+ - LavaflowIssueSeverityMajor
+ - LavaflowIssueSeverityCritical
+ description: The confirmed Code Quality finding's recorded severity. Omitted for other issue sources and when no canonical severity is known; absence does not mean the issue has low severity.
+ event_count:
+ type: integer
+ format: int64
+ description: Errors the issue has grouped so far; for a Code Quality finding, the scans that saw it; 0 for a reported problem.
+ last_seen_at:
+ type: string
+ format: date-time
+ resolved_at:
type: string
format: date-time
nullable: true
+ description: When the issue was resolved; null unless it is resolved now.
+ regressed_at:
+ type: string
+ format: date-time
+ nullable: true
+ description: When the issue was last seen again after it was resolved, and reopened; null if it never was.
+ run_count:
+ type: integer
+ format: int64
+ description: LavaFlow runs on this issue, this one included.
required:
- id
+ - title
+ - culprit
- status
- - expires_at
- DurableApprovalStats:
+ - event_count
+ - last_seen_at
+ - resolved_at
+ - regressed_at
+ - run_count
+ LavaflowSettings:
type: object
+ description: A project's LavaFlow settings. LavaFlow sends this project's logs and source code to an AI service that Volcano operates.
properties:
- from:
+ project_id:
type: string
- format: date-time
- to:
+ format: uuid
+ description: The project the settings belong to.
+ enabled:
+ type: boolean
+ description: Whether LavaFlow works on the project's issues. Off by default.
+ autonomy:
+ $ref: '#/components/schemas/LavaflowAutonomy'
+ merge_policy:
+ $ref: '#/components/schemas/LavaflowMergePolicy'
+ skill_learning:
+ $ref: '#/components/schemas/LavaflowSkillLearning'
+ custom_context:
+ type: string
+ maxLength: 4000
+ description: Context about the project for LavaFlow's runs. Empty when unset. Saved, but runs do not use it yet.
+ system_prompt:
+ type: string
+ maxLength: 4000
+ description: Instructions for LavaFlow's runs, to follow after LavaFlow's own, which take precedence. Empty when unset. Saved, but runs do not use it yet.
+ code_quality:
+ $ref: '#/components/schemas/LavaflowCodeQualitySettings'
+ allow_ungated_workflows:
+ type: boolean
+ description: 'Whether LavaFlow opens a fix''s pull request even where a workflow could run it, or put its text into a command, with the repository''s secrets before a person approves it. Off by default; while off, such a fix stays on its run and no pull request opens. Only the project''s owner turns it on, signed in as a person: with the platform token `volcano login` stores, or another platform token that expires. It applies to the repository their GitHub account can push to. Connecting the project to another repository, or disconnecting it, turns it off, and connecting the first one again doesn''t turn it back on. Workflows in the repository may then run LavaFlow''s pull requests, or put their text into commands, with the repository''s secrets before a person reviews them. LavaFlow writes those changes from the project''s error logs, which its users can influence. Turn it on only if those workflows keep secrets away from untrusted code; gating them on a label a person adds is safer.'
+ updated_at:
type: string
format: date-time
- counts:
- $ref: '#/components/schemas/DurableApprovalCounts'
- approval_rate:
- type: number
- format: double
nullable: true
- description: |
- `approved / (approved + denied)`, from 0 to 1. Null when nothing in
- the window was decided.
- median_seconds_to_decision:
- type: number
- format: double
+ description: When the settings were last saved, or last changed by connecting a repository. Null until they first are.
+ updated_by:
+ type: string
nullable: true
- description: Median time from request to decision. Null when nothing was decided.
- p90_seconds_to_decision:
- type: number
- format: double
+ description: The user ID of the person who made the last save; null when no person made it, such as a project access token.
+ can_update:
+ type: boolean
+ description: 'Whether the caller can save the settings: true only for the project''s owner with a platform token while the owner''s account is active; false for any project access token and for a read-only account.'
+ repository:
+ allOf:
+ - $ref: '#/components/schemas/ProjectGitConnectionSummary'
nullable: true
- description: 90th percentile time from request to decision. Null when nothing was decided.
- functions:
- type: array
- description: |
- The ten workflows that requested the most approvals, most first.
- The rest are summed in `other_functions`.
- items:
- $ref: '#/components/schemas/DurableApprovalFunctionCounts'
- other_functions:
- $ref: '#/components/schemas/DurableApprovalCounts'
- daily:
- type: array
- description: |
- One entry per UTC day in the window that has approvals, oldest
- first. Days with none are omitted.
- items:
- $ref: '#/components/schemas/DurableApprovalDailyCounts'
+ description: The GitHub repository the project is linked to, as `GET /projects/{id}/git-connection` reports it. LavaFlow opens fix pull requests there, against `production_branch`. Null when the project has none.
+ fix_blocker:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowFailure'
+ nullable: true
+ description: 'What in the project''s repository setup stops LavaFlow from fixing issues although it is on. Null when the repository setup doesn''t, and while the project''s `lavaflow` capability isn''t available; null doesn''t mean nothing else stops LavaFlow. `message` is text to show as given. `repository_required`: the project has no linked repository. With `autonomy` `open_pr` or `merge`, LavaFlow diagnoses issues but fixes none; turned on for a repository the project no longer links, it starts no runs. Link a repository with `PUT /projects/{id}/git-connection` or `volcano git connect `. Turned on with none, LavaFlow fixes issues in the first one linked, unless `message` asks to turn it on again after the link; linking the one it was turned on for resumes it. `repository_changed`: the project is linked to a repository LavaFlow wasn''t turned on for. LavaFlow starts no runs until the owner turns it on again, with `{"enabled": true}` or `volcano cloud lavaflow enable`, which makes the linked repository the one it fixes. New codes may appear; show the `message` of one you don''t know.'
required:
- - from
- - to
- - counts
- - approval_rate
- - median_seconds_to_decision
- - p90_seconds_to_decision
- - functions
- - other_functions
- - daily
- DurableApprovalDecisionRequest:
+ - project_id
+ - enabled
+ - autonomy
+ - merge_policy
+ - skill_learning
+ - custom_context
+ - system_prompt
+ - code_quality
+ - allow_ungated_workflows
+ - updated_at
+ - updated_by
+ - can_update
+ - repository
+ - fix_blocker
+ LavaflowSettingsUpdate:
type: object
+ additionalProperties: false
+ minProperties: 2
+ description: The project, and at least one field to change. An omitted field keeps its saved value.
properties:
- comment:
+ project_id:
type: string
- maxLength: 2000
- description: A note for the workflow and the approval's history.
+ format: uuid
+ description: The project whose settings to change.
+ enabled:
+ type: boolean
+ autonomy:
+ $ref: '#/components/schemas/LavaflowAutonomy'
+ merge_policy:
+ $ref: '#/components/schemas/LavaflowMergePolicyUpdate'
+ skill_learning:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowSkillLearning'
+ description: 'Only the project''s owner turns learning up, from `off` to `review` or `auto` or from `review` to `auto`, signed in as a person: with a `volcano login` token whose sign-in is live, or a platform token with an expiry, and with a GitHub account that can push to the project''s repository. Any other credential gets `403` with code `person_required`. Turning it down or off, or sending the saved value, needs no check. A project access token may send `off` with `project_id`, alone or with `code_quality` turned off, and nothing else; any other save it makes gets `403` with code `person_required`.'
+ custom_context:
+ type: string
+ maxLength: 4000
+ system_prompt:
+ type: string
+ maxLength: 4000
+ code_quality:
+ $ref: '#/components/schemas/LavaflowCodeQualityUpdate'
+ allow_ungated_workflows:
+ type: boolean
+ description: 'Turns on opening fixes past ungated workflows, for the repository the project is connected to now; it applies only to that repository. Only the project''s owner turns it on, signed in as a person: with the platform token `volcano login` stores, or another platform token that expires. Their GitHub account must be able to push to that repository. A project access token, a platform token that never expires, or anyone else gets `403` with `person_required`. Any of the owner''s credentials turns it off. Workflows in the repository may then run LavaFlow''s pull requests, or put their text into commands, with the repository''s secrets before a person reviews them. LavaFlow writes those changes from the project''s error logs, which its users can influence. Turn it on only if those workflows keep secrets away from untrusted code; gating them on a label a person adds is safer. While LavaFlow is not available, only `false` is saved, and only with `enabled: false`, `skill_learning: off` or both.'
+ required:
+ - project_id
+ LavaflowRunCreate:
+ type: object
additionalProperties: false
- RequestDurableApprovalRequest:
+ description: The project, and the issue to start a run on.
+ properties:
+ project_id:
+ type: string
+ format: uuid
+ description: The project the issue belongs to.
+ issue_id:
+ type: string
+ format: uuid
+ description: The issue to start a run on.
+ required:
+ - project_id
+ - issue_id
+ LavaflowHeldFixOpen:
type: object
+ additionalProperties: false
+ description: The project, the run, and the diff and jobs of the held fix you read, by the digests the run served them with.
properties:
- execution_ref:
+ project_id:
type: string
- minLength: 1
- maxLength: 2048
- description: Opaque reference to the running execution, supplied by the SDK.
- callback_id:
+ format: uuid
+ description: The project the run belongs to.
+ run_id:
type: string
- minLength: 1
- maxLength: 1024
- description: Opaque approval reference, supplied by the SDK.
- name:
+ format: uuid
+ description: The run whose held fix to open.
+ diff_sha256:
type: string
- minLength: 1
- maxLength: 255
- title:
+ pattern: ^[0-9a-f]{64}$
+ description: The run's `diff_sha256`, as it served it.
+ example: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
+ jobs_sha256:
type: string
- minLength: 1
- maxLength: 200
- description:
+ pattern: ^[0-9a-f]{64}$
+ description: The run's `held_workflows.jobs_sha256`, as it served it.
+ example: 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae
+ required:
+ - project_id
+ - run_id
+ - diff_sha256
+ - jobs_sha256
+ LavaflowDayCounts:
+ type: object
+ properties:
+ date:
type: string
- maxLength: 4000
- details:
- x-go-type: json.RawMessage
- x-go-type-skip-optional-pointer: true
- description: |
- Any JSON value to show the person deciding. A number's exponent must
- be between -324 and 324, and a number too large or too precise to
- store is refused with `400`. Numbers are read back written out in
- full, so the exponents' absolute values may total at most 65,536.
- The whole request is limited to 64 KiB.
+ format: date
+ issues_opened:
+ type: integer
+ format: int64
+ description: Issues LavaFlow took on that UTC day.
+ pull_requests_opened:
+ type: integer
+ format: int64
+ description: Pull requests with a fix LavaFlow opened that UTC day.
required:
- - execution_ref
- - callback_id
+ - date
+ - issues_opened
+ - pull_requests_opened
+ LavaflowStats:
+ type: object
+ properties:
+ project_id:
+ type: string
+ format: uuid
+ description: The project the counts are for.
+ window_start:
+ type: string
+ format: date
+ description: The first UTC day in the window.
+ window_end:
+ type: string
+ format: date
+ description: The last UTC day in the window, today.
+ days:
+ type: array
+ description: One entry per UTC day, oldest first, zeros included.
+ items:
+ $ref: '#/components/schemas/LavaflowDayCounts'
+ totals:
+ type: object
+ properties:
+ issues_opened:
+ type: integer
+ format: int64
+ pull_requests_opened:
+ type: integer
+ format: int64
+ required:
+ - issues_opened
+ - pull_requests_opened
+ required:
+ - project_id
+ - window_start
+ - window_end
+ - days
+ - totals
+ LavaflowResourceReference:
+ type: object
+ description: A function, durable function or frontend in the project, or the project of a user-reported problem.
+ properties:
+ type:
+ type: string
+ enum:
+ - function
+ - durable_function
+ - frontend
+ - project
+ id:
+ type: string
+ format: uuid
+ name:
+ type: string
+ required:
+ - type
+ - id
- name
- - title
- additionalProperties: false
- PaginatedDurableApprovals:
+ LavaflowAnomaly:
+ type: object
+ properties:
+ flagged:
+ type: boolean
+ reason:
+ type: string
+ nullable: true
+ description: Why the resource is flagged, null when it is not.
+ required:
+ - flagged
+ - reason
+ LavaflowResource:
+ type: object
+ properties:
+ project_id:
+ type: string
+ format: uuid
+ description: The project the resource belongs to.
+ resource:
+ $ref: '#/components/schemas/LavaflowResourceReference'
+ last_analyzed_at:
+ type: string
+ format: date-time
+ nullable: true
+ description: When a LavaFlow run last started on the resource, null if never.
+ issues_opened:
+ type: integer
+ format: int64
+ description: Issues LavaFlow took on in the window.
+ pull_requests_opened:
+ type: integer
+ format: int64
+ description: Pull requests with a fix LavaFlow opened in the window.
+ anomaly:
+ $ref: '#/components/schemas/LavaflowAnomaly'
+ required:
+ - project_id
+ - resource
+ - last_analyzed_at
+ - issues_opened
+ - pull_requests_opened
+ - anomaly
+ LavaflowResourceList:
type: object
properties:
data:
type: array
items:
- $ref: '#/components/schemas/DurableApproval'
- page:
- type: integer
- description: Current page number (1-indexed)
- limit:
- type: integer
- description: Number of items per page
- total:
- type: integer
- description: Total number of items across all pages
- has_more:
- type: boolean
- description: Whether there are more pages available
+ $ref: '#/components/schemas/LavaflowResource'
required:
- data
- - page
- - limit
- - total
- - has_more
- DurableMessageName:
- type: string
- minLength: 1
- maxLength: 237
- pattern: ^[ -~]+$
- description: |
- The name a workflow waits on or publishes under: up to 237 printable
- ASCII characters.
- DurableMessageDirection:
+ LavaflowRunStatus:
type: string
enum:
- - in
- - out
- x-enum-varnames:
- - DurableMessageDirectionIn
- - DurableMessageDirectionOut
- description: |
- `in` is a message sent to the execution. `out` is one the execution
- published.
- DurableMessage:
+ - queued
+ - diagnosing
+ - fixing
+ - reviewing
+ - pr_open
+ - completed
+ - failed
+ - cancelled
+ description: Where a run is. `diagnosing`, `fixing` and `reviewing` are the stages of a running run. `pr_open` means its pull request is open; `completed` means it finished, with no pull request or one that was merged or closed.
+ LavaflowPullRequest:
type: object
- description: A message sent to, or published by, a durable execution.
properties:
- id:
- type: string
- format: uuid
- execution_id:
- type: string
- format: uuid
- direction:
- $ref: '#/components/schemas/DurableMessageDirection'
- seq:
+ number:
type: integer
format: int64
- description: |
- Orders the execution's messages in both directions. It increases
- with every message but can skip numbers. Pass the last one you read
- as `after` to read what came next.
- name:
+ url:
type: string
- data:
- x-go-type: json.RawMessage
- x-go-type-skip-optional-pointer: true
+ format: uri
+ branch:
+ type: string
+ description: The recorded pull request branch. Omitted when it was not recorded, the run's fix is withheld because it may add a credential, or the full branch name cannot be served under the project's text privacy checks. It is never shortened.
+ state:
+ type: string
+ enum:
+ - open
+ - merged
+ - closed
+ opened_at:
+ type: string
+ format: date-time
nullable: true
- description: The JSON value sent or published, or null.
- sender:
- $ref: '#/components/schemas/DurableMessageSender'
- status:
- $ref: '#/components/schemas/DurableMessageStatus'
- delivered_at:
+ description: When the run opened the pull request, null for one opened before LavaFlow recorded the time.
+ merged_at:
type: string
format: date-time
nullable: true
- description: When the execution received the message. Null until then, and for `out` messages.
- sent_at:
+ description: When the pull request merged; null unless `state` is `merged`.
+ deployed_at:
type: string
format: date-time
- required:
- - id
- - execution_id
- - direction
- - seq
- - name
- - data
- - sender
- - status
- - delivered_at
- - sent_at
- DurableMessageList:
- type: object
- properties:
- data:
- type: array
- description: Messages after `after`, oldest first.
- items:
- $ref: '#/components/schemas/DurableMessage'
- has_more:
+ nullable: true
+ description: 'When the merged fix went live: the first live deployment of the issue''s resource that includes it finished. When more than 20 deployments went live between the merge and the one LavaFlow found the fix in, LavaFlow can''t tell which first included it, and this is the merge time. Null until LavaFlow finds the fix live, and for a pull request that didn''t merge. LavaFlow watches the resource''s deployments for a week after the merge.'
+ draft:
type: boolean
- description: |
- Whether more messages follow. Read them with `after` set to the
- last message's `seq`.
+ nullable: true
+ description: Whether the pull request is a draft, as GitHub last reported it to LavaFlow. Null for one opened before LavaFlow recorded it.
+ draft_reason:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowDraftReason'
+ nullable: true
+ description: Why the pull request is a draft, null unless `draft` is true.
required:
- - data
- - has_more
- DurableMessageWait:
+ - number
+ - url
+ - state
+ - opened_at
+ - merged_at
+ - deployed_at
+ - draft
+ - draft_reason
+ LavaflowRunMode:
+ type: string
+ enum:
+ - live
+ - code_quality
+ description: 'What the run works on: `live` for an issue seen in the project''s logs, `code_quality` for a Code Quality finding.'
+ LavaflowRunCategory:
+ type: string
+ enum:
+ - bug
+ - performance
+ - security
+ - improvement
+ - configuration
+ - dependency
+ - external
+ description: 'What kind of problem the run works on. `bug`: the project''s code is wrong. `performance`: the code is too slow or uses too much. `security`: the code exposes data or access it shouldn''t. `improvement`: the code mishandles an edge case or an outside failure. `configuration`: a setting, variable or manifest value is wrong or missing. `dependency`: a package or its version causes it. `external`: a service outside the project fails and no repository change is right. A Code Quality run''s is its finding''s, `bug` or `improvement`. Any other run''s is `dependency` or `configuration` for a fix that changes only such files, else the kind its diagnosis names. New values may appear; treat an unknown value as uncategorized.'
+ LavaflowDraftReason:
+ type: string
+ enum:
+ - open_pr
+ - review_unresolved
+ - converted_to_draft
+ x-enum-varnames:
+ - LavaflowDraftReasonOpenPr
+ - LavaflowDraftReasonReviewUnresolved
+ - LavaflowDraftReasonConvertedToDraft
+ description: 'Why a run''s pull request is a draft. `open_pr`: LavaFlow doesn''t merge the fix, because the project''s autonomy is `open_pr`, merging was unavailable when it opened, LavaFlow started the run on its own under settings saved with automatic runs off before this API (sending `autonomy: merge` again as the owner lifts that), or it was already a draft when the run took it on; it waits for a person to review it and mark it ready. `review_unresolved`: LavaFlow''s review didn''t pass the fix, so LavaFlow never merges it; a person decides whether to finish it. `converted_to_draft`: LavaFlow opened it ready for review, and someone made it a draft since.'
+ LavaflowSkipReason:
+ type: string
+ enum:
+ - diagnose_only
+ - not_fixable
+ - low_confidence
+ - no_patch
+ - possible_credential
+ - possible_personal_data
+ - ungated_workflows
+ - convention_unsatisfiable
+ - pull_request_open
+ - source_unavailable
+ - permission_missing
+ - repository_changed
+ - publish_failed
+ - lineage_cap
+ - lineage_held
+ - review_unresolved
+ - duplicate_in_repository
+ - security_finding
+ x-enum-varnames:
+ - LavaflowSkipReasonDiagnoseOnly
+ - LavaflowSkipReasonNotFixable
+ - LavaflowSkipReasonLowConfidence
+ - LavaflowSkipReasonNoPatch
+ - LavaflowSkipReasonPossibleCredential
+ - LavaflowSkipReasonPossiblePersonalData
+ - LavaflowSkipReasonUngatedWorkflows
+ - LavaflowSkipReasonConventionUnsatisfiable
+ - LavaflowSkipReasonPullRequestOpen
+ - LavaflowSkipReasonSourceUnavailable
+ - LavaflowSkipReasonPermissionMissing
+ - LavaflowSkipReasonRepositoryChanged
+ - LavaflowSkipReasonPublishFailed
+ - LavaflowSkipReasonLineageCap
+ - LavaflowSkipReasonLineageHeld
+ - LavaflowSkipReasonReviewUnresolved
+ - LavaflowSkipReasonDuplicateInRepository
+ - LavaflowSkipReasonSecurityFinding
+ description: 'Why a finished run opened no pull request, with what you can do next. `diagnose_only`: the project''s `autonomy` was `diagnose_only` when the run was queued, or became it before the pull request opened, so LavaFlow only diagnosed the issue; read the diagnosis. For later runs to open pull requests, send `"autonomy": "open_pr"` to `PATCH /lavaflow/settings`, or run `volcano cloud lavaflow settings set --autonomy open_pr`. `not_fixable`: the diagnosis found no change in the code that fixes the error, for example because the cause is outside it; read the diagnosis. `low_confidence`: the diagnosis is not confident enough to propose a fix; read the diagnosis. `no_patch`: LavaFlow proposed no change; read the diagnosis. `possible_credential`: the fix or its description held what looks like a credential or a project secret, so LavaFlow pushed nothing; apply the fix yourself from the diagnosis. `possible_personal_data`: the fix adds an email address the repository lacks, and the repository isn''t private, so LavaFlow pushed nothing; apply the fix yourself. `ungated_workflows`: a workflow could run the fix with the repository''s secrets before a person approves it; gate the workflow on a label a person adds, or turn on `allow_ungated_workflows`. `convention_unsatisfiable`: LavaFlow would merge the fix, but no title can meet the repository''s commit convention, so it kept the fix on the run; apply the fix yourself, or relax the convention. `pull_request_open`: when the run checked, before opening a pull request, another LavaFlow pull request for the issue was open, or merged and not yet deployed, so this run opened none; a fix it wrote stays on the run. That pull request may have closed since; find it with `GET /lavaflow/runs?project_id=…&issue_id=…`, whose runs carry their `pull_request`. Review it, or close it if you don''t want it. `source_unavailable`: LavaFlow couldn''t read, or open a fix on, the code that served the error; the run''s `source_unavailable` says why and what to do. `permission_missing`: the Volcano GitHub App, or the project owner''s GitHub account, lacks a permission LavaFlow needs; grant the App''s requested permissions and make sure the owner can push to the repository. `repository_changed`: the project no longer deploys from the repository the run read; a new run uses the current one. `publish_failed`: opening the pull request failed; a new run tries again. `lineage_cap`: LavaFlow opened as many pull requests in this fix''s lineage as it may; review the lineage''s pull requests and fix the rest yourself. `lineage_held`: an earlier pull request in this fix''s lineage was held, stopped or closed, so LavaFlow opens no more in it; apply the fix yourself from the diagnosis. `review_unresolved`: LavaFlow''s review didn''t pass a Code Quality fix; read the diagnosis. `duplicate_in_repository`: when the run checked, another project on the repository already had the Code Quality pull request for the same finding; review that pull request in the repository. `security_finding`: the finding has security impact and the repository isn''t private, so the fix would disclose it; fix it yourself. New reasons may appear.'
+ LavaflowRunSummary:
type: object
- description: A wait an execution has open for a message.
properties:
id:
type: string
format: uuid
- name:
+ project_id:
type: string
+ format: uuid
+ description: The project the run belongs to.
status:
- $ref: '#/components/schemas/DurableMessageWaitStatus'
- expires_at:
+ $ref: '#/components/schemas/LavaflowRunStatus'
+ resource:
+ $ref: '#/components/schemas/LavaflowResourceReference'
+ issue_id:
+ type: string
+ format: uuid
+ title:
type: string
- format: date-time
nullable: true
- description: When the wait times out. Null when the workflow set no timeout.
+ description: 'Names the problem the run worked on, in at most 80 characters: its diagnosis'' title, else the title of the fix it proposed, else the first line or sentence of its diagnosis'' summary. A sentence too long for a title ends at its last clause that fits, or, with none, is cut at a word and ends with `…`. Null while none is known, and when it or the text it comes from may contain a credential or hold one of the project''s secret values.'
+ fix_summary:
+ type: string
+ maxLength: 80
+ description: The saved proposed fix's title, on one line of at most 80 characters. This describes a proposal, not a verified fix, successful review, merge or deployment. It never falls back to the diagnosis. Omitted when no saved patch title is known, the fix is withheld because it may add a credential, or the full title cannot pass the project's text privacy checks. The full title is checked before normalization and shortening, and the resulting text is checked again. A shortened value ends with `…`.
created_at:
type: string
format: date-time
+ finished_at:
+ type: string
+ format: date-time
+ nullable: true
+ pull_request:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowPullRequest'
+ nullable: true
+ merge:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowMerge'
+ nullable: true
+ mode:
+ $ref: '#/components/schemas/LavaflowRunMode'
+ category:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowRunCategory'
+ nullable: true
+ description: A Code Quality run carries its finding's from the start. Any other run's is null until LavaFlow records a diagnosis. Runs from before categories get one when their diagnosis names one or their saved fix's paths imply one, and stay null only when neither does.
+ resources:
+ type: array
+ description: 'Every resource the run involves: the issue''s first, then by name. A run without a recorded diagnosis lists only the issue''s. For a run whose report came from what it saved rather than its source, such as one from before involved resources were recorded, the list may leave out frontends and the functions involved through shared code or the build root''s dependency files.'
+ items:
+ $ref: '#/components/schemas/LavaflowInvolvedResource'
+ issue:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowIssueSummary'
+ nullable: true
+ description: Null only for a run that works on no issue.
+ progress:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowRunProgress'
+ nullable: true
+ description: Where a run LavaFlow is still working on stands; null once it has nothing left to do.
+ pull_request_skipped:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowSkipReason'
+ nullable: true
+ description: Why a finished run opened no pull request. A `completed` run without `pull_request` always has one; it is `diagnose_only` when the project's `autonomy` stopped the run at its diagnosis. Null when the run opened a pull request, while it is queued or runs, and when it failed or was cancelled.
+ lineage:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowLineage'
+ nullable: true
+ description: The fix lineage the run belongs to. Null for a run in no lineage.
+ fix_outcome:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowFixOutcome'
+ nullable: true
+ description: How the run's merged fix fared once it went live. Null until a merged fix goes live with the `lavaflow.lineage` capability on.
required:
- id
- - name
+ - project_id
- status
- - expires_at
+ - resource
+ - issue_id
+ - title
- created_at
- DurableMessageWaitList:
+ - finished_at
+ - pull_request
+ - merge
+ - mode
+ - category
+ - resources
+ - issue
+ - progress
+ - pull_request_skipped
+ - lineage
+ - fix_outcome
+ LavaflowLogLine:
type: object
properties:
- data:
+ timestamp:
+ type: string
+ format: date-time
+ nullable: true
+ level:
+ type: string
+ message:
+ type: string
+ required:
+ - timestamp
+ - level
+ - message
+ LavaflowDiagnosis:
+ type: object
+ description: Each text reads `LavaFlow left this section out because it may contain a credential` when it may contain a credential, holds one of the project's secret values, or is over 4,000 characters, as the fix's pull request description leaves it out. A log line's `level` reads `""` then.
+ properties:
+ summary:
+ type: string
+ root_cause:
+ type: string
+ evidence:
type: array
- description: Open waits, oldest first.
items:
- $ref: '#/components/schemas/DurableMessageWait'
+ type: string
+ log_lines:
+ type: array
+ description: Empty for now. `evidence` cites the log lines the diagnosis relies on.
+ items:
+ $ref: '#/components/schemas/LavaflowLogLine'
required:
- - data
- SendDurableMessageRequest:
+ - summary
+ - root_cause
+ - evidence
+ - log_lines
+ LavaflowReview:
type: object
properties:
- name:
- $ref: '#/components/schemas/DurableMessageName'
- data:
- x-go-type: json.RawMessage
+ verdict:
+ type: string
+ enum:
+ - passed
+ - changes_requested
+ - blocked
+ - error
+ description: The last review round's verdict. `blocked` means a critical or major finding stops the fix; `changes_requested` means only minor findings do; `error` means a reviewer failed without a blocking finding, or no reviewer could run.
+ rounds:
+ type: integer
+ description: The review rounds that ran, 0 when no reviewer could run.
+ stopped:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowReviewStop'
+ nullable: true
+ description: Why the review ended without passing the fix, null when it passed the fix or when the run saved no fix.
+ open_findings:
+ type: array
+ x-go-type-skip-optional-pointer: true
+ items:
+ $ref: '#/components/schemas/LavaflowReviewFinding'
+ description: The findings the review saved with the fix left open. Absent when the review passed the fix, left none open, or the run saved no fix.
+ person_reasons:
+ type: array
x-go-type-skip-optional-pointer: true
+ items:
+ $ref: '#/components/schemas/LavaflowReviewPersonReason'
+ description: What the review saved with the fix asks a person to decide before the fix merges. Absent when it asks nothing or the run saved no fix.
+ required:
+ - verdict
+ - rounds
+ - stopped
+ LavaflowReviewFinding:
+ type: object
+ description: 'A finding the review left open, in the reviewer''s words. When LavaFlow withholds `explanation`, a sentence that says why stands in: `LavaFlow left this explanation out because it may contain a credential` when it may contain a credential or holds one of the project''s secret values; `… because it''s too long to check for a credential` when it is over 4,000 characters; `… because the fix may add a credential` when the run is held with `possible_credential`; `… because it withheld the changes to this file` when `diff` withholds the changes to its `file`, even past a truncated diff''s cut; `… because it withheld this file''s path` when `file` is `""`; and `… because it can''t tell whether it withheld the changes to this file` when the finding has a `file` and `diff` withholds a file it doesn''t name, can''t tell its files apart, or the run saved no `diff`.'
+ properties:
+ severity:
+ type: string
+ enum:
+ - nit
+ - minor
+ - major
+ - critical
+ x-enum-varnames:
+ - LavaflowReviewFindingSeverityNit
+ - LavaflowReviewFindingSeverityMinor
+ - LavaflowReviewFindingSeverityMajor
+ - LavaflowReviewFindingSeverityCritical
+ file:
+ type: string
nullable: true
- description: Any JSON value, up to 64 KiB. Omitted means null.
+ description: The file the finding is about, null when it is about no file. `""` when the path itself may contain a credential, holds a project secret value, or is over 4,000 characters.
+ line:
+ type: integer
+ nullable: true
+ description: The line of `file` the finding is about, null when it is about no one line.
+ explanation:
+ type: string
+ required:
+ - severity
+ - file
+ - line
+ - explanation
+ LavaflowReviewPersonReason:
+ type: object
+ description: 'One decision the review leaves to a person. When LavaFlow withholds `question`, a sentence that says why stands in: `LavaFlow left this question out because it may contain a credential` when it may contain a credential or holds one of the project''s secret values; `… because it''s too long to check for a credential` when it is over 4,000 characters; and `… because the fix may add a credential` when the run is held with `possible_credential`.'
+ properties:
+ kind:
+ type: string
+ description: '`irreversible`: the fix deletes or migrates data, or does what a revert can''t undo. `trust_boundary`: it changes authentication, authorization, secrets, or who can reach what. `breaks_contract`: it changes an interface other code or users depend on. `billing`: it touches payments, pricing, metering, or charges. `unexplained`: it changes behavior its context doesn''t explain. `not_reviewable`: it couldn''t be reviewed closely. New kinds may appear.'
+ question:
+ type: string
+ description: What the person decides, written to show as given.
+ required:
+ - kind
+ - question
+ LavaflowReviewStop:
+ type: string
+ enum:
+ - rounds
+ - no_revision
+ - budget_exhausted
+ - context_limit
+ - timed_out
+ - reviewers_failed
+ - too_few_reviewers
+ - unreadable
+ x-enum-varnames:
+ - LavaflowReviewStopRounds
+ - LavaflowReviewStopNoRevision
+ - LavaflowReviewStopBudgetExhausted
+ - LavaflowReviewStopContextLimit
+ - LavaflowReviewStopTimedOut
+ - LavaflowReviewStopReviewersFailed
+ - LavaflowReviewStopTooFewReviewers
+ - LavaflowReviewStopUnreadable
+ description: 'Why a run''s review ended without passing its fix. `rounds`: the last review round still found problems. `no_revision`: LavaFlow gave no revised fix. `budget_exhausted`: the run used its token budget before LavaFlow could revise the fix; this is the run''s own budget, not the project''s daily spend limit. `context_limit`: the fix''s conversation grew too long for the model before LavaFlow could revise it. `timed_out`: the run''s time for review ran out. `reviewers_failed`: no reviewer of the last round finished. `too_few_reviewers`: fewer reviewers could run than a round needs to pass the fix. `unreadable`: a retried run could not read the review saved with its fix, so a person must review it. More values may be added: treat a value you don''t know as other.'
+ LavaflowFailure:
+ type: object
+ properties:
+ code:
+ type: string
+ description: Stable code, such as `timed_out` or `feature_paused`.
+ message:
+ type: string
+ description: Text to show for the code.
required:
- - name
- additionalProperties: false
- RegisterDurableMessageWaitRequest:
+ - code
+ - message
+ LavaflowRepositoryChecks:
type: object
+ description: Whether LavaFlow ran the repository's own checks, such as its tests, on a fix itself, before it opened a pull request or held the fix, and what they found. When LavaFlow ran them more than once, this is the last time the run's last attempt ran them; `not_run` when that attempt didn't, or while the run is queued or running. CI that runs on the pull request afterwards is the repository's own.
properties:
- execution_ref:
+ status:
type: string
- minLength: 1
- maxLength: 2048
- description: Opaque reference to the running execution, supplied by the SDK.
- callback_id:
+ description: '`passed`: every command the checks ran passed. `failed`: a command failed or timed out; `commands` shows which. `no_checks_found`: LavaFlow found no checks in the repository to run. `not_run`: LavaFlow did not run the repository''s checks on the fix, for the reason `reason` names. Treat a status you don''t know as `not_run`.'
+ reason:
type: string
- minLength: 1
- maxLength: 1024
- description: Opaque wait reference, supplied by the SDK.
- name:
- $ref: '#/components/schemas/DurableMessageName'
+ description: 'Stable code for why the checks did not run, present only when `status` is `not_run`. `dependencies_changed`: the fix changes the repository''s dependencies. `dependencies_not_installed`: LavaFlow couldn''t install the repository''s dependencies. `run_deadline`: the run reached its time limit. `sandbox_capacity`: no sandbox slot was free in time to run them. `sandbox_budget`: LavaFlow''s sandbox allowance for checks was used up. `sandbox_not_isolated`: LavaFlow couldn''t confirm the sandbox was isolated. `sandbox_plan_limit`: LavaFlow couldn''t start a sandbox large enough to run them. `sandbox_unavailable`: LavaFlow couldn''t run them itself. `source_too_large`: the repository is too large to copy into a sandbox. `source_unavailable`: LavaFlow couldn''t fetch the fix''s source to check it, as when the repository was disconnected or changed during the run. `tool_unavailable`: a tool the checks need isn''t available. New reasons may appear; treat one you don''t know like any other `not_run`.'
+ message:
+ type: string
+ description: 'Text to show for the status and reason. It names the pull request when one opened. For `not_run` on a fix whose pull request opened, a second sentence says what became of the repository''s CI there, as the run stands when read: whether LavaFlow started it, tried to, may still, or won''t.'
+ revised:
+ type: boolean
+ x-go-type-skip-optional-pointer: true
+ description: Present and `true` only when `status` is `failed` and LavaFlow then revised the fix once without running the checks again. `status` and `commands` describe that earlier version, not the fix as saved, which the checks never ran on.
+ commands:
+ type: array
+ x-go-type-skip-optional-pointer: true
+ items:
+ $ref: '#/components/schemas/LavaflowRepositoryCheckCommand'
+ description: The commands the checks ran, in order. Absent when LavaFlow recorded none, as for `no_checks_found` and `not_run`.
required:
- - execution_ref
- - callback_id
- - name
- additionalProperties: false
- DurableMessageWaitRegistration:
+ - status
+ - message
+ LavaflowRepositoryCheckCommand:
type: object
- description: The registered wait, as the waiting workflow sees it.
+ description: One command the repository's checks ran. `command` and `output` are the repository's own text, served as LavaFlow recorded it. `command` reads `LavaFlow left this command out because it may contain a credential`, and `output` reads `LavaFlow left this output out because it may contain a credential`, when that text may contain a credential, holds one of the project's secret values, or is over 4,000 characters, and when the run is held with `possible_credential`.
properties:
- id:
+ command:
type: string
- format: uuid
+ description: The command as LavaFlow ran it.
status:
- $ref: '#/components/schemas/DurableMessageWaitStatus'
- expires_at:
type: string
- format: date-time
+ description: '`passed`: the command succeeded. `failed`: it exited with an error. `timed_out`: it ran past its time limit, and LavaFlow stopped it. Treat a status you don''t know as `failed`.'
+ exit_code:
+ type: integer
nullable: true
+ description: The code the command exited with, null when it gave none, as a command that timed out may not.
+ output:
+ type: string
+ description: The end of what the command printed, present only when `status` is `failed` or `timed_out` and LavaFlow kept it; `""` when it printed nothing.
required:
- - id
+ - command
- status
- - expires_at
- OpenDurableMessageSessionRequest:
- type: object
+ - exit_code
+ LavaflowRun:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowRunSummary'
+ - type: object
+ properties:
+ source_commit:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowSourceCommit'
+ nullable: true
+ description: The commit the run read the code at. Null when it read none, as for a run that diagnosed from the logs alone.
+ diagnosis:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowDiagnosis'
+ nullable: true
+ diff:
+ type: string
+ nullable: true
+ description: The fix LavaFlow saved, as the unified diff its reviewers read, cut short past 256 KiB as they read it, with a last line that starts with `[diff truncated`. When a file's content, before or after the fix, or any change to it may hold a credential, or the file is too long for LavaFlow to read whole (over 64 KiB, or past 256 KiB across the fix's files), every change to that file is left out, with one line in their place that starts with `# LavaFlow withheld` and names the file. A run held with `possible_credential` leaves out every file. Null for a run with no saved fix, or one saved before LavaFlow kept its diff.
+ diff_sha256:
+ type: string
+ nullable: true
+ pattern: ^[0-9a-f]{64}$
+ description: The SHA-256, in hex, of `diff` exactly as served, its UTF-8 bytes. Null whenever `diff` is.
+ example: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
+ diff_truncated:
+ type: boolean
+ description: '`diff` was cut short, so it does not show the whole fix. False when `diff` is null.'
+ diff_withheld:
+ type: array
+ items:
+ type: string
+ description: The files whose changes `diff` leaves out, by path, as its `# LavaFlow withheld` lines name them; an empty string for a file whose path may itself hold a credential. Empty when `diff` shows every file, or is null.
+ review:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowReview'
+ nullable: true
+ description: The review of the run's fix. When no reviewer could run, it still says why in `stopped`. Null when no review ran.
+ repository_checks:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowRepositoryChecks'
+ nullable: true
+ description: Whether LavaFlow ran the repository's own checks on the fix itself. Null for a run with no fix.
+ failure:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowFailure'
+ nullable: true
+ description: Why the run stopped or waits, null when nothing went wrong.
+ changed_files:
+ type: array
+ items:
+ type: string
+ description: Repository paths the fix changes, sorted; empty without a fix. A path that may itself hold a credential is listed as "", as `diff_withheld` lists it, and so is every path when `diff` can't tell the fix's files apart. A file past a truncated `diff`'s cut is listed.
+ ungated_workflows:
+ type: array
+ nullable: true
+ items:
+ $ref: '#/components/schemas/LavaflowAllowedWorkflow'
+ description: The workflow jobs the run's pull request opened past because the project's owner allowed ungated workflows, the first one on each branch or commit checked. Empty when none or when the run opened no pull request. Null when there is no record of the workflows its pull request opened past, as for pull requests opened before LavaFlow recorded them. Under the merge stage, LavaFlow holds such a fix as unchecked, with `ungated_workflows`.
+ lineage_evidence:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowLineageEvidence'
+ nullable: true
+ description: What tied the run's issue to a recent LavaFlow fix's deploy. Null when nothing did, and for a recurrence, whose issue came back after the fix.
+ held_workflows:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowHeldWorkflows'
+ nullable: true
+ description: For a run whose `pull_request_skipped` is `ungated_workflows`, every workflow job that held its fix. Null for any other run, and for a held run whose workflows LavaFlow couldn't read to the end, such as one with a workflow it couldn't parse, or more than 256 such jobs.
+ source_unavailable:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowSourceUnavailable'
+ nullable: true
+ description: For a run whose `pull_request_skipped` is `source_unavailable`, why LavaFlow couldn't read, or open a fix on, the code that served the error. Null for any other run, for a run recorded before LavaFlow kept the reason, and when LavaFlow couldn't tell why.
+ required:
+ - source_commit
+ - diagnosis
+ - diff
+ - diff_sha256
+ - diff_truncated
+ - diff_withheld
+ - review
+ - repository_checks
+ - failure
+ - changed_files
+ - ungated_workflows
+ - lineage_evidence
+ - held_workflows
+ - source_unavailable
+ LavaflowAllowedWorkflow:
+ type: object
+ description: A workflow job that could run a fix's pull request with the repository's secrets before a person approves it.
properties:
- execution_ref:
+ source:
type: string
- minLength: 1
- maxLength: 2048
- description: Opaque reference to the running execution, supplied by the SDK.
- callback_id:
+ description: The branch or commit whose workflows run it.
+ example: main
+ path:
type: string
- minLength: 1
- maxLength: 1024
- description: Opaque session reference, supplied by the SDK.
+ example: .github/workflows/preview.yml
+ job:
+ type: string
+ description: The job, absent for a workflow that could not be read.
+ example: deploy-preview
+ trigger:
+ type: string
+ description: The event that runs it, absent for a workflow that could not be read.
+ example: pull_request_target
required:
- - execution_ref
- - callback_id
- additionalProperties: false
- DurableMessageSessionRegistration:
+ - source
+ - path
+ LavaflowHeldWorkflows:
type: object
- description: |
- The registered session. Its token reaches the workflow through the
- workflow itself, never in this response.
+ description: Every workflow job that could run a held fix's pull request with the repository's secrets before a person approves it, as LavaFlow found them when it held the fix, and the commits it read the workflows at.
properties:
- id:
+ read_at:
+ type: array
+ items:
+ $ref: '#/components/schemas/LavaflowWorkflowSource'
+ description: 'Each branch or commit whose workflows LavaFlow read: the project''s production branch, the repository''s default branch, and the commit the fix is cut from.'
+ jobs:
+ type: array
+ items:
+ $ref: '#/components/schemas/LavaflowAllowedWorkflow'
+ description: Every such job, at most 256, sorted by source, path and job. Empty when LavaFlow read every workflow to the end and found none, such as when they changed between the hold and the read.
+ jobs_sha256:
type: string
- format: uuid
+ pattern: ^[0-9a-f]{64}$
+ description: 'Identifies `read_at` and `jobs` together. Treat it as opaque: it changes when a listed job, or a commit the workflows were read at, does.'
+ example: 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae
required:
- - id
- PublishDurableMessageRequest:
+ - read_at
+ - jobs
+ - jobs_sha256
+ LavaflowWorkflowSource:
type: object
+ description: A branch or commit whose workflows LavaFlow read, and the commit it read them at.
properties:
- name:
- $ref: '#/components/schemas/DurableMessageName'
- data:
- x-go-type: json.RawMessage
- x-go-type-skip-optional-pointer: true
- nullable: true
- description: Any JSON value, up to 64 KiB. Omitted means null.
+ source:
+ type: string
+ description: The branch, or the commit SHA for a commit.
+ example: main
+ commit_sha:
+ type: string
+ description: The commit LavaFlow read the workflows at.
+ example: 3f786850e387550fdab836ed7e6dc881de23001b
required:
- - name
- additionalProperties: false
- RegisterDurableCallbackRequest:
+ - source
+ - commit_sha
+ LavaflowSourceUnavailable:
type: object
+ description: Why LavaFlow couldn't read, or open a fix on, the code that served a run's error, so the run opened no pull request.
properties:
- execution_ref:
- type: string
- minLength: 1
- maxLength: 2048
- description: Opaque reference to the running execution, supplied by the SDK.
- callback_id:
- type: string
- minLength: 1
- maxLength: 1024
- description: Opaque reference to the waiting step, supplied by the SDK.
- name:
- type: string
- minLength: 1
- maxLength: 237
- pattern: ^[ -~]+$
- description: The waiting step's name, up to 237 printable ASCII characters.
- operation_id:
+ reason:
+ $ref: '#/components/schemas/LavaflowSourceUnavailableReason'
+ deployment_id:
type: string
- minLength: 1
- maxLength: 64
- pattern: ^[0-9a-f]+$
- description: |
- The operation an earlier run of the workflow opened the waiting step
- under, supplied by the SDK when a replay registers it. Volcano then
- looks for the step further back in the execution's history than a
- first registration reads.
+ format: uuid
+ nullable: true
+ description: The deployment of the run's `resource` that served the error, for `no_commit`, `uncommitted_changes`, `unverified_commit` and `other_repository`. Null for any other reason, including `deployment_unattributed`, and when no deployment was serving.
+ example: 7c2e5a1f-3b8d-4e6a-9f0c-1d2e3f4a5b6c
required:
- - execution_ref
- - callback_id
- - name
- additionalProperties: false
- DurableCallbackRegistration:
+ - reason
+ - deployment_id
+ LavaflowSourceUnavailableReason:
+ type: string
+ enum:
+ - no_repository
+ - no_commit
+ - uncommitted_changes
+ - unverified_commit
+ - other_repository
+ - repository_unreadable
+ - commit_not_on_production_branch
+ - deployment_unattributed
+ x-enum-varnames:
+ - LavaflowSourceUnavailableReasonNoRepository
+ - LavaflowSourceUnavailableReasonNoCommit
+ - LavaflowSourceUnavailableReasonUncommittedChanges
+ - LavaflowSourceUnavailableReasonUnverifiedCommit
+ - LavaflowSourceUnavailableReasonOtherRepository
+ - LavaflowSourceUnavailableReasonRepositoryUnreadable
+ - LavaflowSourceUnavailableReasonCommitNotOnProductionBranch
+ - LavaflowSourceUnavailableReasonDeploymentUnattributed
+ description: 'Why LavaFlow couldn''t read, or open a fix on, the code that served the error, with what you can do. LavaFlow reads the deployment that served the error, so once you deploy code it can read, it starts a new run when the error happens again. `no_repository`: LavaFlow is on for no repository; link one. `no_commit`: the deployment recorded no commit, nor did the build a redeploy serves, or no deployment was serving; deploy by pushing to the linked repository''s production branch, or with the CLI from a clean checkout of a commit on that branch. `uncommitted_changes`: the deployment''s files differ from its commit (`dirty: true`), as when the checkout had uncommitted changes; commit and push them, then deploy from the clean checkout. `unverified_commit`: Volcano couldn''t verify the deployment''s commit against the linked repository (`verification: none`), for example because the commit isn''t on the production branch, or the deployment is a function redeploy, which doesn''t carry its upload''s `verification: repository` commit; push the commit to the production branch and deploy it again. `other_repository`: the commit LavaFlow would read is from a repository other than the one LavaFlow is on for, Volcano checked it under an earlier repository link, or the project no longer links that repository. For a deployment, deploy again from the linked repository; for a reported problem or a Code Quality finding, start a new run while the project links the repository LavaFlow is on for. `repository_unreadable`: LavaFlow couldn''t read the repository at the commit, for example because the Volcano GitHub App lost access to it; check the project''s repository link and the App''s access. `commit_not_on_production_branch`: the production branch no longer holds the commit the fix is on, so LavaFlow opened no pull request; deploy from the production branch. `deployment_unattributed`: a newer deployment was going live when the error happened, so LavaFlow couldn''t tell which one threw it; if the error happens again, LavaFlow starts a new run once; if that run also ends `deployment_unattributed`, the next waits for a new deploy. A `deployment_unattributed` run right after another one, even one a deploy started, gets no such run. New reasons may appear.'
+ PaginatedLavaflowRuns:
type: object
- description: The token for the waiting step, as the workflow receives it.
properties:
- token:
- $ref: '#/components/schemas/DurableCallbackToken'
- expires_at:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/LavaflowRunSummary'
+ limit:
+ type: integer
+ description: Number of items per page
+ has_more:
+ type: boolean
+ description: Whether a next page exists
+ next_cursor:
type: string
- format: date-time
- nullable: true
- description: |
- When the waiting step times out and the token stops working. Null
- when the workflow set no timeout, in which case the token works
- until the execution ends.
+ description: Opaque cursor for the next page, present if has_more is true. It works only for the same project_id, caller and order.
+ counts:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowRunCounts'
+ description: Present with `include=counts`.
required:
- - token
- - expires_at
- SucceedDurableCallbackRequest:
+ - data
+ - limit
+ - has_more
+ LavaflowSkillStatus:
+ type: string
+ enum:
+ - proposed
+ - active
+ - retired
+ description: '`proposed` waits for the owner to activate it. `active` is in force. `retired` is set aside and can be restored.'
+ LavaflowSkillRetiredReason:
+ type: string
+ enum:
+ - harmful
+ - unused
+ - stale
+ - repository_changed
+ - gate
+ - owner
+ description: 'Why a skill retired. `repository_changed`: the project points at another repository, or none. `owner`: the owner retired it. `harmful`, `unused`, `stale` and `gate` are reserved for retirement LavaFlow does on its own, which comes in a later release.'
+ LavaflowSkillScope:
+ type: string
+ enum:
+ - project
+ - volcano
+ x-enum-varnames:
+ - LavaflowSkillScopeProject
+ - LavaflowSkillScopeVolcano
+ description: '`project` skills belong to this project and never leave it. `volcano` skills are written by Volcano for every project.'
+ LavaflowSkillAppliesTo:
type: object
+ description: Where a skill applies. Empty lists apply it to the whole project.
properties:
- token:
- $ref: '#/components/schemas/DurableCallbackToken'
- result:
- x-go-type: json.RawMessage
- x-go-type-skip-optional-pointer: true
- description: |
- Any JSON value other than null, up to 64 KiB. The waiting step
- resolves with it. Null is refused because a timeout resolves the
- step with null.
+ resource_ids:
+ type: array
+ maxItems: 20
+ items:
+ type: string
+ format: uuid
+ description: Functions, durable functions and frontends it applies to.
+ paths:
+ type: array
+ maxItems: 20
+ items:
+ type: string
+ minLength: 1
+ maxLength: 512
+ description: Repository path globs it applies to, relative to the repository root.
required:
- - token
- - result
- additionalProperties: false
- FailDurableCallbackRequest:
+ - resource_ids
+ - paths
+ LavaflowSkillCitation:
type: object
+ description: 'Repository code a skill rests on: a path and a string the file holds.'
properties:
- token:
- $ref: '#/components/schemas/DurableCallbackToken'
- error:
- $ref: '#/components/schemas/DurableCallbackError'
+ path:
+ type: string
+ anchor:
+ type: string
+ maxLength: 128
required:
- - token
- - error
- additionalProperties: false
- HeartbeatDurableCallbackRequest:
+ - path
+ - anchor
+ LavaflowSkillSource:
type: object
+ description: 'Where a version came from: a writer''s act on a fix''s pull request, or the owner''s edit.'
properties:
- token:
- $ref: '#/components/schemas/DurableCallbackToken'
+ kind:
+ type: string
+ enum:
+ - run
+ - person
+ run_id:
+ type: string
+ format: uuid
+ nullable: true
+ description: The run whose pull request taught it, for `run`.
+ pull_request:
+ type: integer
+ format: int64
+ nullable: true
+ description: That run's pull request number.
+ act:
+ type: string
+ enum:
+ - commit
+ - review
+ - comment
+ nullable: true
+ description: The writer's act it came from, for `run`.
+ user_id:
+ type: string
+ nullable: true
+ description: The person who edited it, for `person`.
required:
- - token
- additionalProperties: false
- DurableCallbackOutcome:
+ - kind
+ - run_id
+ - pull_request
+ - act
+ - user_id
+ LavaflowSkillCounts:
type: object
properties:
- status:
- $ref: '#/components/schemas/DurableCallbackStatus'
+ helpful:
+ type: integer
+ format: int64
+ description: Fixes that used the skill and merged as LavaFlow left them.
+ harmful:
+ type: integer
+ format: int64
+ description: Fixes that used the skill and a writer corrected or closed, or whose issue came back.
+ used:
+ type: integer
+ format: int64
+ description: Runs that loaded the skill's body.
required:
- - status
- Issue:
+ - helpful
+ - harmful
+ - used
+ LavaflowSkill:
type: object
- description: Runtime errors from one function or frontend, grouped by error type and stack.
+ description: A project skill with its active version.
properties:
id:
type: string
@@ -23274,49 +32634,53 @@ components:
project_id:
type: string
format: uuid
- resource:
- $ref: '#/components/schemas/ResourceReference'
- title:
- type: string
- description: |
- The error type and message, with values such as IDs, numbers, and
- URLs replaced by placeholders like `` and ``.
- error_type:
- type: string
- description: The exception class, such as `TypeError`. Omitted when the error has none.
- culprit:
+ scope:
+ $ref: '#/components/schemas/LavaflowSkillScope'
+ name:
type: string
- description: The innermost frame of your code in the stack, as `function (file)`. Omitted without a stack.
+ description: Unique in the project.
status:
- $ref: '#/components/schemas/IssueStatus'
- event_count:
+ $ref: '#/components/schemas/LavaflowSkillStatus'
+ retired_reason:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowSkillRetiredReason'
+ nullable: true
+ description: Why it retired, null unless `status` is `retired`.
+ version:
type: integer
format: int64
- description: Errors counted in this issue. A retried delivery can count an error twice.
- first_seen_at:
- type: string
- format: date-time
- last_seen_at:
+ description: The active version.
+ description:
type: string
- format: date-time
- last_region:
+ description: When the skill applies.
+ body:
type: string
- description: The region that served the latest error, such as `us-east-1`.
- sample_event_id:
+ description: Markdown, at most 2 KiB.
+ applies_to:
+ $ref: '#/components/schemas/LavaflowSkillAppliesTo'
+ citations:
+ type: array
+ items:
+ $ref: '#/components/schemas/LavaflowSkillCitation'
+ content_sha256:
type: string
- description: The ID of the latest error's log event, while logs retain it.
- sample_event_at:
+ description: The hash of the active version's text, as a run records it.
+ source:
+ $ref: '#/components/schemas/LavaflowSkillSource'
+ counts:
+ $ref: '#/components/schemas/LavaflowSkillCounts'
+ last_used_at:
type: string
format: date-time
- description: When the latest error's log event was written.
- resolved_at:
+ nullable: true
+ last_renewed_at:
type: string
format: date-time
- description: When the issue was resolved. Present only while it is resolved.
- regressed_at:
+ description: When the skill was created, or last renewed by the owner's edit, activation or restore.
+ retired_at:
type: string
format: date-time
- description: When a resolved issue was last seen again and reopened.
+ nullable: true
created_at:
type: string
format: date-time
@@ -23326,427 +32690,555 @@ components:
required:
- id
- project_id
- - resource
- - title
+ - scope
+ - name
- status
- - event_count
- - first_seen_at
- - last_seen_at
+ - retired_reason
+ - version
+ - description
+ - body
+ - applies_to
+ - citations
+ - content_sha256
+ - source
+ - counts
+ - last_used_at
+ - last_renewed_at
+ - retired_at
- created_at
- updated_at
- IssueStatus:
- type: string
- enum:
- - open
- - resolved
- - ignored
- description: |
- `open` until someone resolves or ignores the issue. A resolved issue
- seen again reopens.
- PaginatedIssues:
+ LavaflowSkillList:
type: object
properties:
data:
type: array
items:
- $ref: '#/components/schemas/Issue'
- limit:
+ $ref: '#/components/schemas/LavaflowSkill'
+ required:
+ - data
+ LavaflowSkillVersion:
+ type: object
+ properties:
+ skill_id:
+ type: string
+ format: uuid
+ project_id:
+ type: string
+ format: uuid
+ version:
type: integer
- description: Number of items per page
- has_more:
- type: boolean
- description: Whether a next page exists
- next_cursor:
+ format: int64
+ description:
type: string
- description: Opaque cursor for the next page (present if has_more is true)
+ body:
+ type: string
+ applies_to:
+ $ref: '#/components/schemas/LavaflowSkillAppliesTo'
+ citations:
+ type: array
+ items:
+ $ref: '#/components/schemas/LavaflowSkillCitation'
+ content_sha256:
+ type: string
+ source:
+ $ref: '#/components/schemas/LavaflowSkillSource'
+ created_at:
+ type: string
+ format: date-time
+ required:
+ - skill_id
+ - project_id
+ - version
+ - description
+ - body
+ - applies_to
+ - citations
+ - content_sha256
+ - source
+ - created_at
+ LavaflowSkillVersionList:
+ type: object
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/LavaflowSkillVersion'
+ required:
+ - data
+ LavaflowSkillAppliesToUpdate:
+ type: object
+ additionalProperties: false
+ minProperties: 1
+ description: The members of `applies_to` to change. An omitted member keeps its value, and a list you send replaces it, so `[]` clears it.
+ properties:
+ resource_ids:
+ type: array
+ maxItems: 20
+ items:
+ type: string
+ format: uuid
+ description: Functions, durable functions and frontends it applies to.
+ paths:
+ type: array
+ maxItems: 20
+ items:
+ type: string
+ minLength: 1
+ maxLength: 512
+ description: Repository path globs it applies to, relative to the repository root.
+ LavaflowSkillUpdate:
+ type: object
+ additionalProperties: false
+ minProperties: 1
+ description: The fields to change. An omitted field keeps its value.
+ properties:
+ description:
+ type: string
+ minLength: 1
+ maxLength: 300
+ body:
+ type: string
+ minLength: 1
+ maxLength: 2048
+ applies_to:
+ $ref: '#/components/schemas/LavaflowSkillAppliesToUpdate'
+ status:
+ type: string
+ enum:
+ - active
+ - retired
+ description: '`active` activates a proposed skill or restores a retired one. `retired` retires it.'
+ LavaflowSkillError:
+ type: object
+ description: An error, with the rules a refused skill failed.
+ properties:
+ error:
+ type: string
+ code:
+ type: string
+ description: '`skill_refused` means the skill check refused the text. `feature_unavailable` means the change needs the project''s `lavaflow.skills` capability.'
+ rules:
+ type: array
+ items:
+ type: string
+ enum:
+ - characters
+ - shape
+ - credential_scan
+ - sanitizer
+ - credential
+ - secret
+ - read_value
+ - email
+ - link
+ - directive
+ - policy
+ description: With `skill_refused`, the rules the text failed. The answer never repeats the text.
+ required:
+ - error
+ LavaflowGlobalSkillAppliesTo:
+ type: object
+ description: Where a global skill applies. Empty lists apply it to every project.
+ properties:
+ runtimes:
+ type: array
+ items:
+ type: string
+ frameworks:
+ type: array
+ items:
+ type: string
+ resource_types:
+ type: array
+ items:
+ type: string
+ required:
+ - runtimes
+ - frameworks
+ - resource_types
+ LavaflowGlobalSkill:
+ type: object
+ description: A skill Volcano wrote for every project. It holds no customer content.
+ properties:
+ scope:
+ $ref: '#/components/schemas/LavaflowSkillScope'
+ name:
+ type: string
+ description: Runs list it as `volcano:`.
+ description:
+ type: string
+ body:
+ type: string
+ applies_to:
+ $ref: '#/components/schemas/LavaflowGlobalSkillAppliesTo'
+ content_sha256:
+ type: string
+ description: The hash of the skill's file, which identifies its version.
+ required:
+ - scope
+ - name
+ - description
+ - body
+ - applies_to
+ - content_sha256
+ LavaflowGlobalSkillList:
+ type: object
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/LavaflowGlobalSkill'
+ required:
+ - data
+ LavaflowRunProgress:
+ type: object
+ description: 'How far an active run has come. The steps are `queued`, `diagnosing`, `fixing`, `reviewing`, `waiting_for_checks` and `merge_queued`, in that order, and a run takes as many as its autonomy when it was queued allows: 2 for `diagnose_only`, 4 for `open_pr` (opening the pull request ends it), 6 for `merge` (the merge ends it).'
+ properties:
+ stage:
+ type: string
+ enum:
+ - queued
+ - diagnosing
+ - fixing
+ - reviewing
+ - waiting_for_checks
+ - merge_queued
+ description: New stages may appear.
+ step:
+ type: integer
+ description: The stage's place among the run's steps, from 1.
+ steps:
+ type: integer
+ description: How many steps the run takes.
+ required:
+ - stage
+ - step
+ - steps
+ LavaflowRunCounts:
+ type: object
+ description: Runs that match the request. `total` applies every filter. Each breakdown applies every filter but its own, so it shows what picking another value would return.
+ properties:
+ total:
+ type: integer
+ format: int64
+ status:
+ $ref: '#/components/schemas/LavaflowRunStatusCounts'
+ category:
+ $ref: '#/components/schemas/LavaflowCategoryCounts'
+ pull_request_state:
+ $ref: '#/components/schemas/LavaflowPullRequestStateCounts'
+ involved_resources:
+ type: array
+ maxItems: 50
+ description: Resources involved in at least one matching run, most runs first, then by name; at most 50. A run counts once per resource it involves. A run whose report came from what it saved rather than its source, such as one from before involved resources were recorded, may leave out frontends and the functions involved through shared code or the build root's dependency files, so these counts can undercount them.
+ items:
+ $ref: '#/components/schemas/LavaflowInvolvedResourceCount'
+ required:
+ - total
+ - status
+ - category
+ - pull_request_state
+ - involved_resources
+ LavaflowRunStatusCounts:
+ type: object
+ description: Matching runs in each status, zeros included.
+ properties:
+ queued:
+ type: integer
+ format: int64
+ diagnosing:
+ type: integer
+ format: int64
+ fixing:
+ type: integer
+ format: int64
+ reviewing:
+ type: integer
+ format: int64
+ pr_open:
+ type: integer
+ format: int64
+ completed:
+ type: integer
+ format: int64
+ failed:
+ type: integer
+ format: int64
+ cancelled:
+ type: integer
+ format: int64
+ required:
+ - queued
+ - diagnosing
+ - fixing
+ - reviewing
+ - pr_open
+ - completed
+ - failed
+ - cancelled
+ LavaflowCategoryCounts:
+ type: object
+ description: Matching runs in each category, zeros included. `uncategorized` counts runs whose `category` is null.
+ properties:
+ bug:
+ type: integer
+ format: int64
+ performance:
+ type: integer
+ format: int64
+ security:
+ type: integer
+ format: int64
+ improvement:
+ type: integer
+ format: int64
+ configuration:
+ type: integer
+ format: int64
+ dependency:
+ type: integer
+ format: int64
+ external:
+ type: integer
+ format: int64
+ uncategorized:
+ type: integer
+ format: int64
+ required:
+ - bug
+ - performance
+ - security
+ - improvement
+ - configuration
+ - dependency
+ - external
+ - uncategorized
+ LavaflowPullRequestStateCounts:
+ type: object
+ description: Matching runs by the state of their pull request, zeros included. `none` counts runs without one.
+ properties:
+ open:
+ type: integer
+ format: int64
+ merged:
+ type: integer
+ format: int64
+ closed:
+ type: integer
+ format: int64
+ none:
+ type: integer
+ format: int64
required:
- - data
- - limit
- - has_more
- UpdateIssueRequest:
+ - open
+ - merged
+ - closed
+ - none
+ LavaflowInvolvedResourceCount:
type: object
- additionalProperties: false
+ description: A resource and how many matching runs involve it.
properties:
- status:
- $ref: '#/components/schemas/IssueStatus'
+ resource:
+ $ref: '#/components/schemas/LavaflowResourceReference'
+ runs:
+ type: integer
+ format: int64
required:
- - status
- AutofixSettings:
+ - resource
+ - runs
+ LavaflowCodeQualitySettings:
type: object
- additionalProperties: false
+ description: 'LavaFlow Code Quality: whether LavaFlow reviews the code each production deploy changes and opens pull requests that fix what it confirms.'
properties:
- project_id:
- type: string
- format: uuid
enabled:
type: boolean
- description: Whether Volcano diagnoses the project's issues with AI.
- max_stage:
- $ref: '#/components/schemas/AutofixStage'
- auto_trigger:
- type: boolean
- description: Whether a new or reopened issue starts a run on its own. When false, runs start only on request.
- provider:
- $ref: '#/components/schemas/AutofixProvider'
- model:
- $ref: '#/components/schemas/AutofixModel'
- api_key_configured:
- type: boolean
- description: Whether your own API key is stored. The key itself is never returned.
- api_key_provider:
- allOf:
- - $ref: '#/components/schemas/AutofixProvider'
- description: The provider the stored key belongs to, present when one is stored.
- api_key_last4:
- type: string
- description: The stored key's last four characters, present when one is stored.
- plan_includes_autofix:
- type: boolean
- description: Whether the owner's plan includes autofix. When false, saved settings stay stored and no run starts. Absent when a save that needed no plan succeeded but the plan could not be resolved.
- updated_at:
- type: string
- format: date-time
- description: When the settings were last saved. Absent until the first save.
+ description: Whether Code Quality reviews the project's deploys. Off by default. It reads as off while the project points at another repository than the one it was turned on for, and works only while LavaFlow is on.
required:
- - project_id
- enabled
- - max_stage
- - auto_trigger
- - provider
- - model
- - api_key_configured
- AutofixStage:
- type: string
- enum:
- - diagnose
- - pull_request
- x-enum-varnames:
- - AutofixStageDiagnose
- - AutofixStagePullRequest
- description: How far a run may go. `diagnose` stops at a root-cause diagnosis. `pull_request` may also open a draft pull request with a fix in the project's connected repository.
- AutofixProvider:
- type: string
- enum:
- - volcano
- - anthropic
- x-enum-varnames:
- - AutofixProviderVolcano
- - AutofixProviderAnthropic
- description: Who serves the model. `volcano` runs on Volcano's models. `anthropic` runs on your own Anthropic API key.
- AutofixModel:
- type: string
- enum:
- - claude-fable-5-1
- - claude-opus-5-5
- - claude-sonnet-5-5
- - claude-haiku-5-5
- - claude-opus-5
- - claude-sonnet-5
- - claude-haiku-4-5
- x-enum-varnames:
- - AutofixModelClaudeFable51
- - AutofixModelClaudeOpus55
- - AutofixModelClaudeSonnet55
- - AutofixModelClaudeHaiku55
- - AutofixModelClaudeOpus5
- - AutofixModelClaudeSonnet5
- - AutofixModelClaudeHaiku45
- description: The Claude model a run uses. `claude-opus-5-5` is the default.
- UpdateAutofixSettingsRequest:
+ LavaflowCodeQualityUpdate:
type: object
additionalProperties: false
+ description: Turns Code Quality on or off. Only the project's owner, signed in, can turn it on; any credential that can save the settings can turn it off.
properties:
enabled:
type: boolean
- max_stage:
- $ref: '#/components/schemas/AutofixStage'
- auto_trigger:
- type: boolean
- default: false
- provider:
- $ref: '#/components/schemas/AutofixProvider'
- model:
- $ref: '#/components/schemas/AutofixModel'
- api_key:
- type: string
- format: password
- writeOnly: true
- minLength: 20
- maxLength: 512
- pattern: ^[!-~]+$
- description: Your own API key for `provider`, such as an Anthropic key for `anthropic`. Omit it to keep the stored key. Encrypted at rest and never returned.
required:
- enabled
- AutofixRunStatus:
+ LavaflowScanStatus:
type: string
enum:
- - queued
+ - waiting
- running
- - succeeded
+ - completed
- failed
- - canceled
- x-enum-varnames:
- - AutofixRunStatusQueued
- - AutofixRunStatusRunning
- - AutofixRunStatusSucceeded
- - AutofixRunStatusFailed
- - AutofixRunStatusCanceled
- description: Where a run is. `canceled` means the project's settings or plan stopped allowing the run before it finished; `failure_code` says which.
- AutofixRunTrigger:
- type: string
- enum:
- - manual
- - new_issue
- - regression
- x-enum-varnames:
- - AutofixRunTriggerManual
- - AutofixRunTriggerNewIssue
- - AutofixRunTriggerRegression
- description: What started the run. `manual` is a request; `new_issue` and `regression` are automatic runs for an issue that appeared or reopened.
- AutofixEvidence:
+ - cancelled
+ description: 'Where the scan stands. `waiting` is the project''s next scan: deploys that went live since the last one, waiting out a short settle window or a bound named by `waiting_reason`.'
+ LavaflowScanResource:
type: object
- additionalProperties: false
+ description: A resource whose production deploy the scan covers. Only frontend deploys ask for a scan for now.
properties:
- kind:
+ resource_type:
type: string
enum:
- - log
- - code
- - other
- x-enum-varnames:
- - AutofixEvidenceKindLog
- - AutofixEvidenceKindCode
- - AutofixEvidenceKindOther
- detail:
- type: string
- location:
- type: string
- description: A file and line, or a log timestamp. Absent when the evidence has none.
- required:
- - kind
- - detail
- AutofixDiagnosis:
- type: object
- additionalProperties: false
- properties:
- summary:
- type: string
- description: One or two sentences on what goes wrong.
- root_cause:
- type: string
- evidence:
- type: array
- items:
- $ref: '#/components/schemas/AutofixEvidence'
- suggested_fix:
+ - function
+ - frontend
+ resource_id:
type: string
- confidence:
+ format: uuid
+ deployment_id:
type: string
- enum:
- - low
- - medium
- - high
- x-enum-varnames:
- - AutofixConfidenceLow
- - AutofixConfidenceMedium
- - AutofixConfidenceHigh
- fixable:
- type: boolean
- description: Whether a change to the project's code would fix the issue.
- files:
- type: array
- description: Repository paths a fix would change.
- items:
- type: string
+ format: uuid
required:
- - summary
- - root_cause
- - evidence
- - suggested_fix
- - confidence
- - fixable
- - files
- AutofixRunUsage:
+ - resource_type
+ - resource_id
+ - deployment_id
+ LavaflowScanCounts:
type: object
- additionalProperties: false
- description: Model tokens the run used across every attempt.
+ description: What the scan did with the problems it found.
properties:
- input_tokens:
+ found:
+ type: integer
+ format: int64
+ description: Candidates the scan found in the changed lines.
+ created:
+ type: integer
+ format: int64
+ description: New issues the scan opened.
+ duplicate:
type: integer
format: int64
- output_tokens:
+ description: Candidates that matched an issue the project already has, or a finding the scan already kept.
+ suppressed:
type: integer
format: int64
- cache_read_input_tokens:
+ description: Candidates a person had already turned down, by closing their pull request or ignoring their issue.
+ capped:
type: integer
format: int64
- cache_creation_input_tokens:
+ description: Confirmed findings past the plan's findings per scan, which no later scan reports again.
+ rejected:
type: integer
format: int64
+ description: Candidates LavaFlow's second check didn't confirm, or that it couldn't report.
required:
- - input_tokens
- - output_tokens
- - cache_read_input_tokens
- - cache_creation_input_tokens
- AutofixEdit:
+ - found
+ - created
+ - duplicate
+ - suppressed
+ - capped
+ - rejected
+ LavaflowScanBilledFinding:
type: object
- additionalProperties: false
- description: One exact text replacement. An empty `old_text` creates the file.
+ description: A finding of the scan whose Code Quality runs were billed.
properties:
- path:
- type: string
- old_text:
+ issue_id:
type: string
- new_text:
+ format: uuid
+ description: The finding's issue. Its `finding` says where the problem is and why.
+ rule:
type: string
- required:
- - path
- - old_text
- - new_text
- AutofixPatch:
- type: object
- additionalProperties: false
- description: The fix the model proposed, applied to the deployed commit. Present whenever the run opened a pull request, and when a valid fix could not be published.
- properties:
+ description: The rule the finding is about.
title:
type: string
- edits:
- type: array
- items:
- $ref: '#/components/schemas/AutofixEdit'
+ billable_events:
+ type: object
+ additionalProperties:
+ type: integer
+ format: int64
+ description: How many billable events of each kind the finding's runs recorded, keyed by kind, such as `issue_diagnosed` and `pull_request_opened`.
required:
+ - issue_id
+ - rule
- title
- - edits
- AutofixPullRequestState:
- type: string
- enum:
- - open
- - merged
- - closed
- x-enum-varnames:
- - AutofixPullRequestStateOpen
- - AutofixPullRequestStateMerged
- - AutofixPullRequestStateClosed
- AutofixPullRequest:
- type: object
- additionalProperties: false
- description: The draft pull request the run opened on the connected repository.
- properties:
- number:
- type: integer
- format: int64
- url:
- type: string
- format: uri
- branch:
- type: string
- description: The branch the fix is on, `volcano/autofix/`.
- state:
- $ref: '#/components/schemas/AutofixPullRequestState'
- closed_at:
- type: string
- format: date-time
- description: When the pull request was merged or closed.
- deployed_at:
- type: string
- format: date-time
- description: When a deployment that includes the merged fix went live. The issue resolves then, unless it occurred again since. When more than 20 deployments went live after the merge before Volcano checked, it is the merge time instead.
- required:
- - number
- - url
- - branch
- - state
- AutofixPullRequestSkipped:
- type: string
- enum:
- - source_unavailable
- - pull_request_open
- - not_fixable
- - low_confidence
- - no_patch
- - permission_missing
- - repository_changed
- - publish_failed
- x-enum-varnames:
- - AutofixPullRequestSkippedSourceUnavailable
- - AutofixPullRequestSkippedPullRequestOpen
- - AutofixPullRequestSkippedNotFixable
- - AutofixPullRequestSkippedLowConfidence
- - AutofixPullRequestSkippedNoPatch
- - AutofixPullRequestSkippedPermissionMissing
- - AutofixPullRequestSkippedRepositoryChanged
- - AutofixPullRequestSkippedPublishFailed
- description: Why a run whose `max_stage` is `pull_request` opened no pull request. The diagnosis stands either way.
- AutofixRun:
+ - billable_events
+ LavaflowScan:
type: object
- additionalProperties: false
+ description: One Code Quality scan of the code a project's deploys changed.
properties:
id:
type: string
format: uuid
+ nullable: true
+ description: The scan's ID, null while it is waiting.
project_id:
type: string
format: uuid
- issue_id:
+ source:
type: string
- format: uuid
- trigger:
- $ref: '#/components/schemas/AutofixRunTrigger'
+ enum:
+ - deployment
+ description: What asked for the scan.
status:
- $ref: '#/components/schemas/AutofixRunStatus'
- max_stage:
- $ref: '#/components/schemas/AutofixStage'
- stage_reached:
- $ref: '#/components/schemas/AutofixStage'
- provider:
- $ref: '#/components/schemas/AutofixProvider'
- model:
- $ref: '#/components/schemas/AutofixModel'
- diagnosis:
- $ref: '#/components/schemas/AutofixDiagnosis'
- patch:
- $ref: '#/components/schemas/AutofixPatch'
- pull_request:
- $ref: '#/components/schemas/AutofixPullRequest'
- pull_request_skipped:
- $ref: '#/components/schemas/AutofixPullRequestSkipped'
- commit_sha:
+ $ref: '#/components/schemas/LavaflowScanStatus'
+ outcome:
type: string
- description: The commit the diagnosis read, when a push to the connected repository deployed the resource. Absent when the run read logs only.
- failure_code:
+ nullable: true
+ description: 'How a finished scan ended: `scanned`; `no_changes` when the deploy changed nothing since the last scan, as after a redeploy or a rollback; `no_base` when there was no earlier commit to compare against, so the head became the starting point; `unreachable` when the head commit is on neither the project''s production branch nor the repository''s default branch; `repository_changed`; `failed`; or `cancelled`. Null until it ends.'
+ waiting_reason:
type: string
- description: Why the run failed or was canceled, or why its last attempt will be retried. One of `api_key_rejected`, `model_request_rejected`, `model_unavailable`, `model_refused`, `no_diagnosis`, `budget_exhausted`, `timed_out`, `attempts_exhausted`, `autofix_disabled`, `plan_required`, `managed_models_unavailable`, `settings_changed`, `issue_not_found`, or `internal_error`.
- failure_message:
+ nullable: true
+ description: 'The bound a waiting scan waits at: `findings_limit`, `pull_request_limit`, `spend_limit`, `scan_limit` or `feature_unavailable`. Null while it only waits out its settle window, and for a scan that started. A waiting scan skips no deploy: it covers every commit since the last scan when it starts.'
+ repository_id:
+ type: integer
+ format: int64
+ description: The GitHub repository the scan reads.
+ base_sha:
type: string
- usage:
- $ref: '#/components/schemas/AutofixRunUsage'
- created_at:
+ nullable: true
+ description: The commit the scan compares against, null while waiting or when there was none.
+ head_sha:
+ type: string
+ description: The newest deployed commit the scan covers.
+ resources:
+ type: array
+ items:
+ $ref: '#/components/schemas/LavaflowScanResource'
+ truncated:
+ type: boolean
+ description: Whether the scan reviewed only part of the change. A change too large to review whole keeps the files with the most changed lines, a review that stops early keeps what it found, and a repository too large to read whole skips the files past what it read. No later scan covers the rest.
+ counts:
+ $ref: '#/components/schemas/LavaflowScanCounts'
+ billed:
+ type: array
+ items:
+ $ref: '#/components/schemas/LavaflowScanBilledFinding'
+ description: The scan's findings whose runs were billed.
+ requested_at:
type: string
format: date-time
+ description: When the first deploy the scan covers asked for it.
started_at:
type: string
format: date-time
+ nullable: true
completed_at:
type: string
format: date-time
+ nullable: true
required:
- id
- project_id
- - issue_id
- - trigger
+ - source
- status
- - max_stage
- - provider
- - model
- - usage
- - created_at
- PaginatedAutofixRuns:
+ - outcome
+ - waiting_reason
+ - repository_id
+ - base_sha
+ - head_sha
+ - resources
+ - truncated
+ - counts
+ - billed
+ - requested_at
+ - started_at
+ - completed_at
+ PaginatedLavaflowScans:
type: object
properties:
data:
type: array
items:
- $ref: '#/components/schemas/AutofixRun'
+ $ref: '#/components/schemas/LavaflowScan'
limit:
type: integer
description: Number of items per page
@@ -23755,11 +33247,68 @@ components:
description: Whether a next page exists
next_cursor:
type: string
- description: Opaque cursor for the next page (present if has_more is true)
+ description: Opaque cursor for the next page, present if has_more is true. It works only for the same project_id and caller.
required:
- data
- limit
- has_more
+ NotificationSettings:
+ type: object
+ additionalProperties: false
+ properties:
+ project_id:
+ type: string
+ format: uuid
+ email:
+ $ref: '#/components/schemas/NotificationEmailSettings'
+ webhook:
+ $ref: '#/components/schemas/NotificationWebhookSettings'
+ scheduler_failures:
+ $ref: '#/components/schemas/SchedulerFailureAlertPolicy'
+ updated_at:
+ type: string
+ format: date-time
+ description: When the settings were last saved. Absent until the first save.
+ required:
+ - project_id
+ - email
+ - webhook
+ - scheduler_failures
+ UpdateNotificationSettingsRequest:
+ type: object
+ additionalProperties: false
+ description: Omitted fields keep their current values.
+ properties:
+ email:
+ $ref: '#/components/schemas/UpdateNotificationEmail'
+ webhook:
+ $ref: '#/components/schemas/UpdateNotificationWebhook'
+ scheduler_failures:
+ $ref: '#/components/schemas/UpdateSchedulerFailureAlertPolicy'
+ NotificationTestResult:
+ type: object
+ additionalProperties: false
+ properties:
+ deliveries:
+ type: array
+ items:
+ $ref: '#/components/schemas/NotificationTestDelivery'
+ required:
+ - deliveries
+ GitRepositoryReference:
+ type: object
+ description: A GitHub repository, by its stable id and its name.
+ properties:
+ id:
+ type: integer
+ format: int64
+ description: GitHub's repository id. It stays the same through a rename or a transfer.
+ full_name:
+ type: string
+ description: The repository's owner and name, such as `acme/shop`.
+ required:
+ - id
+ - full_name
PaginatedProjectCustomDomains:
type: object
properties:
@@ -24107,8 +33656,10 @@ components:
$ref: '#/components/schemas/ProjectConfigBucket'
realtime:
$ref: '#/components/schemas/ProjectConfigRealtime'
- autofix:
- $ref: '#/components/schemas/ProjectConfigAutofix'
+ lavaflow:
+ $ref: '#/components/schemas/ProjectConfigLavaFlow'
+ notifications:
+ $ref: '#/components/schemas/ProjectConfigNotifications'
auth:
$ref: '#/components/schemas/ProjectConfigAuth'
functions:
@@ -24251,6 +33802,9 @@ components:
type: boolean
max_age:
type: integer
+ allow_frontend_previews:
+ type: boolean
+ description: Allow the origins of the project's own live frontend previews.
ProjectConfigAuthEmail:
type: object
additionalProperties: false
@@ -24270,8 +33824,10 @@ components:
properties:
address:
type: string
+ description: Sender email address. New or changed values containing carriage returns or newlines return 422. Unchanged exported values are preserved.
name:
type: string
+ description: Sender display name; supports punctuation and Unicode. New or changed values containing carriage returns or newlines return 422. Unchanged exported values are preserved.
ProjectConfigAuthEmailPasswordProvider:
type: object
additionalProperties: false
@@ -24519,7 +34075,44 @@ components:
tls:
$ref: '#/components/schemas/ProjectConfigFrontendCustomDomainTLSConfig'
required:
- - domain
+ - domain
+ ProjectConfigFrontendCustomDomain:
+ type: object
+ additionalProperties: false
+ description: |
+ One of the frontend's custom domains. `domain` and `tls` behave as in
+ `custom_domain`. With `redirect`, the domain redirects every request to
+ another listed domain that serves the frontend.
+ properties:
+ domain:
+ type: string
+ maxLength: 253
+ description: 'Fully-qualified domain name (hostname only, no scheme/path). Managed TLS (`tls.mode: managed`) accepts at most 219 characters; BYOC accepts 253.'
+ tls:
+ $ref: '#/components/schemas/ProjectConfigFrontendCustomDomainTLSConfig'
+ redirect:
+ $ref: '#/components/schemas/ProjectConfigCustomDomainRedirect'
+ required:
+ - domain
+ ProjectConfigCustomDomainRedirect:
+ type: object
+ additionalProperties: false
+ properties:
+ to:
+ type: string
+ minLength: 1
+ maxLength: 253
+ description: Another domain in the same `custom_domains` list, without `redirect`.
+ status:
+ type: integer
+ enum:
+ - 301
+ - 302
+ - 307
+ - 308
+ default: 308
+ required:
+ - to
ProjectConfigDatabase:
type: object
additionalProperties: false
@@ -24568,6 +34161,7 @@ components:
properties:
subject:
type: string
+ description: Subject template. For new or changed values, literal interior carriage returns or newlines after Go template whitespace trimming return 422. Outer whitespace and trailing block-scalar newlines are allowed. Unchanged stored subjects are preserved.
html_body:
type: string
maxLength: 262144
@@ -24598,8 +34192,7 @@ components:
additionalProperties: false
description: |
Configuration for an existing (deployed) frontend. Frontends are never
- created or deleted through the manifest. A declared frontend entry
- without `custom_domain` deletes an existing custom domain.
+ created or deleted through the manifest.
properties:
variable_scope:
type: string
@@ -24619,13 +34212,41 @@ components:
type: string
minLength: 1
custom_domain:
- $ref: '#/components/schemas/ProjectConfigCustomDomain'
+ allOf:
+ - $ref: '#/components/schemas/ProjectConfigCustomDomain'
+ nullable: true
+ x-go-type: nullable.Nullable[ProjectConfigCustomDomain]
+ x-go-type-skip-optional-pointer: true
+ description: |
+ The frontend's custom domain. Omission leaves an existing domain
+ untouched; null deletes it. For a frontend with more than one
+ domain, or a redirect, use `custom_domains`; an entry may not set
+ both.
+ custom_domains:
+ type: array
+ maxItems: 100
+ description: |
+ Complete set of the frontend's custom domains when declared.
+ Domains not listed are deleted; an empty list deletes all of them.
+ Omission leaves existing domains untouched. More than one domain
+ needs a plan that allows it.
+ items:
+ $ref: '#/components/schemas/ProjectConfigFrontendCustomDomain'
function_routes:
type: array
maxItems: 64
description: Complete set of same-origin Function path mappings when declared. Omission preserves existing mappings; an empty list deletes all mappings.
items:
$ref: '#/components/schemas/ProjectConfigFrontendFunctionRoute'
+ frontend_routes:
+ type: array
+ maxItems: 64
+ description: |
+ Complete set of paths this frontend serves from another frontend in the project when
+ declared. Omission preserves existing routes; an empty list deletes all of them.
+ Function and Frontend routes share one path namespace and the 64-route limit.
+ items:
+ $ref: '#/components/schemas/ProjectConfigFrontendRoute'
required:
- name
ProjectConfigFunction:
@@ -24836,21 +34457,10 @@ components:
type: boolean
postgres_changes_enabled:
type: boolean
- ProjectConfigAutofix:
+ ProjectConfigLavaFlow:
type: object
- additionalProperties: false
- description: 'AI diagnosis and fix settings. Omitted fields keep their current value. Your API key is never part of the manifest, and an apply never sets or deletes it: set it with `PUT /projects/{id}/autofix` before turning on a provider that runs on your own key.'
- properties:
- enabled:
- type: boolean
- max_stage:
- $ref: '#/components/schemas/AutofixStage'
- auto_trigger:
- type: boolean
- provider:
- $ref: '#/components/schemas/AutofixProvider'
- model:
- $ref: '#/components/schemas/AutofixModel'
+ deprecated: true
+ description: Ignored. The manifest doesn't configure LavaFlow. A manifest that still declares this section applies as before, without it, and the result reports it as `unchanged` with a notice. Export never includes it.
ProjectConfigScheduler:
type: object
additionalProperties: false
@@ -25306,6 +34916,8 @@ components:
format: date-time
progress:
$ref: '#/components/schemas/DeploymentProgress'
+ commit:
+ $ref: '#/components/schemas/DeploymentCommit'
created_at:
type: string
format: date-time
@@ -25497,7 +35109,7 @@ components:
description: Canonical function ID used for invocation routing
invoke_url:
type: string
- description: 'Canonical HTTPS endpoint for invoking this function. Use it as-is: it does not share a domain with the API, so a host derived from the API URL will not reach the function. Omitted when the deployment serves no public invocation domain, as in local development; invoke through POST /functions/{functionId}/invoke instead.'
+ description: 'Canonical HTTPS endpoint for invoking this function. Use it as-is: it does not share a domain with the API, so a host derived from the API URL will not reach the function. Omitted in local development and when the deployment serves no public invocation domain; invoke through POST /functions/{functionId}/invoke instead.'
cache_ttl_seconds:
type: integer
minimum: 1
@@ -25539,7 +35151,8 @@ components:
type: string
description: |
Full JWT token for Authorization header.
- Returned on create, get, and list (decrypted from storage).
+ Returned on create, get, and list (decrypted from storage). List
+ responses leave it out for a key that holds `ai.invoke`.
**Store securely - NEVER expose in frontend code!**
key_prefix:
type: string
@@ -25862,6 +35475,7 @@ components:
to_email:
type: string
format: email
+ x-go-type: string
description: Recipient address for the diagnostic email.
subject:
type: string
@@ -25945,6 +35559,9 @@ components:
type: boolean
cors_max_age:
type: integer
+ cors_allow_frontend_previews:
+ type: boolean
+ description: Allow the origins of the project's own live frontend previews.
enable_anonymous_signins:
type: boolean
allowed_email_domains:
@@ -25997,8 +35614,10 @@ components:
description: Enable transactional email sending. Cannot be false while require_email_confirmation is true.
email_from_address:
type: string
+ description: Sender email address. New or changed values containing carriage returns or newlines return 400. Unchanged stored or exported values are preserved. Leading and trailing whitespace in previously saved settings is ignored when sending.
email_from_name:
type: string
+ description: Sender display name; supports punctuation and Unicode. New or changed values containing carriage returns or newlines return 400. Unchanged stored or exported values are preserved. Leading and trailing whitespace in previously saved settings is ignored when sending.
smtp_host:
type: string
smtp_port:
@@ -26015,10 +35634,13 @@ components:
type: boolean
email_confirmation_subject:
type: string
+ description: Subject template. For new or changed values, literal interior carriage returns or newlines after Go template whitespace trimming return 400. Outer whitespace and trailing block-scalar newlines are allowed. Unchanged stored subjects are preserved.
email_password_reset_subject:
type: string
+ description: Subject template. For new or changed values, literal interior carriage returns or newlines after Go template whitespace trimming return 400. Outer whitespace and trailing block-scalar newlines are allowed. Unchanged stored subjects are preserved.
email_password_changed_subject:
type: string
+ description: Subject template. For new or changed values, literal interior carriage returns or newlines after Go template whitespace trimming return 400. Outer whitespace and trailing block-scalar newlines are allowed. Unchanged stored subjects are preserved.
managed_auth_enabled:
type: boolean
description: Enable or disable managed auth hosted pages for the project.
@@ -26089,6 +35711,7 @@ components:
properties:
subject:
type: string
+ description: Subject template. For new or changed values, literal interior carriage returns or newlines after Go template whitespace trimming return 400. Outer whitespace and trailing block-scalar newlines are allowed. Unchanged stored subjects are preserved.
html_body:
type: string
text_body:
@@ -26359,6 +35982,35 @@ components:
description: |
This OpenAPI document, with every reference resolved. Shared by the JSON
and YAML operations, which differ only in serialization.
+ SandboxSessionExecutions:
+ type: object
+ additionalProperties: false
+ description: How the session's command executions are kept. Fixed when the session is created.
+ properties:
+ keep_output:
+ type: boolean
+ description: When false, every command in the session keeps no output. stdout and stderr are returned once in the command's response, and Volcano's control plane never stores them in the execution journal, database, logs or traces. This does not cover the Sandbox's memory or a suspended session's snapshot. A retry with the same Idempotency-Key returns the exit code with empty streams. A command in such a session that sets `keep_output` to true is refused with 400 and code `sandbox_session_keeps_no_output`. False is refused with 400 and code `feature_unavailable` while the `sandboxes.output_not_kept` capability is unavailable.
+ required:
+ - keep_output
+ ProjectTemplateInstallationSource:
+ type: object
+ description: The share release a fork was installed from.
+ required:
+ - kind
+ - share_id
+ - release_id
+ properties:
+ kind:
+ type: string
+ enum:
+ - share_release
+ share_id:
+ type: string
+ description: The share the release belongs to.
+ release_id:
+ type: string
+ format: uuid
+ description: The release the project was installed from.
ProjectTemplateInstallation:
type: object
description: |
@@ -26386,6 +36038,32 @@ components:
- deploy
- verify
- ready
+ source:
+ $ref: '#/components/schemas/ProjectTemplateInstallationSource'
+ failure_code:
+ type: string
+ example: source_withdrawn
+ description: |
+ Why the installation failed. Present only when `status` is `failed`, and
+ absent for installations that failed before Volcano recorded a reason.
+ New codes can be added, so treat an unknown one as a generic failure.
+ `source_withdrawn`: the deploy link was switched off or deleted, or its
+ project is being deleted. `source_invalid`: the source failed Volcano's checks,
+ such as a release archive whose digest, size or contents are wrong.
+ `source_access_lost`: Volcano can no longer read the source repository.
+ `invalid_source_configuration`: the source's `volcano-config.yaml` is
+ invalid, or it declares a variable the new project does not have.
+ `nothing_to_deploy`: the source has no function or frontend.
+ `database_not_supported`: the source ships database SQL.
+ `function_deploy_refused`: a function in the source cannot be deployed
+ as defined. `function_quota_exceeded`,
+ `durable_function_quota_exceeded`, `frontend_quota_exceeded`,
+ `frontend_deploy_limit` and `build_minutes_exceeded`: the project
+ reached a plan limit. `build_failed`: a function or frontend from the
+ source failed to build or deploy; its deployment's build logs say why.
+ `retry_budget_exhausted`: the installation kept failing and Volcano
+ stopped retrying. `internal_error`: Volcano failed for a reason of its
+ own.
ProjectGitConnectionSummary:
type: object
properties:
@@ -26404,6 +36082,7 @@ components:
updated_at:
type: string
format: date-time
+ description: 'When the connection last changed: its repository, root directory or production branch. Naming the branch it already uses, and other changes to the project, leave it alone. A connection that has not changed since Volcano began tracking this reports the project''s last change before then.'
required:
- repo_installation_id
- repo_id
@@ -26430,6 +36109,61 @@ components:
step, and is invoked asynchronously through its own executions
collection. A function's kind is fixed when it is created and cannot be
changed afterwards. Omitting this field means `standard`.
+ UpdateNotificationEmail:
+ type: object
+ additionalProperties: false
+ properties:
+ enabled:
+ type: boolean
+ recipients:
+ type: array
+ maxItems: 10
+ items:
+ type: string
+ format: email
+ maxLength: 254
+ description: Only the project owner's verified account email address is supported. An empty list, or one naming only that address, emails the owner and is saved as an empty list. Any other list is refused as invalid.
+ UpdateNotificationWebhook:
+ type: object
+ additionalProperties: false
+ properties:
+ url:
+ type: string
+ maxLength: 2048
+ pattern: ^\s*(|[hH][tT][tT][pP][sS]?://.+)\s*$
+ description: An `http` or `https` URL. Surrounding whitespace is trimmed. An empty string removes the webhook and its secret.
+ SchedulerFailureNotifyOn:
+ type: string
+ enum:
+ - first_failure
+ - consecutive_failures
+ x-enum-varnames:
+ - SchedulerFailureNotifyOnFirstFailure
+ - SchedulerFailureNotifyOnConsecutiveFailures
+ description: 'When a failing scheduler is announced: on its first failed run, or once `threshold` runs in a row have failed. Either way a streak is announced once, and a scheduler is announced failing at most once an hour.'
+ UpdateSchedulerFailureAlertPolicy:
+ type: object
+ additionalProperties: false
+ properties:
+ notify_on:
+ $ref: '#/components/schemas/SchedulerFailureNotifyOn'
+ threshold:
+ type: integer
+ minimum: 1
+ maximum: 100
+ notify_on_recovery:
+ type: boolean
+ ProjectConfigNotifications:
+ type: object
+ additionalProperties: false
+ description: 'Where the project''s alerts go and when a failing scheduler is announced. Omitted fields keep their current value. The webhook signing secret is never part of the manifest: setting `webhook.url` on a project without a webhook generates one that is never shown. Rotate it with `POST /projects/{id}/notifications/webhook-secret` to get a secret you can use.'
+ properties:
+ email:
+ $ref: '#/components/schemas/UpdateNotificationEmail'
+ webhook:
+ $ref: '#/components/schemas/UpdateNotificationWebhook'
+ scheduler_failures:
+ $ref: '#/components/schemas/UpdateSchedulerFailureAlertPolicy'
AuthPageThemeColors:
type: object
additionalProperties: false
@@ -26554,6 +36288,22 @@ components:
required:
- function
- path_prefix
+ ProjectConfigFrontendRoute:
+ type: object
+ additionalProperties: false
+ properties:
+ frontend:
+ type: string
+ minLength: 1
+ description: Name of another existing frontend in the project to mount. Paths are forwarded unchanged.
+ path_prefix:
+ type: string
+ minLength: 2
+ maxLength: 512
+ pattern: ^/[^?#\\]*[^/?#\\]$
+ required:
+ - frontend
+ - path_prefix
ProjectConfigSandbox:
type: object
additionalProperties: false
@@ -26713,6 +36463,41 @@ components:
- elapsed_seconds
- phases
- updated_at
+ DeploymentCommit:
+ type: object
+ description: The commit a deploy client reported for the deployment's source. Absent when the client reported none. A frontend deployment that publishes another deployment's build carries that deployment's commit.
+ properties:
+ repository:
+ type: string
+ description: GitHub repository as `owner/name`, normalized from what the client sent.
+ example: acme/app
+ sha:
+ type: string
+ pattern: ^[0-9a-f]{40}$
+ description: Full commit ID.
+ dirty:
+ type: boolean
+ description: '`true` when the client reported that the uploaded files differ from the commit, or Volcano found an uploaded file in the project''s root directory that the commit does not hold, so the deployed code may differ from the commit.'
+ verified:
+ type: boolean
+ description: '`true` only when `verification` is `files`: Volcano confirmed that the deployed files are the commit''s. A commit verified at the `repository` level is not `verified`.'
+ verification:
+ type: string
+ enum:
+ - none
+ - repository
+ - files
+ x-enum-varnames:
+ - DeploymentCommitVerificationNone
+ - DeploymentCommitVerificationRepository
+ - DeploymentCommitVerificationFiles
+ description: 'What Volcano confirmed about the commit, through the project''s GitHub connection, when it recorded the deployment. `files`: `repository` is the project''s connected repository, `sha` is on its production branch, every uploaded file is the commit''s file at its path, and the upload holds the commit''s files under its root but those deploy clients leave out. Only a frontend upload is checked this far. `repository`: `repository` is the project''s connected repository and `sha` is on its production branch, but the uploaded files were not compared with the commit, since a function upload holds build output rather than the repository''s layout. Only a function upload the client reports clean is checked at this level. `none`: Volcano confirmed nothing, as for a commit the client reports dirty, one from another branch or repository, one from a project without a connection, or one it couldn''t check in time.'
+ required:
+ - repository
+ - sha
+ - dirty
+ - verified
+ - verification
DurableMessageSender:
type: object
description: Who sent the message.
@@ -26879,6 +36664,89 @@ components:
description: Deployment stage that produced the log event, when available.
required:
- id
+ NotificationEmailStatus:
+ type: string
+ enum:
+ - delivering
+ - disabled
+ - owner_email_unverified
+ description: Whether alerts are being emailed. `owner_email_unverified` means email is enabled but the project owner has no active account with a verified email address, so no alert is emailed, and email does not count as a channel when deciding whether to announce a failing scheduler, until the owner verifies it. Changing the account email address needs a new verification.
+ NotificationEmailSettings:
+ type: object
+ additionalProperties: false
+ properties:
+ enabled:
+ type: boolean
+ description: Whether alerts are emailed.
+ recipients:
+ type: array
+ maxItems: 10
+ items:
+ type: string
+ format: email
+ description: Empty. Alerts are emailed to the project owner's verified account email address, the only recipient supported.
+ status:
+ $ref: '#/components/schemas/NotificationEmailStatus'
+ required:
+ - enabled
+ - recipients
+ - status
+ NotificationWebhookSettings:
+ type: object
+ additionalProperties: false
+ properties:
+ url:
+ type: string
+ description: Where alerts are posted. Absent when no webhook is configured.
+ secret_configured:
+ type: boolean
+ description: Whether a signing secret is set. The secret itself is returned only once.
+ secret:
+ type: string
+ description: 'The signing secret, starting with `whsec_`. Present only in the response that generated it: the update that first set `url`, or a rotation. Store it then; it cannot be read again.'
+ required:
+ - secret_configured
+ SchedulerFailureAlertPolicy:
+ type: object
+ additionalProperties: false
+ properties:
+ notify_on:
+ $ref: '#/components/schemas/SchedulerFailureNotifyOn'
+ threshold:
+ type: integer
+ minimum: 1
+ maximum: 100
+ description: How many runs in a row have to fail before a `consecutive_failures` alert. Ignored for `first_failure`.
+ notify_on_recovery:
+ type: boolean
+ description: Whether a successful run after an alerted failure streak sends a `scheduler.recovered` alert.
+ required:
+ - notify_on
+ - threshold
+ - notify_on_recovery
+ NotificationTestDelivery:
+ type: object
+ additionalProperties: false
+ properties:
+ channel:
+ type: string
+ enum:
+ - email
+ - webhook
+ x-enum-varnames:
+ - NotificationChannelEmail
+ - NotificationChannelWebhook
+ delivered:
+ type: boolean
+ status_code:
+ type: integer
+ description: The webhook's response status. Absent for email, and when no response arrived.
+ error:
+ type: string
+ description: Why the delivery failed. Absent when it arrived.
+ required:
+ - channel
+ - delivered
DurableMessageWaitStatus:
type: string
enum:
@@ -26927,11 +36795,267 @@ components:
message:
type: string
maxLength: 32768
- pattern: ^[^\x00]*$
- description: A human-readable explanation, up to 32 KiB.
+ pattern: ^[^\x00-\x08\x0B-\x1F\x7F]*$
+ description: |
+ A human-readable explanation of up to 32,768 bytes of UTF-8, with
+ tab and newline as its only control characters. A character
+ outside ASCII takes more than one byte, so such text reaches the
+ limit before `maxLength`.
required:
- type
additionalProperties: false
+ LavaflowSkillLearning:
+ type: string
+ enum:
+ - auto
+ - review
+ - 'off'
+ description: What LavaFlow will do with a skill it learns from a writer's correction of one of its fixes, once learning ships in a later release. `auto`, the default, activates it at once. `review` keeps it `proposed` until the owner activates it. `off` learns none and loads no project skill; the project's skills stay readable and deletable. A writer of the repository can steer LavaFlow through what it learns, outside the repository's history and branch protection, so a repository that protects its guidance, or relays CI output through a bot account with write access, should use `review`. Turning learning up needs the project's `lavaflow.skills` capability.
+ LavaflowRunReference:
+ type: object
+ description: Another LavaFlow run of the same project.
+ properties:
+ id:
+ type: string
+ format: uuid
+ title:
+ type: string
+ nullable: true
+ description: The run's title, as `LavaflowRunSummary.title` gives it.
+ required:
+ - id
+ - title
+ LavaflowLineage:
+ type: object
+ description: 'A chain of LavaFlow fixes: a merged fix, and the runs that followed up an issue traced to it or to a fix after it.'
+ properties:
+ id:
+ type: string
+ format: uuid
+ description: The lineage's root run.
+ depth:
+ type: integer
+ format: int64
+ description: 0 for the root fix.
+ relation:
+ type: string
+ enum:
+ - regression
+ - recurrence
+ nullable: true
+ description: '`regression` for an issue traced to the parent''s deploy, `recurrence` for an issue that came back after the parent went live. Null for the root.'
+ confidence:
+ type: string
+ enum:
+ - strong
+ - weak
+ nullable: true
+ description: 'Null for the root, and otherwise `strong`. `weak` is reserved: nothing writes it.'
+ parent:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowRunReference'
+ nullable: true
+ description: The fix this run follows up. Null for the root.
+ covered_by:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowRunReference'
+ nullable: true
+ description: The run whose fix also covers this issue, so this run opened nothing.
+ remedy:
+ type: string
+ enum:
+ - fix
+ - revert
+ - none
+ x-enum-varnames:
+ - LavaflowLineageRemedyFix
+ - LavaflowLineageRemedyRevert
+ - LavaflowLineageRemedyNone
+ description: 'How the run follows up its parent. Currently always `fix`: a regression gets a follow-up fix. `revert` and `none` are reserved.'
+ state:
+ type: string
+ enum:
+ - active
+ - settled
+ - held
+ hold_reason:
+ type: string
+ nullable: true
+ description: 'Why the lineage holds: `lineage_cap`, `lineage_held` or `repository_changed`. New values may appear. Null unless `state` is `held`.'
+ pull_requests_opened:
+ type: integer
+ format: int64
+ description: Pull requests the lineage opened, counting the root's.
+ pull_request_cap:
+ type: integer
+ format: int64
+ description: The most pull requests a lineage opens before it holds.
+ required:
+ - id
+ - depth
+ - relation
+ - confidence
+ - parent
+ - covered_by
+ - remedy
+ - state
+ - hold_reason
+ - pull_requests_opened
+ - pull_request_cap
+ LavaflowFixOutcome:
+ type: object
+ description: How a merged LavaFlow fix fared once it went live.
+ properties:
+ state:
+ type: string
+ enum:
+ - awaiting_deploy
+ - watching
+ - effective
+ - ineffective
+ - regressed
+ - reverted
+ description: '`watching` for 14 days after the fix goes live, then `effective` unless its issue came back (`ineffective`) or a new issue was traced to its deploy (`regressed`). An outcome never moves back. `reverted` is reserved and not produced yet.'
+ live_at:
+ type: string
+ format: date-time
+ nullable: true
+ watch_until:
+ type: string
+ format: date-time
+ nullable: true
+ follow_ups:
+ type: integer
+ format: int64
+ description: Runs linked to this fix.
+ required:
+ - state
+ - live_at
+ - watch_until
+ - follow_ups
+ LavaflowCommitOrigin:
+ type: string
+ enum:
+ - push
+ - client_reported
+ - client_reported_repository
+ - repository
+ x-enum-varnames:
+ - LavaflowCommitOriginPush
+ - LavaflowCommitOriginClientReported
+ - LavaflowCommitOriginClientReportedRepository
+ - LavaflowCommitOriginRepository
+ description: 'Where the commit a run read came from. `push`: a push to the project''s connected repository deployed it. `client_reported`: the deploy client reported it, and Volcano matched the deployed files against it. `client_reported_repository`: the deploy client reported it, and Volcano confirmed only that the connected repository''s production branch holds it, without matching the deployed files, which for a function are build output. A fix on such a commit opens only while the production branch still holds it. `repository`: a reported problem''s run read the production branch at a commit it pinned, which need not be deployed.'
+ LavaflowSourceCommit:
+ type: object
+ description: The commit a run read its source at.
+ properties:
+ sha:
+ type: string
+ description: The commit's full SHA.
+ origin:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowCommitOrigin'
+ nullable: true
+ description: Where the commit came from. Null for a run recorded before Volcano kept it.
+ required:
+ - sha
+ - origin
+ LavaflowLineageEvidence:
+ type: object
+ description: What tied the run's issue to a recent LavaFlow fix. A `display` link rests on less than a strong one and joins no lineage.
+ properties:
+ confidence:
+ type: string
+ enum:
+ - strong
+ - weak
+ - display
+ description: '`strong` or `display`. `weak` is reserved: nothing writes it.'
+ parent:
+ allOf:
+ - $ref: '#/components/schemas/LavaflowRunReference'
+ description: The fix the issue was traced to.
+ deployment:
+ type: object
+ properties:
+ commit_sha:
+ type: string
+ description: The commit of the deployment that served the occurrence attribution judged (`opened_at`).
+ commit_origin:
+ type: string
+ description: '`push` for a commit Volcano built from a push, `client_reported` for one the deploy client reported. New values may appear.'
+ required:
+ - commit_sha
+ - commit_origin
+ previous_commit_sha:
+ type: string
+ nullable: true
+ description: The commit of the deployment before it.
+ fix_live_at:
+ type: string
+ format: date-time
+ opened_at:
+ type: string
+ format: date-time
+ description: The occurrence attribution judged.
+ overlapping_functions:
+ type: array
+ items:
+ type: string
+ overlapping_files:
+ type: array
+ items:
+ type: string
+ required:
+ - confidence
+ - parent
+ - deployment
+ - previous_commit_sha
+ - fix_live_at
+ - opened_at
+ - overlapping_functions
+ - overlapping_files
+ IssueFinding:
+ type: object
+ description: The LavaFlow Code Quality finding behind a `code_quality` issue.
+ properties:
+ rule:
+ type: string
+ description: The rule the finding names, such as `null-dereference`.
+ severity:
+ type: string
+ enum:
+ - nit
+ - minor
+ - major
+ - critical
+ description: How much the problem matters, as the finding was confirmed.
+ commit_sha:
+ type: string
+ description: The deployed commit the scan found the problem in.
+ path:
+ type: string
+ description: The file, from the repository root.
+ start_line:
+ type: integer
+ format: int64
+ description: The first line of the problem in that commit, from 1.
+ end_line:
+ type: integer
+ format: int64
+ description: The last line of the problem in that commit.
+ explanation:
+ type: string
+ description: What fails and on which input, as plain text. When it may contain a credential, LavaFlow withholds it whole, and it reads `LavaFlow left this explanation out because it may contain a credential`.
+ required:
+ - rule
+ - severity
+ - commit_sha
+ - path
+ - start_line
+ - end_line
+ - explanation
DurableApprovalFunction:
type: object
description: |
diff --git a/src/volcano_sdk/_auth_values.py b/src/volcano_sdk/_auth_values.py
index 0b2c6b9b..d2d8a809 100644
--- a/src/volcano_sdk/_auth_values.py
+++ b/src/volcano_sdk/_auth_values.py
@@ -2,6 +2,7 @@
from __future__ import annotations
+import re
import secrets
from collections.abc import Mapping
from datetime import datetime
@@ -77,6 +78,11 @@
INVALID_LINKED_OAUTH_PROVIDERS = "Expected complete linked OAuth providers"
+OAUTH_PROVIDER_TIMESTAMP = re.compile(
+ r"\d{4}-\d{2}-\d{2}T(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)"
+)
+
+
INVALID_OAUTH_LINK = "Expected an OAuth authorization URL"
@@ -387,16 +393,19 @@ def session_page_from_payload(payload: object) -> SessionPage:
def linked_oauth_provider_from_model(
item: AuthListOAuthProvidersResponse200ProvidersItem,
) -> LinkedOAuthProvider:
- provider = item.provider
- if not isinstance(provider, str) or not provider.strip():
- raise VolcanoError(INVALID_LINKED_OAUTH_PROVIDERS)
return LinkedOAuthProvider(
- provider=provider,
+ provider=linked_oauth_provider_string(item.provider),
linked_at=linked_oauth_datetime(item.linked_at),
updated_at=linked_oauth_datetime(item.updated_at),
)
+def linked_oauth_provider_string(value: object) -> str:
+ if not isinstance(value, str) or not value.strip():
+ raise VolcanoError(INVALID_LINKED_OAUTH_PROVIDERS)
+ return value
+
+
def linked_oauth_datetime(value: object) -> datetime:
if not isinstance(value, datetime):
raise VolcanoError(INVALID_LINKED_OAUTH_PROVIDERS)
@@ -406,6 +415,11 @@ def linked_oauth_datetime(value: object) -> datetime:
def linked_oauth_providers_from_payload(
payload: object,
) -> tuple[LinkedOAuthProvider, ...]:
+ if is_object_mapping(payload):
+ providers = payload.get("providers")
+ if not is_object_sequence(providers):
+ raise VolcanoError(INVALID_LINKED_OAUTH_PROVIDERS)
+ return tuple(linked_oauth_provider_from_wire(item) for item in providers)
if not isinstance(payload, AuthListOAuthProvidersResponse200) or isinstance(
payload.providers, Unset
):
@@ -415,6 +429,25 @@ def linked_oauth_providers_from_payload(
)
+def linked_oauth_provider_from_wire(value: object) -> LinkedOAuthProvider:
+ if not is_object_mapping(value):
+ raise VolcanoError(INVALID_LINKED_OAUTH_PROVIDERS)
+ return LinkedOAuthProvider(
+ provider=linked_oauth_provider_string(value.get("provider")),
+ linked_at=linked_oauth_wire_datetime(value.get("linked_at")),
+ updated_at=linked_oauth_wire_datetime(value.get("updated_at")),
+ )
+
+
+def linked_oauth_wire_datetime(value: object) -> datetime:
+ if not isinstance(value, str) or not OAUTH_PROVIDER_TIMESTAMP.fullmatch(value):
+ raise VolcanoError(INVALID_LINKED_OAUTH_PROVIDERS)
+ try:
+ return datetime.fromisoformat(value)
+ except ValueError as error:
+ raise VolcanoError(INVALID_LINKED_OAUTH_PROVIDERS) from error
+
+
def oauth_provider_name(value: object) -> OAuthProviderName:
if not isinstance(value, str) or value not in OAUTH_PROVIDERS:
raise ValueError(UNSUPPORTED_OAUTH_PROVIDER)
diff --git a/src/volcano_sdk/_generated/api/autofix/__init__.py b/src/volcano_sdk/_generated/api/account_sessions/__init__.py
similarity index 100%
rename from src/volcano_sdk/_generated/api/autofix/__init__.py
rename to src/volcano_sdk/_generated/api/account_sessions/__init__.py
diff --git a/src/volcano_sdk/_generated/api/account_sessions/list_account_sessions.py b/src/volcano_sdk/_generated/api/account_sessions/list_account_sessions.py
new file mode 100644
index 00000000..544013a9
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/account_sessions/list_account_sessions.py
@@ -0,0 +1,366 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.account_session_list import AccountSessionList
+from ...models.error import Error
+from ...models.list_account_sessions_sort import check_list_account_sessions_sort
+from ...models.list_account_sessions_sort import ListAccountSessionsSort
+from ...models.list_account_sessions_status import check_list_account_sessions_status
+from ...models.list_account_sessions_status import ListAccountSessionsStatus
+from ...types import UNSET, Unset
+from typing import cast
+
+
+
+def request_kwargs(
+ *,
+ page: int | Unset = UNSET,
+ limit: int | Unset = UNSET,
+ sort: ListAccountSessionsSort | Unset = 'last_activity',
+ status: ListAccountSessionsStatus | Unset = UNSET,
+ cursor: str | Unset = UNSET,
+ ending_before: str | Unset = UNSET,
+ offset: int | Unset = UNSET,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ params["page"] = page
+
+ params["limit"] = limit
+
+ json_sort: str | Unset = UNSET
+ if not isinstance(sort, Unset):
+ json_sort = sort
+
+ params["sort"] = json_sort
+
+ json_status: str | Unset = UNSET
+ if not isinstance(status, Unset):
+ json_status = status
+
+ params["status"] = json_status
+
+ params["cursor"] = cursor
+
+ params["ending_before"] = ending_before
+
+ params["offset"] = offset
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/user/sessions",
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> AccountSessionList | Error | None:
+ if response.status_code == 200:
+ response_200 = AccountSessionList.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if response.status_code == 501:
+ response_501 = Error.from_dict(response.json())
+
+
+
+ return response_501
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[AccountSessionList | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ page: int | Unset = UNSET,
+ limit: int | Unset = UNSET,
+ sort: ListAccountSessionsSort | Unset = 'last_activity',
+ status: ListAccountSessionsStatus | Unset = UNSET,
+ cursor: str | Unset = UNSET,
+ ending_before: str | Unset = UNSET,
+ offset: int | Unset = UNSET,
+
+) -> Response[AccountSessionList | Error]:
+ """ List your account's sign-in sessions
+
+ Lists the sign-in sessions of the account that owns the calling
+ platform token: dashboard sign-ins (`kind: browser`) and CLI logins
+ (`kind: cli`). The session the calling token was exchanged from is
+ marked `is_current: true`. A token created in the dashboard or through
+ the management API, rather than by signing in, has no session, so no
+ session is current.
+
+ Ordering and pagination match `GET /auth/user/sessions`.
+
+ Only a platform token (`pk-`) can call it. A project access token is
+ refused with `403`.
+
+ Args:
+ page (int | Unset):
+ limit (int | Unset):
+ sort (ListAccountSessionsSort | Unset): Default: 'last_activity'.
+ status (ListAccountSessionsStatus | Unset):
+ cursor (str | Unset):
+ ending_before (str | Unset):
+ offset (int | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[AccountSessionList | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ page=page,
+limit=limit,
+sort=sort,
+status=status,
+cursor=cursor,
+ending_before=ending_before,
+offset=offset,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ page: int | Unset = UNSET,
+ limit: int | Unset = UNSET,
+ sort: ListAccountSessionsSort | Unset = 'last_activity',
+ status: ListAccountSessionsStatus | Unset = UNSET,
+ cursor: str | Unset = UNSET,
+ ending_before: str | Unset = UNSET,
+ offset: int | Unset = UNSET,
+
+) -> AccountSessionList | Error | None:
+ """ List your account's sign-in sessions
+
+ Lists the sign-in sessions of the account that owns the calling
+ platform token: dashboard sign-ins (`kind: browser`) and CLI logins
+ (`kind: cli`). The session the calling token was exchanged from is
+ marked `is_current: true`. A token created in the dashboard or through
+ the management API, rather than by signing in, has no session, so no
+ session is current.
+
+ Ordering and pagination match `GET /auth/user/sessions`.
+
+ Only a platform token (`pk-`) can call it. A project access token is
+ refused with `403`.
+
+ Args:
+ page (int | Unset):
+ limit (int | Unset):
+ sort (ListAccountSessionsSort | Unset): Default: 'last_activity'.
+ status (ListAccountSessionsStatus | Unset):
+ cursor (str | Unset):
+ ending_before (str | Unset):
+ offset (int | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ AccountSessionList | Error
+ """
+
+
+ return sync_detailed(
+ client=client,
+page=page,
+limit=limit,
+sort=sort,
+status=status,
+cursor=cursor,
+ending_before=ending_before,
+offset=offset,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ page: int | Unset = UNSET,
+ limit: int | Unset = UNSET,
+ sort: ListAccountSessionsSort | Unset = 'last_activity',
+ status: ListAccountSessionsStatus | Unset = UNSET,
+ cursor: str | Unset = UNSET,
+ ending_before: str | Unset = UNSET,
+ offset: int | Unset = UNSET,
+
+) -> Response[AccountSessionList | Error]:
+ """ List your account's sign-in sessions
+
+ Lists the sign-in sessions of the account that owns the calling
+ platform token: dashboard sign-ins (`kind: browser`) and CLI logins
+ (`kind: cli`). The session the calling token was exchanged from is
+ marked `is_current: true`. A token created in the dashboard or through
+ the management API, rather than by signing in, has no session, so no
+ session is current.
+
+ Ordering and pagination match `GET /auth/user/sessions`.
+
+ Only a platform token (`pk-`) can call it. A project access token is
+ refused with `403`.
+
+ Args:
+ page (int | Unset):
+ limit (int | Unset):
+ sort (ListAccountSessionsSort | Unset): Default: 'last_activity'.
+ status (ListAccountSessionsStatus | Unset):
+ cursor (str | Unset):
+ ending_before (str | Unset):
+ offset (int | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[AccountSessionList | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ page=page,
+limit=limit,
+sort=sort,
+status=status,
+cursor=cursor,
+ending_before=ending_before,
+offset=offset,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ page: int | Unset = UNSET,
+ limit: int | Unset = UNSET,
+ sort: ListAccountSessionsSort | Unset = 'last_activity',
+ status: ListAccountSessionsStatus | Unset = UNSET,
+ cursor: str | Unset = UNSET,
+ ending_before: str | Unset = UNSET,
+ offset: int | Unset = UNSET,
+
+) -> AccountSessionList | Error | None:
+ """ List your account's sign-in sessions
+
+ Lists the sign-in sessions of the account that owns the calling
+ platform token: dashboard sign-ins (`kind: browser`) and CLI logins
+ (`kind: cli`). The session the calling token was exchanged from is
+ marked `is_current: true`. A token created in the dashboard or through
+ the management API, rather than by signing in, has no session, so no
+ session is current.
+
+ Ordering and pagination match `GET /auth/user/sessions`.
+
+ Only a platform token (`pk-`) can call it. A project access token is
+ refused with `403`.
+
+ Args:
+ page (int | Unset):
+ limit (int | Unset):
+ sort (ListAccountSessionsSort | Unset): Default: 'last_activity'.
+ status (ListAccountSessionsStatus | Unset):
+ cursor (str | Unset):
+ ending_before (str | Unset):
+ offset (int | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ AccountSessionList | Error
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+page=page,
+limit=limit,
+sort=sort,
+status=status,
+cursor=cursor,
+ending_before=ending_before,
+offset=offset,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/account_sessions/revoke_account_session.py b/src/volcano_sdk/_generated/api/account_sessions/revoke_account_session.py
new file mode 100644
index 00000000..6b21c7a9
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/account_sessions/revoke_account_session.py
@@ -0,0 +1,219 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from typing import cast
+
+
+
+def request_kwargs(
+ session_id: str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "delete",
+ "url": "/user/sessions/{session_id}".format(session_id=quote(str(session_id), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | Error | None:
+ if response.status_code == 204:
+ response_204 = cast(Any, None)
+ return response_204
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if response.status_code == 501:
+ response_501 = Error.from_dict(response.json())
+
+
+
+ return response_501
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ session_id: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Any | Error]:
+ """ Sign out one session
+
+ Ends one of the account's sessions and revokes the platform tokens
+ exchanged from it. A session that is not the account's, or does not
+ exist, answers `404`.
+
+ Args:
+ session_id (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ session_id=session_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ session_id: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Any | Error | None:
+ """ Sign out one session
+
+ Ends one of the account's sessions and revokes the platform tokens
+ exchanged from it. A session that is not the account's, or does not
+ exist, answers `404`.
+
+ Args:
+ session_id (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return sync_detailed(
+ session_id=session_id,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ session_id: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Any | Error]:
+ """ Sign out one session
+
+ Ends one of the account's sessions and revokes the platform tokens
+ exchanged from it. A session that is not the account's, or does not
+ exist, answers `404`.
+
+ Args:
+ session_id (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ session_id=session_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ session_id: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Any | Error | None:
+ """ Sign out one session
+
+ Ends one of the account's sessions and revokes the platform tokens
+ exchanged from it. A session that is not the account's, or does not
+ exist, answers `404`.
+
+ Args:
+ session_id (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return (await asyncio_detailed(
+ session_id=session_id,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/account_sessions/revoke_current_user_token.py b/src/volcano_sdk/_generated/api/account_sessions/revoke_current_user_token.py
new file mode 100644
index 00000000..270b45c5
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/account_sessions/revoke_current_user_token.py
@@ -0,0 +1,207 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from typing import cast
+
+
+
+def request_kwargs(
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "delete",
+ "url": "/user/tokens/current",
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | Error | None:
+ if response.status_code == 204:
+ response_204 = cast(Any, None)
+ return response_204
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if response.status_code == 501:
+ response_501 = Error.from_dict(response.json())
+
+
+
+ return response_501
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Any | Error]:
+ """ Revoke the calling platform token
+
+ Revokes the platform token that authenticates this request, and ends
+ the sign-in session it was created from, if any. Ending the session
+ also revokes every other token created from it. Every later request
+ with the token answers `401`.
+
+ Only a platform token (`pk-`) can call it. A project access token is
+ refused with `403`.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+
+) -> Any | Error | None:
+ """ Revoke the calling platform token
+
+ Revokes the platform token that authenticates this request, and ends
+ the sign-in session it was created from, if any. Ending the session
+ also revokes every other token created from it. Every later request
+ with the token answers `401`.
+
+ Only a platform token (`pk-`) can call it. A project access token is
+ refused with `403`.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return sync_detailed(
+ client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Any | Error]:
+ """ Revoke the calling platform token
+
+ Revokes the platform token that authenticates this request, and ends
+ the sign-in session it was created from, if any. Ending the session
+ also revokes every other token created from it. Every later request
+ with the token answers `401`.
+
+ Only a platform token (`pk-`) can call it. A project access token is
+ refused with `403`.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+
+) -> Any | Error | None:
+ """ Revoke the calling platform token
+
+ Revokes the platform token that authenticates this request, and ends
+ the sign-in session it was created from, if any. Ending the session
+ also revokes every other token created from it. Every later request
+ with the token answers `401`.
+
+ Only a platform token (`pk-`) can call it. A project access token is
+ refused with `403`.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/account_sessions/revoke_other_account_sessions.py b/src/volcano_sdk/_generated/api/account_sessions/revoke_other_account_sessions.py
new file mode 100644
index 00000000..994b60d6
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/account_sessions/revoke_other_account_sessions.py
@@ -0,0 +1,207 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from typing import cast
+
+
+
+def request_kwargs(
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "delete",
+ "url": "/user/sessions",
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | Error | None:
+ if response.status_code == 204:
+ response_204 = cast(Any, None)
+ return response_204
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if response.status_code == 501:
+ response_501 = Error.from_dict(response.json())
+
+
+
+ return response_501
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Any | Error]:
+ """ Sign out every other session
+
+ Ends every session of the account except the one the calling token
+ was exchanged from, and revokes the platform tokens exchanged from
+ them. When the calling token has no session, every session ends.
+
+ Platform tokens that were never linked to a session, such as one
+ created in the dashboard or through the management API, keep working.
+ Revoke each with `DELETE /user/tokens/current`.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+
+) -> Any | Error | None:
+ """ Sign out every other session
+
+ Ends every session of the account except the one the calling token
+ was exchanged from, and revokes the platform tokens exchanged from
+ them. When the calling token has no session, every session ends.
+
+ Platform tokens that were never linked to a session, such as one
+ created in the dashboard or through the management API, keep working.
+ Revoke each with `DELETE /user/tokens/current`.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return sync_detailed(
+ client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Any | Error]:
+ """ Sign out every other session
+
+ Ends every session of the account except the one the calling token
+ was exchanged from, and revokes the platform tokens exchanged from
+ them. When the calling token has no session, every session ends.
+
+ Platform tokens that were never linked to a session, such as one
+ created in the dashboard or through the management API, keep working.
+ Revoke each with `DELETE /user/tokens/current`.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+
+) -> Any | Error | None:
+ """ Sign out every other session
+
+ Ends every session of the account except the one the calling token
+ was exchanged from, and revokes the platform tokens exchanged from
+ them. When the calling token has no session, every session ends.
+
+ Platform tokens that were never linked to a session, such as one
+ created in the dashboard or through the management API, keep working.
+ Revoke each with `DELETE /user/tokens/current`.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/anon_keys/create_anon_key.py b/src/volcano_sdk/_generated/api/anon_keys/create_anon_key.py
index 682efb30..98abc90d 100644
--- a/src/volcano_sdk/_generated/api/anon_keys/create_anon_key.py
+++ b/src/volcano_sdk/_generated/api/anon_keys/create_anon_key.py
@@ -10,6 +10,7 @@
from ...models.anon_key import AnonKey
from ...models.create_anon_key_body import CreateAnonKeyBody
+from ...models.error import Error
from typing import cast
from uuid import UUID
@@ -42,7 +43,7 @@ def request_kwargs(
-def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> AnonKey | None:
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> AnonKey | Error | None:
if response.status_code == 201:
response_201 = AnonKey.from_dict(response.json())
@@ -50,13 +51,27 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return response_201
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
else:
return None
-def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[AnonKey]:
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[AnonKey | Error]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
@@ -71,7 +86,7 @@ def sync_detailed(
client: AuthenticatedClient,
body: CreateAnonKeyBody,
-) -> Response[AnonKey]:
+) -> Response[AnonKey | Error]:
""" Create anon key
Args:
@@ -83,7 +98,7 @@ def sync_detailed(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[AnonKey]
+ Response[AnonKey | Error]
"""
@@ -105,7 +120,7 @@ def sync(
client: AuthenticatedClient,
body: CreateAnonKeyBody,
-) -> AnonKey | None:
+) -> AnonKey | Error | None:
""" Create anon key
Args:
@@ -117,7 +132,7 @@ def sync(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- AnonKey
+ AnonKey | Error
"""
@@ -134,7 +149,7 @@ async def asyncio_detailed(
client: AuthenticatedClient,
body: CreateAnonKeyBody,
-) -> Response[AnonKey]:
+) -> Response[AnonKey | Error]:
""" Create anon key
Args:
@@ -146,7 +161,7 @@ async def asyncio_detailed(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[AnonKey]
+ Response[AnonKey | Error]
"""
@@ -168,7 +183,7 @@ async def asyncio(
client: AuthenticatedClient,
body: CreateAnonKeyBody,
-) -> AnonKey | None:
+) -> AnonKey | Error | None:
""" Create anon key
Args:
@@ -180,7 +195,7 @@ async def asyncio(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- AnonKey
+ AnonKey | Error
"""
diff --git a/src/volcano_sdk/_generated/api/anon_keys/regenerate_anon_key.py b/src/volcano_sdk/_generated/api/anon_keys/regenerate_anon_key.py
index 83e6c576..3ef8ce99 100644
--- a/src/volcano_sdk/_generated/api/anon_keys/regenerate_anon_key.py
+++ b/src/volcano_sdk/_generated/api/anon_keys/regenerate_anon_key.py
@@ -9,6 +9,7 @@
from ... import errors
from ...models.anon_key import AnonKey
+from ...models.error import Error
from typing import cast
from uuid import UUID
@@ -35,7 +36,7 @@ def request_kwargs(
-def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> AnonKey | None:
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> AnonKey | Error | None:
if response.status_code == 200:
response_200 = AnonKey.from_dict(response.json())
@@ -43,13 +44,20 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return response_200
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
else:
return None
-def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[AnonKey]:
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[AnonKey | Error]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
@@ -64,7 +72,7 @@ def sync_detailed(
*,
client: AuthenticatedClient,
-) -> Response[AnonKey]:
+) -> Response[AnonKey | Error]:
""" Regenerate anon key
Generate new JWT value for existing key
@@ -78,7 +86,7 @@ def sync_detailed(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[AnonKey]
+ Response[AnonKey | Error]
"""
@@ -100,7 +108,7 @@ def sync(
*,
client: AuthenticatedClient,
-) -> AnonKey | None:
+) -> AnonKey | Error | None:
""" Regenerate anon key
Generate new JWT value for existing key
@@ -114,7 +122,7 @@ def sync(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- AnonKey
+ AnonKey | Error
"""
@@ -131,7 +139,7 @@ async def asyncio_detailed(
*,
client: AuthenticatedClient,
-) -> Response[AnonKey]:
+) -> Response[AnonKey | Error]:
""" Regenerate anon key
Generate new JWT value for existing key
@@ -145,7 +153,7 @@ async def asyncio_detailed(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[AnonKey]
+ Response[AnonKey | Error]
"""
@@ -167,7 +175,7 @@ async def asyncio(
*,
client: AuthenticatedClient,
-) -> AnonKey | None:
+) -> AnonKey | Error | None:
""" Regenerate anon key
Generate new JWT value for existing key
@@ -181,7 +189,7 @@ async def asyncio(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- AnonKey
+ AnonKey | Error
"""
diff --git a/src/volcano_sdk/_generated/api/anon_keys/set_default_anon_key.py b/src/volcano_sdk/_generated/api/anon_keys/set_default_anon_key.py
index f7c5cf55..38562119 100644
--- a/src/volcano_sdk/_generated/api/anon_keys/set_default_anon_key.py
+++ b/src/volcano_sdk/_generated/api/anon_keys/set_default_anon_key.py
@@ -53,7 +53,10 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return response_403
if response.status_code == 404:
- response_404 = cast(Any, None)
+ response_404 = Error.from_dict(response.json())
+
+
+
return response_404
if response.status_code == 500:
diff --git a/src/volcano_sdk/_generated/api/auth_configuration/get_default_email_template.py b/src/volcano_sdk/_generated/api/auth_configuration/get_default_email_template.py
index 8f6b852e..aed4699b 100644
--- a/src/volcano_sdk/_generated/api/auth_configuration/get_default_email_template.py
+++ b/src/volcano_sdk/_generated/api/auth_configuration/get_default_email_template.py
@@ -8,7 +8,8 @@
from ...types import Response, UNSET
from ... import errors
-from ...models.email_template import EmailTemplate
+from ...models.default_email_template import DefaultEmailTemplate
+from ...models.error import Error
from ...models.get_default_email_template_type import check_get_default_email_template_type
from ...models.get_default_email_template_type import GetDefaultEmailTemplateType
from typing import cast
@@ -35,16 +36,19 @@ def request_kwargs(
-def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | EmailTemplate | None:
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> DefaultEmailTemplate | Error | None:
if response.status_code == 200:
- response_200 = EmailTemplate.from_dict(response.json())
+ response_200 = DefaultEmailTemplate.from_dict(response.json())
return response_200
if response.status_code == 404:
- response_404 = cast(Any, None)
+ response_404 = Error.from_dict(response.json())
+
+
+
return response_404
if client.raise_on_unexpected_status:
@@ -53,7 +57,7 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return None
-def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | EmailTemplate]:
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[DefaultEmailTemplate | Error]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
@@ -67,7 +71,7 @@ def sync_detailed(
*,
client: AuthenticatedClient | Client,
-) -> Response[Any | EmailTemplate]:
+) -> Response[DefaultEmailTemplate | Error]:
""" Get default email template by type
Args:
@@ -78,7 +82,7 @@ def sync_detailed(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[Any | EmailTemplate]
+ Response[DefaultEmailTemplate | Error]
"""
@@ -98,7 +102,7 @@ def sync(
*,
client: AuthenticatedClient | Client,
-) -> Any | EmailTemplate | None:
+) -> DefaultEmailTemplate | Error | None:
""" Get default email template by type
Args:
@@ -109,7 +113,7 @@ def sync(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Any | EmailTemplate
+ DefaultEmailTemplate | Error
"""
@@ -124,7 +128,7 @@ async def asyncio_detailed(
*,
client: AuthenticatedClient | Client,
-) -> Response[Any | EmailTemplate]:
+) -> Response[DefaultEmailTemplate | Error]:
""" Get default email template by type
Args:
@@ -135,7 +139,7 @@ async def asyncio_detailed(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[Any | EmailTemplate]
+ Response[DefaultEmailTemplate | Error]
"""
@@ -155,7 +159,7 @@ async def asyncio(
*,
client: AuthenticatedClient | Client,
-) -> Any | EmailTemplate | None:
+) -> DefaultEmailTemplate | Error | None:
""" Get default email template by type
Args:
@@ -166,7 +170,7 @@ async def asyncio(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Any | EmailTemplate
+ DefaultEmailTemplate | Error
"""
diff --git a/src/volcano_sdk/_generated/api/auth_configuration/test_email_config.py b/src/volcano_sdk/_generated/api/auth_configuration/test_email_config.py
index c65d5579..47caeb87 100644
--- a/src/volcano_sdk/_generated/api/auth_configuration/test_email_config.py
+++ b/src/volcano_sdk/_generated/api/auth_configuration/test_email_config.py
@@ -107,6 +107,9 @@ def sync_detailed(
subject or a blank message. Also rejects with 400 if
`email_enabled=false`, `smtp_host` is empty, or the saved
`smtp_password` can't be read and must be set again.
+ Sender values with interior line breaks return 400 before SMTP delivery.
+ Rendered override subjects containing a line break have outer whitespace
+ trimmed; any remaining interior line break returns 400 before delivery.
Args:
id (UUID):
@@ -162,6 +165,9 @@ def sync(
subject or a blank message. Also rejects with 400 if
`email_enabled=false`, `smtp_host` is empty, or the saved
`smtp_password` can't be read and must be set again.
+ Sender values with interior line breaks return 400 before SMTP delivery.
+ Rendered override subjects containing a line break have outer whitespace
+ trimmed; any remaining interior line break returns 400 before delivery.
Args:
id (UUID):
@@ -212,6 +218,9 @@ async def asyncio_detailed(
subject or a blank message. Also rejects with 400 if
`email_enabled=false`, `smtp_host` is empty, or the saved
`smtp_password` can't be read and must be set again.
+ Sender values with interior line breaks return 400 before SMTP delivery.
+ Rendered override subjects containing a line break have outer whitespace
+ trimmed; any remaining interior line break returns 400 before delivery.
Args:
id (UUID):
@@ -267,6 +276,9 @@ async def asyncio(
subject or a blank message. Also rejects with 400 if
`email_enabled=false`, `smtp_host` is empty, or the saved
`smtp_password` can't be read and must be set again.
+ Sender values with interior line breaks return 400 before SMTP delivery.
+ Rendered override subjects containing a line break have outer whitespace
+ trimmed; any remaining interior line break returns 400 before delivery.
Args:
id (UUID):
diff --git a/src/volcano_sdk/_generated/api/auth_configuration/update_auth_config.py b/src/volcano_sdk/_generated/api/auth_configuration/update_auth_config.py
index b4bb3e43..f3289f6d 100644
--- a/src/volcano_sdk/_generated/api/auth_configuration/update_auth_config.py
+++ b/src/volcano_sdk/_generated/api/auth_configuration/update_auth_config.py
@@ -54,6 +54,13 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return response_200
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
if response.status_code == 403:
response_403 = Error.from_dict(response.json())
diff --git a/src/volcano_sdk/_generated/api/auth_configuration/update_email_template.py b/src/volcano_sdk/_generated/api/auth_configuration/update_email_template.py
index d16ed402..cf8a35b0 100644
--- a/src/volcano_sdk/_generated/api/auth_configuration/update_email_template.py
+++ b/src/volcano_sdk/_generated/api/auth_configuration/update_email_template.py
@@ -54,6 +54,13 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return response_200
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
if response.status_code == 403:
response_403 = Error.from_dict(response.json())
diff --git a/src/volcano_sdk/_generated/api/authentication/auth_reset_password.py b/src/volcano_sdk/_generated/api/authentication/auth_reset_password.py
index 4147b7cc..658e98c1 100644
--- a/src/volcano_sdk/_generated/api/authentication/auth_reset_password.py
+++ b/src/volcano_sdk/_generated/api/authentication/auth_reset_password.py
@@ -66,6 +66,13 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
response_401 = cast(Any, None)
return response_401
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
if response.status_code == 503:
response_503 = Error.from_dict(response.json())
diff --git a/src/volcano_sdk/_generated/api/authentication/auth_update_user.py b/src/volcano_sdk/_generated/api/authentication/auth_update_user.py
index a53c132e..5d06c8b8 100644
--- a/src/volcano_sdk/_generated/api/authentication/auth_update_user.py
+++ b/src/volcano_sdk/_generated/api/authentication/auth_update_user.py
@@ -66,6 +66,13 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return response_401
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
if response.status_code == 503:
response_503 = Error.from_dict(response.json())
diff --git a/src/volcano_sdk/_generated/api/autofix/start_autofix_run.py b/src/volcano_sdk/_generated/api/autofix/start_autofix_run.py
deleted file mode 100644
index 0fee78e8..00000000
--- a/src/volcano_sdk/_generated/api/autofix/start_autofix_run.py
+++ /dev/null
@@ -1,291 +0,0 @@
-from http import HTTPStatus
-from typing import Any, cast
-from urllib.parse import quote
-
-import httpx
-
-from ...client import AuthenticatedClient, Client
-from ...types import Response, UNSET
-from ... import errors
-
-from ...models.autofix_run import AutofixRun
-from ...models.error import Error
-from typing import cast
-from uuid import UUID
-
-
-
-def request_kwargs(
- id: UUID | str,
- issue_id: UUID | str,
-
-) -> dict[str, Any]:
-
-
-
-
-
-
- _kwargs: dict[str, Any] = {
- "method": "post",
- "url": "/projects/{id}/issues/{issue_id}/autofix-runs".format(id=quote(str(id), safe=""),issue_id=quote(str(issue_id), safe=""),),
- }
-
-
- return _kwargs
-
-
-
-def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> AutofixRun | Error | None:
- if response.status_code == 202:
- response_202 = AutofixRun.from_dict(response.json())
-
-
-
- return response_202
-
- if response.status_code == 400:
- response_400 = Error.from_dict(response.json())
-
-
-
- return response_400
-
- if response.status_code == 403:
- response_403 = Error.from_dict(response.json())
-
-
-
- return response_403
-
- if response.status_code == 404:
- response_404 = Error.from_dict(response.json())
-
-
-
- return response_404
-
- if response.status_code == 409:
- response_409 = Error.from_dict(response.json())
-
-
-
- return response_409
-
- if response.status_code == 429:
- response_429 = Error.from_dict(response.json())
-
-
-
- return response_429
-
- if response.status_code == 501:
- response_501 = Error.from_dict(response.json())
-
-
-
- return response_501
-
- if response.status_code == 503:
- response_503 = Error.from_dict(response.json())
-
-
-
- return response_503
-
- if client.raise_on_unexpected_status:
- raise errors.UnexpectedStatus(response.status_code, response.content)
- else:
- return None
-
-
-def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[AutofixRun | Error]:
- return Response(
- status_code=HTTPStatus(response.status_code),
- content=response.content,
- headers=response.headers,
- parsed=_parse_response(client=client, response=response),
- )
-
-
-def sync_detailed(
- id: UUID | str,
- issue_id: UUID | str,
- *,
- client: AuthenticatedClient,
-
-) -> Response[AutofixRun | Error]:
- """ Diagnose an issue
-
- Queues a run that diagnoses the issue with AI. The run reads the
- issue's runtime logs and, when a push to the project's connected
- repository built the deployment that was live when the issue was
- last seen, its source at that commit. Poll the run until its status is
- `succeeded`, `failed`, or `canceled`.
-
- Autofix must be on for the project. An issue has at most one queued or
- running run, a project runs one at a time, and a project starts at most
- 25 runs, manual and automatic, in any 24 hours.
-
- Project access tokens are refused. A run spends model tokens on the
- project's provider, so a person starts it with a platform token or in
- the dashboard.
-
- Args:
- id (UUID):
- issue_id (UUID):
-
- Raises:
- errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
- httpx.TimeoutException: If the request takes longer than Client.timeout.
-
- Returns:
- Response[AutofixRun | Error]
- """
-
-
- kwargs = request_kwargs(
- id=id,
-issue_id=issue_id,
-
- )
-
- response = client.get_httpx_client().request(
- **kwargs,
- )
-
- return build_response(client=client, response=response)
-
-def sync(
- id: UUID | str,
- issue_id: UUID | str,
- *,
- client: AuthenticatedClient,
-
-) -> AutofixRun | Error | None:
- """ Diagnose an issue
-
- Queues a run that diagnoses the issue with AI. The run reads the
- issue's runtime logs and, when a push to the project's connected
- repository built the deployment that was live when the issue was
- last seen, its source at that commit. Poll the run until its status is
- `succeeded`, `failed`, or `canceled`.
-
- Autofix must be on for the project. An issue has at most one queued or
- running run, a project runs one at a time, and a project starts at most
- 25 runs, manual and automatic, in any 24 hours.
-
- Project access tokens are refused. A run spends model tokens on the
- project's provider, so a person starts it with a platform token or in
- the dashboard.
-
- Args:
- id (UUID):
- issue_id (UUID):
-
- Raises:
- errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
- httpx.TimeoutException: If the request takes longer than Client.timeout.
-
- Returns:
- AutofixRun | Error
- """
-
-
- return sync_detailed(
- id=id,
-issue_id=issue_id,
-client=client,
-
- ).parsed
-
-async def asyncio_detailed(
- id: UUID | str,
- issue_id: UUID | str,
- *,
- client: AuthenticatedClient,
-
-) -> Response[AutofixRun | Error]:
- """ Diagnose an issue
-
- Queues a run that diagnoses the issue with AI. The run reads the
- issue's runtime logs and, when a push to the project's connected
- repository built the deployment that was live when the issue was
- last seen, its source at that commit. Poll the run until its status is
- `succeeded`, `failed`, or `canceled`.
-
- Autofix must be on for the project. An issue has at most one queued or
- running run, a project runs one at a time, and a project starts at most
- 25 runs, manual and automatic, in any 24 hours.
-
- Project access tokens are refused. A run spends model tokens on the
- project's provider, so a person starts it with a platform token or in
- the dashboard.
-
- Args:
- id (UUID):
- issue_id (UUID):
-
- Raises:
- errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
- httpx.TimeoutException: If the request takes longer than Client.timeout.
-
- Returns:
- Response[AutofixRun | Error]
- """
-
-
- kwargs = request_kwargs(
- id=id,
-issue_id=issue_id,
-
- )
-
- response = await client.get_async_httpx_client().request(
- **kwargs
- )
-
- return build_response(client=client, response=response)
-
-async def asyncio(
- id: UUID | str,
- issue_id: UUID | str,
- *,
- client: AuthenticatedClient,
-
-) -> AutofixRun | Error | None:
- """ Diagnose an issue
-
- Queues a run that diagnoses the issue with AI. The run reads the
- issue's runtime logs and, when a push to the project's connected
- repository built the deployment that was live when the issue was
- last seen, its source at that commit. Poll the run until its status is
- `succeeded`, `failed`, or `canceled`.
-
- Autofix must be on for the project. An issue has at most one queued or
- running run, a project runs one at a time, and a project starts at most
- 25 runs, manual and automatic, in any 24 hours.
-
- Project access tokens are refused. A run spends model tokens on the
- project's provider, so a person starts it with a platform token or in
- the dashboard.
-
- Args:
- id (UUID):
- issue_id (UUID):
-
- Raises:
- errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
- httpx.TimeoutException: If the request takes longer than Client.timeout.
-
- Returns:
- AutofixRun | Error
- """
-
-
- return (await asyncio_detailed(
- id=id,
-issue_id=issue_id,
-client=client,
-
- )).parsed
diff --git a/src/volcano_sdk/_generated/api/autofix/update_autofix_settings.py b/src/volcano_sdk/_generated/api/autofix/update_autofix_settings.py
deleted file mode 100644
index 0949213d..00000000
--- a/src/volcano_sdk/_generated/api/autofix/update_autofix_settings.py
+++ /dev/null
@@ -1,332 +0,0 @@
-from http import HTTPStatus
-from typing import Any, cast
-from urllib.parse import quote
-
-import httpx
-
-from ...client import AuthenticatedClient, Client
-from ...types import Response, UNSET
-from ... import errors
-
-from ...models.autofix_settings import AutofixSettings
-from ...models.error import Error
-from ...models.update_autofix_settings_request import UpdateAutofixSettingsRequest
-from typing import cast
-from uuid import UUID
-
-
-
-def request_kwargs(
- id: UUID | str,
- *,
- body: UpdateAutofixSettingsRequest,
-
-) -> dict[str, Any]:
- headers: dict[str, Any] = {}
-
-
-
-
-
-
- _kwargs: dict[str, Any] = {
- "method": "put",
- "url": "/projects/{id}/autofix".format(id=quote(str(id), safe=""),),
- }
-
- _kwargs["json"] = body.to_dict()
-
- headers["Content-Type"] = "application/json"
-
- _kwargs["headers"] = headers
- return _kwargs
-
-
-
-def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> AutofixSettings | Error | None:
- if response.status_code == 200:
- response_200 = AutofixSettings.from_dict(response.json())
-
-
-
- return response_200
-
- if response.status_code == 400:
- response_400 = Error.from_dict(response.json())
-
-
-
- return response_400
-
- if response.status_code == 403:
- response_403 = Error.from_dict(response.json())
-
-
-
- return response_403
-
- if response.status_code == 404:
- response_404 = Error.from_dict(response.json())
-
-
-
- return response_404
-
- if response.status_code == 501:
- response_501 = Error.from_dict(response.json())
-
-
-
- return response_501
-
- if response.status_code == 503:
- response_503 = Error.from_dict(response.json())
-
-
-
- return response_503
-
- if client.raise_on_unexpected_status:
- raise errors.UnexpectedStatus(response.status_code, response.content)
- else:
- return None
-
-
-def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[AutofixSettings | Error]:
- return Response(
- status_code=HTTPStatus(response.status_code),
- content=response.content,
- headers=response.headers,
- parsed=_parse_response(client=client, response=response),
- )
-
-
-def sync_detailed(
- id: UUID | str,
- *,
- client: AuthenticatedClient,
- body: UpdateAutofixSettingsRequest,
-
-) -> Response[AutofixSettings | Error]:
- """ Replace autofix settings
-
- Replaces the project's autofix settings. Omitted fields take their
- defaults, except three: an omitted `provider` or `model` keeps its saved
- value, and an omitted `api_key` keeps the stored key. So
- `{"enabled": false}` turns autofix off and keeps the key.
-
- Project access tokens are refused. Autofix opens pull requests in the
- project's repository, so a person turns it on with a platform token or
- in the dashboard.
-
- Turning autofix on needs a plan that includes it. Settings that are
- already on stay stored after a downgrade, and saving them again is not
- refused, but no run starts until the plan includes autofix again. Other
- saves need no plan.
-
- Provider `anthropic` runs on your own API key. A key belongs to the
- provider it was saved with, and turning autofix on with a provider that
- runs on your own key needs one for it. Turning autofix off or switching
- providers keeps the stored key; only
- `DELETE /projects/{id}/autofix/api-key` removes it. Turning autofix on
- with provider `volcano` needs the `autofix.managed_models` capability;
- without it the request answers `400` with code `feature_unavailable`.
-
- Where autofix is not available, a project with saved settings can
- still change them with `enabled: false`. Turning autofix on answers
- `404` with code `feature_unavailable`.
-
- Args:
- id (UUID):
- body (UpdateAutofixSettingsRequest):
-
- Raises:
- errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
- httpx.TimeoutException: If the request takes longer than Client.timeout.
-
- Returns:
- Response[AutofixSettings | Error]
- """
-
-
- kwargs = request_kwargs(
- id=id,
-body=body,
-
- )
-
- response = client.get_httpx_client().request(
- **kwargs,
- )
-
- return build_response(client=client, response=response)
-
-def sync(
- id: UUID | str,
- *,
- client: AuthenticatedClient,
- body: UpdateAutofixSettingsRequest,
-
-) -> AutofixSettings | Error | None:
- """ Replace autofix settings
-
- Replaces the project's autofix settings. Omitted fields take their
- defaults, except three: an omitted `provider` or `model` keeps its saved
- value, and an omitted `api_key` keeps the stored key. So
- `{"enabled": false}` turns autofix off and keeps the key.
-
- Project access tokens are refused. Autofix opens pull requests in the
- project's repository, so a person turns it on with a platform token or
- in the dashboard.
-
- Turning autofix on needs a plan that includes it. Settings that are
- already on stay stored after a downgrade, and saving them again is not
- refused, but no run starts until the plan includes autofix again. Other
- saves need no plan.
-
- Provider `anthropic` runs on your own API key. A key belongs to the
- provider it was saved with, and turning autofix on with a provider that
- runs on your own key needs one for it. Turning autofix off or switching
- providers keeps the stored key; only
- `DELETE /projects/{id}/autofix/api-key` removes it. Turning autofix on
- with provider `volcano` needs the `autofix.managed_models` capability;
- without it the request answers `400` with code `feature_unavailable`.
-
- Where autofix is not available, a project with saved settings can
- still change them with `enabled: false`. Turning autofix on answers
- `404` with code `feature_unavailable`.
-
- Args:
- id (UUID):
- body (UpdateAutofixSettingsRequest):
-
- Raises:
- errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
- httpx.TimeoutException: If the request takes longer than Client.timeout.
-
- Returns:
- AutofixSettings | Error
- """
-
-
- return sync_detailed(
- id=id,
-client=client,
-body=body,
-
- ).parsed
-
-async def asyncio_detailed(
- id: UUID | str,
- *,
- client: AuthenticatedClient,
- body: UpdateAutofixSettingsRequest,
-
-) -> Response[AutofixSettings | Error]:
- """ Replace autofix settings
-
- Replaces the project's autofix settings. Omitted fields take their
- defaults, except three: an omitted `provider` or `model` keeps its saved
- value, and an omitted `api_key` keeps the stored key. So
- `{"enabled": false}` turns autofix off and keeps the key.
-
- Project access tokens are refused. Autofix opens pull requests in the
- project's repository, so a person turns it on with a platform token or
- in the dashboard.
-
- Turning autofix on needs a plan that includes it. Settings that are
- already on stay stored after a downgrade, and saving them again is not
- refused, but no run starts until the plan includes autofix again. Other
- saves need no plan.
-
- Provider `anthropic` runs on your own API key. A key belongs to the
- provider it was saved with, and turning autofix on with a provider that
- runs on your own key needs one for it. Turning autofix off or switching
- providers keeps the stored key; only
- `DELETE /projects/{id}/autofix/api-key` removes it. Turning autofix on
- with provider `volcano` needs the `autofix.managed_models` capability;
- without it the request answers `400` with code `feature_unavailable`.
-
- Where autofix is not available, a project with saved settings can
- still change them with `enabled: false`. Turning autofix on answers
- `404` with code `feature_unavailable`.
-
- Args:
- id (UUID):
- body (UpdateAutofixSettingsRequest):
-
- Raises:
- errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
- httpx.TimeoutException: If the request takes longer than Client.timeout.
-
- Returns:
- Response[AutofixSettings | Error]
- """
-
-
- kwargs = request_kwargs(
- id=id,
-body=body,
-
- )
-
- response = await client.get_async_httpx_client().request(
- **kwargs
- )
-
- return build_response(client=client, response=response)
-
-async def asyncio(
- id: UUID | str,
- *,
- client: AuthenticatedClient,
- body: UpdateAutofixSettingsRequest,
-
-) -> AutofixSettings | Error | None:
- """ Replace autofix settings
-
- Replaces the project's autofix settings. Omitted fields take their
- defaults, except three: an omitted `provider` or `model` keeps its saved
- value, and an omitted `api_key` keeps the stored key. So
- `{"enabled": false}` turns autofix off and keeps the key.
-
- Project access tokens are refused. Autofix opens pull requests in the
- project's repository, so a person turns it on with a platform token or
- in the dashboard.
-
- Turning autofix on needs a plan that includes it. Settings that are
- already on stay stored after a downgrade, and saving them again is not
- refused, but no run starts until the plan includes autofix again. Other
- saves need no plan.
-
- Provider `anthropic` runs on your own API key. A key belongs to the
- provider it was saved with, and turning autofix on with a provider that
- runs on your own key needs one for it. Turning autofix off or switching
- providers keeps the stored key; only
- `DELETE /projects/{id}/autofix/api-key` removes it. Turning autofix on
- with provider `volcano` needs the `autofix.managed_models` capability;
- without it the request answers `400` with code `feature_unavailable`.
-
- Where autofix is not available, a project with saved settings can
- still change them with `enabled: false`. Turning autofix on answers
- `404` with code `feature_unavailable`.
-
- Args:
- id (UUID):
- body (UpdateAutofixSettingsRequest):
-
- Raises:
- errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
- httpx.TimeoutException: If the request takes longer than Client.timeout.
-
- Returns:
- AutofixSettings | Error
- """
-
-
- return (await asyncio_detailed(
- id=id,
-client=client,
-body=body,
-
- )).parsed
diff --git a/src/volcano_sdk/_generated/api/connectors/__init__.py b/src/volcano_sdk/_generated/api/connectors/__init__.py
new file mode 100644
index 00000000..c9921b5f
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/connectors/__init__.py
@@ -0,0 +1 @@
+""" Contains endpoint functions for accessing the API """
diff --git a/src/volcano_sdk/_generated/api/connectors/delete_connector.py b/src/volcano_sdk/_generated/api/connectors/delete_connector.py
new file mode 100644
index 00000000..3ff6e5f4
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/connectors/delete_connector.py
@@ -0,0 +1,244 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ connector_id: UUID | str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "delete",
+ "url": "/connectors/{connector_id}".format(connector_id=quote(str(connector_id), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | Error | None:
+ if response.status_code == 204:
+ response_204 = cast(Any, None)
+ return response_204
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 502:
+ response_502 = Error.from_dict(response.json())
+
+
+
+ return response_502
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ connector_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Any | Error]:
+ """ Remove a connector
+
+ Removes a connector. Removing a `slack` connector uninstalls the
+ Volcano app from the Slack workspace, for every Volcano account that
+ uses it. Only the person who installed the app there can remove it
+ (`removable` is `true` for them); anyone else can uninstall the app in
+ Slack. The workspace's channels stop reporting problems at their next
+ check, which also cancels reports still queued. The channel bindings
+ stay, and report again if the app is installed in the workspace again.
+ It works whether or not reporting problems from Slack is available in
+ this environment.
+
+ Args:
+ connector_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ connector_id=connector_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ connector_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Any | Error | None:
+ """ Remove a connector
+
+ Removes a connector. Removing a `slack` connector uninstalls the
+ Volcano app from the Slack workspace, for every Volcano account that
+ uses it. Only the person who installed the app there can remove it
+ (`removable` is `true` for them); anyone else can uninstall the app in
+ Slack. The workspace's channels stop reporting problems at their next
+ check, which also cancels reports still queued. The channel bindings
+ stay, and report again if the app is installed in the workspace again.
+ It works whether or not reporting problems from Slack is available in
+ this environment.
+
+ Args:
+ connector_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return sync_detailed(
+ connector_id=connector_id,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ connector_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Any | Error]:
+ """ Remove a connector
+
+ Removes a connector. Removing a `slack` connector uninstalls the
+ Volcano app from the Slack workspace, for every Volcano account that
+ uses it. Only the person who installed the app there can remove it
+ (`removable` is `true` for them); anyone else can uninstall the app in
+ Slack. The workspace's channels stop reporting problems at their next
+ check, which also cancels reports still queued. The channel bindings
+ stay, and report again if the app is installed in the workspace again.
+ It works whether or not reporting problems from Slack is available in
+ this environment.
+
+ Args:
+ connector_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ connector_id=connector_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ connector_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Any | Error | None:
+ """ Remove a connector
+
+ Removes a connector. Removing a `slack` connector uninstalls the
+ Volcano app from the Slack workspace, for every Volcano account that
+ uses it. Only the person who installed the app there can remove it
+ (`removable` is `true` for them); anyone else can uninstall the app in
+ Slack. The workspace's channels stop reporting problems at their next
+ check, which also cancels reports still queued. The channel bindings
+ stay, and report again if the app is installed in the workspace again.
+ It works whether or not reporting problems from Slack is available in
+ this environment.
+
+ Args:
+ connector_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return (await asyncio_detailed(
+ connector_id=connector_id,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/connectors/get_connector.py b/src/volcano_sdk/_generated/api/connectors/get_connector.py
new file mode 100644
index 00000000..e3ce4a5b
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/connectors/get_connector.py
@@ -0,0 +1,210 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.connector import Connector
+from ...models.error import Error
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ connector_id: UUID | str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/connectors/{connector_id}".format(connector_id=quote(str(connector_id), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Connector | Error | None:
+ if response.status_code == 200:
+ response_200 = Connector.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Connector | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ connector_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Connector | Error]:
+ """ Get a connector
+
+ Returns one connector the caller can use, as listing connectors shows
+ it. A connector the caller cannot see answers like one that doesn't
+ exist.
+
+ Args:
+ connector_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Connector | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ connector_id=connector_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ connector_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Connector | Error | None:
+ """ Get a connector
+
+ Returns one connector the caller can use, as listing connectors shows
+ it. A connector the caller cannot see answers like one that doesn't
+ exist.
+
+ Args:
+ connector_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Connector | Error
+ """
+
+
+ return sync_detailed(
+ connector_id=connector_id,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ connector_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Connector | Error]:
+ """ Get a connector
+
+ Returns one connector the caller can use, as listing connectors shows
+ it. A connector the caller cannot see answers like one that doesn't
+ exist.
+
+ Args:
+ connector_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Connector | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ connector_id=connector_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ connector_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Connector | Error | None:
+ """ Get a connector
+
+ Returns one connector the caller can use, as listing connectors shows
+ it. A connector the caller cannot see answers like one that doesn't
+ exist.
+
+ Args:
+ connector_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Connector | Error
+ """
+
+
+ return (await asyncio_detailed(
+ connector_id=connector_id,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/connectors/list_connectors.py b/src/volcano_sdk/_generated/api/connectors/list_connectors.py
new file mode 100644
index 00000000..f1880049
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/connectors/list_connectors.py
@@ -0,0 +1,194 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.connectors_response import ConnectorsResponse
+from ...models.error import Error
+from typing import cast
+
+
+
+def request_kwargs(
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/connectors",
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> ConnectorsResponse | Error | None:
+ if response.status_code == 200:
+ response_200 = ConnectorsResponse.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[ConnectorsResponse | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[ConnectorsResponse | Error]:
+ """ List connectors
+
+ Lists the connectors the caller can use. A connector links Volcano to
+ an outside service. A `slack` connector is a Slack workspace the
+ Volcano app is installed in: it is listed to the person who installed
+ it there, and to anyone with a Slack identity in that workspace
+ connected to their Volcano account. Add one with
+ `POST /user/slack/installations`. The list answers whether or not
+ reporting problems from Slack is available in this environment, so
+ turning it off strands no connector.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[ConnectorsResponse | Error]
+ """
+
+
+ kwargs = request_kwargs(
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+
+) -> ConnectorsResponse | Error | None:
+ """ List connectors
+
+ Lists the connectors the caller can use. A connector links Volcano to
+ an outside service. A `slack` connector is a Slack workspace the
+ Volcano app is installed in: it is listed to the person who installed
+ it there, and to anyone with a Slack identity in that workspace
+ connected to their Volcano account. Add one with
+ `POST /user/slack/installations`. The list answers whether or not
+ reporting problems from Slack is available in this environment, so
+ turning it off strands no connector.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ ConnectorsResponse | Error
+ """
+
+
+ return sync_detailed(
+ client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[ConnectorsResponse | Error]:
+ """ List connectors
+
+ Lists the connectors the caller can use. A connector links Volcano to
+ an outside service. A `slack` connector is a Slack workspace the
+ Volcano app is installed in: it is listed to the person who installed
+ it there, and to anyone with a Slack identity in that workspace
+ connected to their Volcano account. Add one with
+ `POST /user/slack/installations`. The list answers whether or not
+ reporting problems from Slack is available in this environment, so
+ turning it off strands no connector.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[ConnectorsResponse | Error]
+ """
+
+
+ kwargs = request_kwargs(
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+
+) -> ConnectorsResponse | Error | None:
+ """ List connectors
+
+ Lists the connectors the caller can use. A connector links Volcano to
+ an outside service. A `slack` connector is a Slack workspace the
+ Volcano app is installed in: it is listed to the person who installed
+ it there, and to anyone with a Slack identity in that workspace
+ connected to their Volcano account. Add one with
+ `POST /user/slack/installations`. The list answers whether or not
+ reporting problems from Slack is available in this environment, so
+ turning it off strands no connector.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ ConnectorsResponse | Error
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/database_backups/create_database_restore.py b/src/volcano_sdk/_generated/api/database_backups/create_database_restore.py
index 0189862d..23c3f868 100644
--- a/src/volcano_sdk/_generated/api/database_backups/create_database_restore.py
+++ b/src/volcano_sdk/_generated/api/database_backups/create_database_restore.py
@@ -10,6 +10,7 @@
from ...models.create_database_restore_request import CreateDatabaseRestoreRequest
from ...models.database_restore import DatabaseRestore
+from ...models.database_restore_conflict_error import DatabaseRestoreConflictError
from ...models.error import Error
from typing import cast
from uuid import UUID
@@ -44,7 +45,7 @@ def request_kwargs(
-def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> DatabaseRestore | Error | None:
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> DatabaseRestore | DatabaseRestoreConflictError | Error | None:
if response.status_code == 202:
response_202 = DatabaseRestore.from_dict(response.json())
@@ -74,7 +75,7 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return response_404
if response.status_code == 409:
- response_409 = Error.from_dict(response.json())
+ response_409 = DatabaseRestoreConflictError.from_dict(response.json())
@@ -93,7 +94,7 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return None
-def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[DatabaseRestore | Error]:
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[DatabaseRestore | DatabaseRestoreConflictError | Error]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
@@ -109,7 +110,7 @@ def sync_detailed(
client: AuthenticatedClient,
body: CreateDatabaseRestoreRequest,
-) -> Response[DatabaseRestore | Error]:
+) -> Response[DatabaseRestore | DatabaseRestoreConflictError | Error]:
""" Restore a database
Replaces the database's data, either with a named backup or with its
@@ -138,7 +139,7 @@ def sync_detailed(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[DatabaseRestore | Error]
+ Response[DatabaseRestore | DatabaseRestoreConflictError | Error]
"""
@@ -162,7 +163,7 @@ def sync(
client: AuthenticatedClient,
body: CreateDatabaseRestoreRequest,
-) -> DatabaseRestore | Error | None:
+) -> DatabaseRestore | DatabaseRestoreConflictError | Error | None:
""" Restore a database
Replaces the database's data, either with a named backup or with its
@@ -191,7 +192,7 @@ def sync(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- DatabaseRestore | Error
+ DatabaseRestore | DatabaseRestoreConflictError | Error
"""
@@ -210,7 +211,7 @@ async def asyncio_detailed(
client: AuthenticatedClient,
body: CreateDatabaseRestoreRequest,
-) -> Response[DatabaseRestore | Error]:
+) -> Response[DatabaseRestore | DatabaseRestoreConflictError | Error]:
""" Restore a database
Replaces the database's data, either with a named backup or with its
@@ -239,7 +240,7 @@ async def asyncio_detailed(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[DatabaseRestore | Error]
+ Response[DatabaseRestore | DatabaseRestoreConflictError | Error]
"""
@@ -263,7 +264,7 @@ async def asyncio(
client: AuthenticatedClient,
body: CreateDatabaseRestoreRequest,
-) -> DatabaseRestore | Error | None:
+) -> DatabaseRestore | DatabaseRestoreConflictError | Error | None:
""" Restore a database
Replaces the database's data, either with a named backup or with its
@@ -292,7 +293,7 @@ async def asyncio(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- DatabaseRestore | Error
+ DatabaseRestore | DatabaseRestoreConflictError | Error
"""
diff --git a/src/volcano_sdk/_generated/api/database_backups/list_database_backups.py b/src/volcano_sdk/_generated/api/database_backups/list_database_backups.py
index 1140f955..d421c958 100644
--- a/src/volcano_sdk/_generated/api/database_backups/list_database_backups.py
+++ b/src/volcano_sdk/_generated/api/database_backups/list_database_backups.py
@@ -99,9 +99,9 @@ def sync_detailed(
Returns every backup of the database, newest first, together with the
window a point-in-time restore may target.
- Both backups you took and backups the schedule produced are listed;
- `source` tells them apart. Only manual backups count against the plan's
- backup allowance.
+ Backups you took, backups the schedule produced, and backups taken
+ before migrations are all listed; `source` tells them apart. Only manual
+ backups count against the plan's backup allowance.
Args:
id (UUID):
@@ -140,9 +140,9 @@ def sync(
Returns every backup of the database, newest first, together with the
window a point-in-time restore may target.
- Both backups you took and backups the schedule produced are listed;
- `source` tells them apart. Only manual backups count against the plan's
- backup allowance.
+ Backups you took, backups the schedule produced, and backups taken
+ before migrations are all listed; `source` tells them apart. Only manual
+ backups count against the plan's backup allowance.
Args:
id (UUID):
@@ -176,9 +176,9 @@ async def asyncio_detailed(
Returns every backup of the database, newest first, together with the
window a point-in-time restore may target.
- Both backups you took and backups the schedule produced are listed;
- `source` tells them apart. Only manual backups count against the plan's
- backup allowance.
+ Backups you took, backups the schedule produced, and backups taken
+ before migrations are all listed; `source` tells them apart. Only manual
+ backups count against the plan's backup allowance.
Args:
id (UUID):
@@ -217,9 +217,9 @@ async def asyncio(
Returns every backup of the database, newest first, together with the
window a point-in-time restore may target.
- Both backups you took and backups the schedule produced are listed;
- `source` tells them apart. Only manual backups count against the plan's
- backup allowance.
+ Backups you took, backups the schedule produced, and backups taken
+ before migrations are all listed; `source` tells them apart. Only manual
+ backups count against the plan's backup allowance.
Args:
id (UUID):
diff --git a/src/volcano_sdk/_generated/api/database_migrations/__init__.py b/src/volcano_sdk/_generated/api/database_migrations/__init__.py
new file mode 100644
index 00000000..c9921b5f
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/database_migrations/__init__.py
@@ -0,0 +1 @@
+""" Contains endpoint functions for accessing the API """
diff --git a/src/volcano_sdk/_generated/api/database_migrations/baseline_database_migrations.py b/src/volcano_sdk/_generated/api/database_migrations/baseline_database_migrations.py
new file mode 100644
index 00000000..9792595c
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/database_migrations/baseline_database_migrations.py
@@ -0,0 +1,322 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.database_migration_baseline import DatabaseMigrationBaseline
+from ...models.database_migration_conflict_error import DatabaseMigrationConflictError
+from ...models.database_migration_files_request import DatabaseMigrationFilesRequest
+from ...models.error import Error
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ database_name: str,
+ *,
+ body: DatabaseMigrationFilesRequest,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/projects/{id}/databases/{database_name}/migrations/baseline".format(id=quote(str(id), safe=""),database_name=quote(str(database_name), safe=""),),
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> DatabaseMigrationBaseline | DatabaseMigrationConflictError | Error | None:
+ if response.status_code == 200:
+ response_200 = DatabaseMigrationBaseline.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = DatabaseMigrationConflictError.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 413:
+ response_413 = Error.from_dict(response.json())
+
+
+
+ return response_413
+
+ if response.status_code == 503:
+ response_503 = Error.from_dict(response.json())
+
+
+
+ return response_503
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[DatabaseMigrationBaseline | DatabaseMigrationConflictError | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ database_name: str,
+ *,
+ client: AuthenticatedClient,
+ body: DatabaseMigrationFilesRequest,
+
+) -> Response[DatabaseMigrationBaseline | DatabaseMigrationConflictError | Error]:
+ """ Record migrations as applied without running them
+
+ Records each file in the database's migration history as applied,
+ without running it. Use it once for a database whose schema already
+ reflects the files, such as one migrated before Volcano tracked its
+ migrations, so later runs apply only newer files. It is refused while
+ a run is queued or running, and no run starts while it records. It
+ does not queue: while another request is changing the database, or the
+ database holds it up, such as with a lock on the migration history, it
+ answers `409` with code `database_busy`.
+
+ Files the history already records with the same checksum are skipped, so
+ repeating the request changes nothing. A file recorded with a different
+ checksum is refused, and nothing is recorded.
+
+ It also rebuilds a history that was lost (`history_missing`): send
+ exactly the files that were already applied, and later runs apply only
+ the rest.
+
+ Where migration runs are not available, answers `404` with code
+ `feature_unavailable`.
+
+ Args:
+ id (UUID):
+ database_name (str):
+ body (DatabaseMigrationFilesRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[DatabaseMigrationBaseline | DatabaseMigrationConflictError | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+database_name=database_name,
+body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ database_name: str,
+ *,
+ client: AuthenticatedClient,
+ body: DatabaseMigrationFilesRequest,
+
+) -> DatabaseMigrationBaseline | DatabaseMigrationConflictError | Error | None:
+ """ Record migrations as applied without running them
+
+ Records each file in the database's migration history as applied,
+ without running it. Use it once for a database whose schema already
+ reflects the files, such as one migrated before Volcano tracked its
+ migrations, so later runs apply only newer files. It is refused while
+ a run is queued or running, and no run starts while it records. It
+ does not queue: while another request is changing the database, or the
+ database holds it up, such as with a lock on the migration history, it
+ answers `409` with code `database_busy`.
+
+ Files the history already records with the same checksum are skipped, so
+ repeating the request changes nothing. A file recorded with a different
+ checksum is refused, and nothing is recorded.
+
+ It also rebuilds a history that was lost (`history_missing`): send
+ exactly the files that were already applied, and later runs apply only
+ the rest.
+
+ Where migration runs are not available, answers `404` with code
+ `feature_unavailable`.
+
+ Args:
+ id (UUID):
+ database_name (str):
+ body (DatabaseMigrationFilesRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ DatabaseMigrationBaseline | DatabaseMigrationConflictError | Error
+ """
+
+
+ return sync_detailed(
+ id=id,
+database_name=database_name,
+client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ database_name: str,
+ *,
+ client: AuthenticatedClient,
+ body: DatabaseMigrationFilesRequest,
+
+) -> Response[DatabaseMigrationBaseline | DatabaseMigrationConflictError | Error]:
+ """ Record migrations as applied without running them
+
+ Records each file in the database's migration history as applied,
+ without running it. Use it once for a database whose schema already
+ reflects the files, such as one migrated before Volcano tracked its
+ migrations, so later runs apply only newer files. It is refused while
+ a run is queued or running, and no run starts while it records. It
+ does not queue: while another request is changing the database, or the
+ database holds it up, such as with a lock on the migration history, it
+ answers `409` with code `database_busy`.
+
+ Files the history already records with the same checksum are skipped, so
+ repeating the request changes nothing. A file recorded with a different
+ checksum is refused, and nothing is recorded.
+
+ It also rebuilds a history that was lost (`history_missing`): send
+ exactly the files that were already applied, and later runs apply only
+ the rest.
+
+ Where migration runs are not available, answers `404` with code
+ `feature_unavailable`.
+
+ Args:
+ id (UUID):
+ database_name (str):
+ body (DatabaseMigrationFilesRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[DatabaseMigrationBaseline | DatabaseMigrationConflictError | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+database_name=database_name,
+body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ database_name: str,
+ *,
+ client: AuthenticatedClient,
+ body: DatabaseMigrationFilesRequest,
+
+) -> DatabaseMigrationBaseline | DatabaseMigrationConflictError | Error | None:
+ """ Record migrations as applied without running them
+
+ Records each file in the database's migration history as applied,
+ without running it. Use it once for a database whose schema already
+ reflects the files, such as one migrated before Volcano tracked its
+ migrations, so later runs apply only newer files. It is refused while
+ a run is queued or running, and no run starts while it records. It
+ does not queue: while another request is changing the database, or the
+ database holds it up, such as with a lock on the migration history, it
+ answers `409` with code `database_busy`.
+
+ Files the history already records with the same checksum are skipped, so
+ repeating the request changes nothing. A file recorded with a different
+ checksum is refused, and nothing is recorded.
+
+ It also rebuilds a history that was lost (`history_missing`): send
+ exactly the files that were already applied, and later runs apply only
+ the rest.
+
+ Where migration runs are not available, answers `404` with code
+ `feature_unavailable`.
+
+ Args:
+ id (UUID):
+ database_name (str):
+ body (DatabaseMigrationFilesRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ DatabaseMigrationBaseline | DatabaseMigrationConflictError | Error
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+database_name=database_name,
+client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/database_migrations/create_database_migration_run.py b/src/volcano_sdk/_generated/api/database_migrations/create_database_migration_run.py
new file mode 100644
index 00000000..b983bc5a
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/database_migrations/create_database_migration_run.py
@@ -0,0 +1,319 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.database_migration_conflict_error import DatabaseMigrationConflictError
+from ...models.database_migration_files_request import DatabaseMigrationFilesRequest
+from ...models.database_migration_run import DatabaseMigrationRun
+from ...models.error import Error
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ database_name: str,
+ *,
+ body: DatabaseMigrationFilesRequest,
+ idempotency_key: str | Unset = UNSET,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+ if not isinstance(idempotency_key, Unset):
+ headers["Idempotency-Key"] = idempotency_key
+
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/projects/{id}/databases/{database_name}/migration-runs".format(id=quote(str(id), safe=""),database_name=quote(str(database_name), safe=""),),
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> DatabaseMigrationConflictError | DatabaseMigrationRun | Error | None:
+ if response.status_code == 200:
+ response_200 = DatabaseMigrationRun.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 202:
+ response_202 = DatabaseMigrationRun.from_dict(response.json())
+
+
+
+ return response_202
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = DatabaseMigrationConflictError.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 413:
+ response_413 = Error.from_dict(response.json())
+
+
+
+ return response_413
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[DatabaseMigrationConflictError | DatabaseMigrationRun | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ database_name: str,
+ *,
+ client: AuthenticatedClient,
+ body: DatabaseMigrationFilesRequest,
+ idempotency_key: str | Unset = UNSET,
+
+) -> Response[DatabaseMigrationConflictError | DatabaseMigrationRun | Error]:
+ """ Apply migrations to a database
+
+ Starts a migration run: Volcano compares the files with the database's
+ history, rehearses the pending ones on a short-lived branch of the
+ database, takes a backup, and applies them in name order. Files the
+ history already records with the same checksum are skipped.
+
+ Asynchronous: the response is `202` with the run `queued`. Poll the run
+ until its `status` is `succeeded` or `failed`.
+
+ Send `Idempotency-Key` to make a retry safe: a repeat with a key this
+ database has seen returns that run with `200` and starts nothing. A
+ database runs one migration run at a time.
+
+ Where migration runs are not available, answers `404` with code
+ `feature_unavailable`.
+
+ Args:
+ id (UUID):
+ database_name (str):
+ idempotency_key (str | Unset):
+ body (DatabaseMigrationFilesRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[DatabaseMigrationConflictError | DatabaseMigrationRun | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+database_name=database_name,
+body=body,
+idempotency_key=idempotency_key,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ database_name: str,
+ *,
+ client: AuthenticatedClient,
+ body: DatabaseMigrationFilesRequest,
+ idempotency_key: str | Unset = UNSET,
+
+) -> DatabaseMigrationConflictError | DatabaseMigrationRun | Error | None:
+ """ Apply migrations to a database
+
+ Starts a migration run: Volcano compares the files with the database's
+ history, rehearses the pending ones on a short-lived branch of the
+ database, takes a backup, and applies them in name order. Files the
+ history already records with the same checksum are skipped.
+
+ Asynchronous: the response is `202` with the run `queued`. Poll the run
+ until its `status` is `succeeded` or `failed`.
+
+ Send `Idempotency-Key` to make a retry safe: a repeat with a key this
+ database has seen returns that run with `200` and starts nothing. A
+ database runs one migration run at a time.
+
+ Where migration runs are not available, answers `404` with code
+ `feature_unavailable`.
+
+ Args:
+ id (UUID):
+ database_name (str):
+ idempotency_key (str | Unset):
+ body (DatabaseMigrationFilesRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ DatabaseMigrationConflictError | DatabaseMigrationRun | Error
+ """
+
+
+ return sync_detailed(
+ id=id,
+database_name=database_name,
+client=client,
+body=body,
+idempotency_key=idempotency_key,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ database_name: str,
+ *,
+ client: AuthenticatedClient,
+ body: DatabaseMigrationFilesRequest,
+ idempotency_key: str | Unset = UNSET,
+
+) -> Response[DatabaseMigrationConflictError | DatabaseMigrationRun | Error]:
+ """ Apply migrations to a database
+
+ Starts a migration run: Volcano compares the files with the database's
+ history, rehearses the pending ones on a short-lived branch of the
+ database, takes a backup, and applies them in name order. Files the
+ history already records with the same checksum are skipped.
+
+ Asynchronous: the response is `202` with the run `queued`. Poll the run
+ until its `status` is `succeeded` or `failed`.
+
+ Send `Idempotency-Key` to make a retry safe: a repeat with a key this
+ database has seen returns that run with `200` and starts nothing. A
+ database runs one migration run at a time.
+
+ Where migration runs are not available, answers `404` with code
+ `feature_unavailable`.
+
+ Args:
+ id (UUID):
+ database_name (str):
+ idempotency_key (str | Unset):
+ body (DatabaseMigrationFilesRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[DatabaseMigrationConflictError | DatabaseMigrationRun | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+database_name=database_name,
+body=body,
+idempotency_key=idempotency_key,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ database_name: str,
+ *,
+ client: AuthenticatedClient,
+ body: DatabaseMigrationFilesRequest,
+ idempotency_key: str | Unset = UNSET,
+
+) -> DatabaseMigrationConflictError | DatabaseMigrationRun | Error | None:
+ """ Apply migrations to a database
+
+ Starts a migration run: Volcano compares the files with the database's
+ history, rehearses the pending ones on a short-lived branch of the
+ database, takes a backup, and applies them in name order. Files the
+ history already records with the same checksum are skipped.
+
+ Asynchronous: the response is `202` with the run `queued`. Poll the run
+ until its `status` is `succeeded` or `failed`.
+
+ Send `Idempotency-Key` to make a retry safe: a repeat with a key this
+ database has seen returns that run with `200` and starts nothing. A
+ database runs one migration run at a time.
+
+ Where migration runs are not available, answers `404` with code
+ `feature_unavailable`.
+
+ Args:
+ id (UUID):
+ database_name (str):
+ idempotency_key (str | Unset):
+ body (DatabaseMigrationFilesRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ DatabaseMigrationConflictError | DatabaseMigrationRun | Error
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+database_name=database_name,
+client=client,
+body=body,
+idempotency_key=idempotency_key,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/database_migrations/get_database_migration_run.py b/src/volcano_sdk/_generated/api/database_migrations/get_database_migration_run.py
new file mode 100644
index 00000000..0bd1aaeb
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/database_migrations/get_database_migration_run.py
@@ -0,0 +1,226 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.database_migration_run import DatabaseMigrationRun
+from ...models.error import Error
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ database_name: str,
+ run_id: UUID | str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/projects/{id}/databases/{database_name}/migration-runs/{run_id}".format(id=quote(str(id), safe=""),database_name=quote(str(database_name), safe=""),run_id=quote(str(run_id), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> DatabaseMigrationRun | Error | None:
+ if response.status_code == 200:
+ response_200 = DatabaseMigrationRun.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[DatabaseMigrationRun | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ database_name: str,
+ run_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[DatabaseMigrationRun | Error]:
+ """ Get a migration run
+
+ Returns the run with each file's outcome. Poll this after starting a
+ run.
+
+ Available whether or not migration runs are.
+
+ Args:
+ id (UUID):
+ database_name (str):
+ run_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[DatabaseMigrationRun | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+database_name=database_name,
+run_id=run_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ database_name: str,
+ run_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> DatabaseMigrationRun | Error | None:
+ """ Get a migration run
+
+ Returns the run with each file's outcome. Poll this after starting a
+ run.
+
+ Available whether or not migration runs are.
+
+ Args:
+ id (UUID):
+ database_name (str):
+ run_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ DatabaseMigrationRun | Error
+ """
+
+
+ return sync_detailed(
+ id=id,
+database_name=database_name,
+run_id=run_id,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ database_name: str,
+ run_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[DatabaseMigrationRun | Error]:
+ """ Get a migration run
+
+ Returns the run with each file's outcome. Poll this after starting a
+ run.
+
+ Available whether or not migration runs are.
+
+ Args:
+ id (UUID):
+ database_name (str):
+ run_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[DatabaseMigrationRun | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+database_name=database_name,
+run_id=run_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ database_name: str,
+ run_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> DatabaseMigrationRun | Error | None:
+ """ Get a migration run
+
+ Returns the run with each file's outcome. Poll this after starting a
+ run.
+
+ Available whether or not migration runs are.
+
+ Args:
+ id (UUID):
+ database_name (str):
+ run_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ DatabaseMigrationRun | Error
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+database_name=database_name,
+run_id=run_id,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/database_migrations/get_database_migrations.py b/src/volcano_sdk/_generated/api/database_migrations/get_database_migrations.py
new file mode 100644
index 00000000..6dab949d
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/database_migrations/get_database_migrations.py
@@ -0,0 +1,291 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.database_migrations import DatabaseMigrations
+from ...models.error import Error
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ database_name: str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/projects/{id}/databases/{database_name}/migrations".format(id=quote(str(id), safe=""),database_name=quote(str(database_name), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> DatabaseMigrations | Error | None:
+ if response.status_code == 200:
+ response_200 = DatabaseMigrations.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 503:
+ response_503 = Error.from_dict(response.json())
+
+
+
+ return response_503
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[DatabaseMigrations | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ database_name: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[DatabaseMigrations | Error]:
+ """ Get a database's migration history
+
+ Returns the migrations the database has recorded, in name order, read
+ from the database's own `_volcano_migrations.history` table. The history
+ is empty until a migration run or a baseline first records a file.
+
+ `active_run_id` is the run that is queued or running, if any.
+
+ If the history table is gone from a database where migrations ran,
+ answers `409` with code `history_missing`, and every run fails with
+ that code, rather than running files again. Record a baseline of the
+ files that were already applied to rebuild it. Dropping the whole
+ `_volcano_migrations` schema is not supported: the database then reads
+ as new, and the next run applies every file again.
+
+ Volcano reads at most 1,000 history entries, as many files as one run
+ may carry. A history with more answers `409` with code
+ `history_too_large`. A baseline is refused with that code, and a run
+ fails with it. Deleting the entries of files no longer among your
+ migrations brings the history back under the bound.
+
+ Available whether or not migration runs are.
+
+ Args:
+ id (UUID):
+ database_name (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[DatabaseMigrations | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+database_name=database_name,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ database_name: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> DatabaseMigrations | Error | None:
+ """ Get a database's migration history
+
+ Returns the migrations the database has recorded, in name order, read
+ from the database's own `_volcano_migrations.history` table. The history
+ is empty until a migration run or a baseline first records a file.
+
+ `active_run_id` is the run that is queued or running, if any.
+
+ If the history table is gone from a database where migrations ran,
+ answers `409` with code `history_missing`, and every run fails with
+ that code, rather than running files again. Record a baseline of the
+ files that were already applied to rebuild it. Dropping the whole
+ `_volcano_migrations` schema is not supported: the database then reads
+ as new, and the next run applies every file again.
+
+ Volcano reads at most 1,000 history entries, as many files as one run
+ may carry. A history with more answers `409` with code
+ `history_too_large`. A baseline is refused with that code, and a run
+ fails with it. Deleting the entries of files no longer among your
+ migrations brings the history back under the bound.
+
+ Available whether or not migration runs are.
+
+ Args:
+ id (UUID):
+ database_name (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ DatabaseMigrations | Error
+ """
+
+
+ return sync_detailed(
+ id=id,
+database_name=database_name,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ database_name: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[DatabaseMigrations | Error]:
+ """ Get a database's migration history
+
+ Returns the migrations the database has recorded, in name order, read
+ from the database's own `_volcano_migrations.history` table. The history
+ is empty until a migration run or a baseline first records a file.
+
+ `active_run_id` is the run that is queued or running, if any.
+
+ If the history table is gone from a database where migrations ran,
+ answers `409` with code `history_missing`, and every run fails with
+ that code, rather than running files again. Record a baseline of the
+ files that were already applied to rebuild it. Dropping the whole
+ `_volcano_migrations` schema is not supported: the database then reads
+ as new, and the next run applies every file again.
+
+ Volcano reads at most 1,000 history entries, as many files as one run
+ may carry. A history with more answers `409` with code
+ `history_too_large`. A baseline is refused with that code, and a run
+ fails with it. Deleting the entries of files no longer among your
+ migrations brings the history back under the bound.
+
+ Available whether or not migration runs are.
+
+ Args:
+ id (UUID):
+ database_name (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[DatabaseMigrations | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+database_name=database_name,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ database_name: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> DatabaseMigrations | Error | None:
+ """ Get a database's migration history
+
+ Returns the migrations the database has recorded, in name order, read
+ from the database's own `_volcano_migrations.history` table. The history
+ is empty until a migration run or a baseline first records a file.
+
+ `active_run_id` is the run that is queued or running, if any.
+
+ If the history table is gone from a database where migrations ran,
+ answers `409` with code `history_missing`, and every run fails with
+ that code, rather than running files again. Record a baseline of the
+ files that were already applied to rebuild it. Dropping the whole
+ `_volcano_migrations` schema is not supported: the database then reads
+ as new, and the next run applies every file again.
+
+ Volcano reads at most 1,000 history entries, as many files as one run
+ may carry. A history with more answers `409` with code
+ `history_too_large`. A baseline is refused with that code, and a run
+ fails with it. Deleting the entries of files no longer among your
+ migrations brings the history back under the bound.
+
+ Available whether or not migration runs are.
+
+ Args:
+ id (UUID):
+ database_name (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ DatabaseMigrations | Error
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+database_name=database_name,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/database_migrations/list_database_migration_runs.py b/src/volcano_sdk/_generated/api/database_migrations/list_database_migration_runs.py
new file mode 100644
index 00000000..dde5e0ca
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/database_migrations/list_database_migration_runs.py
@@ -0,0 +1,213 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.database_migration_run_list import DatabaseMigrationRunList
+from ...models.error import Error
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ database_name: str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/projects/{id}/databases/{database_name}/migration-runs".format(id=quote(str(id), safe=""),database_name=quote(str(database_name), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> DatabaseMigrationRunList | Error | None:
+ if response.status_code == 200:
+ response_200 = DatabaseMigrationRunList.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[DatabaseMigrationRunList | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ database_name: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[DatabaseMigrationRunList | Error]:
+ """ List a database's migration runs
+
+ Returns the database's 50 most recent migration runs, newest first,
+ without their files; get a run for its files. There is no pagination.
+
+ Available whether or not migration runs are.
+
+ Args:
+ id (UUID):
+ database_name (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[DatabaseMigrationRunList | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+database_name=database_name,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ database_name: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> DatabaseMigrationRunList | Error | None:
+ """ List a database's migration runs
+
+ Returns the database's 50 most recent migration runs, newest first,
+ without their files; get a run for its files. There is no pagination.
+
+ Available whether or not migration runs are.
+
+ Args:
+ id (UUID):
+ database_name (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ DatabaseMigrationRunList | Error
+ """
+
+
+ return sync_detailed(
+ id=id,
+database_name=database_name,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ database_name: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[DatabaseMigrationRunList | Error]:
+ """ List a database's migration runs
+
+ Returns the database's 50 most recent migration runs, newest first,
+ without their files; get a run for its files. There is no pagination.
+
+ Available whether or not migration runs are.
+
+ Args:
+ id (UUID):
+ database_name (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[DatabaseMigrationRunList | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+database_name=database_name,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ database_name: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> DatabaseMigrationRunList | Error | None:
+ """ List a database's migration runs
+
+ Returns the database's 50 most recent migration runs, newest first,
+ without their files; get a run for its files. There is no pagination.
+
+ Available whether or not migration runs are.
+
+ Args:
+ id (UUID):
+ database_name (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ DatabaseMigrationRunList | Error
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+database_name=database_name,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/database_queries/query_database_branch_select.py b/src/volcano_sdk/_generated/api/database_queries/query_database_branch_select.py
index cfccc2a6..1309c5bf 100644
--- a/src/volcano_sdk/_generated/api/database_queries/query_database_branch_select.py
+++ b/src/volcano_sdk/_generated/api/database_queries/query_database_branch_select.py
@@ -122,7 +122,8 @@ def sync_detailed(
**Authentication:** Requires auth user access token (from signup/signin)
- **Row-Level Security:** Automatically enforced - you see only data you have access to
+ **Row-Level Security:** Applied on tables with RLS enabled. A table without RLS returns every row
+ your role is granted
**Use Cases:**
- Query from browser/mobile apps
@@ -176,7 +177,8 @@ def sync(
**Authentication:** Requires auth user access token (from signup/signin)
- **Row-Level Security:** Automatically enforced - you see only data you have access to
+ **Row-Level Security:** Applied on tables with RLS enabled. A table without RLS returns every row
+ your role is granted
**Use Cases:**
- Query from browser/mobile apps
@@ -225,7 +227,8 @@ async def asyncio_detailed(
**Authentication:** Requires auth user access token (from signup/signin)
- **Row-Level Security:** Automatically enforced - you see only data you have access to
+ **Row-Level Security:** Applied on tables with RLS enabled. A table without RLS returns every row
+ your role is granted
**Use Cases:**
- Query from browser/mobile apps
@@ -279,7 +282,8 @@ async def asyncio(
**Authentication:** Requires auth user access token (from signup/signin)
- **Row-Level Security:** Automatically enforced - you see only data you have access to
+ **Row-Level Security:** Applied on tables with RLS enabled. A table without RLS returns every row
+ your role is granted
**Use Cases:**
- Query from browser/mobile apps
diff --git a/src/volcano_sdk/_generated/api/database_queries/query_database_select.py b/src/volcano_sdk/_generated/api/database_queries/query_database_select.py
index 0c3f9ec9..671d7fbd 100644
--- a/src/volcano_sdk/_generated/api/database_queries/query_database_select.py
+++ b/src/volcano_sdk/_generated/api/database_queries/query_database_select.py
@@ -113,7 +113,8 @@ def sync_detailed(
**Authentication:** Requires auth user access token (from signup/signin)
- **Row-Level Security:** Automatically enforced - you see only data you have access to
+ **Row-Level Security:** Applied on tables with RLS enabled. A table without RLS returns every row
+ your role is granted
**Use Cases:**
- Query from browser/mobile apps
@@ -160,7 +161,8 @@ def sync(
**Authentication:** Requires auth user access token (from signup/signin)
- **Row-Level Security:** Automatically enforced - you see only data you have access to
+ **Row-Level Security:** Applied on tables with RLS enabled. A table without RLS returns every row
+ your role is granted
**Use Cases:**
- Query from browser/mobile apps
@@ -202,7 +204,8 @@ async def asyncio_detailed(
**Authentication:** Requires auth user access token (from signup/signin)
- **Row-Level Security:** Automatically enforced - you see only data you have access to
+ **Row-Level Security:** Applied on tables with RLS enabled. A table without RLS returns every row
+ your role is granted
**Use Cases:**
- Query from browser/mobile apps
@@ -249,7 +252,8 @@ async def asyncio(
**Authentication:** Requires auth user access token (from signup/signin)
- **Row-Level Security:** Automatically enforced - you see only data you have access to
+ **Row-Level Security:** Applied on tables with RLS enabled. A table without RLS returns every row
+ your role is granted
**Use Cases:**
- Query from browser/mobile apps
diff --git a/src/volcano_sdk/_generated/api/databases/update_database_type.py b/src/volcano_sdk/_generated/api/databases/update_database_type.py
index cc5d5ba7..a6054f9e 100644
--- a/src/volcano_sdk/_generated/api/databases/update_database_type.py
+++ b/src/volcano_sdk/_generated/api/databases/update_database_type.py
@@ -44,7 +44,7 @@ def request_kwargs(
-def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | Database | Error | None:
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Database | Error | None:
if response.status_code == 200:
response_200 = Database.from_dict(response.json())
@@ -53,11 +53,31 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return response_200
if response.status_code == 400:
- response_400 = cast(Any, None)
+ response_400 = Error.from_dict(response.json())
+
+
+
return response_400
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
if response.status_code == 404:
- response_404 = cast(Any, None)
+ response_404 = Error.from_dict(response.json())
+
+
+
return response_404
if response.status_code == 409:
@@ -67,6 +87,13 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return response_409
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
if response.status_code == 503:
response_503 = Error.from_dict(response.json())
@@ -80,7 +107,7 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return None
-def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | Database | Error]:
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Database | Error]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
@@ -96,7 +123,7 @@ def sync_detailed(
client: AuthenticatedClient,
body: UpdateDatabaseTypeRequest,
-) -> Response[Any | Database | Error]:
+) -> Response[Database | Error]:
""" Update database size
Change the size tier of a database. This may briefly interrupt active connections.
@@ -119,7 +146,7 @@ def sync_detailed(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[Any | Database | Error]
+ Response[Database | Error]
"""
@@ -143,7 +170,7 @@ def sync(
client: AuthenticatedClient,
body: UpdateDatabaseTypeRequest,
-) -> Any | Database | Error | None:
+) -> Database | Error | None:
""" Update database size
Change the size tier of a database. This may briefly interrupt active connections.
@@ -166,7 +193,7 @@ def sync(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Any | Database | Error
+ Database | Error
"""
@@ -185,7 +212,7 @@ async def asyncio_detailed(
client: AuthenticatedClient,
body: UpdateDatabaseTypeRequest,
-) -> Response[Any | Database | Error]:
+) -> Response[Database | Error]:
""" Update database size
Change the size tier of a database. This may briefly interrupt active connections.
@@ -208,7 +235,7 @@ async def asyncio_detailed(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[Any | Database | Error]
+ Response[Database | Error]
"""
@@ -232,7 +259,7 @@ async def asyncio(
client: AuthenticatedClient,
body: UpdateDatabaseTypeRequest,
-) -> Any | Database | Error | None:
+) -> Database | Error | None:
""" Update database size
Change the size tier of a database. This may briefly interrupt active connections.
@@ -255,7 +282,7 @@ async def asyncio(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Any | Database | Error
+ Database | Error
"""
diff --git a/src/volcano_sdk/_generated/api/durable_functions/get_durable_execution_from_application.py b/src/volcano_sdk/_generated/api/durable_functions/get_durable_execution_from_application.py
new file mode 100644
index 00000000..f4f26717
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/durable_functions/get_durable_execution_from_application.py
@@ -0,0 +1,333 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.durable_execution import DurableExecution
+from ...models.error import Error
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ function_id: str,
+ execution_id: UUID | str,
+ *,
+ x_volcano_client_token: str | Unset = UNSET,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+ if not isinstance(x_volcano_client_token, Unset):
+ headers["X-Volcano-Client-Token"] = x_volcano_client_token
+
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/durable-functions/{function_id}/executions/{execution_id}".format(function_id=quote(str(function_id), safe=""),execution_id=quote(str(execution_id), safe=""),),
+ }
+
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> DurableExecution | Error | None:
+ if response.status_code == 200:
+ response_200 = DurableExecution.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 429:
+ response_429 = Error.from_dict(response.json())
+
+
+
+ return response_429
+
+ if response.status_code == 503:
+ response_503 = Error.from_dict(response.json())
+
+
+
+ return response_503
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[DurableExecution | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ function_id: str,
+ execution_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ x_volcano_client_token: str | Unset = UNSET,
+
+) -> Response[DurableExecution | Error]:
+ """ Get a durable execution from an application
+
+ Returns the execution's current state with the credential that started
+ it, including its `result` once it has succeeded. Poll this to wait for
+ an execution to finish.
+
+ **With a service key:** any execution in the project when the key holds
+ `*`, the default. A key scoped to a list without `*` reaches an
+ execution whose `X-Volcano-Client-Token` the request carries, as an
+ anon key does; the start returns that token.
+
+ **With an auth user token:** an execution the user started, or one
+ whose `X-Volcano-Client-Token` the request carries, of a durable
+ function whose `visibility` is `authenticated` or `public`.
+
+ **With an anon key:** an execution whose `X-Volcano-Client-Token` the
+ request carries, of a function with `visibility: public`.
+
+ Only a service key holding `*` reaches an execution that is still
+ `pending`. Any other execution answers `404`, as a missing one does.
+
+ The response is the one `GET
+ /projects/{id}/durable-functions/{functionId}/executions/{executionId}`
+ returns. It never carries `client_token`.
+
+ Args:
+ function_id (str):
+ execution_id (UUID):
+ x_volcano_client_token (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[DurableExecution | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ function_id=function_id,
+execution_id=execution_id,
+x_volcano_client_token=x_volcano_client_token,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ function_id: str,
+ execution_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ x_volcano_client_token: str | Unset = UNSET,
+
+) -> DurableExecution | Error | None:
+ """ Get a durable execution from an application
+
+ Returns the execution's current state with the credential that started
+ it, including its `result` once it has succeeded. Poll this to wait for
+ an execution to finish.
+
+ **With a service key:** any execution in the project when the key holds
+ `*`, the default. A key scoped to a list without `*` reaches an
+ execution whose `X-Volcano-Client-Token` the request carries, as an
+ anon key does; the start returns that token.
+
+ **With an auth user token:** an execution the user started, or one
+ whose `X-Volcano-Client-Token` the request carries, of a durable
+ function whose `visibility` is `authenticated` or `public`.
+
+ **With an anon key:** an execution whose `X-Volcano-Client-Token` the
+ request carries, of a function with `visibility: public`.
+
+ Only a service key holding `*` reaches an execution that is still
+ `pending`. Any other execution answers `404`, as a missing one does.
+
+ The response is the one `GET
+ /projects/{id}/durable-functions/{functionId}/executions/{executionId}`
+ returns. It never carries `client_token`.
+
+ Args:
+ function_id (str):
+ execution_id (UUID):
+ x_volcano_client_token (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ DurableExecution | Error
+ """
+
+
+ return sync_detailed(
+ function_id=function_id,
+execution_id=execution_id,
+client=client,
+x_volcano_client_token=x_volcano_client_token,
+
+ ).parsed
+
+async def asyncio_detailed(
+ function_id: str,
+ execution_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ x_volcano_client_token: str | Unset = UNSET,
+
+) -> Response[DurableExecution | Error]:
+ """ Get a durable execution from an application
+
+ Returns the execution's current state with the credential that started
+ it, including its `result` once it has succeeded. Poll this to wait for
+ an execution to finish.
+
+ **With a service key:** any execution in the project when the key holds
+ `*`, the default. A key scoped to a list without `*` reaches an
+ execution whose `X-Volcano-Client-Token` the request carries, as an
+ anon key does; the start returns that token.
+
+ **With an auth user token:** an execution the user started, or one
+ whose `X-Volcano-Client-Token` the request carries, of a durable
+ function whose `visibility` is `authenticated` or `public`.
+
+ **With an anon key:** an execution whose `X-Volcano-Client-Token` the
+ request carries, of a function with `visibility: public`.
+
+ Only a service key holding `*` reaches an execution that is still
+ `pending`. Any other execution answers `404`, as a missing one does.
+
+ The response is the one `GET
+ /projects/{id}/durable-functions/{functionId}/executions/{executionId}`
+ returns. It never carries `client_token`.
+
+ Args:
+ function_id (str):
+ execution_id (UUID):
+ x_volcano_client_token (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[DurableExecution | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ function_id=function_id,
+execution_id=execution_id,
+x_volcano_client_token=x_volcano_client_token,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ function_id: str,
+ execution_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ x_volcano_client_token: str | Unset = UNSET,
+
+) -> DurableExecution | Error | None:
+ """ Get a durable execution from an application
+
+ Returns the execution's current state with the credential that started
+ it, including its `result` once it has succeeded. Poll this to wait for
+ an execution to finish.
+
+ **With a service key:** any execution in the project when the key holds
+ `*`, the default. A key scoped to a list without `*` reaches an
+ execution whose `X-Volcano-Client-Token` the request carries, as an
+ anon key does; the start returns that token.
+
+ **With an auth user token:** an execution the user started, or one
+ whose `X-Volcano-Client-Token` the request carries, of a durable
+ function whose `visibility` is `authenticated` or `public`.
+
+ **With an anon key:** an execution whose `X-Volcano-Client-Token` the
+ request carries, of a function with `visibility: public`.
+
+ Only a service key holding `*` reaches an execution that is still
+ `pending`. Any other execution answers `404`, as a missing one does.
+
+ The response is the one `GET
+ /projects/{id}/durable-functions/{functionId}/executions/{executionId}`
+ returns. It never carries `client_token`.
+
+ Args:
+ function_id (str):
+ execution_id (UUID):
+ x_volcano_client_token (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ DurableExecution | Error
+ """
+
+
+ return (await asyncio_detailed(
+ function_id=function_id,
+execution_id=execution_id,
+client=client,
+x_volcano_client_token=x_volcano_client_token,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/durable_functions/register_durable_callback.py b/src/volcano_sdk/_generated/api/durable_functions/register_durable_callback.py
index bc734510..c855309f 100644
--- a/src/volcano_sdk/_generated/api/durable_functions/register_durable_callback.py
+++ b/src/volcano_sdk/_generated/api/durable_functions/register_durable_callback.py
@@ -131,7 +131,9 @@ def sync_detailed(
the step's own timeout, and only for that step.
Retrying is safe: a request for a step that is already registered
- returns the same token with `200`.
+ returns the same token with `200` while the step still waits. Once
+ the token is answered, or the step times out or ends, a retry answers
+ `409` with `callback_closed`.
Args:
body (RegisterDurableCallbackRequest):
@@ -174,7 +176,9 @@ def sync(
the step's own timeout, and only for that step.
Retrying is safe: a request for a step that is already registered
- returns the same token with `200`.
+ returns the same token with `200` while the step still waits. Once
+ the token is answered, or the step times out or ends, a retry answers
+ `409` with `callback_closed`.
Args:
body (RegisterDurableCallbackRequest):
@@ -212,7 +216,9 @@ async def asyncio_detailed(
the step's own timeout, and only for that step.
Retrying is safe: a request for a step that is already registered
- returns the same token with `200`.
+ returns the same token with `200` while the step still waits. Once
+ the token is answered, or the step times out or ends, a retry answers
+ `409` with `callback_closed`.
Args:
body (RegisterDurableCallbackRequest):
@@ -255,7 +261,9 @@ async def asyncio(
the step's own timeout, and only for that step.
Retrying is safe: a request for a step that is already registered
- returns the same token with `200`.
+ returns the same token with `200` while the step still waits. Once
+ the token is answered, or the step times out or ends, a retry answers
+ `409` with `callback_closed`.
Args:
body (RegisterDurableCallbackRequest):
diff --git a/src/volcano_sdk/_generated/api/durable_functions/send_durable_message_from_application.py b/src/volcano_sdk/_generated/api/durable_functions/send_durable_message_from_application.py
index bed60a85..c8e2132e 100644
--- a/src/volcano_sdk/_generated/api/durable_functions/send_durable_message_from_application.py
+++ b/src/volcano_sdk/_generated/api/durable_functions/send_durable_message_from_application.py
@@ -159,7 +159,11 @@ def sync_detailed(
Messages never decide an approval: a workflow waiting in
`ctx.waitForApproval` is not resumed by one.
- **With a service key:** any execution in the project.
+ **With a service key:** any execution in the project when the key holds
+ `*`, the default. A key scoped to a list without `*`, such as
+ `["functions.invoke"]`, reaches an execution whose
+ `X-Volcano-Client-Token` the request carries, as an anon key does; the
+ start returns that token.
**With an auth user token:** an execution the user started, or one
whose `X-Volcano-Client-Token` the request carries, of a durable
@@ -225,7 +229,11 @@ def sync(
Messages never decide an approval: a workflow waiting in
`ctx.waitForApproval` is not resumed by one.
- **With a service key:** any execution in the project.
+ **With a service key:** any execution in the project when the key holds
+ `*`, the default. A key scoped to a list without `*`, such as
+ `["functions.invoke"]`, reaches an execution whose
+ `X-Volcano-Client-Token` the request carries, as an anon key does; the
+ start returns that token.
**With an auth user token:** an execution the user started, or one
whose `X-Volcano-Client-Token` the request carries, of a durable
@@ -286,7 +294,11 @@ async def asyncio_detailed(
Messages never decide an approval: a workflow waiting in
`ctx.waitForApproval` is not resumed by one.
- **With a service key:** any execution in the project.
+ **With a service key:** any execution in the project when the key holds
+ `*`, the default. A key scoped to a list without `*`, such as
+ `["functions.invoke"]`, reaches an execution whose
+ `X-Volcano-Client-Token` the request carries, as an anon key does; the
+ start returns that token.
**With an auth user token:** an execution the user started, or one
whose `X-Volcano-Client-Token` the request carries, of a durable
@@ -352,7 +364,11 @@ async def asyncio(
Messages never decide an approval: a workflow waiting in
`ctx.waitForApproval` is not resumed by one.
- **With a service key:** any execution in the project.
+ **With a service key:** any execution in the project when the key holds
+ `*`, the default. A key scoped to a list without `*`, such as
+ `["functions.invoke"]`, reaches an execution whose
+ `X-Volcano-Client-Token` the request carries, as an anon key does; the
+ start returns that token.
**With an auth user token:** an execution the user started, or one
whose `X-Volcano-Client-Token` the request carries, of a durable
diff --git a/src/volcano_sdk/_generated/api/durable_functions/start_durable_execution_from_application.py b/src/volcano_sdk/_generated/api/durable_functions/start_durable_execution_from_application.py
index 282b2377..5a8839b1 100644
--- a/src/volcano_sdk/_generated/api/durable_functions/start_durable_execution_from_application.py
+++ b/src/volcano_sdk/_generated/api/durable_functions/start_durable_execution_from_application.py
@@ -157,10 +157,13 @@ def sync_detailed(
A `private` durable function answers every credential but a service key
exactly as a missing one, with 404.
- Starting is all this endpoint does. Reading a result or stopping an
- execution requires the project owner's token, because an anon key is
- shared by everyone who loads the page and an execution is addressed by
- id alone.
+ The start returns a `client_token`. An anon key, a service key scoped
+ to a list without `*`, or a user who did not start the execution,
+ sends it as `X-Volcano-Client-Token` to read the execution, stop it,
+ and reach its messages. An anon key is shared by everyone who loads
+ the page, so the id alone never reaches an
+ execution. Listing executions takes the project owner's token or a
+ project access token.
Send `X-Volcano-Execution-Name` to make the start idempotent: repeating
a start with the same name returns the existing execution instead of
@@ -230,10 +233,13 @@ def sync(
A `private` durable function answers every credential but a service key
exactly as a missing one, with 404.
- Starting is all this endpoint does. Reading a result or stopping an
- execution requires the project owner's token, because an anon key is
- shared by everyone who loads the page and an execution is addressed by
- id alone.
+ The start returns a `client_token`. An anon key, a service key scoped
+ to a list without `*`, or a user who did not start the execution,
+ sends it as `X-Volcano-Client-Token` to read the execution, stop it,
+ and reach its messages. An anon key is shared by everyone who loads
+ the page, so the id alone never reaches an
+ execution. Listing executions takes the project owner's token or a
+ project access token.
Send `X-Volcano-Execution-Name` to make the start idempotent: repeating
a start with the same name returns the existing execution instead of
@@ -298,10 +304,13 @@ async def asyncio_detailed(
A `private` durable function answers every credential but a service key
exactly as a missing one, with 404.
- Starting is all this endpoint does. Reading a result or stopping an
- execution requires the project owner's token, because an anon key is
- shared by everyone who loads the page and an execution is addressed by
- id alone.
+ The start returns a `client_token`. An anon key, a service key scoped
+ to a list without `*`, or a user who did not start the execution,
+ sends it as `X-Volcano-Client-Token` to read the execution, stop it,
+ and reach its messages. An anon key is shared by everyone who loads
+ the page, so the id alone never reaches an
+ execution. Listing executions takes the project owner's token or a
+ project access token.
Send `X-Volcano-Execution-Name` to make the start idempotent: repeating
a start with the same name returns the existing execution instead of
@@ -371,10 +380,13 @@ async def asyncio(
A `private` durable function answers every credential but a service key
exactly as a missing one, with 404.
- Starting is all this endpoint does. Reading a result or stopping an
- execution requires the project owner's token, because an anon key is
- shared by everyone who loads the page and an execution is addressed by
- id alone.
+ The start returns a `client_token`. An anon key, a service key scoped
+ to a list without `*`, or a user who did not start the execution,
+ sends it as `X-Volcano-Client-Token` to read the execution, stop it,
+ and reach its messages. An anon key is shared by everyone who loads
+ the page, so the id alone never reaches an
+ execution. Listing executions takes the project owner's token or a
+ project access token.
Send `X-Volcano-Execution-Name` to make the start idempotent: repeating
a start with the same name returns the existing execution instead of
diff --git a/src/volcano_sdk/_generated/api/durable_functions/stop_durable_execution_from_application.py b/src/volcano_sdk/_generated/api/durable_functions/stop_durable_execution_from_application.py
new file mode 100644
index 00000000..06387e68
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/durable_functions/stop_durable_execution_from_application.py
@@ -0,0 +1,300 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.durable_execution import DurableExecution
+from ...models.error import Error
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ function_id: str,
+ execution_id: UUID | str,
+ *,
+ x_volcano_client_token: str | Unset = UNSET,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+ if not isinstance(x_volcano_client_token, Unset):
+ headers["X-Volcano-Client-Token"] = x_volcano_client_token
+
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/durable-functions/{function_id}/executions/{execution_id}/stop".format(function_id=quote(str(function_id), safe=""),execution_id=quote(str(execution_id), safe=""),),
+ }
+
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> DurableExecution | Error | None:
+ if response.status_code == 200:
+ response_200 = DurableExecution.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 429:
+ response_429 = Error.from_dict(response.json())
+
+
+
+ return response_429
+
+ if response.status_code == 503:
+ response_503 = Error.from_dict(response.json())
+
+
+
+ return response_503
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[DurableExecution | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ function_id: str,
+ execution_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ x_volcano_client_token: str | Unset = UNSET,
+
+) -> Response[DurableExecution | Error]:
+ """ Stop a durable execution from an application
+
+ Cancels a running execution with the credential that started it. Its
+ completed steps are not undone.
+
+ Access follows the same rules as reading the execution.
+
+ The call is accepted rather than awaited: the response reports the
+ execution as it was read back and may still say `running`. Poll
+ `GET /durable-functions/{functionId}/executions/{executionId}` to see
+ it settle into `stopped`.
+
+ Stopping an execution that already finished is not an error: the
+ response carries the state it settled in.
+
+ Args:
+ function_id (str):
+ execution_id (UUID):
+ x_volcano_client_token (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[DurableExecution | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ function_id=function_id,
+execution_id=execution_id,
+x_volcano_client_token=x_volcano_client_token,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ function_id: str,
+ execution_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ x_volcano_client_token: str | Unset = UNSET,
+
+) -> DurableExecution | Error | None:
+ """ Stop a durable execution from an application
+
+ Cancels a running execution with the credential that started it. Its
+ completed steps are not undone.
+
+ Access follows the same rules as reading the execution.
+
+ The call is accepted rather than awaited: the response reports the
+ execution as it was read back and may still say `running`. Poll
+ `GET /durable-functions/{functionId}/executions/{executionId}` to see
+ it settle into `stopped`.
+
+ Stopping an execution that already finished is not an error: the
+ response carries the state it settled in.
+
+ Args:
+ function_id (str):
+ execution_id (UUID):
+ x_volcano_client_token (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ DurableExecution | Error
+ """
+
+
+ return sync_detailed(
+ function_id=function_id,
+execution_id=execution_id,
+client=client,
+x_volcano_client_token=x_volcano_client_token,
+
+ ).parsed
+
+async def asyncio_detailed(
+ function_id: str,
+ execution_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ x_volcano_client_token: str | Unset = UNSET,
+
+) -> Response[DurableExecution | Error]:
+ """ Stop a durable execution from an application
+
+ Cancels a running execution with the credential that started it. Its
+ completed steps are not undone.
+
+ Access follows the same rules as reading the execution.
+
+ The call is accepted rather than awaited: the response reports the
+ execution as it was read back and may still say `running`. Poll
+ `GET /durable-functions/{functionId}/executions/{executionId}` to see
+ it settle into `stopped`.
+
+ Stopping an execution that already finished is not an error: the
+ response carries the state it settled in.
+
+ Args:
+ function_id (str):
+ execution_id (UUID):
+ x_volcano_client_token (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[DurableExecution | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ function_id=function_id,
+execution_id=execution_id,
+x_volcano_client_token=x_volcano_client_token,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ function_id: str,
+ execution_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ x_volcano_client_token: str | Unset = UNSET,
+
+) -> DurableExecution | Error | None:
+ """ Stop a durable execution from an application
+
+ Cancels a running execution with the credential that started it. Its
+ completed steps are not undone.
+
+ Access follows the same rules as reading the execution.
+
+ The call is accepted rather than awaited: the response reports the
+ execution as it was read back and may still say `running`. Poll
+ `GET /durable-functions/{functionId}/executions/{executionId}` to see
+ it settle into `stopped`.
+
+ Stopping an execution that already finished is not an error: the
+ response carries the state it settled in.
+
+ Args:
+ function_id (str):
+ execution_id (UUID):
+ x_volcano_client_token (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ DurableExecution | Error
+ """
+
+
+ return (await asyncio_detailed(
+ function_id=function_id,
+execution_id=execution_id,
+client=client,
+x_volcano_client_token=x_volcano_client_token,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/forks/__init__.py b/src/volcano_sdk/_generated/api/forks/__init__.py
new file mode 100644
index 00000000..c9921b5f
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/forks/__init__.py
@@ -0,0 +1 @@
+""" Contains endpoint functions for accessing the API """
diff --git a/src/volcano_sdk/_generated/api/forks/create_fork.py b/src/volcano_sdk/_generated/api/forks/create_fork.py
new file mode 100644
index 00000000..725de661
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/forks/create_fork.py
@@ -0,0 +1,338 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.fork_create_request import ForkCreateRequest
+from ...models.project import Project
+from ...types import UNSET, Unset
+from typing import cast
+
+
+
+def request_kwargs(
+ *,
+ body: ForkCreateRequest,
+ idempotency_key: str | Unset = UNSET,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+ if not isinstance(idempotency_key, Unset):
+ headers["Idempotency-Key"] = idempotency_key
+
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/forks",
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | Project | None:
+ if response.status_code == 201:
+ response_201 = Project.from_dict(response.json())
+
+
+
+ return response_201
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 422:
+ response_422 = Error.from_dict(response.json())
+
+
+
+ return response_422
+
+ if response.status_code == 429:
+ response_429 = Error.from_dict(response.json())
+
+
+
+ return response_429
+
+ if response.status_code == 451:
+ response_451 = Error.from_dict(response.json())
+
+
+
+ return response_451
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if response.status_code == 503:
+ response_503 = Error.from_dict(response.json())
+
+
+
+ return response_503
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | Project]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: ForkCreateRequest,
+ idempotency_key: str | Unset = UNSET,
+
+) -> Response[Error | Project]:
+ """ Fork a share into a project of your own
+
+ Creates a project in the caller's account from the release a share offers,
+ and queues its install: the release's functions and frontends, never the
+ owner's data, variable values, keys or sign-in settings. Every variable the
+ release declares is created; one the visitor gives no value for is created
+ empty. Installation is asynchronous: poll the project until
+ `template_installation.status` is `ready`. A `201` without
+ `template_installation` means nothing is being installed.
+
+ The fork is checked against what the release recorded when it was published
+ (its functions, frontends and variables, and the plan's room for them); the
+ release's archive is read and checked by the install. A stored archive that
+ fails those checks fails the install with `failure_code` `source_invalid`
+ rather than refusing the request.
+
+ Send the `release_id` that `GET /share-previews/{share_id}` returned. If the
+ share moved to a new release since, nothing is created and the answer is
+ `409` with code `release_changed`.
+
+ Args:
+ idempotency_key (str | Unset):
+ body (ForkCreateRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | Project]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+idempotency_key=idempotency_key,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ body: ForkCreateRequest,
+ idempotency_key: str | Unset = UNSET,
+
+) -> Error | Project | None:
+ """ Fork a share into a project of your own
+
+ Creates a project in the caller's account from the release a share offers,
+ and queues its install: the release's functions and frontends, never the
+ owner's data, variable values, keys or sign-in settings. Every variable the
+ release declares is created; one the visitor gives no value for is created
+ empty. Installation is asynchronous: poll the project until
+ `template_installation.status` is `ready`. A `201` without
+ `template_installation` means nothing is being installed.
+
+ The fork is checked against what the release recorded when it was published
+ (its functions, frontends and variables, and the plan's room for them); the
+ release's archive is read and checked by the install. A stored archive that
+ fails those checks fails the install with `failure_code` `source_invalid`
+ rather than refusing the request.
+
+ Send the `release_id` that `GET /share-previews/{share_id}` returned. If the
+ share moved to a new release since, nothing is created and the answer is
+ `409` with code `release_changed`.
+
+ Args:
+ idempotency_key (str | Unset):
+ body (ForkCreateRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | Project
+ """
+
+
+ return sync_detailed(
+ client=client,
+body=body,
+idempotency_key=idempotency_key,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: ForkCreateRequest,
+ idempotency_key: str | Unset = UNSET,
+
+) -> Response[Error | Project]:
+ """ Fork a share into a project of your own
+
+ Creates a project in the caller's account from the release a share offers,
+ and queues its install: the release's functions and frontends, never the
+ owner's data, variable values, keys or sign-in settings. Every variable the
+ release declares is created; one the visitor gives no value for is created
+ empty. Installation is asynchronous: poll the project until
+ `template_installation.status` is `ready`. A `201` without
+ `template_installation` means nothing is being installed.
+
+ The fork is checked against what the release recorded when it was published
+ (its functions, frontends and variables, and the plan's room for them); the
+ release's archive is read and checked by the install. A stored archive that
+ fails those checks fails the install with `failure_code` `source_invalid`
+ rather than refusing the request.
+
+ Send the `release_id` that `GET /share-previews/{share_id}` returned. If the
+ share moved to a new release since, nothing is created and the answer is
+ `409` with code `release_changed`.
+
+ Args:
+ idempotency_key (str | Unset):
+ body (ForkCreateRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | Project]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+idempotency_key=idempotency_key,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ body: ForkCreateRequest,
+ idempotency_key: str | Unset = UNSET,
+
+) -> Error | Project | None:
+ """ Fork a share into a project of your own
+
+ Creates a project in the caller's account from the release a share offers,
+ and queues its install: the release's functions and frontends, never the
+ owner's data, variable values, keys or sign-in settings. Every variable the
+ release declares is created; one the visitor gives no value for is created
+ empty. Installation is asynchronous: poll the project until
+ `template_installation.status` is `ready`. A `201` without
+ `template_installation` means nothing is being installed.
+
+ The fork is checked against what the release recorded when it was published
+ (its functions, frontends and variables, and the plan's room for them); the
+ release's archive is read and checked by the install. A stored archive that
+ fails those checks fails the install with `failure_code` `source_invalid`
+ rather than refusing the request.
+
+ Send the `release_id` that `GET /share-previews/{share_id}` returned. If the
+ share moved to a new release since, nothing is created and the answer is
+ `409` with code `release_changed`.
+
+ Args:
+ idempotency_key (str | Unset):
+ body (ForkCreateRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | Project
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+body=body,
+idempotency_key=idempotency_key,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/frontends/create_frontend.py b/src/volcano_sdk/_generated/api/frontends/create_frontend.py
index 1509d39f..5ab0f70d 100644
--- a/src/volcano_sdk/_generated/api/frontends/create_frontend.py
+++ b/src/volcano_sdk/_generated/api/frontends/create_frontend.py
@@ -152,13 +152,13 @@ def sync_detailed(
22.x or 24.x. The Node.js runtime is inferred from
`package.json` `engines.node`; if omitted, Volcano uses Node.js 22.x.
The selected Node.js family must also satisfy the installed Next.js package's
- `engines.node` constraint. Volcano tests Next 15.5.28 (`^18.18.0 || ^19.8.0 || >=20.0.0`) and Next
- 16.4.2 (`>=20.9.0`).
+ `engines.node` constraint. Volcano tests Next 15.5.29 (`^18.18.0 || ^19.8.0 || >=20.0.0`) and Next
+ 16.4.5 (`>=20.9.0`).
Source archive size is enforced by the API with `SOURCE_ARCHIVE_SIZE_LIMIT_MB`; the CLI
does not apply its own source archive size limit. After the final container images are
built, the publish build enforces `LAMBDA_TARGET_CONTAINER_SIZE_LIMIT_MB` before pushing.
- This operation is limited by plan-based frontend deployment quotas (`FREE_FRONTEND_DEPLOYMENTS`,
- `PRO_FRONTEND_DEPLOYMENTS`).
+ Plans do not limit how many frontends a project has; usage allowances apply across all of a user's
+ frontends.
Each project can contain up to 10,000 frontends regardless of plan.
Args:
@@ -216,13 +216,13 @@ def sync(
22.x or 24.x. The Node.js runtime is inferred from
`package.json` `engines.node`; if omitted, Volcano uses Node.js 22.x.
The selected Node.js family must also satisfy the installed Next.js package's
- `engines.node` constraint. Volcano tests Next 15.5.28 (`^18.18.0 || ^19.8.0 || >=20.0.0`) and Next
- 16.4.2 (`>=20.9.0`).
+ `engines.node` constraint. Volcano tests Next 15.5.29 (`^18.18.0 || ^19.8.0 || >=20.0.0`) and Next
+ 16.4.5 (`>=20.9.0`).
Source archive size is enforced by the API with `SOURCE_ARCHIVE_SIZE_LIMIT_MB`; the CLI
does not apply its own source archive size limit. After the final container images are
built, the publish build enforces `LAMBDA_TARGET_CONTAINER_SIZE_LIMIT_MB` before pushing.
- This operation is limited by plan-based frontend deployment quotas (`FREE_FRONTEND_DEPLOYMENTS`,
- `PRO_FRONTEND_DEPLOYMENTS`).
+ Plans do not limit how many frontends a project has; usage allowances apply across all of a user's
+ frontends.
Each project can contain up to 10,000 frontends regardless of plan.
Args:
@@ -275,13 +275,13 @@ async def asyncio_detailed(
22.x or 24.x. The Node.js runtime is inferred from
`package.json` `engines.node`; if omitted, Volcano uses Node.js 22.x.
The selected Node.js family must also satisfy the installed Next.js package's
- `engines.node` constraint. Volcano tests Next 15.5.28 (`^18.18.0 || ^19.8.0 || >=20.0.0`) and Next
- 16.4.2 (`>=20.9.0`).
+ `engines.node` constraint. Volcano tests Next 15.5.29 (`^18.18.0 || ^19.8.0 || >=20.0.0`) and Next
+ 16.4.5 (`>=20.9.0`).
Source archive size is enforced by the API with `SOURCE_ARCHIVE_SIZE_LIMIT_MB`; the CLI
does not apply its own source archive size limit. After the final container images are
built, the publish build enforces `LAMBDA_TARGET_CONTAINER_SIZE_LIMIT_MB` before pushing.
- This operation is limited by plan-based frontend deployment quotas (`FREE_FRONTEND_DEPLOYMENTS`,
- `PRO_FRONTEND_DEPLOYMENTS`).
+ Plans do not limit how many frontends a project has; usage allowances apply across all of a user's
+ frontends.
Each project can contain up to 10,000 frontends regardless of plan.
Args:
@@ -339,13 +339,13 @@ async def asyncio(
22.x or 24.x. The Node.js runtime is inferred from
`package.json` `engines.node`; if omitted, Volcano uses Node.js 22.x.
The selected Node.js family must also satisfy the installed Next.js package's
- `engines.node` constraint. Volcano tests Next 15.5.28 (`^18.18.0 || ^19.8.0 || >=20.0.0`) and Next
- 16.4.2 (`>=20.9.0`).
+ `engines.node` constraint. Volcano tests Next 15.5.29 (`^18.18.0 || ^19.8.0 || >=20.0.0`) and Next
+ 16.4.5 (`>=20.9.0`).
Source archive size is enforced by the API with `SOURCE_ARCHIVE_SIZE_LIMIT_MB`; the CLI
does not apply its own source archive size limit. After the final container images are
built, the publish build enforces `LAMBDA_TARGET_CONTAINER_SIZE_LIMIT_MB` before pushing.
- This operation is limited by plan-based frontend deployment quotas (`FREE_FRONTEND_DEPLOYMENTS`,
- `PRO_FRONTEND_DEPLOYMENTS`).
+ Plans do not limit how many frontends a project has; usage allowances apply across all of a user's
+ frontends.
Each project can contain up to 10,000 frontends regardless of plan.
Args:
diff --git a/src/volcano_sdk/_generated/api/frontends/create_frontend_candidate.py b/src/volcano_sdk/_generated/api/frontends/create_frontend_candidate.py
new file mode 100644
index 00000000..81ec65d8
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/frontends/create_frontend_candidate.py
@@ -0,0 +1,337 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.create_frontend_candidate_body import CreateFrontendCandidateBody
+from ...models.error import Error
+from ...models.frontend_candidate import FrontendCandidate
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ body: CreateFrontendCandidateBody,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/projects/{id}/frontends/{frontend_id}/candidates".format(id=quote(str(id), safe=""),frontend_id=quote(str(frontend_id), safe=""),),
+ }
+
+ _kwargs["files"] = body.to_multipart()
+
+ headers["Content-Type"] = "multipart/form-data; boundary=+++"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | FrontendCandidate | None:
+ if response.status_code == 202:
+ response_202 = FrontendCandidate.from_dict(response.json())
+
+
+
+ return response_202
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 413:
+ response_413 = Error.from_dict(response.json())
+
+
+
+ return response_413
+
+ if response.status_code == 429:
+ response_429 = Error.from_dict(response.json())
+
+
+
+ return response_429
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if response.status_code == 503:
+ response_503 = Error.from_dict(response.json())
+
+
+
+ return response_503
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | FrontendCandidate]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendCandidateBody,
+
+) -> Response[Error | FrontendCandidate]:
+ """ Create a frontend Candidate
+
+ Builds a copy of the frontend from the uploaded archive, with the frontend's own variable
+ selection, and deploys it to one region: the first region the frontend deploys to, or the
+ project's first region by name if it has not deployed yet. The Candidate is served at its own
+ URL, so it can be checked without changing what the frontend serves. The URL is reachable by
+ anyone who holds it and is not indexed; a Candidate is never public and does not claim to be
+ private. The response is `202` while the first deployment runs; read the Candidate for its
+ `status` and `url`.
+
+ Creating a Candidate is available while the `frontends.candidates` capability is. While it is
+ not, this operation, redeploying, promoting and rolling back to a Candidate answer `404` with
+ code `feature_unavailable`; reading and deleting existing Candidates, and rolling back to the
+ frontend's own runtime, keep working.
+
+ A Candidate builds like any deploy and spends the project's build minutes. A frontend has at
+ most 20 live Candidates, and each name is unique within the frontend. Without `ttl_seconds` a
+ Candidate is kept until it is deleted.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (CreateFrontendCandidateBody):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendCandidate]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendCandidateBody,
+
+) -> Error | FrontendCandidate | None:
+ """ Create a frontend Candidate
+
+ Builds a copy of the frontend from the uploaded archive, with the frontend's own variable
+ selection, and deploys it to one region: the first region the frontend deploys to, or the
+ project's first region by name if it has not deployed yet. The Candidate is served at its own
+ URL, so it can be checked without changing what the frontend serves. The URL is reachable by
+ anyone who holds it and is not indexed; a Candidate is never public and does not claim to be
+ private. The response is `202` while the first deployment runs; read the Candidate for its
+ `status` and `url`.
+
+ Creating a Candidate is available while the `frontends.candidates` capability is. While it is
+ not, this operation, redeploying, promoting and rolling back to a Candidate answer `404` with
+ code `feature_unavailable`; reading and deleting existing Candidates, and rolling back to the
+ frontend's own runtime, keep working.
+
+ A Candidate builds like any deploy and spends the project's build minutes. A frontend has at
+ most 20 live Candidates, and each name is unique within the frontend. Without `ttl_seconds` a
+ Candidate is kept until it is deleted.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (CreateFrontendCandidateBody):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendCandidate
+ """
+
+
+ return sync_detailed(
+ id=id,
+frontend_id=frontend_id,
+client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendCandidateBody,
+
+) -> Response[Error | FrontendCandidate]:
+ """ Create a frontend Candidate
+
+ Builds a copy of the frontend from the uploaded archive, with the frontend's own variable
+ selection, and deploys it to one region: the first region the frontend deploys to, or the
+ project's first region by name if it has not deployed yet. The Candidate is served at its own
+ URL, so it can be checked without changing what the frontend serves. The URL is reachable by
+ anyone who holds it and is not indexed; a Candidate is never public and does not claim to be
+ private. The response is `202` while the first deployment runs; read the Candidate for its
+ `status` and `url`.
+
+ Creating a Candidate is available while the `frontends.candidates` capability is. While it is
+ not, this operation, redeploying, promoting and rolling back to a Candidate answer `404` with
+ code `feature_unavailable`; reading and deleting existing Candidates, and rolling back to the
+ frontend's own runtime, keep working.
+
+ A Candidate builds like any deploy and spends the project's build minutes. A frontend has at
+ most 20 live Candidates, and each name is unique within the frontend. Without `ttl_seconds` a
+ Candidate is kept until it is deleted.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (CreateFrontendCandidateBody):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendCandidate]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendCandidateBody,
+
+) -> Error | FrontendCandidate | None:
+ """ Create a frontend Candidate
+
+ Builds a copy of the frontend from the uploaded archive, with the frontend's own variable
+ selection, and deploys it to one region: the first region the frontend deploys to, or the
+ project's first region by name if it has not deployed yet. The Candidate is served at its own
+ URL, so it can be checked without changing what the frontend serves. The URL is reachable by
+ anyone who holds it and is not indexed; a Candidate is never public and does not claim to be
+ private. The response is `202` while the first deployment runs; read the Candidate for its
+ `status` and `url`.
+
+ Creating a Candidate is available while the `frontends.candidates` capability is. While it is
+ not, this operation, redeploying, promoting and rolling back to a Candidate answer `404` with
+ code `feature_unavailable`; reading and deleting existing Candidates, and rolling back to the
+ frontend's own runtime, keep working.
+
+ A Candidate builds like any deploy and spends the project's build minutes. A frontend has at
+ most 20 live Candidates, and each name is unique within the frontend. Without `ttl_seconds` a
+ Candidate is kept until it is deleted.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (CreateFrontendCandidateBody):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendCandidate
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+frontend_id=frontend_id,
+client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/frontends/create_frontend_custom_domain.py b/src/volcano_sdk/_generated/api/frontends/create_frontend_custom_domain.py
index 85ce955c..112abcda 100644
--- a/src/volcano_sdk/_generated/api/frontends/create_frontend_custom_domain.py
+++ b/src/volcano_sdk/_generated/api/frontends/create_frontend_custom_domain.py
@@ -134,7 +134,10 @@ def sync_detailed(
) -> Response[Error | FrontendCustomDomainConflictError | FrontendCustomDomainResponse]:
""" Configure frontend custom domain
- Configures one custom domain for a frontend.
+ Deprecated: use `POST /projects/{id}/frontends/{frontendId}/domains`, which adds a domain beside the
+ frontend's others.
+ Configures one custom domain for a frontend. When the frontend already has a domain, a request for
+ another hostname returns `409`.
The default Volcano-generated frontend URL remains active.
Wildcard Volcano frontend TLS remains valid and isolated from custom-domain certificate changes.
The account must own the hostname: it must have verified the hostname or a domain above it (see
@@ -197,7 +200,10 @@ def sync(
) -> Error | FrontendCustomDomainConflictError | FrontendCustomDomainResponse | None:
""" Configure frontend custom domain
- Configures one custom domain for a frontend.
+ Deprecated: use `POST /projects/{id}/frontends/{frontendId}/domains`, which adds a domain beside the
+ frontend's others.
+ Configures one custom domain for a frontend. When the frontend already has a domain, a request for
+ another hostname returns `409`.
The default Volcano-generated frontend URL remains active.
Wildcard Volcano frontend TLS remains valid and isolated from custom-domain certificate changes.
The account must own the hostname: it must have verified the hostname or a domain above it (see
@@ -255,7 +261,10 @@ async def asyncio_detailed(
) -> Response[Error | FrontendCustomDomainConflictError | FrontendCustomDomainResponse]:
""" Configure frontend custom domain
- Configures one custom domain for a frontend.
+ Deprecated: use `POST /projects/{id}/frontends/{frontendId}/domains`, which adds a domain beside the
+ frontend's others.
+ Configures one custom domain for a frontend. When the frontend already has a domain, a request for
+ another hostname returns `409`.
The default Volcano-generated frontend URL remains active.
Wildcard Volcano frontend TLS remains valid and isolated from custom-domain certificate changes.
The account must own the hostname: it must have verified the hostname or a domain above it (see
@@ -318,7 +327,10 @@ async def asyncio(
) -> Error | FrontendCustomDomainConflictError | FrontendCustomDomainResponse | None:
""" Configure frontend custom domain
- Configures one custom domain for a frontend.
+ Deprecated: use `POST /projects/{id}/frontends/{frontendId}/domains`, which adds a domain beside the
+ frontend's others.
+ Configures one custom domain for a frontend. When the frontend already has a domain, a request for
+ another hostname returns `409`.
The default Volcano-generated frontend URL remains active.
Wildcard Volcano frontend TLS remains valid and isolated from custom-domain certificate changes.
The account must own the hostname: it must have verified the hostname or a domain above it (see
diff --git a/src/volcano_sdk/_generated/api/frontends/create_frontend_deployment.py b/src/volcano_sdk/_generated/api/frontends/create_frontend_deployment.py
new file mode 100644
index 00000000..7bc34f28
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/frontends/create_frontend_deployment.py
@@ -0,0 +1,345 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.create_frontend_deployment_request import CreateFrontendDeploymentRequest
+from ...models.error import Error
+from ...models.frontend import Frontend
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ body: CreateFrontendDeploymentRequest,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/projects/{id}/frontends/{frontend_id}/deployments".format(id=quote(str(id), safe=""),frontend_id=quote(str(frontend_id), safe=""),),
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | Frontend | None:
+ if response.status_code == 200:
+ response_200 = Frontend.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 429:
+ response_429 = Error.from_dict(response.json())
+
+
+
+ return response_429
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if response.status_code == 501:
+ response_501 = Error.from_dict(response.json())
+
+
+
+ return response_501
+
+ if response.status_code == 503:
+ response_503 = Error.from_dict(response.json())
+
+
+
+ return response_503
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | Frontend]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendDeploymentRequest,
+
+) -> Response[Error | Frontend]:
+ """ Deploy an existing build to a frontend
+
+ Deploys the build of another frontend's deployment in the same project to this frontend, without
+ compiling it again. Use it to serve one build from several frontends, such as one per region or
+ brand. This frontend gets its own copy of the source archive and the build, so later changes to the
+ source frontend do not reach it, and a later redeploy of this frontend compiles that copied source.
+
+ The build-time variables this frontend would build with must equal those the source build read,
+ compared by name and value. Volcano records a keyed digest of each value, unique to the build, and
+ never stores the values. A mismatch returns `409` with `code: build_variables_differ` and the
+ differing
+ names in `error`. The source deployment must be `active` or `degraded`, and both frontends must use
+ the same framework and app root.
+
+ Admission is the redeploy's: the deployment starts with `status: provisioning`, or, while another
+ deployment is in progress, is exposed through `pending_deployment_id` and supersedes any older
+ queued deployment. Nothing is compiled: the deployment's build minutes cover publishing the build
+ alone. The checks run again when a queued deployment starts. A refusal then fails the deployment
+ without a retry, its `error_message` starting with the refusal's code.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (CreateFrontendDeploymentRequest): Deploys the build of an existing deployment
+ instead of compiling the frontend's source.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | Frontend]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendDeploymentRequest,
+
+) -> Error | Frontend | None:
+ """ Deploy an existing build to a frontend
+
+ Deploys the build of another frontend's deployment in the same project to this frontend, without
+ compiling it again. Use it to serve one build from several frontends, such as one per region or
+ brand. This frontend gets its own copy of the source archive and the build, so later changes to the
+ source frontend do not reach it, and a later redeploy of this frontend compiles that copied source.
+
+ The build-time variables this frontend would build with must equal those the source build read,
+ compared by name and value. Volcano records a keyed digest of each value, unique to the build, and
+ never stores the values. A mismatch returns `409` with `code: build_variables_differ` and the
+ differing
+ names in `error`. The source deployment must be `active` or `degraded`, and both frontends must use
+ the same framework and app root.
+
+ Admission is the redeploy's: the deployment starts with `status: provisioning`, or, while another
+ deployment is in progress, is exposed through `pending_deployment_id` and supersedes any older
+ queued deployment. Nothing is compiled: the deployment's build minutes cover publishing the build
+ alone. The checks run again when a queued deployment starts. A refusal then fails the deployment
+ without a retry, its `error_message` starting with the refusal's code.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (CreateFrontendDeploymentRequest): Deploys the build of an existing deployment
+ instead of compiling the frontend's source.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | Frontend
+ """
+
+
+ return sync_detailed(
+ id=id,
+frontend_id=frontend_id,
+client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendDeploymentRequest,
+
+) -> Response[Error | Frontend]:
+ """ Deploy an existing build to a frontend
+
+ Deploys the build of another frontend's deployment in the same project to this frontend, without
+ compiling it again. Use it to serve one build from several frontends, such as one per region or
+ brand. This frontend gets its own copy of the source archive and the build, so later changes to the
+ source frontend do not reach it, and a later redeploy of this frontend compiles that copied source.
+
+ The build-time variables this frontend would build with must equal those the source build read,
+ compared by name and value. Volcano records a keyed digest of each value, unique to the build, and
+ never stores the values. A mismatch returns `409` with `code: build_variables_differ` and the
+ differing
+ names in `error`. The source deployment must be `active` or `degraded`, and both frontends must use
+ the same framework and app root.
+
+ Admission is the redeploy's: the deployment starts with `status: provisioning`, or, while another
+ deployment is in progress, is exposed through `pending_deployment_id` and supersedes any older
+ queued deployment. Nothing is compiled: the deployment's build minutes cover publishing the build
+ alone. The checks run again when a queued deployment starts. A refusal then fails the deployment
+ without a retry, its `error_message` starting with the refusal's code.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (CreateFrontendDeploymentRequest): Deploys the build of an existing deployment
+ instead of compiling the frontend's source.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | Frontend]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendDeploymentRequest,
+
+) -> Error | Frontend | None:
+ """ Deploy an existing build to a frontend
+
+ Deploys the build of another frontend's deployment in the same project to this frontend, without
+ compiling it again. Use it to serve one build from several frontends, such as one per region or
+ brand. This frontend gets its own copy of the source archive and the build, so later changes to the
+ source frontend do not reach it, and a later redeploy of this frontend compiles that copied source.
+
+ The build-time variables this frontend would build with must equal those the source build read,
+ compared by name and value. Volcano records a keyed digest of each value, unique to the build, and
+ never stores the values. A mismatch returns `409` with `code: build_variables_differ` and the
+ differing
+ names in `error`. The source deployment must be `active` or `degraded`, and both frontends must use
+ the same framework and app root.
+
+ Admission is the redeploy's: the deployment starts with `status: provisioning`, or, while another
+ deployment is in progress, is exposed through `pending_deployment_id` and supersedes any older
+ queued deployment. Nothing is compiled: the deployment's build minutes cover publishing the build
+ alone. The checks run again when a queued deployment starts. A refusal then fails the deployment
+ without a retry, its `error_message` starting with the refusal's code.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (CreateFrontendDeploymentRequest): Deploys the build of an existing deployment
+ instead of compiling the frontend's source.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | Frontend
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+frontend_id=frontend_id,
+client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/frontends/create_frontend_domain.py b/src/volcano_sdk/_generated/api/frontends/create_frontend_domain.py
new file mode 100644
index 00000000..acd8b673
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/frontends/create_frontend_domain.py
@@ -0,0 +1,315 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.create_frontend_domain_request import CreateFrontendDomainRequest
+from ...models.error import Error
+from ...models.frontend_custom_domain_conflict_error import FrontendCustomDomainConflictError
+from ...models.frontend_custom_domain_response import FrontendCustomDomainResponse
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ body: CreateFrontendDomainRequest,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/projects/{id}/frontends/{frontend_id}/domains".format(id=quote(str(id), safe=""),frontend_id=quote(str(frontend_id), safe=""),),
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | FrontendCustomDomainConflictError | FrontendCustomDomainResponse | None:
+ if response.status_code == 200:
+ response_200 = FrontendCustomDomainResponse.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 201:
+ response_201 = FrontendCustomDomainResponse.from_dict(response.json())
+
+
+
+ return response_201
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = FrontendCustomDomainConflictError.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if response.status_code == 503:
+ response_503 = Error.from_dict(response.json())
+
+
+
+ return response_503
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | FrontendCustomDomainConflictError | FrontendCustomDomainResponse]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendDomainRequest,
+
+) -> Response[Error | FrontendCustomDomainConflictError | FrontendCustomDomainResponse]:
+ """ Add a custom domain to a frontend
+
+ Adds a custom domain beside the frontend's others, up to the plan's
+ custom domains per frontend. The domain serves the frontend, or, with
+ `redirect`, redirects every request to `redirect.to`, another active
+ domain of the same frontend that serves it, keeping the path and query
+ string.
+ A redirecting domain still needs TLS, so it takes `tls` like any other.
+
+ Ownership, verification records, TLS mode switches, and the `409` codes
+ work as on `POST /projects/{id}/frontends/{frontendId}/domain`. A
+ request for a hostname the frontend already has returns it with `200`,
+ or switches its TLS mode in place. When the request's redirect differs
+ from the domain's, it returns `409`; change a redirect with `PATCH`.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (CreateFrontendDomainRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendCustomDomainConflictError | FrontendCustomDomainResponse]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendDomainRequest,
+
+) -> Error | FrontendCustomDomainConflictError | FrontendCustomDomainResponse | None:
+ """ Add a custom domain to a frontend
+
+ Adds a custom domain beside the frontend's others, up to the plan's
+ custom domains per frontend. The domain serves the frontend, or, with
+ `redirect`, redirects every request to `redirect.to`, another active
+ domain of the same frontend that serves it, keeping the path and query
+ string.
+ A redirecting domain still needs TLS, so it takes `tls` like any other.
+
+ Ownership, verification records, TLS mode switches, and the `409` codes
+ work as on `POST /projects/{id}/frontends/{frontendId}/domain`. A
+ request for a hostname the frontend already has returns it with `200`,
+ or switches its TLS mode in place. When the request's redirect differs
+ from the domain's, it returns `409`; change a redirect with `PATCH`.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (CreateFrontendDomainRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendCustomDomainConflictError | FrontendCustomDomainResponse
+ """
+
+
+ return sync_detailed(
+ id=id,
+frontend_id=frontend_id,
+client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendDomainRequest,
+
+) -> Response[Error | FrontendCustomDomainConflictError | FrontendCustomDomainResponse]:
+ """ Add a custom domain to a frontend
+
+ Adds a custom domain beside the frontend's others, up to the plan's
+ custom domains per frontend. The domain serves the frontend, or, with
+ `redirect`, redirects every request to `redirect.to`, another active
+ domain of the same frontend that serves it, keeping the path and query
+ string.
+ A redirecting domain still needs TLS, so it takes `tls` like any other.
+
+ Ownership, verification records, TLS mode switches, and the `409` codes
+ work as on `POST /projects/{id}/frontends/{frontendId}/domain`. A
+ request for a hostname the frontend already has returns it with `200`,
+ or switches its TLS mode in place. When the request's redirect differs
+ from the domain's, it returns `409`; change a redirect with `PATCH`.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (CreateFrontendDomainRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendCustomDomainConflictError | FrontendCustomDomainResponse]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendDomainRequest,
+
+) -> Error | FrontendCustomDomainConflictError | FrontendCustomDomainResponse | None:
+ """ Add a custom domain to a frontend
+
+ Adds a custom domain beside the frontend's others, up to the plan's
+ custom domains per frontend. The domain serves the frontend, or, with
+ `redirect`, redirects every request to `redirect.to`, another active
+ domain of the same frontend that serves it, keeping the path and query
+ string.
+ A redirecting domain still needs TLS, so it takes `tls` like any other.
+
+ Ownership, verification records, TLS mode switches, and the `409` codes
+ work as on `POST /projects/{id}/frontends/{frontendId}/domain`. A
+ request for a hostname the frontend already has returns it with `200`,
+ or switches its TLS mode in place. When the request's redirect differs
+ from the domain's, it returns `409`; change a redirect with `PATCH`.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (CreateFrontendDomainRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendCustomDomainConflictError | FrontendCustomDomainResponse
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+frontend_id=frontend_id,
+client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/frontends/create_frontend_route.py b/src/volcano_sdk/_generated/api/frontends/create_frontend_route.py
new file mode 100644
index 00000000..e147c7fb
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/frontends/create_frontend_route.py
@@ -0,0 +1,288 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.create_frontend_route_request import CreateFrontendRouteRequest
+from ...models.error import Error
+from ...models.frontend_route import FrontendRoute
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ body: CreateFrontendRouteRequest,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/projects/{id}/frontends/{frontend_id}/frontend-routes".format(id=quote(str(id), safe=""),frontend_id=quote(str(frontend_id), safe=""),),
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | FrontendRoute | None:
+ if response.status_code == 201:
+ response_201 = FrontendRoute.from_dict(response.json())
+
+
+
+ return response_201
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | FrontendRoute]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendRouteRequest,
+
+) -> Response[Error | FrontendRoute]:
+ """ Mount another Frontend at a path
+
+ Serves `path_prefix` and everything under it on this Frontend's hostnames from another
+ Frontend in the same Project. The path is forwarded unchanged, so the mounted Frontend must
+ serve its pages under the prefix (page directories or a matching `basePath`). Its root
+ `/_next/static` files and `/_next/image` requests are sent to it too. A Frontend may be
+ mounted at several prefixes. Function and Frontend routes share one path namespace and the
+ 64-route limit; the most specific prefix wins. A mounted Frontend's own routes do not apply
+ to requests it receives through a route. The route applies to every hostname that resolves
+ to this Frontend, including generated, custom-domain, and local hostnames. While the mounted
+ Frontend has no active deployment, its paths answer 502, as its own hostname does.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (CreateFrontendRouteRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendRoute]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendRouteRequest,
+
+) -> Error | FrontendRoute | None:
+ """ Mount another Frontend at a path
+
+ Serves `path_prefix` and everything under it on this Frontend's hostnames from another
+ Frontend in the same Project. The path is forwarded unchanged, so the mounted Frontend must
+ serve its pages under the prefix (page directories or a matching `basePath`). Its root
+ `/_next/static` files and `/_next/image` requests are sent to it too. A Frontend may be
+ mounted at several prefixes. Function and Frontend routes share one path namespace and the
+ 64-route limit; the most specific prefix wins. A mounted Frontend's own routes do not apply
+ to requests it receives through a route. The route applies to every hostname that resolves
+ to this Frontend, including generated, custom-domain, and local hostnames. While the mounted
+ Frontend has no active deployment, its paths answer 502, as its own hostname does.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (CreateFrontendRouteRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendRoute
+ """
+
+
+ return sync_detailed(
+ id=id,
+frontend_id=frontend_id,
+client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendRouteRequest,
+
+) -> Response[Error | FrontendRoute]:
+ """ Mount another Frontend at a path
+
+ Serves `path_prefix` and everything under it on this Frontend's hostnames from another
+ Frontend in the same Project. The path is forwarded unchanged, so the mounted Frontend must
+ serve its pages under the prefix (page directories or a matching `basePath`). Its root
+ `/_next/static` files and `/_next/image` requests are sent to it too. A Frontend may be
+ mounted at several prefixes. Function and Frontend routes share one path namespace and the
+ 64-route limit; the most specific prefix wins. A mounted Frontend's own routes do not apply
+ to requests it receives through a route. The route applies to every hostname that resolves
+ to this Frontend, including generated, custom-domain, and local hostnames. While the mounted
+ Frontend has no active deployment, its paths answer 502, as its own hostname does.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (CreateFrontendRouteRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendRoute]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendRouteRequest,
+
+) -> Error | FrontendRoute | None:
+ """ Mount another Frontend at a path
+
+ Serves `path_prefix` and everything under it on this Frontend's hostnames from another
+ Frontend in the same Project. The path is forwarded unchanged, so the mounted Frontend must
+ serve its pages under the prefix (page directories or a matching `basePath`). Its root
+ `/_next/static` files and `/_next/image` requests are sent to it too. A Frontend may be
+ mounted at several prefixes. Function and Frontend routes share one path namespace and the
+ 64-route limit; the most specific prefix wins. A mounted Frontend's own routes do not apply
+ to requests it receives through a route. The route applies to every hostname that resolves
+ to this Frontend, including generated, custom-domain, and local hostnames. While the mounted
+ Frontend has no active deployment, its paths answer 502, as its own hostname does.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (CreateFrontendRouteRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendRoute
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+frontend_id=frontend_id,
+client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/frontends/delete_frontend.py b/src/volcano_sdk/_generated/api/frontends/delete_frontend.py
index 99063d9a..e095bb6a 100644
--- a/src/volcano_sdk/_generated/api/frontends/delete_frontend.py
+++ b/src/volcano_sdk/_generated/api/frontends/delete_frontend.py
@@ -68,6 +68,13 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return response_404
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
if response.status_code == 500:
response_500 = Error.from_dict(response.json())
diff --git a/src/volcano_sdk/_generated/api/frontends/delete_frontend_candidate.py b/src/volcano_sdk/_generated/api/frontends/delete_frontend_candidate.py
new file mode 100644
index 00000000..4ce5e9f5
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/frontends/delete_frontend_candidate.py
@@ -0,0 +1,269 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "delete",
+ "url": "/projects/{id}/frontends/{frontend_id}/candidates/{candidate_id}".format(id=quote(str(id), safe=""),frontend_id=quote(str(frontend_id), safe=""),candidate_id=quote(str(candidate_id), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | Error | None:
+ if response.status_code == 202:
+ response_202 = cast(Any, None)
+ return response_202
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Any | Error]:
+ """ Delete a frontend Candidate
+
+ Starts deleting the Candidate: its regional runtime, images, edge state and stored source are
+ removed once any running deployment finishes. Asking again for a Candidate that is already being
+ deleted is the same request. The Candidate answers `404` once it is gone.
+
+ A Candidate the frontend serves cannot be deleted: roll back first. A Candidate the frontend only
+ keeps as the runtime a rollback returns to can be deleted, and doing so gives up that rollback;
+ rolling back to the frontend's own runtime stays possible.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ candidate_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+candidate_id=candidate_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Any | Error | None:
+ """ Delete a frontend Candidate
+
+ Starts deleting the Candidate: its regional runtime, images, edge state and stored source are
+ removed once any running deployment finishes. Asking again for a Candidate that is already being
+ deleted is the same request. The Candidate answers `404` once it is gone.
+
+ A Candidate the frontend serves cannot be deleted: roll back first. A Candidate the frontend only
+ keeps as the runtime a rollback returns to can be deleted, and doing so gives up that rollback;
+ rolling back to the frontend's own runtime stays possible.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ candidate_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return sync_detailed(
+ id=id,
+frontend_id=frontend_id,
+candidate_id=candidate_id,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Any | Error]:
+ """ Delete a frontend Candidate
+
+ Starts deleting the Candidate: its regional runtime, images, edge state and stored source are
+ removed once any running deployment finishes. Asking again for a Candidate that is already being
+ deleted is the same request. The Candidate answers `404` once it is gone.
+
+ A Candidate the frontend serves cannot be deleted: roll back first. A Candidate the frontend only
+ keeps as the runtime a rollback returns to can be deleted, and doing so gives up that rollback;
+ rolling back to the frontend's own runtime stays possible.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ candidate_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+candidate_id=candidate_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Any | Error | None:
+ """ Delete a frontend Candidate
+
+ Starts deleting the Candidate: its regional runtime, images, edge state and stored source are
+ removed once any running deployment finishes. Asking again for a Candidate that is already being
+ deleted is the same request. The Candidate answers `404` once it is gone.
+
+ A Candidate the frontend serves cannot be deleted: roll back first. A Candidate the frontend only
+ keeps as the runtime a rollback returns to can be deleted, and doing so gives up that rollback;
+ rolling back to the frontend's own runtime stays possible.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ candidate_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+frontend_id=frontend_id,
+candidate_id=candidate_id,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/frontends/delete_frontend_custom_domain.py b/src/volcano_sdk/_generated/api/frontends/delete_frontend_custom_domain.py
index 216768e1..abbcb898 100644
--- a/src/volcano_sdk/_generated/api/frontends/delete_frontend_custom_domain.py
+++ b/src/volcano_sdk/_generated/api/frontends/delete_frontend_custom_domain.py
@@ -106,6 +106,10 @@ def sync_detailed(
) -> Response[Any | Error]:
""" Delete frontend custom domain
+ Deprecated: use `DELETE /projects/{id}/frontends/{frontendId}/domains/{domain}`.
+ Deletes the frontend's custom domain. A frontend with several domains
+ returns `409`; name the one to delete on the collection route.
+
Args:
id (UUID):
frontend_id (UUID):
@@ -140,6 +144,10 @@ def sync(
) -> Any | Error | None:
""" Delete frontend custom domain
+ Deprecated: use `DELETE /projects/{id}/frontends/{frontendId}/domains/{domain}`.
+ Deletes the frontend's custom domain. A frontend with several domains
+ returns `409`; name the one to delete on the collection route.
+
Args:
id (UUID):
frontend_id (UUID):
@@ -169,6 +177,10 @@ async def asyncio_detailed(
) -> Response[Any | Error]:
""" Delete frontend custom domain
+ Deprecated: use `DELETE /projects/{id}/frontends/{frontendId}/domains/{domain}`.
+ Deletes the frontend's custom domain. A frontend with several domains
+ returns `409`; name the one to delete on the collection route.
+
Args:
id (UUID):
frontend_id (UUID):
@@ -203,6 +215,10 @@ async def asyncio(
) -> Any | Error | None:
""" Delete frontend custom domain
+ Deprecated: use `DELETE /projects/{id}/frontends/{frontendId}/domains/{domain}`.
+ Deletes the frontend's custom domain. A frontend with several domains
+ returns `409`; name the one to delete on the collection route.
+
Args:
id (UUID):
frontend_id (UUID):
diff --git a/src/volcano_sdk/_generated/api/frontends/delete_frontend_domain.py b/src/volcano_sdk/_generated/api/frontends/delete_frontend_domain.py
new file mode 100644
index 00000000..26a769f6
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/frontends/delete_frontend_domain.py
@@ -0,0 +1,242 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ domain: str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "delete",
+ "url": "/projects/{id}/frontends/{frontend_id}/domains/{domain}".format(id=quote(str(id), safe=""),frontend_id=quote(str(frontend_id), safe=""),domain=quote(str(domain), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | Error | None:
+ if response.status_code == 204:
+ response_204 = cast(Any, None)
+ return response_204
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ domain: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Any | Error]:
+ """ Remove a custom domain from a frontend
+
+ Detaches the domain. A domain other domains redirect to cannot be
+ removed until those redirects are removed or retargeted.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ domain (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+domain=domain,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ domain: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Any | Error | None:
+ """ Remove a custom domain from a frontend
+
+ Detaches the domain. A domain other domains redirect to cannot be
+ removed until those redirects are removed or retargeted.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ domain (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return sync_detailed(
+ id=id,
+frontend_id=frontend_id,
+domain=domain,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ domain: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Any | Error]:
+ """ Remove a custom domain from a frontend
+
+ Detaches the domain. A domain other domains redirect to cannot be
+ removed until those redirects are removed or retargeted.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ domain (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+domain=domain,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ domain: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Any | Error | None:
+ """ Remove a custom domain from a frontend
+
+ Detaches the domain. A domain other domains redirect to cannot be
+ removed until those redirects are removed or retargeted.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ domain (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+frontend_id=frontend_id,
+domain=domain,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/frontends/delete_frontend_route.py b/src/volcano_sdk/_generated/api/frontends/delete_frontend_route.py
new file mode 100644
index 00000000..85abf3d7
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/frontends/delete_frontend_route.py
@@ -0,0 +1,223 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ route_id: UUID | str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "delete",
+ "url": "/projects/{id}/frontends/{frontend_id}/frontend-routes/{route_id}".format(id=quote(str(id), safe=""),frontend_id=quote(str(frontend_id), safe=""),route_id=quote(str(route_id), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | Error | None:
+ if response.status_code == 204:
+ response_204 = cast(Any, None)
+ return response_204
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ route_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Any | Error]:
+ """ Delete a Frontend route
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ route_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+route_id=route_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ route_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Any | Error | None:
+ """ Delete a Frontend route
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ route_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return sync_detailed(
+ id=id,
+frontend_id=frontend_id,
+route_id=route_id,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ route_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Any | Error]:
+ """ Delete a Frontend route
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ route_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+route_id=route_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ route_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Any | Error | None:
+ """ Delete a Frontend route
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ route_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+frontend_id=frontend_id,
+route_id=route_id,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/frontends/get_frontend_candidate.py b/src/volcano_sdk/_generated/api/frontends/get_frontend_candidate.py
new file mode 100644
index 00000000..3ccc3b9f
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/frontends/get_frontend_candidate.py
@@ -0,0 +1,234 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.frontend_candidate import FrontendCandidate
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/projects/{id}/frontends/{frontend_id}/candidates/{candidate_id}".format(id=quote(str(id), safe=""),frontend_id=quote(str(frontend_id), safe=""),candidate_id=quote(str(candidate_id), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | FrontendCandidate | None:
+ if response.status_code == 200:
+ response_200 = FrontendCandidate.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | FrontendCandidate]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Error | FrontendCandidate]:
+ """ Get a frontend Candidate
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ candidate_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendCandidate]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+candidate_id=candidate_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Error | FrontendCandidate | None:
+ """ Get a frontend Candidate
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ candidate_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendCandidate
+ """
+
+
+ return sync_detailed(
+ id=id,
+frontend_id=frontend_id,
+candidate_id=candidate_id,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Error | FrontendCandidate]:
+ """ Get a frontend Candidate
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ candidate_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendCandidate]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+candidate_id=candidate_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Error | FrontendCandidate | None:
+ """ Get a frontend Candidate
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ candidate_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendCandidate
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+frontend_id=frontend_id,
+candidate_id=candidate_id,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/frontends/get_frontend_custom_domain.py b/src/volcano_sdk/_generated/api/frontends/get_frontend_custom_domain.py
index 8f281e76..5cfae9e8 100644
--- a/src/volcano_sdk/_generated/api/frontends/get_frontend_custom_domain.py
+++ b/src/volcano_sdk/_generated/api/frontends/get_frontend_custom_domain.py
@@ -116,6 +116,9 @@ def sync_detailed(
) -> Response[Error | FrontendCustomDomainResponse | None]:
""" Get frontend custom domain status
+ Deprecated: use `GET /projects/{id}/frontends/{frontendId}/domains`.
+ Returns the frontend's oldest domain that serves it rather than redirecting.
+
Args:
id (UUID):
frontend_id (UUID):
@@ -150,6 +153,9 @@ def sync(
) -> Error | FrontendCustomDomainResponse | None | None:
""" Get frontend custom domain status
+ Deprecated: use `GET /projects/{id}/frontends/{frontendId}/domains`.
+ Returns the frontend's oldest domain that serves it rather than redirecting.
+
Args:
id (UUID):
frontend_id (UUID):
@@ -179,6 +185,9 @@ async def asyncio_detailed(
) -> Response[Error | FrontendCustomDomainResponse | None]:
""" Get frontend custom domain status
+ Deprecated: use `GET /projects/{id}/frontends/{frontendId}/domains`.
+ Returns the frontend's oldest domain that serves it rather than redirecting.
+
Args:
id (UUID):
frontend_id (UUID):
@@ -213,6 +222,9 @@ async def asyncio(
) -> Error | FrontendCustomDomainResponse | None | None:
""" Get frontend custom domain status
+ Deprecated: use `GET /projects/{id}/frontends/{frontendId}/domains`.
+ Returns the frontend's oldest domain that serves it rather than redirecting.
+
Args:
id (UUID):
frontend_id (UUID):
diff --git a/src/volcano_sdk/_generated/api/frontends/get_frontend_domain.py b/src/volcano_sdk/_generated/api/frontends/get_frontend_domain.py
new file mode 100644
index 00000000..016c7e3d
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/frontends/get_frontend_domain.py
@@ -0,0 +1,227 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.frontend_custom_domain_response import FrontendCustomDomainResponse
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ domain: str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/projects/{id}/frontends/{frontend_id}/domains/{domain}".format(id=quote(str(id), safe=""),frontend_id=quote(str(frontend_id), safe=""),domain=quote(str(domain), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | FrontendCustomDomainResponse | None:
+ if response.status_code == 200:
+ response_200 = FrontendCustomDomainResponse.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | FrontendCustomDomainResponse]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ domain: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Error | FrontendCustomDomainResponse]:
+ """ Get a frontend custom domain
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ domain (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendCustomDomainResponse]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+domain=domain,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ domain: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Error | FrontendCustomDomainResponse | None:
+ """ Get a frontend custom domain
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ domain (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendCustomDomainResponse
+ """
+
+
+ return sync_detailed(
+ id=id,
+frontend_id=frontend_id,
+domain=domain,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ domain: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Error | FrontendCustomDomainResponse]:
+ """ Get a frontend custom domain
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ domain (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendCustomDomainResponse]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+domain=domain,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ domain: str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Error | FrontendCustomDomainResponse | None:
+ """ Get a frontend custom domain
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ domain (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendCustomDomainResponse
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+frontend_id=frontend_id,
+domain=domain,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/autofix/delete_autofix_api_key.py b/src/volcano_sdk/_generated/api/frontends/get_frontend_serving.py
similarity index 54%
rename from src/volcano_sdk/_generated/api/autofix/delete_autofix_api_key.py
rename to src/volcano_sdk/_generated/api/frontends/get_frontend_serving.py
index 55698d32..d4810c13 100644
--- a/src/volcano_sdk/_generated/api/autofix/delete_autofix_api_key.py
+++ b/src/volcano_sdk/_generated/api/frontends/get_frontend_serving.py
@@ -8,8 +8,8 @@
from ...types import Response, UNSET
from ... import errors
-from ...models.autofix_settings import AutofixSettings
from ...models.error import Error
+from ...models.frontend_serving import FrontendServing
from typing import cast
from uuid import UUID
@@ -17,6 +17,7 @@
def request_kwargs(
id: UUID | str,
+ frontend_id: UUID | str,
) -> dict[str, Any]:
@@ -26,8 +27,8 @@ def request_kwargs(
_kwargs: dict[str, Any] = {
- "method": "delete",
- "url": "/projects/{id}/autofix/api-key".format(id=quote(str(id), safe=""),),
+ "method": "get",
+ "url": "/projects/{id}/frontends/{frontend_id}/serving".format(id=quote(str(id), safe=""),frontend_id=quote(str(frontend_id), safe=""),),
}
@@ -35,14 +36,28 @@ def request_kwargs(
-def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> AutofixSettings | Error | None:
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | FrontendServing | None:
if response.status_code == 200:
- response_200 = AutofixSettings.from_dict(response.json())
+ response_200 = FrontendServing.from_dict(response.json())
return response_200
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
if response.status_code == 403:
response_403 = Error.from_dict(response.json())
@@ -57,12 +72,12 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return response_404
- if response.status_code == 501:
- response_501 = Error.from_dict(response.json())
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
- return response_501
+ return response_500
if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
@@ -70,7 +85,7 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return None
-def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[AutofixSettings | Error]:
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | FrontendServing]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
@@ -81,36 +96,32 @@ def build_response(*, client: AuthenticatedClient | Client, response: httpx.Resp
def sync_detailed(
id: UUID | str,
+ frontend_id: UUID | str,
*,
client: AuthenticatedClient,
-) -> Response[AutofixSettings | Error]:
- """ Delete the API key
+) -> Response[Error | FrontendServing]:
+ """ Get what a frontend serves
- Deletes the project's stored API key and returns the settings. Autofix
- on the key's provider runs on that key, so it turns off; on another
- provider it stays as it is. Deleting when no key is stored succeeds.
-
- Turning autofix off or switching providers never deletes the key, and
- neither does applying a project configuration. This works where
- autofix is not available, for a project that saved settings.
-
- Project access tokens are refused.
+ Reports whether the frontend serves its own runtime or a promoted Candidate's, and the
+ revision a promotion or rollback must name.
Args:
id (UUID):
+ frontend_id (UUID):
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[AutofixSettings | Error]
+ Response[Error | FrontendServing]
"""
kwargs = request_kwargs(
id=id,
+frontend_id=frontend_id,
)
@@ -122,72 +133,64 @@ def sync_detailed(
def sync(
id: UUID | str,
+ frontend_id: UUID | str,
*,
client: AuthenticatedClient,
-) -> AutofixSettings | Error | None:
- """ Delete the API key
-
- Deletes the project's stored API key and returns the settings. Autofix
- on the key's provider runs on that key, so it turns off; on another
- provider it stays as it is. Deleting when no key is stored succeeds.
-
- Turning autofix off or switching providers never deletes the key, and
- neither does applying a project configuration. This works where
- autofix is not available, for a project that saved settings.
+) -> Error | FrontendServing | None:
+ """ Get what a frontend serves
- Project access tokens are refused.
+ Reports whether the frontend serves its own runtime or a promoted Candidate's, and the
+ revision a promotion or rollback must name.
Args:
id (UUID):
+ frontend_id (UUID):
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- AutofixSettings | Error
+ Error | FrontendServing
"""
return sync_detailed(
id=id,
+frontend_id=frontend_id,
client=client,
).parsed
async def asyncio_detailed(
id: UUID | str,
+ frontend_id: UUID | str,
*,
client: AuthenticatedClient,
-) -> Response[AutofixSettings | Error]:
- """ Delete the API key
+) -> Response[Error | FrontendServing]:
+ """ Get what a frontend serves
- Deletes the project's stored API key and returns the settings. Autofix
- on the key's provider runs on that key, so it turns off; on another
- provider it stays as it is. Deleting when no key is stored succeeds.
-
- Turning autofix off or switching providers never deletes the key, and
- neither does applying a project configuration. This works where
- autofix is not available, for a project that saved settings.
-
- Project access tokens are refused.
+ Reports whether the frontend serves its own runtime or a promoted Candidate's, and the
+ revision a promotion or rollback must name.
Args:
id (UUID):
+ frontend_id (UUID):
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[AutofixSettings | Error]
+ Response[Error | FrontendServing]
"""
kwargs = request_kwargs(
id=id,
+frontend_id=frontend_id,
)
@@ -199,36 +202,32 @@ async def asyncio_detailed(
async def asyncio(
id: UUID | str,
+ frontend_id: UUID | str,
*,
client: AuthenticatedClient,
-) -> AutofixSettings | Error | None:
- """ Delete the API key
-
- Deletes the project's stored API key and returns the settings. Autofix
- on the key's provider runs on that key, so it turns off; on another
- provider it stays as it is. Deleting when no key is stored succeeds.
-
- Turning autofix off or switching providers never deletes the key, and
- neither does applying a project configuration. This works where
- autofix is not available, for a project that saved settings.
+) -> Error | FrontendServing | None:
+ """ Get what a frontend serves
- Project access tokens are refused.
+ Reports whether the frontend serves its own runtime or a promoted Candidate's, and the
+ revision a promotion or rollback must name.
Args:
id (UUID):
+ frontend_id (UUID):
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- AutofixSettings | Error
+ Error | FrontendServing
"""
return (await asyncio_detailed(
id=id,
+frontend_id=frontend_id,
client=client,
)).parsed
diff --git a/src/volcano_sdk/_generated/api/autofix/get_autofix_settings.py b/src/volcano_sdk/_generated/api/frontends/list_frontend_candidates.py
similarity index 51%
rename from src/volcano_sdk/_generated/api/autofix/get_autofix_settings.py
rename to src/volcano_sdk/_generated/api/frontends/list_frontend_candidates.py
index 35eeeff4..31bd4d95 100644
--- a/src/volcano_sdk/_generated/api/autofix/get_autofix_settings.py
+++ b/src/volcano_sdk/_generated/api/frontends/list_frontend_candidates.py
@@ -8,8 +8,8 @@
from ...types import Response, UNSET
from ... import errors
-from ...models.autofix_settings import AutofixSettings
from ...models.error import Error
+from ...models.frontend_candidate_list import FrontendCandidateList
from typing import cast
from uuid import UUID
@@ -17,6 +17,7 @@
def request_kwargs(
id: UUID | str,
+ frontend_id: UUID | str,
) -> dict[str, Any]:
@@ -27,7 +28,7 @@ def request_kwargs(
_kwargs: dict[str, Any] = {
"method": "get",
- "url": "/projects/{id}/autofix".format(id=quote(str(id), safe=""),),
+ "url": "/projects/{id}/frontends/{frontend_id}/candidates".format(id=quote(str(id), safe=""),frontend_id=quote(str(frontend_id), safe=""),),
}
@@ -35,34 +36,48 @@ def request_kwargs(
-def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> AutofixSettings | Error | None:
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | FrontendCandidateList | None:
if response.status_code == 200:
- response_200 = AutofixSettings.from_dict(response.json())
+ response_200 = FrontendCandidateList.from_dict(response.json())
return response_200
- if response.status_code == 404:
- response_404 = Error.from_dict(response.json())
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
- return response_404
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
- if response.status_code == 501:
- response_501 = Error.from_dict(response.json())
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
- return response_501
+ return response_404
- if response.status_code == 503:
- response_503 = Error.from_dict(response.json())
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
- return response_503
+ return response_500
if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
@@ -70,7 +85,7 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return None
-def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[AutofixSettings | Error]:
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | FrontendCandidateList]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
@@ -81,37 +96,32 @@ def build_response(*, client: AuthenticatedClient | Client, response: httpx.Resp
def sync_detailed(
id: UUID | str,
+ frontend_id: UUID | str,
*,
client: AuthenticatedClient,
-) -> Response[AutofixSettings | Error]:
- """ Get autofix settings
+) -> Response[Error | FrontendCandidateList]:
+ """ List a frontend's Candidates
- Returns whether Volcano diagnoses the project's issues with AI, how far
- a run may go, and which model it uses. A project that never saved
- settings returns the defaults, with autofix off.
-
- Your API key is never returned. `api_key_configured`,
- `api_key_provider`, and `api_key_last4` show whether one is set and
- which provider it belongs to.
-
- Where autofix is not available, saved settings stay readable. A project
- that never saved any answers `404` with code `feature_unavailable`.
+ Returns the frontend's Candidates, oldest first, each with its latest deployment. A frontend
+ has at most 20 live Candidates. Reading never depends on the `frontends.candidates` capability.
Args:
id (UUID):
+ frontend_id (UUID):
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[AutofixSettings | Error]
+ Response[Error | FrontendCandidateList]
"""
kwargs = request_kwargs(
id=id,
+frontend_id=frontend_id,
)
@@ -123,74 +133,64 @@ def sync_detailed(
def sync(
id: UUID | str,
+ frontend_id: UUID | str,
*,
client: AuthenticatedClient,
-) -> AutofixSettings | Error | None:
- """ Get autofix settings
-
- Returns whether Volcano diagnoses the project's issues with AI, how far
- a run may go, and which model it uses. A project that never saved
- settings returns the defaults, with autofix off.
+) -> Error | FrontendCandidateList | None:
+ """ List a frontend's Candidates
- Your API key is never returned. `api_key_configured`,
- `api_key_provider`, and `api_key_last4` show whether one is set and
- which provider it belongs to.
-
- Where autofix is not available, saved settings stay readable. A project
- that never saved any answers `404` with code `feature_unavailable`.
+ Returns the frontend's Candidates, oldest first, each with its latest deployment. A frontend
+ has at most 20 live Candidates. Reading never depends on the `frontends.candidates` capability.
Args:
id (UUID):
+ frontend_id (UUID):
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- AutofixSettings | Error
+ Error | FrontendCandidateList
"""
return sync_detailed(
id=id,
+frontend_id=frontend_id,
client=client,
).parsed
async def asyncio_detailed(
id: UUID | str,
+ frontend_id: UUID | str,
*,
client: AuthenticatedClient,
-) -> Response[AutofixSettings | Error]:
- """ Get autofix settings
-
- Returns whether Volcano diagnoses the project's issues with AI, how far
- a run may go, and which model it uses. A project that never saved
- settings returns the defaults, with autofix off.
-
- Your API key is never returned. `api_key_configured`,
- `api_key_provider`, and `api_key_last4` show whether one is set and
- which provider it belongs to.
+) -> Response[Error | FrontendCandidateList]:
+ """ List a frontend's Candidates
- Where autofix is not available, saved settings stay readable. A project
- that never saved any answers `404` with code `feature_unavailable`.
+ Returns the frontend's Candidates, oldest first, each with its latest deployment. A frontend
+ has at most 20 live Candidates. Reading never depends on the `frontends.candidates` capability.
Args:
id (UUID):
+ frontend_id (UUID):
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[AutofixSettings | Error]
+ Response[Error | FrontendCandidateList]
"""
kwargs = request_kwargs(
id=id,
+frontend_id=frontend_id,
)
@@ -202,37 +202,32 @@ async def asyncio_detailed(
async def asyncio(
id: UUID | str,
+ frontend_id: UUID | str,
*,
client: AuthenticatedClient,
-) -> AutofixSettings | Error | None:
- """ Get autofix settings
-
- Returns whether Volcano diagnoses the project's issues with AI, how far
- a run may go, and which model it uses. A project that never saved
- settings returns the defaults, with autofix off.
-
- Your API key is never returned. `api_key_configured`,
- `api_key_provider`, and `api_key_last4` show whether one is set and
- which provider it belongs to.
+) -> Error | FrontendCandidateList | None:
+ """ List a frontend's Candidates
- Where autofix is not available, saved settings stay readable. A project
- that never saved any answers `404` with code `feature_unavailable`.
+ Returns the frontend's Candidates, oldest first, each with its latest deployment. A frontend
+ has at most 20 live Candidates. Reading never depends on the `frontends.candidates` capability.
Args:
id (UUID):
+ frontend_id (UUID):
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- AutofixSettings | Error
+ Error | FrontendCandidateList
"""
return (await asyncio_detailed(
id=id,
+frontend_id=frontend_id,
client=client,
)).parsed
diff --git a/src/volcano_sdk/_generated/api/frontends/list_frontend_domains.py b/src/volcano_sdk/_generated/api/frontends/list_frontend_domains.py
new file mode 100644
index 00000000..c727467a
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/frontends/list_frontend_domains.py
@@ -0,0 +1,230 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.frontend_custom_domain_list import FrontendCustomDomainList
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ frontend_id: UUID | str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/projects/{id}/frontends/{frontend_id}/domains".format(id=quote(str(id), safe=""),frontend_id=quote(str(frontend_id), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | FrontendCustomDomainList | None:
+ if response.status_code == 200:
+ response_200 = FrontendCustomDomainList.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | FrontendCustomDomainList]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Error | FrontendCustomDomainList]:
+ """ List a frontend's custom domains
+
+ Lists the frontend's custom domains, oldest first. Each domain either
+ serves the frontend or, with `redirect` set, redirects every request to
+ another domain of the frontend.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendCustomDomainList]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Error | FrontendCustomDomainList | None:
+ """ List a frontend's custom domains
+
+ Lists the frontend's custom domains, oldest first. Each domain either
+ serves the frontend or, with `redirect` set, redirects every request to
+ another domain of the frontend.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendCustomDomainList
+ """
+
+
+ return sync_detailed(
+ id=id,
+frontend_id=frontend_id,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Error | FrontendCustomDomainList]:
+ """ List a frontend's custom domains
+
+ Lists the frontend's custom domains, oldest first. Each domain either
+ serves the frontend or, with `redirect` set, redirects every request to
+ another domain of the frontend.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendCustomDomainList]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Error | FrontendCustomDomainList | None:
+ """ List a frontend's custom domains
+
+ Lists the frontend's custom domains, oldest first. Each domain either
+ serves the frontend or, with `redirect` set, redirects every request to
+ another domain of the frontend.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendCustomDomainList
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+frontend_id=frontend_id,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/frontends/list_frontend_routes.py b/src/volcano_sdk/_generated/api/frontends/list_frontend_routes.py
new file mode 100644
index 00000000..a8bcbae1
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/frontends/list_frontend_routes.py
@@ -0,0 +1,207 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.frontend_route_list import FrontendRouteList
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ frontend_id: UUID | str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/projects/{id}/frontends/{frontend_id}/frontend-routes".format(id=quote(str(id), safe=""),frontend_id=quote(str(frontend_id), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | FrontendRouteList | None:
+ if response.status_code == 200:
+ response_200 = FrontendRouteList.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | FrontendRouteList]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Error | FrontendRouteList]:
+ """ List a Frontend's Frontend routes
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendRouteList]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Error | FrontendRouteList | None:
+ """ List a Frontend's Frontend routes
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendRouteList
+ """
+
+
+ return sync_detailed(
+ id=id,
+frontend_id=frontend_id,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Error | FrontendRouteList]:
+ """ List a Frontend's Frontend routes
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendRouteList]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Error | FrontendRouteList | None:
+ """ List a Frontend's Frontend routes
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendRouteList
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+frontend_id=frontend_id,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/frontends/promote_frontend_candidate.py b/src/volcano_sdk/_generated/api/frontends/promote_frontend_candidate.py
new file mode 100644
index 00000000..bef7b52f
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/frontends/promote_frontend_candidate.py
@@ -0,0 +1,328 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.frontend_serving import FrontendServing
+from ...models.promote_frontend_candidate_body import PromoteFrontendCandidateBody
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+ *,
+ body: PromoteFrontendCandidateBody,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/projects/{id}/frontends/{frontend_id}/candidates/{candidate_id}/promote".format(id=quote(str(id), safe=""),frontend_id=quote(str(frontend_id), safe=""),candidate_id=quote(str(candidate_id), safe=""),),
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | FrontendServing | None:
+ if response.status_code == 200:
+ response_200 = FrontendServing.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 413:
+ response_413 = Error.from_dict(response.json())
+
+
+
+ return response_413
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | FrontendServing]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: PromoteFrontendCandidateBody,
+
+) -> Response[Error | FrontendServing]:
+ """ Promote a frontend Candidate
+
+ Makes the Candidate what the frontend serves. Nothing is rebuilt or copied: the frontend's
+ traffic is routed to the Candidate's runtime, its own custom domains and metering are
+ unchanged, and what it served becomes the runtime a rollback returns to.
+
+ The Candidate must be ready and serving an active deployment, and that deployment must have
+ been built with the variables the frontend selects now. A Candidate that serves stops expiring and
+ cannot be deleted. While one
+ serves, deploying the frontend itself answers `409`; roll back to the frontend's own runtime
+ first. Promotion names the revision the caller read from `serving`; a competing activation
+ makes it fail with `409`. Once the project's repository is the source of truth, promotion
+ is refused with `409`, as a direct deploy is, and so is rolling back to a Candidate; rolling
+ back to the frontend's own runtime is not. While the `frontends.candidates` capability is
+ unavailable, promotion and rolling back to a Candidate answer `404` with code
+ `feature_unavailable`; rolling back to the frontend's own runtime does not.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ candidate_id (UUID):
+ body (PromoteFrontendCandidateBody):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendServing]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+candidate_id=candidate_id,
+body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: PromoteFrontendCandidateBody,
+
+) -> Error | FrontendServing | None:
+ """ Promote a frontend Candidate
+
+ Makes the Candidate what the frontend serves. Nothing is rebuilt or copied: the frontend's
+ traffic is routed to the Candidate's runtime, its own custom domains and metering are
+ unchanged, and what it served becomes the runtime a rollback returns to.
+
+ The Candidate must be ready and serving an active deployment, and that deployment must have
+ been built with the variables the frontend selects now. A Candidate that serves stops expiring and
+ cannot be deleted. While one
+ serves, deploying the frontend itself answers `409`; roll back to the frontend's own runtime
+ first. Promotion names the revision the caller read from `serving`; a competing activation
+ makes it fail with `409`. Once the project's repository is the source of truth, promotion
+ is refused with `409`, as a direct deploy is, and so is rolling back to a Candidate; rolling
+ back to the frontend's own runtime is not. While the `frontends.candidates` capability is
+ unavailable, promotion and rolling back to a Candidate answer `404` with code
+ `feature_unavailable`; rolling back to the frontend's own runtime does not.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ candidate_id (UUID):
+ body (PromoteFrontendCandidateBody):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendServing
+ """
+
+
+ return sync_detailed(
+ id=id,
+frontend_id=frontend_id,
+candidate_id=candidate_id,
+client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: PromoteFrontendCandidateBody,
+
+) -> Response[Error | FrontendServing]:
+ """ Promote a frontend Candidate
+
+ Makes the Candidate what the frontend serves. Nothing is rebuilt or copied: the frontend's
+ traffic is routed to the Candidate's runtime, its own custom domains and metering are
+ unchanged, and what it served becomes the runtime a rollback returns to.
+
+ The Candidate must be ready and serving an active deployment, and that deployment must have
+ been built with the variables the frontend selects now. A Candidate that serves stops expiring and
+ cannot be deleted. While one
+ serves, deploying the frontend itself answers `409`; roll back to the frontend's own runtime
+ first. Promotion names the revision the caller read from `serving`; a competing activation
+ makes it fail with `409`. Once the project's repository is the source of truth, promotion
+ is refused with `409`, as a direct deploy is, and so is rolling back to a Candidate; rolling
+ back to the frontend's own runtime is not. While the `frontends.candidates` capability is
+ unavailable, promotion and rolling back to a Candidate answer `404` with code
+ `feature_unavailable`; rolling back to the frontend's own runtime does not.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ candidate_id (UUID):
+ body (PromoteFrontendCandidateBody):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendServing]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+candidate_id=candidate_id,
+body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: PromoteFrontendCandidateBody,
+
+) -> Error | FrontendServing | None:
+ """ Promote a frontend Candidate
+
+ Makes the Candidate what the frontend serves. Nothing is rebuilt or copied: the frontend's
+ traffic is routed to the Candidate's runtime, its own custom domains and metering are
+ unchanged, and what it served becomes the runtime a rollback returns to.
+
+ The Candidate must be ready and serving an active deployment, and that deployment must have
+ been built with the variables the frontend selects now. A Candidate that serves stops expiring and
+ cannot be deleted. While one
+ serves, deploying the frontend itself answers `409`; roll back to the frontend's own runtime
+ first. Promotion names the revision the caller read from `serving`; a competing activation
+ makes it fail with `409`. Once the project's repository is the source of truth, promotion
+ is refused with `409`, as a direct deploy is, and so is rolling back to a Candidate; rolling
+ back to the frontend's own runtime is not. While the `frontends.candidates` capability is
+ unavailable, promotion and rolling back to a Candidate answer `404` with code
+ `feature_unavailable`; rolling back to the frontend's own runtime does not.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ candidate_id (UUID):
+ body (PromoteFrontendCandidateBody):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendServing
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+frontend_id=frontend_id,
+candidate_id=candidate_id,
+client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/frontends/redeploy_frontend_candidate.py b/src/volcano_sdk/_generated/api/frontends/redeploy_frontend_candidate.py
new file mode 100644
index 00000000..f8bc0497
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/frontends/redeploy_frontend_candidate.py
@@ -0,0 +1,306 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.frontend_candidate_deployment import FrontendCandidateDeployment
+from ...models.redeploy_frontend_candidate_body import RedeployFrontendCandidateBody
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+ *,
+ body: RedeployFrontendCandidateBody,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/projects/{id}/frontends/{frontend_id}/candidates/{candidate_id}/deployments".format(id=quote(str(id), safe=""),frontend_id=quote(str(frontend_id), safe=""),candidate_id=quote(str(candidate_id), safe=""),),
+ }
+
+ _kwargs["files"] = body.to_multipart()
+
+ headers["Content-Type"] = "multipart/form-data; boundary=+++"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | FrontendCandidateDeployment | None:
+ if response.status_code == 202:
+ response_202 = FrontendCandidateDeployment.from_dict(response.json())
+
+
+
+ return response_202
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 413:
+ response_413 = Error.from_dict(response.json())
+
+
+
+ return response_413
+
+ if response.status_code == 429:
+ response_429 = Error.from_dict(response.json())
+
+
+
+ return response_429
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if response.status_code == 503:
+ response_503 = Error.from_dict(response.json())
+
+
+
+ return response_503
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | FrontendCandidateDeployment]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: RedeployFrontendCandidateBody,
+
+) -> Response[Error | FrontendCandidateDeployment]:
+ """ Deploy a new archive to a frontend Candidate
+
+ Builds the uploaded archive with the frontend's own variable selection and deploys it to the
+ Candidate. The Candidate keeps serving its previous deployment until this one succeeds, and a
+ failed deployment leaves it on the previous one. A Candidate takes one deployment at a time.
+ While the `frontends.candidates` capability is unavailable, it answers `404` with code
+ `feature_unavailable`.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ candidate_id (UUID):
+ body (RedeployFrontendCandidateBody):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendCandidateDeployment]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+candidate_id=candidate_id,
+body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: RedeployFrontendCandidateBody,
+
+) -> Error | FrontendCandidateDeployment | None:
+ """ Deploy a new archive to a frontend Candidate
+
+ Builds the uploaded archive with the frontend's own variable selection and deploys it to the
+ Candidate. The Candidate keeps serving its previous deployment until this one succeeds, and a
+ failed deployment leaves it on the previous one. A Candidate takes one deployment at a time.
+ While the `frontends.candidates` capability is unavailable, it answers `404` with code
+ `feature_unavailable`.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ candidate_id (UUID):
+ body (RedeployFrontendCandidateBody):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendCandidateDeployment
+ """
+
+
+ return sync_detailed(
+ id=id,
+frontend_id=frontend_id,
+candidate_id=candidate_id,
+client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: RedeployFrontendCandidateBody,
+
+) -> Response[Error | FrontendCandidateDeployment]:
+ """ Deploy a new archive to a frontend Candidate
+
+ Builds the uploaded archive with the frontend's own variable selection and deploys it to the
+ Candidate. The Candidate keeps serving its previous deployment until this one succeeds, and a
+ failed deployment leaves it on the previous one. A Candidate takes one deployment at a time.
+ While the `frontends.candidates` capability is unavailable, it answers `404` with code
+ `feature_unavailable`.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ candidate_id (UUID):
+ body (RedeployFrontendCandidateBody):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendCandidateDeployment]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+candidate_id=candidate_id,
+body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ candidate_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: RedeployFrontendCandidateBody,
+
+) -> Error | FrontendCandidateDeployment | None:
+ """ Deploy a new archive to a frontend Candidate
+
+ Builds the uploaded archive with the frontend's own variable selection and deploys it to the
+ Candidate. The Candidate keeps serving its previous deployment until this one succeeds, and a
+ failed deployment leaves it on the previous one. A Candidate takes one deployment at a time.
+ While the `frontends.candidates` capability is unavailable, it answers `404` with code
+ `feature_unavailable`.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ candidate_id (UUID):
+ body (RedeployFrontendCandidateBody):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendCandidateDeployment
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+frontend_id=frontend_id,
+candidate_id=candidate_id,
+client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/frontends/rollback_frontend_serving.py b/src/volcano_sdk/_generated/api/frontends/rollback_frontend_serving.py
new file mode 100644
index 00000000..c46de922
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/frontends/rollback_frontend_serving.py
@@ -0,0 +1,287 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.frontend_serving import FrontendServing
+from ...models.rollback_frontend_serving_body import RollbackFrontendServingBody
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ body: RollbackFrontendServingBody,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/projects/{id}/frontends/{frontend_id}/serving/rollback".format(id=quote(str(id), safe=""),frontend_id=quote(str(frontend_id), safe=""),),
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | FrontendServing | None:
+ if response.status_code == 200:
+ response_200 = FrontendServing.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 413:
+ response_413 = Error.from_dict(response.json())
+
+
+
+ return response_413
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | FrontendServing]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: RollbackFrontendServingBody,
+
+) -> Response[Error | FrontendServing]:
+ """ Roll a frontend back to the runtime it served before
+
+ Returns the frontend's traffic to the runtime it served before the last activation, or to its
+ own runtime with `to_production`. A rollback is a new activation, so what it leaves becomes the
+ runtime a further rollback returns to, and it can itself be undone. It names the revision the
+ caller read; a competing activation makes it fail with `409`.
+
+ Rolling back to a Candidate promotes it again and is refused with `409` when promoting it would
+ be. Rolling back to the frontend's own runtime is not.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (RollbackFrontendServingBody):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendServing]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: RollbackFrontendServingBody,
+
+) -> Error | FrontendServing | None:
+ """ Roll a frontend back to the runtime it served before
+
+ Returns the frontend's traffic to the runtime it served before the last activation, or to its
+ own runtime with `to_production`. A rollback is a new activation, so what it leaves becomes the
+ runtime a further rollback returns to, and it can itself be undone. It names the revision the
+ caller read; a competing activation makes it fail with `409`.
+
+ Rolling back to a Candidate promotes it again and is refused with `409` when promoting it would
+ be. Rolling back to the frontend's own runtime is not.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (RollbackFrontendServingBody):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendServing
+ """
+
+
+ return sync_detailed(
+ id=id,
+frontend_id=frontend_id,
+client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: RollbackFrontendServingBody,
+
+) -> Response[Error | FrontendServing]:
+ """ Roll a frontend back to the runtime it served before
+
+ Returns the frontend's traffic to the runtime it served before the last activation, or to its
+ own runtime with `to_production`. A rollback is a new activation, so what it leaves becomes the
+ runtime a further rollback returns to, and it can itself be undone. It names the revision the
+ caller read; a competing activation makes it fail with `409`.
+
+ Rolling back to a Candidate promotes it again and is refused with `409` when promoting it would
+ be. Rolling back to the frontend's own runtime is not.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (RollbackFrontendServingBody):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendServing]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: RollbackFrontendServingBody,
+
+) -> Error | FrontendServing | None:
+ """ Roll a frontend back to the runtime it served before
+
+ Returns the frontend's traffic to the runtime it served before the last activation, or to its
+ own runtime with `to_production`. A rollback is a new activation, so what it leaves becomes the
+ runtime a further rollback returns to, and it can itself be undone. It names the revision the
+ caller read; a competing activation makes it fail with `409`.
+
+ Rolling back to a Candidate promotes it again and is refused with `409` when promoting it would
+ be. Rolling back to the frontend's own runtime is not.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ body (RollbackFrontendServingBody):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendServing
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+frontend_id=frontend_id,
+client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/frontends/update_frontend_domain.py b/src/volcano_sdk/_generated/api/frontends/update_frontend_domain.py
new file mode 100644
index 00000000..c5a1a46c
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/frontends/update_frontend_domain.py
@@ -0,0 +1,285 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.frontend_custom_domain_response import FrontendCustomDomainResponse
+from ...models.update_frontend_custom_domain_request import UpdateFrontendCustomDomainRequest
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ domain: str,
+ *,
+ body: UpdateFrontendCustomDomainRequest,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "patch",
+ "url": "/projects/{id}/frontends/{frontend_id}/domains/{domain}".format(id=quote(str(id), safe=""),frontend_id=quote(str(frontend_id), safe=""),domain=quote(str(domain), safe=""),),
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | FrontendCustomDomainResponse | None:
+ if response.status_code == 200:
+ response_200 = FrontendCustomDomainResponse.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | FrontendCustomDomainResponse]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ domain: str,
+ *,
+ client: AuthenticatedClient,
+ body: UpdateFrontendCustomDomainRequest,
+
+) -> Response[Error | FrontendCustomDomainResponse]:
+ """ Set or clear a custom domain's redirect
+
+ `{"redirect": {"to": "www.example.com", "status": 308}}` makes the
+ domain redirect to another active domain of the frontend that serves it.
+ `{"redirect": null}` makes it serve the frontend again. A domain other
+ domains redirect to cannot become a redirect itself. `status` defaults
+ to `308`. Proxies apply the change within seconds.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ domain (str):
+ body (UpdateFrontendCustomDomainRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendCustomDomainResponse]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+domain=domain,
+body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ domain: str,
+ *,
+ client: AuthenticatedClient,
+ body: UpdateFrontendCustomDomainRequest,
+
+) -> Error | FrontendCustomDomainResponse | None:
+ """ Set or clear a custom domain's redirect
+
+ `{"redirect": {"to": "www.example.com", "status": 308}}` makes the
+ domain redirect to another active domain of the frontend that serves it.
+ `{"redirect": null}` makes it serve the frontend again. A domain other
+ domains redirect to cannot become a redirect itself. `status` defaults
+ to `308`. Proxies apply the change within seconds.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ domain (str):
+ body (UpdateFrontendCustomDomainRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendCustomDomainResponse
+ """
+
+
+ return sync_detailed(
+ id=id,
+frontend_id=frontend_id,
+domain=domain,
+client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ domain: str,
+ *,
+ client: AuthenticatedClient,
+ body: UpdateFrontendCustomDomainRequest,
+
+) -> Response[Error | FrontendCustomDomainResponse]:
+ """ Set or clear a custom domain's redirect
+
+ `{"redirect": {"to": "www.example.com", "status": 308}}` makes the
+ domain redirect to another active domain of the frontend that serves it.
+ `{"redirect": null}` makes it serve the frontend again. A domain other
+ domains redirect to cannot become a redirect itself. `status` defaults
+ to `308`. Proxies apply the change within seconds.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ domain (str):
+ body (UpdateFrontendCustomDomainRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendCustomDomainResponse]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+domain=domain,
+body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ domain: str,
+ *,
+ client: AuthenticatedClient,
+ body: UpdateFrontendCustomDomainRequest,
+
+) -> Error | FrontendCustomDomainResponse | None:
+ """ Set or clear a custom domain's redirect
+
+ `{"redirect": {"to": "www.example.com", "status": 308}}` makes the
+ domain redirect to another active domain of the frontend that serves it.
+ `{"redirect": null}` makes it serve the frontend again. A domain other
+ domains redirect to cannot become a redirect itself. `status` defaults
+ to `308`. Proxies apply the change within seconds.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ domain (str):
+ body (UpdateFrontendCustomDomainRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendCustomDomainResponse
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+frontend_id=frontend_id,
+domain=domain,
+client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/frontends/update_frontend_route.py b/src/volcano_sdk/_generated/api/frontends/update_frontend_route.py
new file mode 100644
index 00000000..c67bb52e
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/frontends/update_frontend_route.py
@@ -0,0 +1,273 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.create_frontend_route_request import CreateFrontendRouteRequest
+from ...models.error import Error
+from ...models.frontend_route import FrontendRoute
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ route_id: UUID | str,
+ *,
+ body: CreateFrontendRouteRequest,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "put",
+ "url": "/projects/{id}/frontends/{frontend_id}/frontend-routes/{route_id}".format(id=quote(str(id), safe=""),frontend_id=quote(str(frontend_id), safe=""),route_id=quote(str(route_id), safe=""),),
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | FrontendRoute | None:
+ if response.status_code == 200:
+ response_200 = FrontendRoute.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | FrontendRoute]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ route_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendRouteRequest,
+
+) -> Response[Error | FrontendRoute]:
+ """ Replace a Frontend route
+
+ Replaces the route's mounted Frontend and path. The new values must meet the same rules as on
+ create.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ route_id (UUID):
+ body (CreateFrontendRouteRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendRoute]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+route_id=route_id,
+body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ route_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendRouteRequest,
+
+) -> Error | FrontendRoute | None:
+ """ Replace a Frontend route
+
+ Replaces the route's mounted Frontend and path. The new values must meet the same rules as on
+ create.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ route_id (UUID):
+ body (CreateFrontendRouteRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendRoute
+ """
+
+
+ return sync_detailed(
+ id=id,
+frontend_id=frontend_id,
+route_id=route_id,
+client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ route_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendRouteRequest,
+
+) -> Response[Error | FrontendRoute]:
+ """ Replace a Frontend route
+
+ Replaces the route's mounted Frontend and path. The new values must meet the same rules as on
+ create.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ route_id (UUID):
+ body (CreateFrontendRouteRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | FrontendRoute]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+frontend_id=frontend_id,
+route_id=route_id,
+body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ frontend_id: UUID | str,
+ route_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: CreateFrontendRouteRequest,
+
+) -> Error | FrontendRoute | None:
+ """ Replace a Frontend route
+
+ Replaces the route's mounted Frontend and path. The new values must meet the same rules as on
+ create.
+
+ Args:
+ id (UUID):
+ frontend_id (UUID):
+ route_id (UUID):
+ body (CreateFrontendRouteRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | FrontendRoute
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+frontend_id=frontend_id,
+route_id=route_id,
+client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/functions/resolve_function_for_invocation.py b/src/volcano_sdk/_generated/api/functions/resolve_function_for_invocation.py
index 72f69adc..e4deebab 100644
--- a/src/volcano_sdk/_generated/api/functions/resolve_function_for_invocation.py
+++ b/src/volcano_sdk/_generated/api/functions/resolve_function_for_invocation.py
@@ -105,9 +105,10 @@ def sync_detailed(
SDKs use this endpoint internally to invoke by function name while routing by function ID.
Invoke the returned `invoke_url` as-is. It does not share a domain with the API, so a host
- built from the API URL will not reach the function. When the deployment serves no public
- invocation domain, as in local development, `invoke_url` is omitted and callers invoke
- through `POST /functions/{functionId}/invoke`.
+ built from the API URL will not reach the function. In local development, and when the
+ deployment serves no public invocation domain, `invoke_url` is omitted and callers invoke
+ through `POST /functions/{functionId}/invoke`. A local function's own `invoke_url`, for
+ webhook testing, is on the function resource.
**With Service Key**:
- Allowed
@@ -155,9 +156,10 @@ def sync(
SDKs use this endpoint internally to invoke by function name while routing by function ID.
Invoke the returned `invoke_url` as-is. It does not share a domain with the API, so a host
- built from the API URL will not reach the function. When the deployment serves no public
- invocation domain, as in local development, `invoke_url` is omitted and callers invoke
- through `POST /functions/{functionId}/invoke`.
+ built from the API URL will not reach the function. In local development, and when the
+ deployment serves no public invocation domain, `invoke_url` is omitted and callers invoke
+ through `POST /functions/{functionId}/invoke`. A local function's own `invoke_url`, for
+ webhook testing, is on the function resource.
**With Service Key**:
- Allowed
@@ -200,9 +202,10 @@ async def asyncio_detailed(
SDKs use this endpoint internally to invoke by function name while routing by function ID.
Invoke the returned `invoke_url` as-is. It does not share a domain with the API, so a host
- built from the API URL will not reach the function. When the deployment serves no public
- invocation domain, as in local development, `invoke_url` is omitted and callers invoke
- through `POST /functions/{functionId}/invoke`.
+ built from the API URL will not reach the function. In local development, and when the
+ deployment serves no public invocation domain, `invoke_url` is omitted and callers invoke
+ through `POST /functions/{functionId}/invoke`. A local function's own `invoke_url`, for
+ webhook testing, is on the function resource.
**With Service Key**:
- Allowed
@@ -250,9 +253,10 @@ async def asyncio(
SDKs use this endpoint internally to invoke by function name while routing by function ID.
Invoke the returned `invoke_url` as-is. It does not share a domain with the API, so a host
- built from the API URL will not reach the function. When the deployment serves no public
- invocation domain, as in local development, `invoke_url` is omitted and callers invoke
- through `POST /functions/{functionId}/invoke`.
+ built from the API URL will not reach the function. In local development, and when the
+ deployment serves no public invocation domain, `invoke_url` is omitted and callers invoke
+ through `POST /functions/{functionId}/invoke`. A local function's own `invoke_url`, for
+ webhook testing, is on the function resource.
**With Service Key**:
- Allowed
diff --git a/src/volcano_sdk/_generated/api/git_connections/git_connect_callback.py b/src/volcano_sdk/_generated/api/git_connections/git_connect_callback.py
index 99363251..84222f23 100644
--- a/src/volcano_sdk/_generated/api/git_connections/git_connect_callback.py
+++ b/src/volcano_sdk/_generated/api/git_connections/git_connect_callback.py
@@ -17,8 +17,10 @@
def request_kwargs(
*,
code: str | Unset = UNSET,
- state: str,
+ state: str | Unset = UNSET,
error: str | Unset = UNSET,
+ installation_id: str | Unset = UNSET,
+ setup_action: str | Unset = UNSET,
) -> dict[str, Any]:
@@ -33,6 +35,10 @@ def request_kwargs(
params["error"] = error
+ params["installation_id"] = installation_id
+
+ params["setup_action"] = setup_action
+
params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
@@ -49,6 +55,10 @@ def request_kwargs(
def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | Error | None:
+ if response.status_code == 302:
+ response_302 = cast(Any, None)
+ return response_302
+
if response.status_code == 303:
response_303 = cast(Any, None)
return response_303
@@ -100,8 +110,10 @@ def sync_detailed(
*,
client: AuthenticatedClient | Client,
code: str | Unset = UNSET,
- state: str,
+ state: str | Unset = UNSET,
error: str | Unset = UNSET,
+ installation_id: str | Unset = UNSET,
+ setup_action: str | Unset = UNSET,
) -> Response[Any | Error]:
""" Complete a GitHub App connection callback
@@ -109,10 +121,20 @@ def sync_detailed(
Public GitHub App callback. The signed state and callback binding cookie
bind the provider authorization to the browser that started the flow.
+ GitHub also sends a browser here without `state` when someone installs
+ the App, changes its repository access, or asks an organization owner
+ to install it, on GitHub itself. That request connects nothing: Volcano
+ ignores `code` and `installation_id`, and redirects to the dashboard's
+ Git settings page when `setup_action` is `install`, `update`, or
+ `request`. Any other request without `state` returns 400. An empty or
+ invalid `state` is refused as before and never redirects there.
+
Args:
code (str | Unset):
- state (str):
+ state (str | Unset):
error (str | Unset):
+ installation_id (str | Unset):
+ setup_action (str | Unset):
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -127,6 +149,8 @@ def sync_detailed(
code=code,
state=state,
error=error,
+installation_id=installation_id,
+setup_action=setup_action,
)
@@ -140,8 +164,10 @@ def sync(
*,
client: AuthenticatedClient | Client,
code: str | Unset = UNSET,
- state: str,
+ state: str | Unset = UNSET,
error: str | Unset = UNSET,
+ installation_id: str | Unset = UNSET,
+ setup_action: str | Unset = UNSET,
) -> Any | Error | None:
""" Complete a GitHub App connection callback
@@ -149,10 +175,20 @@ def sync(
Public GitHub App callback. The signed state and callback binding cookie
bind the provider authorization to the browser that started the flow.
+ GitHub also sends a browser here without `state` when someone installs
+ the App, changes its repository access, or asks an organization owner
+ to install it, on GitHub itself. That request connects nothing: Volcano
+ ignores `code` and `installation_id`, and redirects to the dashboard's
+ Git settings page when `setup_action` is `install`, `update`, or
+ `request`. Any other request without `state` returns 400. An empty or
+ invalid `state` is refused as before and never redirects there.
+
Args:
code (str | Unset):
- state (str):
+ state (str | Unset):
error (str | Unset):
+ installation_id (str | Unset):
+ setup_action (str | Unset):
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -168,6 +204,8 @@ def sync(
code=code,
state=state,
error=error,
+installation_id=installation_id,
+setup_action=setup_action,
).parsed
@@ -175,8 +213,10 @@ async def asyncio_detailed(
*,
client: AuthenticatedClient | Client,
code: str | Unset = UNSET,
- state: str,
+ state: str | Unset = UNSET,
error: str | Unset = UNSET,
+ installation_id: str | Unset = UNSET,
+ setup_action: str | Unset = UNSET,
) -> Response[Any | Error]:
""" Complete a GitHub App connection callback
@@ -184,10 +224,20 @@ async def asyncio_detailed(
Public GitHub App callback. The signed state and callback binding cookie
bind the provider authorization to the browser that started the flow.
+ GitHub also sends a browser here without `state` when someone installs
+ the App, changes its repository access, or asks an organization owner
+ to install it, on GitHub itself. That request connects nothing: Volcano
+ ignores `code` and `installation_id`, and redirects to the dashboard's
+ Git settings page when `setup_action` is `install`, `update`, or
+ `request`. Any other request without `state` returns 400. An empty or
+ invalid `state` is refused as before and never redirects there.
+
Args:
code (str | Unset):
- state (str):
+ state (str | Unset):
error (str | Unset):
+ installation_id (str | Unset):
+ setup_action (str | Unset):
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -202,6 +252,8 @@ async def asyncio_detailed(
code=code,
state=state,
error=error,
+installation_id=installation_id,
+setup_action=setup_action,
)
@@ -215,8 +267,10 @@ async def asyncio(
*,
client: AuthenticatedClient | Client,
code: str | Unset = UNSET,
- state: str,
+ state: str | Unset = UNSET,
error: str | Unset = UNSET,
+ installation_id: str | Unset = UNSET,
+ setup_action: str | Unset = UNSET,
) -> Any | Error | None:
""" Complete a GitHub App connection callback
@@ -224,10 +278,20 @@ async def asyncio(
Public GitHub App callback. The signed state and callback binding cookie
bind the provider authorization to the browser that started the flow.
+ GitHub also sends a browser here without `state` when someone installs
+ the App, changes its repository access, or asks an organization owner
+ to install it, on GitHub itself. That request connects nothing: Volcano
+ ignores `code` and `installation_id`, and redirects to the dashboard's
+ Git settings page when `setup_action` is `install`, `update`, or
+ `request`. Any other request without `state` returns 400. An empty or
+ invalid `state` is refused as before and never redirects there.
+
Args:
code (str | Unset):
- state (str):
+ state (str | Unset):
error (str | Unset):
+ installation_id (str | Unset):
+ setup_action (str | Unset):
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -243,5 +307,7 @@ async def asyncio(
code=code,
state=state,
error=error,
+installation_id=installation_id,
+setup_action=setup_action,
)).parsed
diff --git a/src/volcano_sdk/_generated/api/issues/list_issues.py b/src/volcano_sdk/_generated/api/issues/list_issues.py
index cdfbeef0..e4919f53 100644
--- a/src/volcano_sdk/_generated/api/issues/list_issues.py
+++ b/src/volcano_sdk/_generated/api/issues/list_issues.py
@@ -124,7 +124,9 @@ def sync_detailed(
cursor (str | Unset):
status (IssueStatus | Unset): `open` until someone resolves or ignores the issue. A
resolved issue
- seen again reopens.
+ seen again reopens. A reported problem resolves when its LavaFlow fix
+ merges. Volcano ignores one whose report it deleted before any fix
+ merged, so it no longer counts toward the project's open issues.
resource_id (UUID | Unset):
Raises:
@@ -175,7 +177,9 @@ def sync(
cursor (str | Unset):
status (IssueStatus | Unset): `open` until someone resolves or ignores the issue. A
resolved issue
- seen again reopens.
+ seen again reopens. A reported problem resolves when its LavaFlow fix
+ merges. Volcano ignores one whose report it deleted before any fix
+ merged, so it no longer counts toward the project's open issues.
resource_id (UUID | Unset):
Raises:
@@ -221,7 +225,9 @@ async def asyncio_detailed(
cursor (str | Unset):
status (IssueStatus | Unset): `open` until someone resolves or ignores the issue. A
resolved issue
- seen again reopens.
+ seen again reopens. A reported problem resolves when its LavaFlow fix
+ merges. Volcano ignores one whose report it deleted before any fix
+ merged, so it no longer counts toward the project's open issues.
resource_id (UUID | Unset):
Raises:
@@ -272,7 +278,9 @@ async def asyncio(
cursor (str | Unset):
status (IssueStatus | Unset): `open` until someone resolves or ignores the issue. A
resolved issue
- seen again reopens.
+ seen again reopens. A reported problem resolves when its LavaFlow fix
+ merges. Volcano ignores one whose report it deleted before any fix
+ merged, so it no longer counts toward the project's open issues.
resource_id (UUID | Unset):
Raises:
diff --git a/src/volcano_sdk/_generated/api/lava_flow/__init__.py b/src/volcano_sdk/_generated/api/lava_flow/__init__.py
new file mode 100644
index 00000000..c9921b5f
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/__init__.py
@@ -0,0 +1 @@
+""" Contains endpoint functions for accessing the API """
diff --git a/src/volcano_sdk/_generated/api/lava_flow/create_lavaflow_connector_binding.py b/src/volcano_sdk/_generated/api/lava_flow/create_lavaflow_connector_binding.py
new file mode 100644
index 00000000..26690d4b
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/create_lavaflow_connector_binding.py
@@ -0,0 +1,297 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.lavaflow_connector_binding import LavaflowConnectorBinding
+from ...models.lavaflow_connector_binding_create import LavaflowConnectorBindingCreate
+from typing import cast
+
+
+
+def request_kwargs(
+ *,
+ body: LavaflowConnectorBindingCreate,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/lavaflow/connector-bindings",
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | LavaflowConnectorBinding | None:
+ if response.status_code == 200:
+ response_200 = LavaflowConnectorBinding.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 201:
+ response_201 = LavaflowConnectorBinding.from_dict(response.json())
+
+
+
+ return response_201
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 502:
+ response_502 = Error.from_dict(response.json())
+
+
+
+ return response_502
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | LavaflowConnectorBinding]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowConnectorBindingCreate,
+
+) -> Response[Error | LavaflowConnectorBinding]:
+ """ Bind a connector to the project
+
+ Binds a place in a connector to the project, so problems reported
+ there reach LavaFlow for it, and answers `201`. For a `slack`
+ connector the place is a channel. Binding a channel that is already
+ bound answers `200` with that binding, and makes the current owner the
+ one who bound it, so a retry is safe. One of the Slack identities the
+ caller's sign-in session signed in as must belong to the connector's
+ workspace and be a member of the channel, so on an account several
+ people share, each binds only channels they are in. The channel must
+ be one the picker (`GET /user/slack/channels`) lists: one the Volcano
+ app is in, and not archived, a Slack Connect channel, or shared
+ across an organization.
+
+ Only the project's owner can bind, with a platform token. A project
+ access token, or a request made through MCP, gets `403` with code
+ `person_required`. Binding a Slack channel needs the project's
+ `lavaflow.slack` capability: where it is unavailable, this answers
+ `404` with code `feature_unavailable`, or `403` with code
+ `plan_required` when the owner's plan does not include LavaFlow.
+
+ Args:
+ body (LavaflowConnectorBindingCreate):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowConnectorBinding]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowConnectorBindingCreate,
+
+) -> Error | LavaflowConnectorBinding | None:
+ """ Bind a connector to the project
+
+ Binds a place in a connector to the project, so problems reported
+ there reach LavaFlow for it, and answers `201`. For a `slack`
+ connector the place is a channel. Binding a channel that is already
+ bound answers `200` with that binding, and makes the current owner the
+ one who bound it, so a retry is safe. One of the Slack identities the
+ caller's sign-in session signed in as must belong to the connector's
+ workspace and be a member of the channel, so on an account several
+ people share, each binds only channels they are in. The channel must
+ be one the picker (`GET /user/slack/channels`) lists: one the Volcano
+ app is in, and not archived, a Slack Connect channel, or shared
+ across an organization.
+
+ Only the project's owner can bind, with a platform token. A project
+ access token, or a request made through MCP, gets `403` with code
+ `person_required`. Binding a Slack channel needs the project's
+ `lavaflow.slack` capability: where it is unavailable, this answers
+ `404` with code `feature_unavailable`, or `403` with code
+ `plan_required` when the owner's plan does not include LavaFlow.
+
+ Args:
+ body (LavaflowConnectorBindingCreate):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowConnectorBinding
+ """
+
+
+ return sync_detailed(
+ client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowConnectorBindingCreate,
+
+) -> Response[Error | LavaflowConnectorBinding]:
+ """ Bind a connector to the project
+
+ Binds a place in a connector to the project, so problems reported
+ there reach LavaFlow for it, and answers `201`. For a `slack`
+ connector the place is a channel. Binding a channel that is already
+ bound answers `200` with that binding, and makes the current owner the
+ one who bound it, so a retry is safe. One of the Slack identities the
+ caller's sign-in session signed in as must belong to the connector's
+ workspace and be a member of the channel, so on an account several
+ people share, each binds only channels they are in. The channel must
+ be one the picker (`GET /user/slack/channels`) lists: one the Volcano
+ app is in, and not archived, a Slack Connect channel, or shared
+ across an organization.
+
+ Only the project's owner can bind, with a platform token. A project
+ access token, or a request made through MCP, gets `403` with code
+ `person_required`. Binding a Slack channel needs the project's
+ `lavaflow.slack` capability: where it is unavailable, this answers
+ `404` with code `feature_unavailable`, or `403` with code
+ `plan_required` when the owner's plan does not include LavaFlow.
+
+ Args:
+ body (LavaflowConnectorBindingCreate):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowConnectorBinding]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowConnectorBindingCreate,
+
+) -> Error | LavaflowConnectorBinding | None:
+ """ Bind a connector to the project
+
+ Binds a place in a connector to the project, so problems reported
+ there reach LavaFlow for it, and answers `201`. For a `slack`
+ connector the place is a channel. Binding a channel that is already
+ bound answers `200` with that binding, and makes the current owner the
+ one who bound it, so a retry is safe. One of the Slack identities the
+ caller's sign-in session signed in as must belong to the connector's
+ workspace and be a member of the channel, so on an account several
+ people share, each binds only channels they are in. The channel must
+ be one the picker (`GET /user/slack/channels`) lists: one the Volcano
+ app is in, and not archived, a Slack Connect channel, or shared
+ across an organization.
+
+ Only the project's owner can bind, with a platform token. A project
+ access token, or a request made through MCP, gets `403` with code
+ `person_required`. Binding a Slack channel needs the project's
+ `lavaflow.slack` capability: where it is unavailable, this answers
+ `404` with code `feature_unavailable`, or `403` with code
+ `plan_required` when the owner's plan does not include LavaFlow.
+
+ Args:
+ body (LavaflowConnectorBindingCreate):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowConnectorBinding
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/lava_flow/create_lavaflow_held_fix_open.py b/src/volcano_sdk/_generated/api/lava_flow/create_lavaflow_held_fix_open.py
new file mode 100644
index 00000000..124818e0
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/create_lavaflow_held_fix_open.py
@@ -0,0 +1,403 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.lavaflow_held_fix_open import LavaflowHeldFixOpen
+from ...models.lavaflow_run import LavaflowRun
+from typing import cast
+
+
+
+def request_kwargs(
+ *,
+ body: LavaflowHeldFixOpen,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/lavaflow/held-fix-opens",
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | LavaflowRun | None:
+ if response.status_code == 202:
+ response_202 = LavaflowRun.from_dict(response.json())
+
+
+
+ return response_202
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 413:
+ response_413 = Error.from_dict(response.json())
+
+
+
+ return response_413
+
+ if response.status_code == 429:
+ response_429 = Error.from_dict(response.json())
+
+
+
+ return response_429
+
+ if response.status_code == 503:
+ response_503 = Error.from_dict(response.json())
+
+
+
+ return response_503
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | LavaflowRun]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowHeldFixOpen,
+
+) -> Response[Error | LavaflowRun]:
+ """ Open a held LavaFlow fix
+
+ Opens the pull request for a fix LavaFlow held because the
+ repository's workflows could run it with the repository's secrets
+ before a person approves it (`pull_request_skipped:
+ ungated_workflows`). Read the run first: send its `id` as `run_id`,
+ with the `diff_sha256` and `held_workflows.jobs_sha256` it served, to
+ say you read that diff and that list of jobs. LavaFlow opens the fix it
+ saved, exactly as reviewed, past those jobs only. It writes no new
+ fix.
+
+ Right before it queues the run, LavaFlow serves the diff again and
+ reads the workflows again. A diff served differently since you read
+ it, or a job list or a commit the workflows were read at that changed,
+ answers `409` with code `run_changed`; read the run again, which lists
+ what LavaFlow found. The response is the run, `202` while it is
+ `queued`. LavaFlow reads the workflows again before it opens the pull
+ request, and once more as it pushes the fix: a job you didn't read, a
+ new commit on a branch the workflows were read on, even one that
+ changes no job, or a production branch other than the one you read
+ them on holds the fix again with a new list.
+
+ Opening a fix lets its pull request open, nothing more. LavaFlow
+ starts no CI on it and never merges it, as for every fix opened past
+ ungated workflows; a person pushes to the branch or merges it. The
+ pull request's description names who opened it and lists the jobs.
+ One exception: when LavaFlow's read before the pull request opens
+ finds no job that runs the fix before a person approves it, because
+ the workflows were gated since you read them, the fix opens as any
+ other fix and follows the project's merge settings. A run whose
+ `held_workflows` lists no job opens the same way.
+
+ Only the project's owner can open a fix, as a person, while their
+ account is active: with a `volcano login` token
+ whose sign-in is live, or a platform token that expires. Their GitHub
+ account must be able to push to the project's repository. A project
+ access token, a request made through MCP, a platform token that never
+ expires, and a sign-in that ended get `403` with code
+ `person_required`. Opening a fix uses one of the run's attempts: the
+ attempt that opens it is one of the run's, so a run held again on its
+ last attempt can't be opened again. It starts no new run and counts
+ toward no run limit.
+
+ Args:
+ body (LavaflowHeldFixOpen): The project, the run, and the diff and jobs of the held fix
+ you read, by the digests the run served them with.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowRun]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowHeldFixOpen,
+
+) -> Error | LavaflowRun | None:
+ """ Open a held LavaFlow fix
+
+ Opens the pull request for a fix LavaFlow held because the
+ repository's workflows could run it with the repository's secrets
+ before a person approves it (`pull_request_skipped:
+ ungated_workflows`). Read the run first: send its `id` as `run_id`,
+ with the `diff_sha256` and `held_workflows.jobs_sha256` it served, to
+ say you read that diff and that list of jobs. LavaFlow opens the fix it
+ saved, exactly as reviewed, past those jobs only. It writes no new
+ fix.
+
+ Right before it queues the run, LavaFlow serves the diff again and
+ reads the workflows again. A diff served differently since you read
+ it, or a job list or a commit the workflows were read at that changed,
+ answers `409` with code `run_changed`; read the run again, which lists
+ what LavaFlow found. The response is the run, `202` while it is
+ `queued`. LavaFlow reads the workflows again before it opens the pull
+ request, and once more as it pushes the fix: a job you didn't read, a
+ new commit on a branch the workflows were read on, even one that
+ changes no job, or a production branch other than the one you read
+ them on holds the fix again with a new list.
+
+ Opening a fix lets its pull request open, nothing more. LavaFlow
+ starts no CI on it and never merges it, as for every fix opened past
+ ungated workflows; a person pushes to the branch or merges it. The
+ pull request's description names who opened it and lists the jobs.
+ One exception: when LavaFlow's read before the pull request opens
+ finds no job that runs the fix before a person approves it, because
+ the workflows were gated since you read them, the fix opens as any
+ other fix and follows the project's merge settings. A run whose
+ `held_workflows` lists no job opens the same way.
+
+ Only the project's owner can open a fix, as a person, while their
+ account is active: with a `volcano login` token
+ whose sign-in is live, or a platform token that expires. Their GitHub
+ account must be able to push to the project's repository. A project
+ access token, a request made through MCP, a platform token that never
+ expires, and a sign-in that ended get `403` with code
+ `person_required`. Opening a fix uses one of the run's attempts: the
+ attempt that opens it is one of the run's, so a run held again on its
+ last attempt can't be opened again. It starts no new run and counts
+ toward no run limit.
+
+ Args:
+ body (LavaflowHeldFixOpen): The project, the run, and the diff and jobs of the held fix
+ you read, by the digests the run served them with.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowRun
+ """
+
+
+ return sync_detailed(
+ client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowHeldFixOpen,
+
+) -> Response[Error | LavaflowRun]:
+ """ Open a held LavaFlow fix
+
+ Opens the pull request for a fix LavaFlow held because the
+ repository's workflows could run it with the repository's secrets
+ before a person approves it (`pull_request_skipped:
+ ungated_workflows`). Read the run first: send its `id` as `run_id`,
+ with the `diff_sha256` and `held_workflows.jobs_sha256` it served, to
+ say you read that diff and that list of jobs. LavaFlow opens the fix it
+ saved, exactly as reviewed, past those jobs only. It writes no new
+ fix.
+
+ Right before it queues the run, LavaFlow serves the diff again and
+ reads the workflows again. A diff served differently since you read
+ it, or a job list or a commit the workflows were read at that changed,
+ answers `409` with code `run_changed`; read the run again, which lists
+ what LavaFlow found. The response is the run, `202` while it is
+ `queued`. LavaFlow reads the workflows again before it opens the pull
+ request, and once more as it pushes the fix: a job you didn't read, a
+ new commit on a branch the workflows were read on, even one that
+ changes no job, or a production branch other than the one you read
+ them on holds the fix again with a new list.
+
+ Opening a fix lets its pull request open, nothing more. LavaFlow
+ starts no CI on it and never merges it, as for every fix opened past
+ ungated workflows; a person pushes to the branch or merges it. The
+ pull request's description names who opened it and lists the jobs.
+ One exception: when LavaFlow's read before the pull request opens
+ finds no job that runs the fix before a person approves it, because
+ the workflows were gated since you read them, the fix opens as any
+ other fix and follows the project's merge settings. A run whose
+ `held_workflows` lists no job opens the same way.
+
+ Only the project's owner can open a fix, as a person, while their
+ account is active: with a `volcano login` token
+ whose sign-in is live, or a platform token that expires. Their GitHub
+ account must be able to push to the project's repository. A project
+ access token, a request made through MCP, a platform token that never
+ expires, and a sign-in that ended get `403` with code
+ `person_required`. Opening a fix uses one of the run's attempts: the
+ attempt that opens it is one of the run's, so a run held again on its
+ last attempt can't be opened again. It starts no new run and counts
+ toward no run limit.
+
+ Args:
+ body (LavaflowHeldFixOpen): The project, the run, and the diff and jobs of the held fix
+ you read, by the digests the run served them with.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowRun]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowHeldFixOpen,
+
+) -> Error | LavaflowRun | None:
+ """ Open a held LavaFlow fix
+
+ Opens the pull request for a fix LavaFlow held because the
+ repository's workflows could run it with the repository's secrets
+ before a person approves it (`pull_request_skipped:
+ ungated_workflows`). Read the run first: send its `id` as `run_id`,
+ with the `diff_sha256` and `held_workflows.jobs_sha256` it served, to
+ say you read that diff and that list of jobs. LavaFlow opens the fix it
+ saved, exactly as reviewed, past those jobs only. It writes no new
+ fix.
+
+ Right before it queues the run, LavaFlow serves the diff again and
+ reads the workflows again. A diff served differently since you read
+ it, or a job list or a commit the workflows were read at that changed,
+ answers `409` with code `run_changed`; read the run again, which lists
+ what LavaFlow found. The response is the run, `202` while it is
+ `queued`. LavaFlow reads the workflows again before it opens the pull
+ request, and once more as it pushes the fix: a job you didn't read, a
+ new commit on a branch the workflows were read on, even one that
+ changes no job, or a production branch other than the one you read
+ them on holds the fix again with a new list.
+
+ Opening a fix lets its pull request open, nothing more. LavaFlow
+ starts no CI on it and never merges it, as for every fix opened past
+ ungated workflows; a person pushes to the branch or merges it. The
+ pull request's description names who opened it and lists the jobs.
+ One exception: when LavaFlow's read before the pull request opens
+ finds no job that runs the fix before a person approves it, because
+ the workflows were gated since you read them, the fix opens as any
+ other fix and follows the project's merge settings. A run whose
+ `held_workflows` lists no job opens the same way.
+
+ Only the project's owner can open a fix, as a person, while their
+ account is active: with a `volcano login` token
+ whose sign-in is live, or a platform token that expires. Their GitHub
+ account must be able to push to the project's repository. A project
+ access token, a request made through MCP, a platform token that never
+ expires, and a sign-in that ended get `403` with code
+ `person_required`. Opening a fix uses one of the run's attempts: the
+ attempt that opens it is one of the run's, so a run held again on its
+ last attempt can't be opened again. It starts no new run and counts
+ toward no run limit.
+
+ Args:
+ body (LavaflowHeldFixOpen): The project, the run, and the diff and jobs of the held fix
+ you read, by the digests the run served them with.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowRun
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/lava_flow/create_lavaflow_run.py b/src/volcano_sdk/_generated/api/lava_flow/create_lavaflow_run.py
new file mode 100644
index 00000000..8d01599e
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/create_lavaflow_run.py
@@ -0,0 +1,324 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.lavaflow_run import LavaflowRun
+from ...models.lavaflow_run_create import LavaflowRunCreate
+from typing import cast
+
+
+
+def request_kwargs(
+ *,
+ body: LavaflowRunCreate,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/lavaflow/runs",
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | LavaflowRun | None:
+ if response.status_code == 202:
+ response_202 = LavaflowRun.from_dict(response.json())
+
+
+
+ return response_202
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 413:
+ response_413 = Error.from_dict(response.json())
+
+
+
+ return response_413
+
+ if response.status_code == 429:
+ response_429 = Error.from_dict(response.json())
+
+
+
+ return response_429
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | LavaflowRun]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowRunCreate,
+
+) -> Response[Error | LavaflowRun]:
+ """ Start a LavaFlow run
+
+ Starts a run on one of the project's issues. LavaFlow starts runs on
+ its own only for issues with `exception: true`, and only while it is
+ on. Start one here for any other issue, or for one recorded before
+ LavaFlow was turned on. The run follows the project's settings, as
+ one LavaFlow starts on its own does, and answers `202` while it is
+ `queued`; read it with `GET /lavaflow/runs/{run_id}`.
+
+ Only the project's owner can start a run, as a person, while their
+ account is active: with a platform token that expires, or `volcano
+ login`. A platform token that never expires, a `volcano login` token
+ whose sign-in ended, a full-scope project access token, and a request
+ made through MCP get `403` with code `person_required`; a read-only
+ project access token is refused as read-only first, without a code,
+ and so is the owner of a read-only account.
+
+ Every start counts toward the run limits: 5 runs per issue and 200 per
+ project in any 24 hours. An issue has one run in progress at a time,
+ so sending the request again while the first run is in progress
+ answers `409` with code `lavaflow_run_in_progress`.
+
+ A run on a Code Quality issue is a Code Quality run. It starts only
+ while Code Quality is available to the project, as
+ `lavaflow.code_quality` in `GET /capabilities` reports, and on for it.
+
+ Args:
+ body (LavaflowRunCreate): The project, and the issue to start a run on.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowRun]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowRunCreate,
+
+) -> Error | LavaflowRun | None:
+ """ Start a LavaFlow run
+
+ Starts a run on one of the project's issues. LavaFlow starts runs on
+ its own only for issues with `exception: true`, and only while it is
+ on. Start one here for any other issue, or for one recorded before
+ LavaFlow was turned on. The run follows the project's settings, as
+ one LavaFlow starts on its own does, and answers `202` while it is
+ `queued`; read it with `GET /lavaflow/runs/{run_id}`.
+
+ Only the project's owner can start a run, as a person, while their
+ account is active: with a platform token that expires, or `volcano
+ login`. A platform token that never expires, a `volcano login` token
+ whose sign-in ended, a full-scope project access token, and a request
+ made through MCP get `403` with code `person_required`; a read-only
+ project access token is refused as read-only first, without a code,
+ and so is the owner of a read-only account.
+
+ Every start counts toward the run limits: 5 runs per issue and 200 per
+ project in any 24 hours. An issue has one run in progress at a time,
+ so sending the request again while the first run is in progress
+ answers `409` with code `lavaflow_run_in_progress`.
+
+ A run on a Code Quality issue is a Code Quality run. It starts only
+ while Code Quality is available to the project, as
+ `lavaflow.code_quality` in `GET /capabilities` reports, and on for it.
+
+ Args:
+ body (LavaflowRunCreate): The project, and the issue to start a run on.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowRun
+ """
+
+
+ return sync_detailed(
+ client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowRunCreate,
+
+) -> Response[Error | LavaflowRun]:
+ """ Start a LavaFlow run
+
+ Starts a run on one of the project's issues. LavaFlow starts runs on
+ its own only for issues with `exception: true`, and only while it is
+ on. Start one here for any other issue, or for one recorded before
+ LavaFlow was turned on. The run follows the project's settings, as
+ one LavaFlow starts on its own does, and answers `202` while it is
+ `queued`; read it with `GET /lavaflow/runs/{run_id}`.
+
+ Only the project's owner can start a run, as a person, while their
+ account is active: with a platform token that expires, or `volcano
+ login`. A platform token that never expires, a `volcano login` token
+ whose sign-in ended, a full-scope project access token, and a request
+ made through MCP get `403` with code `person_required`; a read-only
+ project access token is refused as read-only first, without a code,
+ and so is the owner of a read-only account.
+
+ Every start counts toward the run limits: 5 runs per issue and 200 per
+ project in any 24 hours. An issue has one run in progress at a time,
+ so sending the request again while the first run is in progress
+ answers `409` with code `lavaflow_run_in_progress`.
+
+ A run on a Code Quality issue is a Code Quality run. It starts only
+ while Code Quality is available to the project, as
+ `lavaflow.code_quality` in `GET /capabilities` reports, and on for it.
+
+ Args:
+ body (LavaflowRunCreate): The project, and the issue to start a run on.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowRun]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowRunCreate,
+
+) -> Error | LavaflowRun | None:
+ """ Start a LavaFlow run
+
+ Starts a run on one of the project's issues. LavaFlow starts runs on
+ its own only for issues with `exception: true`, and only while it is
+ on. Start one here for any other issue, or for one recorded before
+ LavaFlow was turned on. The run follows the project's settings, as
+ one LavaFlow starts on its own does, and answers `202` while it is
+ `queued`; read it with `GET /lavaflow/runs/{run_id}`.
+
+ Only the project's owner can start a run, as a person, while their
+ account is active: with a platform token that expires, or `volcano
+ login`. A platform token that never expires, a `volcano login` token
+ whose sign-in ended, a full-scope project access token, and a request
+ made through MCP get `403` with code `person_required`; a read-only
+ project access token is refused as read-only first, without a code,
+ and so is the owner of a read-only account.
+
+ Every start counts toward the run limits: 5 runs per issue and 200 per
+ project in any 24 hours. An issue has one run in progress at a time,
+ so sending the request again while the first run is in progress
+ answers `409` with code `lavaflow_run_in_progress`.
+
+ A run on a Code Quality issue is a Code Quality run. It starts only
+ while Code Quality is available to the project, as
+ `lavaflow.code_quality` in `GET /capabilities` reports, and on for it.
+
+ Args:
+ body (LavaflowRunCreate): The project, and the issue to start a run on.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowRun
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/lava_flow/delete_lavaflow_connector_binding.py b/src/volcano_sdk/_generated/api/lava_flow/delete_lavaflow_connector_binding.py
new file mode 100644
index 00000000..3db99dda
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/delete_lavaflow_connector_binding.py
@@ -0,0 +1,258 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ binding_id: UUID | str,
+ *,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ json_project_id: str | Unset = UNSET
+ if not isinstance(project_id, Unset):
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "delete",
+ "url": "/lavaflow/connector-bindings/{binding_id}".format(binding_id=quote(str(binding_id), safe=""),),
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | Error | None:
+ if response.status_code == 204:
+ response_204 = cast(Any, None)
+ return response_204
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ binding_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Response[Any | Error]:
+ """ Remove a connector binding
+
+ Stops a bound place, such as a Slack channel, reporting problems for
+ its project. Reports from it still queued are canceled at their next
+ check. The binding's own project authorizes the request. Only the
+ project's owner can remove one, with a platform token. A project
+ access token or MCP gets `403` with code `person_required` for a
+ binding of its own project, and `404` for another project's, as for an
+ unknown one. Removing works whether or not the project's
+ `lavaflow.slack` capability is available.
+
+ Args:
+ binding_id (UUID):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ binding_id=binding_id,
+project_id=project_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ binding_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Any | Error | None:
+ """ Remove a connector binding
+
+ Stops a bound place, such as a Slack channel, reporting problems for
+ its project. Reports from it still queued are canceled at their next
+ check. The binding's own project authorizes the request. Only the
+ project's owner can remove one, with a platform token. A project
+ access token or MCP gets `403` with code `person_required` for a
+ binding of its own project, and `404` for another project's, as for an
+ unknown one. Removing works whether or not the project's
+ `lavaflow.slack` capability is available.
+
+ Args:
+ binding_id (UUID):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return sync_detailed(
+ binding_id=binding_id,
+client=client,
+project_id=project_id,
+
+ ).parsed
+
+async def asyncio_detailed(
+ binding_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Response[Any | Error]:
+ """ Remove a connector binding
+
+ Stops a bound place, such as a Slack channel, reporting problems for
+ its project. Reports from it still queued are canceled at their next
+ check. The binding's own project authorizes the request. Only the
+ project's owner can remove one, with a platform token. A project
+ access token or MCP gets `403` with code `person_required` for a
+ binding of its own project, and `404` for another project's, as for an
+ unknown one. Removing works whether or not the project's
+ `lavaflow.slack` capability is available.
+
+ Args:
+ binding_id (UUID):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ binding_id=binding_id,
+project_id=project_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ binding_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Any | Error | None:
+ """ Remove a connector binding
+
+ Stops a bound place, such as a Slack channel, reporting problems for
+ its project. Reports from it still queued are canceled at their next
+ check. The binding's own project authorizes the request. Only the
+ project's owner can remove one, with a platform token. A project
+ access token or MCP gets `403` with code `person_required` for a
+ binding of its own project, and `404` for another project's, as for an
+ unknown one. Removing works whether or not the project's
+ `lavaflow.slack` capability is available.
+
+ Args:
+ binding_id (UUID):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return (await asyncio_detailed(
+ binding_id=binding_id,
+client=client,
+project_id=project_id,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/lava_flow/delete_lavaflow_skill.py b/src/volcano_sdk/_generated/api/lava_flow/delete_lavaflow_skill.py
new file mode 100644
index 00000000..1caa5c10
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/delete_lavaflow_skill.py
@@ -0,0 +1,265 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ skill_id: UUID | str,
+ *,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ json_project_id: str | Unset = UNSET
+ if not isinstance(project_id, Unset):
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "delete",
+ "url": "/lavaflow/skills/{skill_id}".format(skill_id=quote(str(skill_id), safe=""),),
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | Error | None:
+ if response.status_code == 204:
+ response_204 = cast(Any, None)
+ return response_204
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 429:
+ response_429 = Error.from_dict(response.json())
+
+
+
+ return response_429
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ skill_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Response[Any | Error]:
+ """ Delete a LavaFlow skill
+
+ Deletes a skill and every version of its text. A record that it
+ existed stays, without its text. Only the project's owner deletes a
+ skill, signed in as a person: with a `volcano
+ login` token whose sign-in is live, or a platform token with an
+ expiry. A project access token, MCP, a platform token that never
+ expires, and a sign-in that ended get `403` with code
+ `person_required`. Deleting needs no repository, and works while the
+ project's `lavaflow.skills` capability is unavailable.
+
+ Args:
+ skill_id (UUID):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ skill_id=skill_id,
+project_id=project_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ skill_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Any | Error | None:
+ """ Delete a LavaFlow skill
+
+ Deletes a skill and every version of its text. A record that it
+ existed stays, without its text. Only the project's owner deletes a
+ skill, signed in as a person: with a `volcano
+ login` token whose sign-in is live, or a platform token with an
+ expiry. A project access token, MCP, a platform token that never
+ expires, and a sign-in that ended get `403` with code
+ `person_required`. Deleting needs no repository, and works while the
+ project's `lavaflow.skills` capability is unavailable.
+
+ Args:
+ skill_id (UUID):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return sync_detailed(
+ skill_id=skill_id,
+client=client,
+project_id=project_id,
+
+ ).parsed
+
+async def asyncio_detailed(
+ skill_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Response[Any | Error]:
+ """ Delete a LavaFlow skill
+
+ Deletes a skill and every version of its text. A record that it
+ existed stays, without its text. Only the project's owner deletes a
+ skill, signed in as a person: with a `volcano
+ login` token whose sign-in is live, or a platform token with an
+ expiry. A project access token, MCP, a platform token that never
+ expires, and a sign-in that ended get `403` with code
+ `person_required`. Deleting needs no repository, and works while the
+ project's `lavaflow.skills` capability is unavailable.
+
+ Args:
+ skill_id (UUID):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ skill_id=skill_id,
+project_id=project_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ skill_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Any | Error | None:
+ """ Delete a LavaFlow skill
+
+ Deletes a skill and every version of its text. A record that it
+ existed stays, without its text. Only the project's owner deletes a
+ skill, signed in as a person: with a `volcano
+ login` token whose sign-in is live, or a platform token with an
+ expiry. A project access token, MCP, a platform token that never
+ expires, and a sign-in that ended get `403` with code
+ `person_required`. Deleting needs no repository, and works while the
+ project's `lavaflow.skills` capability is unavailable.
+
+ Args:
+ skill_id (UUID):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return (await asyncio_detailed(
+ skill_id=skill_id,
+client=client,
+project_id=project_id,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/lava_flow/get_lavaflow_run.py b/src/volcano_sdk/_generated/api/lava_flow/get_lavaflow_run.py
new file mode 100644
index 00000000..a78d6f5b
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/get_lavaflow_run.py
@@ -0,0 +1,278 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.lavaflow_run import LavaflowRun
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ run_id: UUID | str,
+ *,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ json_project_id: str | Unset = UNSET
+ if not isinstance(project_id, Unset):
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/lavaflow/runs/{run_id}".format(run_id=quote(str(run_id), safe=""),),
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | LavaflowRun | None:
+ if response.status_code == 200:
+ response_200 = LavaflowRun.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | LavaflowRun]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ run_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Response[Error | LavaflowRun]:
+ """ Get a LavaFlow run
+
+ Returns a run, with its diagnosis, the log lines it cites, its diff,
+ its review, including the findings the review left open and what it
+ asks a person to decide, and whether the repository's own checks
+ passed when LavaFlow ran them on the fix, with the commands they ran.
+ The run's project authorizes the read, so `project_id` is optional.
+ The text holds the project's logs and source code, so this endpoint
+ takes the same access as the project's log endpoints.
+
+ A run held because the repository's workflows could run its fix with
+ the repository's secrets before a person approves it
+ (`pull_request_skipped: ungated_workflows`) lists every such job in
+ `held_workflows`, beside the fix's `diff` and `diff_sha256`.
+
+ Args:
+ run_id (UUID):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowRun]
+ """
+
+
+ kwargs = request_kwargs(
+ run_id=run_id,
+project_id=project_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ run_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Error | LavaflowRun | None:
+ """ Get a LavaFlow run
+
+ Returns a run, with its diagnosis, the log lines it cites, its diff,
+ its review, including the findings the review left open and what it
+ asks a person to decide, and whether the repository's own checks
+ passed when LavaFlow ran them on the fix, with the commands they ran.
+ The run's project authorizes the read, so `project_id` is optional.
+ The text holds the project's logs and source code, so this endpoint
+ takes the same access as the project's log endpoints.
+
+ A run held because the repository's workflows could run its fix with
+ the repository's secrets before a person approves it
+ (`pull_request_skipped: ungated_workflows`) lists every such job in
+ `held_workflows`, beside the fix's `diff` and `diff_sha256`.
+
+ Args:
+ run_id (UUID):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowRun
+ """
+
+
+ return sync_detailed(
+ run_id=run_id,
+client=client,
+project_id=project_id,
+
+ ).parsed
+
+async def asyncio_detailed(
+ run_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Response[Error | LavaflowRun]:
+ """ Get a LavaFlow run
+
+ Returns a run, with its diagnosis, the log lines it cites, its diff,
+ its review, including the findings the review left open and what it
+ asks a person to decide, and whether the repository's own checks
+ passed when LavaFlow ran them on the fix, with the commands they ran.
+ The run's project authorizes the read, so `project_id` is optional.
+ The text holds the project's logs and source code, so this endpoint
+ takes the same access as the project's log endpoints.
+
+ A run held because the repository's workflows could run its fix with
+ the repository's secrets before a person approves it
+ (`pull_request_skipped: ungated_workflows`) lists every such job in
+ `held_workflows`, beside the fix's `diff` and `diff_sha256`.
+
+ Args:
+ run_id (UUID):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowRun]
+ """
+
+
+ kwargs = request_kwargs(
+ run_id=run_id,
+project_id=project_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ run_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Error | LavaflowRun | None:
+ """ Get a LavaFlow run
+
+ Returns a run, with its diagnosis, the log lines it cites, its diff,
+ its review, including the findings the review left open and what it
+ asks a person to decide, and whether the repository's own checks
+ passed when LavaFlow ran them on the fix, with the commands they ran.
+ The run's project authorizes the read, so `project_id` is optional.
+ The text holds the project's logs and source code, so this endpoint
+ takes the same access as the project's log endpoints.
+
+ A run held because the repository's workflows could run its fix with
+ the repository's secrets before a person approves it
+ (`pull_request_skipped: ungated_workflows`) lists every such job in
+ `held_workflows`, beside the fix's `diff` and `diff_sha256`.
+
+ Args:
+ run_id (UUID):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowRun
+ """
+
+
+ return (await asyncio_detailed(
+ run_id=run_id,
+client=client,
+project_id=project_id,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/lava_flow/get_lavaflow_settings.py b/src/volcano_sdk/_generated/api/lava_flow/get_lavaflow_settings.py
new file mode 100644
index 00000000..6fc47f93
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/get_lavaflow_settings.py
@@ -0,0 +1,254 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.lavaflow_settings import LavaflowSettings
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ *,
+ project_id: UUID | str,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/lavaflow/settings",
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | LavaflowSettings | None:
+ if response.status_code == 200:
+ response_200 = LavaflowSettings.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | LavaflowSettings]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+
+) -> Response[Error | LavaflowSettings]:
+ """ Get LavaFlow settings
+
+ Returns whether LavaFlow works on the project's issues, how far it goes
+ on its own, and its saved context and instructions, which runs do not
+ use yet. A project
+ that never saved settings returns the defaults, with LavaFlow off.
+ LavaFlow sends this project's logs and source code to an AI service
+ that Volcano operates.
+
+ `can_update` says whether the caller can save the settings: only the
+ project's owner can, with a platform token. Project access tokens can
+ read the settings, including read-only ones.
+
+ Args:
+ project_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowSettings]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+
+) -> Error | LavaflowSettings | None:
+ """ Get LavaFlow settings
+
+ Returns whether LavaFlow works on the project's issues, how far it goes
+ on its own, and its saved context and instructions, which runs do not
+ use yet. A project
+ that never saved settings returns the defaults, with LavaFlow off.
+ LavaFlow sends this project's logs and source code to an AI service
+ that Volcano operates.
+
+ `can_update` says whether the caller can save the settings: only the
+ project's owner can, with a platform token. Project access tokens can
+ read the settings, including read-only ones.
+
+ Args:
+ project_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowSettings
+ """
+
+
+ return sync_detailed(
+ client=client,
+project_id=project_id,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+
+) -> Response[Error | LavaflowSettings]:
+ """ Get LavaFlow settings
+
+ Returns whether LavaFlow works on the project's issues, how far it goes
+ on its own, and its saved context and instructions, which runs do not
+ use yet. A project
+ that never saved settings returns the defaults, with LavaFlow off.
+ LavaFlow sends this project's logs and source code to an AI service
+ that Volcano operates.
+
+ `can_update` says whether the caller can save the settings: only the
+ project's owner can, with a platform token. Project access tokens can
+ read the settings, including read-only ones.
+
+ Args:
+ project_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowSettings]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+
+) -> Error | LavaflowSettings | None:
+ """ Get LavaFlow settings
+
+ Returns whether LavaFlow works on the project's issues, how far it goes
+ on its own, and its saved context and instructions, which runs do not
+ use yet. A project
+ that never saved settings returns the defaults, with LavaFlow off.
+ LavaFlow sends this project's logs and source code to an AI service
+ that Volcano operates.
+
+ `can_update` says whether the caller can save the settings: only the
+ project's owner can, with a platform token. Project access tokens can
+ read the settings, including read-only ones.
+
+ Args:
+ project_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowSettings
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+project_id=project_id,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/lava_flow/get_lavaflow_skill.py b/src/volcano_sdk/_generated/api/lava_flow/get_lavaflow_skill.py
new file mode 100644
index 00000000..092d2c02
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/get_lavaflow_skill.py
@@ -0,0 +1,242 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.lavaflow_skill import LavaflowSkill
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ skill_id: UUID | str,
+ *,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ json_project_id: str | Unset = UNSET
+ if not isinstance(project_id, Unset):
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/lavaflow/skills/{skill_id}".format(skill_id=quote(str(skill_id), safe=""),),
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | LavaflowSkill | None:
+ if response.status_code == 200:
+ response_200 = LavaflowSkill.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | LavaflowSkill]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ skill_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Response[Error | LavaflowSkill]:
+ """ Get a LavaFlow skill
+
+ Returns one of a project's skills with its active version. The skill's
+ project authorizes the read, so `project_id` is optional. Project
+ access tokens can read skills, including read-only ones.
+
+ Args:
+ skill_id (UUID):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowSkill]
+ """
+
+
+ kwargs = request_kwargs(
+ skill_id=skill_id,
+project_id=project_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ skill_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Error | LavaflowSkill | None:
+ """ Get a LavaFlow skill
+
+ Returns one of a project's skills with its active version. The skill's
+ project authorizes the read, so `project_id` is optional. Project
+ access tokens can read skills, including read-only ones.
+
+ Args:
+ skill_id (UUID):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowSkill
+ """
+
+
+ return sync_detailed(
+ skill_id=skill_id,
+client=client,
+project_id=project_id,
+
+ ).parsed
+
+async def asyncio_detailed(
+ skill_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Response[Error | LavaflowSkill]:
+ """ Get a LavaFlow skill
+
+ Returns one of a project's skills with its active version. The skill's
+ project authorizes the read, so `project_id` is optional. Project
+ access tokens can read skills, including read-only ones.
+
+ Args:
+ skill_id (UUID):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowSkill]
+ """
+
+
+ kwargs = request_kwargs(
+ skill_id=skill_id,
+project_id=project_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ skill_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Error | LavaflowSkill | None:
+ """ Get a LavaFlow skill
+
+ Returns one of a project's skills with its active version. The skill's
+ project authorizes the read, so `project_id` is optional. Project
+ access tokens can read skills, including read-only ones.
+
+ Args:
+ skill_id (UUID):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowSkill
+ """
+
+
+ return (await asyncio_detailed(
+ skill_id=skill_id,
+client=client,
+project_id=project_id,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/lava_flow/get_lavaflow_stats.py b/src/volcano_sdk/_generated/api/lava_flow/get_lavaflow_stats.py
new file mode 100644
index 00000000..880d1c3c
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/get_lavaflow_stats.py
@@ -0,0 +1,287 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.get_lavaflow_stats_category import check_get_lavaflow_stats_category
+from ...models.get_lavaflow_stats_category import GetLavaflowStatsCategory
+from ...models.lavaflow_stats import LavaflowStats
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ *,
+ project_id: UUID | str,
+ days: int | Unset = 30,
+ category: GetLavaflowStatsCategory | Unset = UNSET,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+ params["days"] = days
+
+ json_category: str | Unset = UNSET
+ if not isinstance(category, Unset):
+ json_category = category
+
+ params["category"] = json_category
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/lavaflow/stats",
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | LavaflowStats | None:
+ if response.status_code == 200:
+ response_200 = LavaflowStats.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | LavaflowStats]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ days: int | Unset = 30,
+ category: GetLavaflowStatsCategory | Unset = UNSET,
+
+) -> Response[Error | LavaflowStats]:
+ """ Get LavaFlow stats
+
+ Counts the issues LavaFlow took on and the pull requests it opened per
+ UTC day, oldest first, with every day in the window present. Merges
+ never count. The window ends today, which is partial. The totals equal
+ the sum of `days` and of the per-resource counts from
+ `GET /lavaflow/resources` for the same project, `days` and `category`.
+
+ `category` counts only runs in that category. These counts are issues
+ taken on and pull requests opened, while `GET /lavaflow/runs` counts
+ runs, so the two need not match.
+
+ Args:
+ project_id (UUID):
+ days (int | Unset): Default: 30.
+ category (GetLavaflowStatsCategory | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowStats]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+days=days,
+category=category,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ days: int | Unset = 30,
+ category: GetLavaflowStatsCategory | Unset = UNSET,
+
+) -> Error | LavaflowStats | None:
+ """ Get LavaFlow stats
+
+ Counts the issues LavaFlow took on and the pull requests it opened per
+ UTC day, oldest first, with every day in the window present. Merges
+ never count. The window ends today, which is partial. The totals equal
+ the sum of `days` and of the per-resource counts from
+ `GET /lavaflow/resources` for the same project, `days` and `category`.
+
+ `category` counts only runs in that category. These counts are issues
+ taken on and pull requests opened, while `GET /lavaflow/runs` counts
+ runs, so the two need not match.
+
+ Args:
+ project_id (UUID):
+ days (int | Unset): Default: 30.
+ category (GetLavaflowStatsCategory | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowStats
+ """
+
+
+ return sync_detailed(
+ client=client,
+project_id=project_id,
+days=days,
+category=category,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ days: int | Unset = 30,
+ category: GetLavaflowStatsCategory | Unset = UNSET,
+
+) -> Response[Error | LavaflowStats]:
+ """ Get LavaFlow stats
+
+ Counts the issues LavaFlow took on and the pull requests it opened per
+ UTC day, oldest first, with every day in the window present. Merges
+ never count. The window ends today, which is partial. The totals equal
+ the sum of `days` and of the per-resource counts from
+ `GET /lavaflow/resources` for the same project, `days` and `category`.
+
+ `category` counts only runs in that category. These counts are issues
+ taken on and pull requests opened, while `GET /lavaflow/runs` counts
+ runs, so the two need not match.
+
+ Args:
+ project_id (UUID):
+ days (int | Unset): Default: 30.
+ category (GetLavaflowStatsCategory | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowStats]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+days=days,
+category=category,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ days: int | Unset = 30,
+ category: GetLavaflowStatsCategory | Unset = UNSET,
+
+) -> Error | LavaflowStats | None:
+ """ Get LavaFlow stats
+
+ Counts the issues LavaFlow took on and the pull requests it opened per
+ UTC day, oldest first, with every day in the window present. Merges
+ never count. The window ends today, which is partial. The totals equal
+ the sum of `days` and of the per-resource counts from
+ `GET /lavaflow/resources` for the same project, `days` and `category`.
+
+ `category` counts only runs in that category. These counts are issues
+ taken on and pull requests opened, while `GET /lavaflow/runs` counts
+ runs, so the two need not match.
+
+ Args:
+ project_id (UUID):
+ days (int | Unset): Default: 30.
+ category (GetLavaflowStatsCategory | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowStats
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+project_id=project_id,
+days=days,
+category=category,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_connector_bindings.py b/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_connector_bindings.py
new file mode 100644
index 00000000..9350fa28
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_connector_bindings.py
@@ -0,0 +1,235 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.lavaflow_connector_bindings_response import LavaflowConnectorBindingsResponse
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ *,
+ project_id: UUID | str,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/lavaflow/connector-bindings",
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | LavaflowConnectorBindingsResponse | None:
+ if response.status_code == 200:
+ response_200 = LavaflowConnectorBindingsResponse.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | LavaflowConnectorBindingsResponse]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+
+) -> Response[Error | LavaflowConnectorBindingsResponse]:
+ """ List the project's connector bindings
+
+ Lists where problems are reported to LavaFlow from for the project,
+ such as Slack channels. In a bound Slack channel, someone whose Slack
+ identity is connected to the project owner's account can mention the
+ Volcano app to report a problem. Project access tokens can read the
+ list, including read-only ones, and so can MCP, as
+ `get_lavaflow_connector_bindings`. The list answers whether or not the
+ project's `lavaflow.slack` capability is available.
+
+ Args:
+ project_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowConnectorBindingsResponse]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+
+) -> Error | LavaflowConnectorBindingsResponse | None:
+ """ List the project's connector bindings
+
+ Lists where problems are reported to LavaFlow from for the project,
+ such as Slack channels. In a bound Slack channel, someone whose Slack
+ identity is connected to the project owner's account can mention the
+ Volcano app to report a problem. Project access tokens can read the
+ list, including read-only ones, and so can MCP, as
+ `get_lavaflow_connector_bindings`. The list answers whether or not the
+ project's `lavaflow.slack` capability is available.
+
+ Args:
+ project_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowConnectorBindingsResponse
+ """
+
+
+ return sync_detailed(
+ client=client,
+project_id=project_id,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+
+) -> Response[Error | LavaflowConnectorBindingsResponse]:
+ """ List the project's connector bindings
+
+ Lists where problems are reported to LavaFlow from for the project,
+ such as Slack channels. In a bound Slack channel, someone whose Slack
+ identity is connected to the project owner's account can mention the
+ Volcano app to report a problem. Project access tokens can read the
+ list, including read-only ones, and so can MCP, as
+ `get_lavaflow_connector_bindings`. The list answers whether or not the
+ project's `lavaflow.slack` capability is available.
+
+ Args:
+ project_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowConnectorBindingsResponse]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+
+) -> Error | LavaflowConnectorBindingsResponse | None:
+ """ List the project's connector bindings
+
+ Lists where problems are reported to LavaFlow from for the project,
+ such as Slack channels. In a bound Slack channel, someone whose Slack
+ identity is connected to the project owner's account can mention the
+ Volcano app to report a problem. Project access tokens can read the
+ list, including read-only ones, and so can MCP, as
+ `get_lavaflow_connector_bindings`. The list answers whether or not the
+ project's `lavaflow.slack` capability is available.
+
+ Args:
+ project_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowConnectorBindingsResponse
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+project_id=project_id,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_global_skills.py b/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_global_skills.py
new file mode 100644
index 00000000..eec961fc
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_global_skills.py
@@ -0,0 +1,242 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.lavaflow_global_skill_list import LavaflowGlobalSkillList
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ *,
+ project_id: UUID | str,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/lavaflow/global-skills",
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | LavaflowGlobalSkillList | None:
+ if response.status_code == 200:
+ response_200 = LavaflowGlobalSkillList.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | LavaflowGlobalSkillList]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+
+) -> Response[Error | LavaflowGlobalSkillList]:
+ """ List Volcano's global skills
+
+ Lists the skills Volcano wrote for every project. Volcano writes and
+ reviews each one, and none holds customer content. They belong to no
+ project, so items carry `scope` and no `project_id`; `project_id`
+ authorizes the caller. While the project's `lavaflow.skills`
+ capability is unavailable, the list is empty.
+
+ Project access tokens can list them, including read-only ones.
+
+ Args:
+ project_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowGlobalSkillList]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+
+) -> Error | LavaflowGlobalSkillList | None:
+ """ List Volcano's global skills
+
+ Lists the skills Volcano wrote for every project. Volcano writes and
+ reviews each one, and none holds customer content. They belong to no
+ project, so items carry `scope` and no `project_id`; `project_id`
+ authorizes the caller. While the project's `lavaflow.skills`
+ capability is unavailable, the list is empty.
+
+ Project access tokens can list them, including read-only ones.
+
+ Args:
+ project_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowGlobalSkillList
+ """
+
+
+ return sync_detailed(
+ client=client,
+project_id=project_id,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+
+) -> Response[Error | LavaflowGlobalSkillList]:
+ """ List Volcano's global skills
+
+ Lists the skills Volcano wrote for every project. Volcano writes and
+ reviews each one, and none holds customer content. They belong to no
+ project, so items carry `scope` and no `project_id`; `project_id`
+ authorizes the caller. While the project's `lavaflow.skills`
+ capability is unavailable, the list is empty.
+
+ Project access tokens can list them, including read-only ones.
+
+ Args:
+ project_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowGlobalSkillList]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+
+) -> Error | LavaflowGlobalSkillList | None:
+ """ List Volcano's global skills
+
+ Lists the skills Volcano wrote for every project. Volcano writes and
+ reviews each one, and none holds customer content. They belong to no
+ project, so items carry `scope` and no `project_id`; `project_id`
+ authorizes the caller. While the project's `lavaflow.skills`
+ capability is unavailable, the list is empty.
+
+ Project access tokens can list them, including read-only ones.
+
+ Args:
+ project_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowGlobalSkillList
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+project_id=project_id,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_resources.py b/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_resources.py
new file mode 100644
index 00000000..037351e9
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_resources.py
@@ -0,0 +1,303 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.lavaflow_resource_list import LavaflowResourceList
+from ...models.list_lavaflow_resources_category import check_list_lavaflow_resources_category
+from ...models.list_lavaflow_resources_category import ListLavaflowResourcesCategory
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ *,
+ project_id: UUID | str,
+ days: int | Unset = 30,
+ category: ListLavaflowResourcesCategory | Unset = UNSET,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+ params["days"] = days
+
+ json_category: str | Unset = UNSET
+ if not isinstance(category, Unset):
+ json_category = category
+
+ params["category"] = json_category
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/lavaflow/resources",
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | LavaflowResourceList | None:
+ if response.status_code == 200:
+ response_200 = LavaflowResourceList.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | LavaflowResourceList]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ days: int | Unset = 30,
+ category: ListLavaflowResourcesCategory | Unset = UNSET,
+
+) -> Response[Error | LavaflowResourceList]:
+ """ List LavaFlow's resources
+
+ Lists every function, durable function and frontend in the project with
+ LavaFlow's activity in the window, zeros included, sorted by name. A
+ removed resource is listed when it has activity in the window (in that
+ category, with `category` set), so the counts add up to
+ `GET /lavaflow/stats`.
+
+ `anomaly.flagged` is true when the last 24 hours have at least 3
+ issues opened for the resource and at least 3 times its daily average
+ over the 29 days before, counting that average as at least 1.
+
+ `category` counts, and flags anomalies from, only runs in that
+ category; every current resource is still listed, and
+ `last_analyzed_at` counts every run.
+
+ Args:
+ project_id (UUID):
+ days (int | Unset): Default: 30.
+ category (ListLavaflowResourcesCategory | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowResourceList]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+days=days,
+category=category,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ days: int | Unset = 30,
+ category: ListLavaflowResourcesCategory | Unset = UNSET,
+
+) -> Error | LavaflowResourceList | None:
+ """ List LavaFlow's resources
+
+ Lists every function, durable function and frontend in the project with
+ LavaFlow's activity in the window, zeros included, sorted by name. A
+ removed resource is listed when it has activity in the window (in that
+ category, with `category` set), so the counts add up to
+ `GET /lavaflow/stats`.
+
+ `anomaly.flagged` is true when the last 24 hours have at least 3
+ issues opened for the resource and at least 3 times its daily average
+ over the 29 days before, counting that average as at least 1.
+
+ `category` counts, and flags anomalies from, only runs in that
+ category; every current resource is still listed, and
+ `last_analyzed_at` counts every run.
+
+ Args:
+ project_id (UUID):
+ days (int | Unset): Default: 30.
+ category (ListLavaflowResourcesCategory | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowResourceList
+ """
+
+
+ return sync_detailed(
+ client=client,
+project_id=project_id,
+days=days,
+category=category,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ days: int | Unset = 30,
+ category: ListLavaflowResourcesCategory | Unset = UNSET,
+
+) -> Response[Error | LavaflowResourceList]:
+ """ List LavaFlow's resources
+
+ Lists every function, durable function and frontend in the project with
+ LavaFlow's activity in the window, zeros included, sorted by name. A
+ removed resource is listed when it has activity in the window (in that
+ category, with `category` set), so the counts add up to
+ `GET /lavaflow/stats`.
+
+ `anomaly.flagged` is true when the last 24 hours have at least 3
+ issues opened for the resource and at least 3 times its daily average
+ over the 29 days before, counting that average as at least 1.
+
+ `category` counts, and flags anomalies from, only runs in that
+ category; every current resource is still listed, and
+ `last_analyzed_at` counts every run.
+
+ Args:
+ project_id (UUID):
+ days (int | Unset): Default: 30.
+ category (ListLavaflowResourcesCategory | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowResourceList]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+days=days,
+category=category,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ days: int | Unset = 30,
+ category: ListLavaflowResourcesCategory | Unset = UNSET,
+
+) -> Error | LavaflowResourceList | None:
+ """ List LavaFlow's resources
+
+ Lists every function, durable function and frontend in the project with
+ LavaFlow's activity in the window, zeros included, sorted by name. A
+ removed resource is listed when it has activity in the window (in that
+ category, with `category` set), so the counts add up to
+ `GET /lavaflow/stats`.
+
+ `anomaly.flagged` is true when the last 24 hours have at least 3
+ issues opened for the resource and at least 3 times its daily average
+ over the 29 days before, counting that average as at least 1.
+
+ `category` counts, and flags anomalies from, only runs in that
+ category; every current resource is still listed, and
+ `last_analyzed_at` counts every run.
+
+ Args:
+ project_id (UUID):
+ days (int | Unset): Default: 30.
+ category (ListLavaflowResourcesCategory | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowResourceList
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+project_id=project_id,
+days=days,
+category=category,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_runs.py b/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_runs.py
new file mode 100644
index 00000000..f989f24d
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_runs.py
@@ -0,0 +1,479 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.lavaflow_run_status import check_lavaflow_run_status
+from ...models.lavaflow_run_status import LavaflowRunStatus
+from ...models.list_lavaflow_runs_category import check_list_lavaflow_runs_category
+from ...models.list_lavaflow_runs_category import ListLavaflowRunsCategory
+from ...models.list_lavaflow_runs_include_item import check_list_lavaflow_runs_include_item
+from ...models.list_lavaflow_runs_include_item import ListLavaflowRunsIncludeItem
+from ...models.list_lavaflow_runs_order import check_list_lavaflow_runs_order
+from ...models.list_lavaflow_runs_order import ListLavaflowRunsOrder
+from ...models.list_lavaflow_runs_pull_request_state import check_list_lavaflow_runs_pull_request_state
+from ...models.list_lavaflow_runs_pull_request_state import ListLavaflowRunsPullRequestState
+from ...models.paginated_lavaflow_runs import PaginatedLavaflowRuns
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ *,
+ project_id: UUID | str,
+ limit: int | Unset = 25,
+ cursor: str | Unset = UNSET,
+ status: LavaflowRunStatus | Unset = UNSET,
+ resource_id: UUID | str | Unset = UNSET,
+ category: ListLavaflowRunsCategory | Unset = UNSET,
+ involved_resource_id: UUID | str | Unset = UNSET,
+ issue_id: UUID | str | Unset = UNSET,
+ pull_request_state: ListLavaflowRunsPullRequestState | Unset = UNSET,
+ days: int | Unset = UNSET,
+ order: ListLavaflowRunsOrder | Unset = 'created_at.desc',
+ include: list[ListLavaflowRunsIncludeItem] | Unset = UNSET,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+ params["limit"] = limit
+
+ params["cursor"] = cursor
+
+ json_status: str | Unset = UNSET
+ if not isinstance(status, Unset):
+ json_status = status
+
+ params["status"] = json_status
+
+ json_resource_id: str | Unset = UNSET
+ if not isinstance(resource_id, Unset):
+ json_resource_id = str(resource_id)
+ params["resource_id"] = json_resource_id
+
+ json_category: str | Unset = UNSET
+ if not isinstance(category, Unset):
+ json_category = category
+
+ params["category"] = json_category
+
+ json_involved_resource_id: str | Unset = UNSET
+ if not isinstance(involved_resource_id, Unset):
+ json_involved_resource_id = str(involved_resource_id)
+ params["involved_resource_id"] = json_involved_resource_id
+
+ json_issue_id: str | Unset = UNSET
+ if not isinstance(issue_id, Unset):
+ json_issue_id = str(issue_id)
+ params["issue_id"] = json_issue_id
+
+ json_pull_request_state: str | Unset = UNSET
+ if not isinstance(pull_request_state, Unset):
+ json_pull_request_state = pull_request_state
+
+ params["pull_request_state"] = json_pull_request_state
+
+ params["days"] = days
+
+ json_order: str | Unset = UNSET
+ if not isinstance(order, Unset):
+ json_order = order
+
+ params["order"] = json_order
+
+ json_include: list[str] | Unset = UNSET
+ if not isinstance(include, Unset):
+ json_include = []
+ for include_item_data in include:
+ include_item: str = include_item_data
+ json_include.append(include_item)
+
+
+ params["include"] = json_include
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/lavaflow/runs",
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | PaginatedLavaflowRuns | None:
+ if response.status_code == 200:
+ response_200 = PaginatedLavaflowRuns.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | PaginatedLavaflowRuns]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ limit: int | Unset = 25,
+ cursor: str | Unset = UNSET,
+ status: LavaflowRunStatus | Unset = UNSET,
+ resource_id: UUID | str | Unset = UNSET,
+ category: ListLavaflowRunsCategory | Unset = UNSET,
+ involved_resource_id: UUID | str | Unset = UNSET,
+ issue_id: UUID | str | Unset = UNSET,
+ pull_request_state: ListLavaflowRunsPullRequestState | Unset = UNSET,
+ days: int | Unset = UNSET,
+ order: ListLavaflowRunsOrder | Unset = 'created_at.desc',
+ include: list[ListLavaflowRunsIncludeItem] | Unset = UNSET,
+
+) -> Response[Error | PaginatedLavaflowRuns]:
+ """ List LavaFlow runs
+
+ Pages the project's LavaFlow runs, newest first unless `order` says
+ otherwise. A page carries bounded display text, including the saved
+ proposed fix's optional `fix_summary`; read a run for its diagnosis,
+ log lines and diff. Each run names its category, the resources it
+ involves and its issue. A confirmed Code Quality finding can supply
+ `issue.severity`, and a recorded pull request can supply `branch`.
+ Unknown or withheld optional fields are omitted.
+
+ Every filter narrows the list, and filters combine. `include=counts`
+ adds `counts`, computed from the same filters: ask for them on the
+ first page, since they don't depend on the cursor. Keep the filters
+ and `order` while paging.
+
+ Args:
+ project_id (UUID):
+ limit (int | Unset): Default: 25.
+ cursor (str | Unset):
+ status (LavaflowRunStatus | Unset): Where a run is. `diagnosing`, `fixing` and `reviewing`
+ are the stages of a running run. `pr_open` means its pull request is open; `completed`
+ means it finished, with no pull request or one that was merged or closed.
+ resource_id (UUID | Unset):
+ category (ListLavaflowRunsCategory | Unset):
+ involved_resource_id (UUID | Unset):
+ issue_id (UUID | Unset):
+ pull_request_state (ListLavaflowRunsPullRequestState | Unset):
+ days (int | Unset):
+ order (ListLavaflowRunsOrder | Unset): Default: 'created_at.desc'.
+ include (list[ListLavaflowRunsIncludeItem] | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | PaginatedLavaflowRuns]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+limit=limit,
+cursor=cursor,
+status=status,
+resource_id=resource_id,
+category=category,
+involved_resource_id=involved_resource_id,
+issue_id=issue_id,
+pull_request_state=pull_request_state,
+days=days,
+order=order,
+include=include,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ limit: int | Unset = 25,
+ cursor: str | Unset = UNSET,
+ status: LavaflowRunStatus | Unset = UNSET,
+ resource_id: UUID | str | Unset = UNSET,
+ category: ListLavaflowRunsCategory | Unset = UNSET,
+ involved_resource_id: UUID | str | Unset = UNSET,
+ issue_id: UUID | str | Unset = UNSET,
+ pull_request_state: ListLavaflowRunsPullRequestState | Unset = UNSET,
+ days: int | Unset = UNSET,
+ order: ListLavaflowRunsOrder | Unset = 'created_at.desc',
+ include: list[ListLavaflowRunsIncludeItem] | Unset = UNSET,
+
+) -> Error | PaginatedLavaflowRuns | None:
+ """ List LavaFlow runs
+
+ Pages the project's LavaFlow runs, newest first unless `order` says
+ otherwise. A page carries bounded display text, including the saved
+ proposed fix's optional `fix_summary`; read a run for its diagnosis,
+ log lines and diff. Each run names its category, the resources it
+ involves and its issue. A confirmed Code Quality finding can supply
+ `issue.severity`, and a recorded pull request can supply `branch`.
+ Unknown or withheld optional fields are omitted.
+
+ Every filter narrows the list, and filters combine. `include=counts`
+ adds `counts`, computed from the same filters: ask for them on the
+ first page, since they don't depend on the cursor. Keep the filters
+ and `order` while paging.
+
+ Args:
+ project_id (UUID):
+ limit (int | Unset): Default: 25.
+ cursor (str | Unset):
+ status (LavaflowRunStatus | Unset): Where a run is. `diagnosing`, `fixing` and `reviewing`
+ are the stages of a running run. `pr_open` means its pull request is open; `completed`
+ means it finished, with no pull request or one that was merged or closed.
+ resource_id (UUID | Unset):
+ category (ListLavaflowRunsCategory | Unset):
+ involved_resource_id (UUID | Unset):
+ issue_id (UUID | Unset):
+ pull_request_state (ListLavaflowRunsPullRequestState | Unset):
+ days (int | Unset):
+ order (ListLavaflowRunsOrder | Unset): Default: 'created_at.desc'.
+ include (list[ListLavaflowRunsIncludeItem] | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | PaginatedLavaflowRuns
+ """
+
+
+ return sync_detailed(
+ client=client,
+project_id=project_id,
+limit=limit,
+cursor=cursor,
+status=status,
+resource_id=resource_id,
+category=category,
+involved_resource_id=involved_resource_id,
+issue_id=issue_id,
+pull_request_state=pull_request_state,
+days=days,
+order=order,
+include=include,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ limit: int | Unset = 25,
+ cursor: str | Unset = UNSET,
+ status: LavaflowRunStatus | Unset = UNSET,
+ resource_id: UUID | str | Unset = UNSET,
+ category: ListLavaflowRunsCategory | Unset = UNSET,
+ involved_resource_id: UUID | str | Unset = UNSET,
+ issue_id: UUID | str | Unset = UNSET,
+ pull_request_state: ListLavaflowRunsPullRequestState | Unset = UNSET,
+ days: int | Unset = UNSET,
+ order: ListLavaflowRunsOrder | Unset = 'created_at.desc',
+ include: list[ListLavaflowRunsIncludeItem] | Unset = UNSET,
+
+) -> Response[Error | PaginatedLavaflowRuns]:
+ """ List LavaFlow runs
+
+ Pages the project's LavaFlow runs, newest first unless `order` says
+ otherwise. A page carries bounded display text, including the saved
+ proposed fix's optional `fix_summary`; read a run for its diagnosis,
+ log lines and diff. Each run names its category, the resources it
+ involves and its issue. A confirmed Code Quality finding can supply
+ `issue.severity`, and a recorded pull request can supply `branch`.
+ Unknown or withheld optional fields are omitted.
+
+ Every filter narrows the list, and filters combine. `include=counts`
+ adds `counts`, computed from the same filters: ask for them on the
+ first page, since they don't depend on the cursor. Keep the filters
+ and `order` while paging.
+
+ Args:
+ project_id (UUID):
+ limit (int | Unset): Default: 25.
+ cursor (str | Unset):
+ status (LavaflowRunStatus | Unset): Where a run is. `diagnosing`, `fixing` and `reviewing`
+ are the stages of a running run. `pr_open` means its pull request is open; `completed`
+ means it finished, with no pull request or one that was merged or closed.
+ resource_id (UUID | Unset):
+ category (ListLavaflowRunsCategory | Unset):
+ involved_resource_id (UUID | Unset):
+ issue_id (UUID | Unset):
+ pull_request_state (ListLavaflowRunsPullRequestState | Unset):
+ days (int | Unset):
+ order (ListLavaflowRunsOrder | Unset): Default: 'created_at.desc'.
+ include (list[ListLavaflowRunsIncludeItem] | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | PaginatedLavaflowRuns]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+limit=limit,
+cursor=cursor,
+status=status,
+resource_id=resource_id,
+category=category,
+involved_resource_id=involved_resource_id,
+issue_id=issue_id,
+pull_request_state=pull_request_state,
+days=days,
+order=order,
+include=include,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ limit: int | Unset = 25,
+ cursor: str | Unset = UNSET,
+ status: LavaflowRunStatus | Unset = UNSET,
+ resource_id: UUID | str | Unset = UNSET,
+ category: ListLavaflowRunsCategory | Unset = UNSET,
+ involved_resource_id: UUID | str | Unset = UNSET,
+ issue_id: UUID | str | Unset = UNSET,
+ pull_request_state: ListLavaflowRunsPullRequestState | Unset = UNSET,
+ days: int | Unset = UNSET,
+ order: ListLavaflowRunsOrder | Unset = 'created_at.desc',
+ include: list[ListLavaflowRunsIncludeItem] | Unset = UNSET,
+
+) -> Error | PaginatedLavaflowRuns | None:
+ """ List LavaFlow runs
+
+ Pages the project's LavaFlow runs, newest first unless `order` says
+ otherwise. A page carries bounded display text, including the saved
+ proposed fix's optional `fix_summary`; read a run for its diagnosis,
+ log lines and diff. Each run names its category, the resources it
+ involves and its issue. A confirmed Code Quality finding can supply
+ `issue.severity`, and a recorded pull request can supply `branch`.
+ Unknown or withheld optional fields are omitted.
+
+ Every filter narrows the list, and filters combine. `include=counts`
+ adds `counts`, computed from the same filters: ask for them on the
+ first page, since they don't depend on the cursor. Keep the filters
+ and `order` while paging.
+
+ Args:
+ project_id (UUID):
+ limit (int | Unset): Default: 25.
+ cursor (str | Unset):
+ status (LavaflowRunStatus | Unset): Where a run is. `diagnosing`, `fixing` and `reviewing`
+ are the stages of a running run. `pr_open` means its pull request is open; `completed`
+ means it finished, with no pull request or one that was merged or closed.
+ resource_id (UUID | Unset):
+ category (ListLavaflowRunsCategory | Unset):
+ involved_resource_id (UUID | Unset):
+ issue_id (UUID | Unset):
+ pull_request_state (ListLavaflowRunsPullRequestState | Unset):
+ days (int | Unset):
+ order (ListLavaflowRunsOrder | Unset): Default: 'created_at.desc'.
+ include (list[ListLavaflowRunsIncludeItem] | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | PaginatedLavaflowRuns
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+project_id=project_id,
+limit=limit,
+cursor=cursor,
+status=status,
+resource_id=resource_id,
+category=category,
+involved_resource_id=involved_resource_id,
+issue_id=issue_id,
+pull_request_state=pull_request_state,
+days=days,
+order=order,
+include=include,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_scans.py b/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_scans.py
new file mode 100644
index 00000000..e4c552be
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_scans.py
@@ -0,0 +1,293 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.paginated_lavaflow_scans import PaginatedLavaflowScans
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ *,
+ project_id: UUID | str,
+ limit: int | Unset = 25,
+ cursor: str | Unset = UNSET,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+ params["limit"] = limit
+
+ params["cursor"] = cursor
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/lavaflow/scans",
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | PaginatedLavaflowScans | None:
+ if response.status_code == 200:
+ response_200 = PaginatedLavaflowScans.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | PaginatedLavaflowScans]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ limit: int | Unset = 25,
+ cursor: str | Unset = UNSET,
+
+) -> Response[Error | PaginatedLavaflowScans]:
+ """ List LavaFlow Code Quality scans
+
+ Pages the project's Code Quality scans, newest first. The first page
+ starts with the project's waiting scan, if it has one: the deploys
+ that went live since the last scan, with `status: waiting` and the
+ bound it waits at in `waiting_reason`. A bound never drops a deploy:
+ the waiting scan covers every commit since the last one when it
+ starts.
+
+ Each scan shows the commits it compared, the resources whose deploys
+ it covers, what it did with what it found, and the findings whose
+ runs were billed. Scans stay readable while LavaFlow or Code Quality
+ is off. Project access tokens can read them, including read-only
+ ones.
+
+ Args:
+ project_id (UUID):
+ limit (int | Unset): Default: 25.
+ cursor (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | PaginatedLavaflowScans]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+limit=limit,
+cursor=cursor,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ limit: int | Unset = 25,
+ cursor: str | Unset = UNSET,
+
+) -> Error | PaginatedLavaflowScans | None:
+ """ List LavaFlow Code Quality scans
+
+ Pages the project's Code Quality scans, newest first. The first page
+ starts with the project's waiting scan, if it has one: the deploys
+ that went live since the last scan, with `status: waiting` and the
+ bound it waits at in `waiting_reason`. A bound never drops a deploy:
+ the waiting scan covers every commit since the last one when it
+ starts.
+
+ Each scan shows the commits it compared, the resources whose deploys
+ it covers, what it did with what it found, and the findings whose
+ runs were billed. Scans stay readable while LavaFlow or Code Quality
+ is off. Project access tokens can read them, including read-only
+ ones.
+
+ Args:
+ project_id (UUID):
+ limit (int | Unset): Default: 25.
+ cursor (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | PaginatedLavaflowScans
+ """
+
+
+ return sync_detailed(
+ client=client,
+project_id=project_id,
+limit=limit,
+cursor=cursor,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ limit: int | Unset = 25,
+ cursor: str | Unset = UNSET,
+
+) -> Response[Error | PaginatedLavaflowScans]:
+ """ List LavaFlow Code Quality scans
+
+ Pages the project's Code Quality scans, newest first. The first page
+ starts with the project's waiting scan, if it has one: the deploys
+ that went live since the last scan, with `status: waiting` and the
+ bound it waits at in `waiting_reason`. A bound never drops a deploy:
+ the waiting scan covers every commit since the last one when it
+ starts.
+
+ Each scan shows the commits it compared, the resources whose deploys
+ it covers, what it did with what it found, and the findings whose
+ runs were billed. Scans stay readable while LavaFlow or Code Quality
+ is off. Project access tokens can read them, including read-only
+ ones.
+
+ Args:
+ project_id (UUID):
+ limit (int | Unset): Default: 25.
+ cursor (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | PaginatedLavaflowScans]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+limit=limit,
+cursor=cursor,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ limit: int | Unset = 25,
+ cursor: str | Unset = UNSET,
+
+) -> Error | PaginatedLavaflowScans | None:
+ """ List LavaFlow Code Quality scans
+
+ Pages the project's Code Quality scans, newest first. The first page
+ starts with the project's waiting scan, if it has one: the deploys
+ that went live since the last scan, with `status: waiting` and the
+ bound it waits at in `waiting_reason`. A bound never drops a deploy:
+ the waiting scan covers every commit since the last one when it
+ starts.
+
+ Each scan shows the commits it compared, the resources whose deploys
+ it covers, what it did with what it found, and the findings whose
+ runs were billed. Scans stay readable while LavaFlow or Code Quality
+ is off. Project access tokens can read them, including read-only
+ ones.
+
+ Args:
+ project_id (UUID):
+ limit (int | Unset): Default: 25.
+ cursor (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | PaginatedLavaflowScans
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+project_id=project_id,
+limit=limit,
+cursor=cursor,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_skill_versions.py b/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_skill_versions.py
new file mode 100644
index 00000000..c3494e9e
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_skill_versions.py
@@ -0,0 +1,242 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.lavaflow_skill_version_list import LavaflowSkillVersionList
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ *,
+ project_id: UUID | str,
+ skill_id: UUID | str,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+ json_skill_id = str(skill_id)
+ params["skill_id"] = json_skill_id
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/lavaflow/skill-versions",
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | LavaflowSkillVersionList | None:
+ if response.status_code == 200:
+ response_200 = LavaflowSkillVersionList.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | LavaflowSkillVersionList]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ skill_id: UUID | str,
+
+) -> Response[Error | LavaflowSkillVersionList]:
+ """ List a LavaFlow skill's versions
+
+ Lists a skill's versions, newest first, each with its text, source and
+ content hash. A skill keeps its 20 newest versions and its active one.
+ Project access tokens can list them, including read-only ones.
+
+ Args:
+ project_id (UUID):
+ skill_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowSkillVersionList]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+skill_id=skill_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ skill_id: UUID | str,
+
+) -> Error | LavaflowSkillVersionList | None:
+ """ List a LavaFlow skill's versions
+
+ Lists a skill's versions, newest first, each with its text, source and
+ content hash. A skill keeps its 20 newest versions and its active one.
+ Project access tokens can list them, including read-only ones.
+
+ Args:
+ project_id (UUID):
+ skill_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowSkillVersionList
+ """
+
+
+ return sync_detailed(
+ client=client,
+project_id=project_id,
+skill_id=skill_id,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ skill_id: UUID | str,
+
+) -> Response[Error | LavaflowSkillVersionList]:
+ """ List a LavaFlow skill's versions
+
+ Lists a skill's versions, newest first, each with its text, source and
+ content hash. A skill keeps its 20 newest versions and its active one.
+ Project access tokens can list them, including read-only ones.
+
+ Args:
+ project_id (UUID):
+ skill_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowSkillVersionList]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+skill_id=skill_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ skill_id: UUID | str,
+
+) -> Error | LavaflowSkillVersionList | None:
+ """ List a LavaFlow skill's versions
+
+ Lists a skill's versions, newest first, each with its text, source and
+ content hash. A skill keeps its 20 newest versions and its active one.
+ Project access tokens can list them, including read-only ones.
+
+ Args:
+ project_id (UUID):
+ skill_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowSkillVersionList
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+project_id=project_id,
+skill_id=skill_id,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_skills.py b/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_skills.py
new file mode 100644
index 00000000..e570adc6
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_skills.py
@@ -0,0 +1,288 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.lavaflow_skill_list import LavaflowSkillList
+from ...models.lavaflow_skill_status import check_lavaflow_skill_status
+from ...models.lavaflow_skill_status import LavaflowSkillStatus
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ *,
+ project_id: UUID | str,
+ status: LavaflowSkillStatus | Unset = UNSET,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+ json_status: str | Unset = UNSET
+ if not isinstance(status, Unset):
+ json_status = status
+
+ params["status"] = json_status
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/lavaflow/skills",
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | LavaflowSkillList | None:
+ if response.status_code == 200:
+ response_200 = LavaflowSkillList.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | LavaflowSkillList]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ status: LavaflowSkillStatus | Unset = UNSET,
+
+) -> Response[Error | LavaflowSkillList]:
+ """ List LavaFlow skills
+
+ Lists the project's skills, newest first: short, cited notes on how
+ the project wants something done, with each one's active version,
+ counts and source. A project skill belongs to its project and never
+ leaves it. Filter by `status`. The list holds at most 350 skills, so
+ it has no pages.
+
+ LavaFlow doesn't yet learn skills from corrections to its fixes or
+ load them into runs; both come in a later release.
+
+ Project access tokens can list skills, including read-only ones.
+ Skills stay readable while the project's `lavaflow.skills` capability
+ is unavailable.
+
+ Args:
+ project_id (UUID):
+ status (LavaflowSkillStatus | Unset): `proposed` waits for the owner to activate it.
+ `active` is in force. `retired` is set aside and can be restored.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowSkillList]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+status=status,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ status: LavaflowSkillStatus | Unset = UNSET,
+
+) -> Error | LavaflowSkillList | None:
+ """ List LavaFlow skills
+
+ Lists the project's skills, newest first: short, cited notes on how
+ the project wants something done, with each one's active version,
+ counts and source. A project skill belongs to its project and never
+ leaves it. Filter by `status`. The list holds at most 350 skills, so
+ it has no pages.
+
+ LavaFlow doesn't yet learn skills from corrections to its fixes or
+ load them into runs; both come in a later release.
+
+ Project access tokens can list skills, including read-only ones.
+ Skills stay readable while the project's `lavaflow.skills` capability
+ is unavailable.
+
+ Args:
+ project_id (UUID):
+ status (LavaflowSkillStatus | Unset): `proposed` waits for the owner to activate it.
+ `active` is in force. `retired` is set aside and can be restored.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowSkillList
+ """
+
+
+ return sync_detailed(
+ client=client,
+project_id=project_id,
+status=status,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ status: LavaflowSkillStatus | Unset = UNSET,
+
+) -> Response[Error | LavaflowSkillList]:
+ """ List LavaFlow skills
+
+ Lists the project's skills, newest first: short, cited notes on how
+ the project wants something done, with each one's active version,
+ counts and source. A project skill belongs to its project and never
+ leaves it. Filter by `status`. The list holds at most 350 skills, so
+ it has no pages.
+
+ LavaFlow doesn't yet learn skills from corrections to its fixes or
+ load them into runs; both come in a later release.
+
+ Project access tokens can list skills, including read-only ones.
+ Skills stay readable while the project's `lavaflow.skills` capability
+ is unavailable.
+
+ Args:
+ project_id (UUID):
+ status (LavaflowSkillStatus | Unset): `proposed` waits for the owner to activate it.
+ `active` is in force. `retired` is set aside and can be restored.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowSkillList]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+status=status,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ status: LavaflowSkillStatus | Unset = UNSET,
+
+) -> Error | LavaflowSkillList | None:
+ """ List LavaFlow skills
+
+ Lists the project's skills, newest first: short, cited notes on how
+ the project wants something done, with each one's active version,
+ counts and source. A project skill belongs to its project and never
+ leaves it. Filter by `status`. The list holds at most 350 skills, so
+ it has no pages.
+
+ LavaFlow doesn't yet learn skills from corrections to its fixes or
+ load them into runs; both come in a later release.
+
+ Project access tokens can list skills, including read-only ones.
+ Skills stay readable while the project's `lavaflow.skills` capability
+ is unavailable.
+
+ Args:
+ project_id (UUID):
+ status (LavaflowSkillStatus | Unset): `proposed` waits for the owner to activate it.
+ `active` is in force. `retired` is set aside and can be restored.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowSkillList
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+project_id=project_id,
+status=status,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/lava_flow/patch_lavaflow_settings.py b/src/volcano_sdk/_generated/api/lava_flow/patch_lavaflow_settings.py
new file mode 100644
index 00000000..f2ed1246
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/patch_lavaflow_settings.py
@@ -0,0 +1,639 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.lavaflow_settings import LavaflowSettings
+from ...models.lavaflow_settings_update import LavaflowSettingsUpdate
+from typing import cast
+
+
+
+def request_kwargs(
+ *,
+ body: LavaflowSettingsUpdate,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "patch",
+ "url": "/lavaflow/settings",
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | LavaflowSettings | None:
+ if response.status_code == 200:
+ response_200 = LavaflowSettings.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 413:
+ response_413 = Error.from_dict(response.json())
+
+
+
+ return response_413
+
+ if response.status_code == 429:
+ response_429 = Error.from_dict(response.json())
+
+
+
+ return response_429
+
+ if response.status_code == 503:
+ response_503 = Error.from_dict(response.json())
+
+
+
+ return response_503
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | LavaflowSettings]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowSettingsUpdate,
+
+) -> Response[Error | LavaflowSettings]:
+ """ Update LavaFlow settings
+
+ Changes the fields the request names for the project `project_id`
+ names; an omitted field keeps its saved value, or its default when
+ nothing is saved. `{"project_id": "…", "enabled": true}` turns LavaFlow
+ on for every function, frontend and durable function in the project,
+ and records the repository the project points at as the one LavaFlow
+ works in. A request carrying `"enabled": true` is a turn-on, even while
+ LavaFlow is on. When the project points at no repository at a turn-on,
+ the first repository it connects afterwards is recorded. A request
+ that omits `enabled` never changes which repository is recorded.
+ LavaFlow sends this project's logs and source code to an AI service
+ that Volcano operates.
+
+ Turning LavaFlow on, from off, also starts runs for up to 5 open issues
+ with `exception: true` and an `event_count` of at least 2, last seen in
+ the past 7 days, most recently seen first, leaving out any issue
+ LavaFlow already ran; runs LavaFlow queued on its own and hasn't
+ started count toward the 5. They start like any run LavaFlow starts on
+ its own, one at a time per project. Only the owner's save with a
+ `volcano login` token whose sign-in is live, or a platform token that
+ expires, starts them; any other save turns LavaFlow on without them. A save while LavaFlow is on
+ starts none, and neither
+ does LavaFlow becoming available to the project.
+
+ Only the project's owner can save, with a platform token, while their
+ account is active. A full-scope project access token can only turn
+ settings off: a body with `project_id` and one or both of
+ `"code_quality": {"enabled": false}` and `"skill_learning": "off"`,
+ each field spelled exactly and sent once, and nothing else. Any other
+ body from a project access token, including one that turns a setting
+ on, adds a field, sends `null`, or names a field the schema doesn't
+ have, gets `403` with code `person_required`, as does a request made
+ through MCP. A read-only project access token is refused as read-only
+ first, without a code,
+ and so is the owner of a read-only account.
+
+ `code_quality.enabled: true` turns on LavaFlow Code Quality, which
+ reviews the lines each production deploy of a frontend changes and
+ turns what it confirms into issues and pull requests. Function deploys
+ ask for no scan yet. It needs the project's `lavaflow.code_quality`
+ capability: while Code Quality isn't released here the save answers
+ `400` with code `feature_unavailable`, and while the owner's plan
+ allows no Code Quality findings it answers `403` with code
+ `plan_required`. Only the owner can turn it on, with the check below.
+ Turning it off always works, and drops the deploys waiting to be
+ scanned.
+
+ `autonomy: merge` needs the project's `lavaflow.merge` capability.
+ Without it, a save that sets `autonomy` to `merge`, or changes
+ `merge_policy`, answers `400` with code `feature_unavailable`. A save
+ that sends the saved values again passes this check, though it can
+ still need the owner's check below, and a project at `merge` can
+ still change to another autonomy. The save doesn't read the
+ repository's branch rules: LavaFlow merges only into a base branch
+ that requires at least one status check, and holds every fix with
+ `no_required_checks` on any other.
+
+ Changing `autonomy` to `merge` lets LavaFlow merge with no one else
+ looking. So does turning `enabled` on while `autonomy` stays `merge`,
+ and changing `merge_policy`, `custom_context` or `system_prompt`, to
+ any value, while `autonomy` is, or becomes, `merge`. Under settings
+ saved with automatic runs off before this API, the runs LavaFlow
+ starts on its own stop at a draft pull request. Sending `enabled:
+ true` or `autonomy: merge` again, while LavaFlow is on and `autonomy`
+ is `merge`, lets them merge, so it needs the same check. Turning
+ `allow_ungated_workflows` on lets LavaFlow open a fix
+ where a workflow could run it with the repository's secrets before a
+ person approves it. Turning `code_quality` on starts work on every
+ frontend production deploy with no incident behind it, and turning
+ `skill_learning` up, from `off` to `review` or `auto` or from `review`
+ to `auto`, lets what LavaFlow learns steer later runs with less
+ review. Only the owner can make these changes, with a credential of
+ their own that expires: a `volcano login` token
+ whose sign-in is live, or a platform token with an expiry. The owner's
+ GitHub account must also be able to push to the project's repository.
+ A project access token, MCP, a platform token that never expires, a
+ sign-in that ended, an owner who can't push, and a project with no
+ repository get `403` with code `person_required`, and nothing is
+ saved. Turning LavaFlow, `allow_ungated_workflows` or `code_quality`
+ off, and turning `skill_learning` down or off, needs no check.
+ Nothing is saved either when the push check can't be answered (`429`
+ or `503`, with `Retry-After`). When the project points at another
+ repository, reaches its repository through another Volcano GitHub App
+ installation, or points at none, `autonomy` changes from `merge` to
+ `open_pr`; pointing back doesn't change it back. Reconnecting after a
+ reinstall of the App counts as another installation.
+
+ Turning LavaFlow on needs a plan that includes it (`403`, code
+ `plan_required`). LavaFlow is available where the project's
+ `lavaflow` capability is, which includes the owner's plan. Where it is
+ not, a project with LavaFlow records can still turn LavaFlow, Code
+ Quality or skill learning off, or several of them: a save that sends
+ `enabled: false`, `code_quality: {enabled: false}`,
+ `skill_learning: off` or several of them, and otherwise only
+ `allow_ungated_workflows: false` sent with `enabled` or
+ `skill_learning`. Any other save,
+ and any save for a project without records, answers `404` with code
+ `feature_unavailable` while LavaFlow is not offered to the project, and
+ `403` with code `plan_required` when it is but the owner's plan does
+ not include it.
+
+ Args:
+ body (LavaflowSettingsUpdate): The project, and at least one field to change. An omitted
+ field keeps its saved value.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowSettings]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowSettingsUpdate,
+
+) -> Error | LavaflowSettings | None:
+ """ Update LavaFlow settings
+
+ Changes the fields the request names for the project `project_id`
+ names; an omitted field keeps its saved value, or its default when
+ nothing is saved. `{"project_id": "…", "enabled": true}` turns LavaFlow
+ on for every function, frontend and durable function in the project,
+ and records the repository the project points at as the one LavaFlow
+ works in. A request carrying `"enabled": true` is a turn-on, even while
+ LavaFlow is on. When the project points at no repository at a turn-on,
+ the first repository it connects afterwards is recorded. A request
+ that omits `enabled` never changes which repository is recorded.
+ LavaFlow sends this project's logs and source code to an AI service
+ that Volcano operates.
+
+ Turning LavaFlow on, from off, also starts runs for up to 5 open issues
+ with `exception: true` and an `event_count` of at least 2, last seen in
+ the past 7 days, most recently seen first, leaving out any issue
+ LavaFlow already ran; runs LavaFlow queued on its own and hasn't
+ started count toward the 5. They start like any run LavaFlow starts on
+ its own, one at a time per project. Only the owner's save with a
+ `volcano login` token whose sign-in is live, or a platform token that
+ expires, starts them; any other save turns LavaFlow on without them. A save while LavaFlow is on
+ starts none, and neither
+ does LavaFlow becoming available to the project.
+
+ Only the project's owner can save, with a platform token, while their
+ account is active. A full-scope project access token can only turn
+ settings off: a body with `project_id` and one or both of
+ `"code_quality": {"enabled": false}` and `"skill_learning": "off"`,
+ each field spelled exactly and sent once, and nothing else. Any other
+ body from a project access token, including one that turns a setting
+ on, adds a field, sends `null`, or names a field the schema doesn't
+ have, gets `403` with code `person_required`, as does a request made
+ through MCP. A read-only project access token is refused as read-only
+ first, without a code,
+ and so is the owner of a read-only account.
+
+ `code_quality.enabled: true` turns on LavaFlow Code Quality, which
+ reviews the lines each production deploy of a frontend changes and
+ turns what it confirms into issues and pull requests. Function deploys
+ ask for no scan yet. It needs the project's `lavaflow.code_quality`
+ capability: while Code Quality isn't released here the save answers
+ `400` with code `feature_unavailable`, and while the owner's plan
+ allows no Code Quality findings it answers `403` with code
+ `plan_required`. Only the owner can turn it on, with the check below.
+ Turning it off always works, and drops the deploys waiting to be
+ scanned.
+
+ `autonomy: merge` needs the project's `lavaflow.merge` capability.
+ Without it, a save that sets `autonomy` to `merge`, or changes
+ `merge_policy`, answers `400` with code `feature_unavailable`. A save
+ that sends the saved values again passes this check, though it can
+ still need the owner's check below, and a project at `merge` can
+ still change to another autonomy. The save doesn't read the
+ repository's branch rules: LavaFlow merges only into a base branch
+ that requires at least one status check, and holds every fix with
+ `no_required_checks` on any other.
+
+ Changing `autonomy` to `merge` lets LavaFlow merge with no one else
+ looking. So does turning `enabled` on while `autonomy` stays `merge`,
+ and changing `merge_policy`, `custom_context` or `system_prompt`, to
+ any value, while `autonomy` is, or becomes, `merge`. Under settings
+ saved with automatic runs off before this API, the runs LavaFlow
+ starts on its own stop at a draft pull request. Sending `enabled:
+ true` or `autonomy: merge` again, while LavaFlow is on and `autonomy`
+ is `merge`, lets them merge, so it needs the same check. Turning
+ `allow_ungated_workflows` on lets LavaFlow open a fix
+ where a workflow could run it with the repository's secrets before a
+ person approves it. Turning `code_quality` on starts work on every
+ frontend production deploy with no incident behind it, and turning
+ `skill_learning` up, from `off` to `review` or `auto` or from `review`
+ to `auto`, lets what LavaFlow learns steer later runs with less
+ review. Only the owner can make these changes, with a credential of
+ their own that expires: a `volcano login` token
+ whose sign-in is live, or a platform token with an expiry. The owner's
+ GitHub account must also be able to push to the project's repository.
+ A project access token, MCP, a platform token that never expires, a
+ sign-in that ended, an owner who can't push, and a project with no
+ repository get `403` with code `person_required`, and nothing is
+ saved. Turning LavaFlow, `allow_ungated_workflows` or `code_quality`
+ off, and turning `skill_learning` down or off, needs no check.
+ Nothing is saved either when the push check can't be answered (`429`
+ or `503`, with `Retry-After`). When the project points at another
+ repository, reaches its repository through another Volcano GitHub App
+ installation, or points at none, `autonomy` changes from `merge` to
+ `open_pr`; pointing back doesn't change it back. Reconnecting after a
+ reinstall of the App counts as another installation.
+
+ Turning LavaFlow on needs a plan that includes it (`403`, code
+ `plan_required`). LavaFlow is available where the project's
+ `lavaflow` capability is, which includes the owner's plan. Where it is
+ not, a project with LavaFlow records can still turn LavaFlow, Code
+ Quality or skill learning off, or several of them: a save that sends
+ `enabled: false`, `code_quality: {enabled: false}`,
+ `skill_learning: off` or several of them, and otherwise only
+ `allow_ungated_workflows: false` sent with `enabled` or
+ `skill_learning`. Any other save,
+ and any save for a project without records, answers `404` with code
+ `feature_unavailable` while LavaFlow is not offered to the project, and
+ `403` with code `plan_required` when it is but the owner's plan does
+ not include it.
+
+ Args:
+ body (LavaflowSettingsUpdate): The project, and at least one field to change. An omitted
+ field keeps its saved value.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowSettings
+ """
+
+
+ return sync_detailed(
+ client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowSettingsUpdate,
+
+) -> Response[Error | LavaflowSettings]:
+ """ Update LavaFlow settings
+
+ Changes the fields the request names for the project `project_id`
+ names; an omitted field keeps its saved value, or its default when
+ nothing is saved. `{"project_id": "…", "enabled": true}` turns LavaFlow
+ on for every function, frontend and durable function in the project,
+ and records the repository the project points at as the one LavaFlow
+ works in. A request carrying `"enabled": true` is a turn-on, even while
+ LavaFlow is on. When the project points at no repository at a turn-on,
+ the first repository it connects afterwards is recorded. A request
+ that omits `enabled` never changes which repository is recorded.
+ LavaFlow sends this project's logs and source code to an AI service
+ that Volcano operates.
+
+ Turning LavaFlow on, from off, also starts runs for up to 5 open issues
+ with `exception: true` and an `event_count` of at least 2, last seen in
+ the past 7 days, most recently seen first, leaving out any issue
+ LavaFlow already ran; runs LavaFlow queued on its own and hasn't
+ started count toward the 5. They start like any run LavaFlow starts on
+ its own, one at a time per project. Only the owner's save with a
+ `volcano login` token whose sign-in is live, or a platform token that
+ expires, starts them; any other save turns LavaFlow on without them. A save while LavaFlow is on
+ starts none, and neither
+ does LavaFlow becoming available to the project.
+
+ Only the project's owner can save, with a platform token, while their
+ account is active. A full-scope project access token can only turn
+ settings off: a body with `project_id` and one or both of
+ `"code_quality": {"enabled": false}` and `"skill_learning": "off"`,
+ each field spelled exactly and sent once, and nothing else. Any other
+ body from a project access token, including one that turns a setting
+ on, adds a field, sends `null`, or names a field the schema doesn't
+ have, gets `403` with code `person_required`, as does a request made
+ through MCP. A read-only project access token is refused as read-only
+ first, without a code,
+ and so is the owner of a read-only account.
+
+ `code_quality.enabled: true` turns on LavaFlow Code Quality, which
+ reviews the lines each production deploy of a frontend changes and
+ turns what it confirms into issues and pull requests. Function deploys
+ ask for no scan yet. It needs the project's `lavaflow.code_quality`
+ capability: while Code Quality isn't released here the save answers
+ `400` with code `feature_unavailable`, and while the owner's plan
+ allows no Code Quality findings it answers `403` with code
+ `plan_required`. Only the owner can turn it on, with the check below.
+ Turning it off always works, and drops the deploys waiting to be
+ scanned.
+
+ `autonomy: merge` needs the project's `lavaflow.merge` capability.
+ Without it, a save that sets `autonomy` to `merge`, or changes
+ `merge_policy`, answers `400` with code `feature_unavailable`. A save
+ that sends the saved values again passes this check, though it can
+ still need the owner's check below, and a project at `merge` can
+ still change to another autonomy. The save doesn't read the
+ repository's branch rules: LavaFlow merges only into a base branch
+ that requires at least one status check, and holds every fix with
+ `no_required_checks` on any other.
+
+ Changing `autonomy` to `merge` lets LavaFlow merge with no one else
+ looking. So does turning `enabled` on while `autonomy` stays `merge`,
+ and changing `merge_policy`, `custom_context` or `system_prompt`, to
+ any value, while `autonomy` is, or becomes, `merge`. Under settings
+ saved with automatic runs off before this API, the runs LavaFlow
+ starts on its own stop at a draft pull request. Sending `enabled:
+ true` or `autonomy: merge` again, while LavaFlow is on and `autonomy`
+ is `merge`, lets them merge, so it needs the same check. Turning
+ `allow_ungated_workflows` on lets LavaFlow open a fix
+ where a workflow could run it with the repository's secrets before a
+ person approves it. Turning `code_quality` on starts work on every
+ frontend production deploy with no incident behind it, and turning
+ `skill_learning` up, from `off` to `review` or `auto` or from `review`
+ to `auto`, lets what LavaFlow learns steer later runs with less
+ review. Only the owner can make these changes, with a credential of
+ their own that expires: a `volcano login` token
+ whose sign-in is live, or a platform token with an expiry. The owner's
+ GitHub account must also be able to push to the project's repository.
+ A project access token, MCP, a platform token that never expires, a
+ sign-in that ended, an owner who can't push, and a project with no
+ repository get `403` with code `person_required`, and nothing is
+ saved. Turning LavaFlow, `allow_ungated_workflows` or `code_quality`
+ off, and turning `skill_learning` down or off, needs no check.
+ Nothing is saved either when the push check can't be answered (`429`
+ or `503`, with `Retry-After`). When the project points at another
+ repository, reaches its repository through another Volcano GitHub App
+ installation, or points at none, `autonomy` changes from `merge` to
+ `open_pr`; pointing back doesn't change it back. Reconnecting after a
+ reinstall of the App counts as another installation.
+
+ Turning LavaFlow on needs a plan that includes it (`403`, code
+ `plan_required`). LavaFlow is available where the project's
+ `lavaflow` capability is, which includes the owner's plan. Where it is
+ not, a project with LavaFlow records can still turn LavaFlow, Code
+ Quality or skill learning off, or several of them: a save that sends
+ `enabled: false`, `code_quality: {enabled: false}`,
+ `skill_learning: off` or several of them, and otherwise only
+ `allow_ungated_workflows: false` sent with `enabled` or
+ `skill_learning`. Any other save,
+ and any save for a project without records, answers `404` with code
+ `feature_unavailable` while LavaFlow is not offered to the project, and
+ `403` with code `plan_required` when it is but the owner's plan does
+ not include it.
+
+ Args:
+ body (LavaflowSettingsUpdate): The project, and at least one field to change. An omitted
+ field keeps its saved value.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowSettings]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowSettingsUpdate,
+
+) -> Error | LavaflowSettings | None:
+ """ Update LavaFlow settings
+
+ Changes the fields the request names for the project `project_id`
+ names; an omitted field keeps its saved value, or its default when
+ nothing is saved. `{"project_id": "…", "enabled": true}` turns LavaFlow
+ on for every function, frontend and durable function in the project,
+ and records the repository the project points at as the one LavaFlow
+ works in. A request carrying `"enabled": true` is a turn-on, even while
+ LavaFlow is on. When the project points at no repository at a turn-on,
+ the first repository it connects afterwards is recorded. A request
+ that omits `enabled` never changes which repository is recorded.
+ LavaFlow sends this project's logs and source code to an AI service
+ that Volcano operates.
+
+ Turning LavaFlow on, from off, also starts runs for up to 5 open issues
+ with `exception: true` and an `event_count` of at least 2, last seen in
+ the past 7 days, most recently seen first, leaving out any issue
+ LavaFlow already ran; runs LavaFlow queued on its own and hasn't
+ started count toward the 5. They start like any run LavaFlow starts on
+ its own, one at a time per project. Only the owner's save with a
+ `volcano login` token whose sign-in is live, or a platform token that
+ expires, starts them; any other save turns LavaFlow on without them. A save while LavaFlow is on
+ starts none, and neither
+ does LavaFlow becoming available to the project.
+
+ Only the project's owner can save, with a platform token, while their
+ account is active. A full-scope project access token can only turn
+ settings off: a body with `project_id` and one or both of
+ `"code_quality": {"enabled": false}` and `"skill_learning": "off"`,
+ each field spelled exactly and sent once, and nothing else. Any other
+ body from a project access token, including one that turns a setting
+ on, adds a field, sends `null`, or names a field the schema doesn't
+ have, gets `403` with code `person_required`, as does a request made
+ through MCP. A read-only project access token is refused as read-only
+ first, without a code,
+ and so is the owner of a read-only account.
+
+ `code_quality.enabled: true` turns on LavaFlow Code Quality, which
+ reviews the lines each production deploy of a frontend changes and
+ turns what it confirms into issues and pull requests. Function deploys
+ ask for no scan yet. It needs the project's `lavaflow.code_quality`
+ capability: while Code Quality isn't released here the save answers
+ `400` with code `feature_unavailable`, and while the owner's plan
+ allows no Code Quality findings it answers `403` with code
+ `plan_required`. Only the owner can turn it on, with the check below.
+ Turning it off always works, and drops the deploys waiting to be
+ scanned.
+
+ `autonomy: merge` needs the project's `lavaflow.merge` capability.
+ Without it, a save that sets `autonomy` to `merge`, or changes
+ `merge_policy`, answers `400` with code `feature_unavailable`. A save
+ that sends the saved values again passes this check, though it can
+ still need the owner's check below, and a project at `merge` can
+ still change to another autonomy. The save doesn't read the
+ repository's branch rules: LavaFlow merges only into a base branch
+ that requires at least one status check, and holds every fix with
+ `no_required_checks` on any other.
+
+ Changing `autonomy` to `merge` lets LavaFlow merge with no one else
+ looking. So does turning `enabled` on while `autonomy` stays `merge`,
+ and changing `merge_policy`, `custom_context` or `system_prompt`, to
+ any value, while `autonomy` is, or becomes, `merge`. Under settings
+ saved with automatic runs off before this API, the runs LavaFlow
+ starts on its own stop at a draft pull request. Sending `enabled:
+ true` or `autonomy: merge` again, while LavaFlow is on and `autonomy`
+ is `merge`, lets them merge, so it needs the same check. Turning
+ `allow_ungated_workflows` on lets LavaFlow open a fix
+ where a workflow could run it with the repository's secrets before a
+ person approves it. Turning `code_quality` on starts work on every
+ frontend production deploy with no incident behind it, and turning
+ `skill_learning` up, from `off` to `review` or `auto` or from `review`
+ to `auto`, lets what LavaFlow learns steer later runs with less
+ review. Only the owner can make these changes, with a credential of
+ their own that expires: a `volcano login` token
+ whose sign-in is live, or a platform token with an expiry. The owner's
+ GitHub account must also be able to push to the project's repository.
+ A project access token, MCP, a platform token that never expires, a
+ sign-in that ended, an owner who can't push, and a project with no
+ repository get `403` with code `person_required`, and nothing is
+ saved. Turning LavaFlow, `allow_ungated_workflows` or `code_quality`
+ off, and turning `skill_learning` down or off, needs no check.
+ Nothing is saved either when the push check can't be answered (`429`
+ or `503`, with `Retry-After`). When the project points at another
+ repository, reaches its repository through another Volcano GitHub App
+ installation, or points at none, `autonomy` changes from `merge` to
+ `open_pr`; pointing back doesn't change it back. Reconnecting after a
+ reinstall of the App counts as another installation.
+
+ Turning LavaFlow on needs a plan that includes it (`403`, code
+ `plan_required`). LavaFlow is available where the project's
+ `lavaflow` capability is, which includes the owner's plan. Where it is
+ not, a project with LavaFlow records can still turn LavaFlow, Code
+ Quality or skill learning off, or several of them: a save that sends
+ `enabled: false`, `code_quality: {enabled: false}`,
+ `skill_learning: off` or several of them, and otherwise only
+ `allow_ungated_workflows: false` sent with `enabled` or
+ `skill_learning`. Any other save,
+ and any save for a project without records, answers `404` with code
+ `feature_unavailable` while LavaFlow is not offered to the project, and
+ `403` with code `plan_required` when it is but the owner's plan does
+ not include it.
+
+ Args:
+ body (LavaflowSettingsUpdate): The project, and at least one field to change. An omitted
+ field keeps its saved value.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowSettings
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/lava_flow/update_lavaflow_settings.py b/src/volcano_sdk/_generated/api/lava_flow/update_lavaflow_settings.py
new file mode 100644
index 00000000..39bec15a
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/update_lavaflow_settings.py
@@ -0,0 +1,587 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.lavaflow_settings import LavaflowSettings
+from ...models.lavaflow_settings_update import LavaflowSettingsUpdate
+from typing import cast
+
+
+
+def request_kwargs(
+ *,
+ body: LavaflowSettingsUpdate,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "put",
+ "url": "/lavaflow/settings",
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | LavaflowSettings | None:
+ if response.status_code == 200:
+ response_200 = LavaflowSettings.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 413:
+ response_413 = Error.from_dict(response.json())
+
+
+
+ return response_413
+
+ if response.status_code == 429:
+ response_429 = Error.from_dict(response.json())
+
+
+
+ return response_429
+
+ if response.status_code == 503:
+ response_503 = Error.from_dict(response.json())
+
+
+
+ return response_503
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | LavaflowSettings]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowSettingsUpdate,
+
+) -> Response[Error | LavaflowSettings]:
+ """ Update LavaFlow settings (deprecated)
+
+ Deprecated: use `PATCH /lavaflow/settings`, which takes the same body.
+ This operation keeps working, and refuses every project access token
+ before it reads the body.
+
+ Changes the fields the request names for the project `project_id`
+ names; an omitted field keeps its saved value, or its default when
+ nothing is saved. `{"project_id": "…", "enabled": true}` turns LavaFlow
+ on for every function, frontend and durable function in the project,
+ and records the repository the project points at as the one LavaFlow
+ works in. A request carrying `"enabled": true` is a turn-on, even while
+ LavaFlow is on. When the project points at no repository at a turn-on,
+ the first repository it connects afterwards is recorded. A request
+ that omits `enabled` never changes which repository is recorded.
+ LavaFlow sends this project's logs
+ and source code to an AI service that Volcano operates.
+
+ Turning LavaFlow on, from off, also starts runs for up to 5 open issues
+ with `exception: true` and an `event_count` of at least 2, last seen in
+ the past 7 days, most recently seen first, leaving out any issue
+ LavaFlow already ran; runs LavaFlow queued on its own and hasn't
+ started count toward the 5. They start like any run LavaFlow starts on
+ its own, one at a time per project. Only the owner's save with a
+ `volcano login` token whose sign-in is live, or a platform token that
+ expires, starts them; any other save turns LavaFlow on without them. A save while LavaFlow is on
+ starts none, and neither
+ does LavaFlow becoming available to the project.
+
+ Only the project's owner can save, with a platform token, while their
+ account is active. A full-scope project access token, its save that
+ turns skill learning off included, or a request made through MCP,
+ gets `403` with code `person_required`; a token sends that save with
+ `PATCH`. A read-only project access token is refused as read-only
+ first, without a code, and so is the owner of a read-only account.
+
+ `autonomy: merge` needs the project's `lavaflow.merge` capability.
+ Without it, a save that sets `autonomy` to `merge`, or changes
+ `merge_policy`, answers `400` with code `feature_unavailable`. A save
+ that sends the saved values again passes this check, though it can
+ still need the owner's check below, and a project at `merge` can
+ still change to another autonomy. The save doesn't read the
+ repository's branch rules: LavaFlow merges only into a base branch
+ that requires at least one status check, and holds every fix with
+ `no_required_checks` on any other.
+
+ Changing `autonomy` to `merge` lets LavaFlow merge with no one else
+ looking. So does turning `enabled` on while `autonomy` stays `merge`,
+ and changing `merge_policy`, `custom_context` or `system_prompt`, to
+ any value, while `autonomy` is, or becomes, `merge`. Under settings
+ saved with automatic runs off before this API, the runs LavaFlow
+ starts on its own stop at a draft pull request. Sending `enabled:
+ true` or `autonomy: merge` again, while LavaFlow is on and `autonomy`
+ is `merge`, lets them merge, so it needs the same check. Turning
+ `allow_ungated_workflows` on lets LavaFlow open a fix
+ where a workflow could run it with the repository's secrets before a
+ person approves it. Turning `skill_learning` up, from `off` to
+ `review` or `auto` or from `review` to `auto`, lets what LavaFlow
+ learns steer later runs with less review. Only the owner can make
+ these changes, with a
+ credential of their own that expires: a `volcano
+ login` token whose sign-in is live, or a platform token with an
+ expiry. The owner's GitHub account must also be able to push to the
+ project's repository. A project access token, MCP, a platform token
+ that never expires, a sign-in that ended, an owner who can't push, and
+ a project with no repository get `403` with code `person_required`,
+ and nothing is saved. Turning LavaFlow or `allow_ungated_workflows`
+ off, and turning `skill_learning` down or off, needs no check.
+ Nothing is saved either when the push check can't be answered (`429`
+ or `503`, with `Retry-After`). When the project points at another
+ repository, reaches its repository through another Volcano GitHub App
+ installation, or points at none, `autonomy` changes from `merge` to
+ `open_pr`; pointing back doesn't change it back. Reconnecting after a
+ reinstall of the App counts as another installation.
+
+ Turning LavaFlow on needs a plan that includes it (`403`, code
+ `plan_required`). LavaFlow is available where the project's
+ `lavaflow` capability is, which includes the owner's plan. Where it is
+ not, a project with LavaFlow records can still turn LavaFlow, Code
+ Quality or skill learning off, or several of them: a save that sends
+ `enabled: false`, `code_quality: {enabled: false}`,
+ `skill_learning: off` or several of them, and otherwise only
+ `allow_ungated_workflows: false` sent with `enabled` or
+ `skill_learning`. Any other save,
+ and any save for a project without records, answers `404` with code
+ `feature_unavailable` while LavaFlow is not offered to the project, and
+ `403` with code `plan_required` when it is but the owner's plan does
+ not include it.
+
+ Args:
+ body (LavaflowSettingsUpdate): The project, and at least one field to change. An omitted
+ field keeps its saved value.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowSettings]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowSettingsUpdate,
+
+) -> Error | LavaflowSettings | None:
+ """ Update LavaFlow settings (deprecated)
+
+ Deprecated: use `PATCH /lavaflow/settings`, which takes the same body.
+ This operation keeps working, and refuses every project access token
+ before it reads the body.
+
+ Changes the fields the request names for the project `project_id`
+ names; an omitted field keeps its saved value, or its default when
+ nothing is saved. `{"project_id": "…", "enabled": true}` turns LavaFlow
+ on for every function, frontend and durable function in the project,
+ and records the repository the project points at as the one LavaFlow
+ works in. A request carrying `"enabled": true` is a turn-on, even while
+ LavaFlow is on. When the project points at no repository at a turn-on,
+ the first repository it connects afterwards is recorded. A request
+ that omits `enabled` never changes which repository is recorded.
+ LavaFlow sends this project's logs
+ and source code to an AI service that Volcano operates.
+
+ Turning LavaFlow on, from off, also starts runs for up to 5 open issues
+ with `exception: true` and an `event_count` of at least 2, last seen in
+ the past 7 days, most recently seen first, leaving out any issue
+ LavaFlow already ran; runs LavaFlow queued on its own and hasn't
+ started count toward the 5. They start like any run LavaFlow starts on
+ its own, one at a time per project. Only the owner's save with a
+ `volcano login` token whose sign-in is live, or a platform token that
+ expires, starts them; any other save turns LavaFlow on without them. A save while LavaFlow is on
+ starts none, and neither
+ does LavaFlow becoming available to the project.
+
+ Only the project's owner can save, with a platform token, while their
+ account is active. A full-scope project access token, its save that
+ turns skill learning off included, or a request made through MCP,
+ gets `403` with code `person_required`; a token sends that save with
+ `PATCH`. A read-only project access token is refused as read-only
+ first, without a code, and so is the owner of a read-only account.
+
+ `autonomy: merge` needs the project's `lavaflow.merge` capability.
+ Without it, a save that sets `autonomy` to `merge`, or changes
+ `merge_policy`, answers `400` with code `feature_unavailable`. A save
+ that sends the saved values again passes this check, though it can
+ still need the owner's check below, and a project at `merge` can
+ still change to another autonomy. The save doesn't read the
+ repository's branch rules: LavaFlow merges only into a base branch
+ that requires at least one status check, and holds every fix with
+ `no_required_checks` on any other.
+
+ Changing `autonomy` to `merge` lets LavaFlow merge with no one else
+ looking. So does turning `enabled` on while `autonomy` stays `merge`,
+ and changing `merge_policy`, `custom_context` or `system_prompt`, to
+ any value, while `autonomy` is, or becomes, `merge`. Under settings
+ saved with automatic runs off before this API, the runs LavaFlow
+ starts on its own stop at a draft pull request. Sending `enabled:
+ true` or `autonomy: merge` again, while LavaFlow is on and `autonomy`
+ is `merge`, lets them merge, so it needs the same check. Turning
+ `allow_ungated_workflows` on lets LavaFlow open a fix
+ where a workflow could run it with the repository's secrets before a
+ person approves it. Turning `skill_learning` up, from `off` to
+ `review` or `auto` or from `review` to `auto`, lets what LavaFlow
+ learns steer later runs with less review. Only the owner can make
+ these changes, with a
+ credential of their own that expires: a `volcano
+ login` token whose sign-in is live, or a platform token with an
+ expiry. The owner's GitHub account must also be able to push to the
+ project's repository. A project access token, MCP, a platform token
+ that never expires, a sign-in that ended, an owner who can't push, and
+ a project with no repository get `403` with code `person_required`,
+ and nothing is saved. Turning LavaFlow or `allow_ungated_workflows`
+ off, and turning `skill_learning` down or off, needs no check.
+ Nothing is saved either when the push check can't be answered (`429`
+ or `503`, with `Retry-After`). When the project points at another
+ repository, reaches its repository through another Volcano GitHub App
+ installation, or points at none, `autonomy` changes from `merge` to
+ `open_pr`; pointing back doesn't change it back. Reconnecting after a
+ reinstall of the App counts as another installation.
+
+ Turning LavaFlow on needs a plan that includes it (`403`, code
+ `plan_required`). LavaFlow is available where the project's
+ `lavaflow` capability is, which includes the owner's plan. Where it is
+ not, a project with LavaFlow records can still turn LavaFlow, Code
+ Quality or skill learning off, or several of them: a save that sends
+ `enabled: false`, `code_quality: {enabled: false}`,
+ `skill_learning: off` or several of them, and otherwise only
+ `allow_ungated_workflows: false` sent with `enabled` or
+ `skill_learning`. Any other save,
+ and any save for a project without records, answers `404` with code
+ `feature_unavailable` while LavaFlow is not offered to the project, and
+ `403` with code `plan_required` when it is but the owner's plan does
+ not include it.
+
+ Args:
+ body (LavaflowSettingsUpdate): The project, and at least one field to change. An omitted
+ field keeps its saved value.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowSettings
+ """
+
+
+ return sync_detailed(
+ client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowSettingsUpdate,
+
+) -> Response[Error | LavaflowSettings]:
+ """ Update LavaFlow settings (deprecated)
+
+ Deprecated: use `PATCH /lavaflow/settings`, which takes the same body.
+ This operation keeps working, and refuses every project access token
+ before it reads the body.
+
+ Changes the fields the request names for the project `project_id`
+ names; an omitted field keeps its saved value, or its default when
+ nothing is saved. `{"project_id": "…", "enabled": true}` turns LavaFlow
+ on for every function, frontend and durable function in the project,
+ and records the repository the project points at as the one LavaFlow
+ works in. A request carrying `"enabled": true` is a turn-on, even while
+ LavaFlow is on. When the project points at no repository at a turn-on,
+ the first repository it connects afterwards is recorded. A request
+ that omits `enabled` never changes which repository is recorded.
+ LavaFlow sends this project's logs
+ and source code to an AI service that Volcano operates.
+
+ Turning LavaFlow on, from off, also starts runs for up to 5 open issues
+ with `exception: true` and an `event_count` of at least 2, last seen in
+ the past 7 days, most recently seen first, leaving out any issue
+ LavaFlow already ran; runs LavaFlow queued on its own and hasn't
+ started count toward the 5. They start like any run LavaFlow starts on
+ its own, one at a time per project. Only the owner's save with a
+ `volcano login` token whose sign-in is live, or a platform token that
+ expires, starts them; any other save turns LavaFlow on without them. A save while LavaFlow is on
+ starts none, and neither
+ does LavaFlow becoming available to the project.
+
+ Only the project's owner can save, with a platform token, while their
+ account is active. A full-scope project access token, its save that
+ turns skill learning off included, or a request made through MCP,
+ gets `403` with code `person_required`; a token sends that save with
+ `PATCH`. A read-only project access token is refused as read-only
+ first, without a code, and so is the owner of a read-only account.
+
+ `autonomy: merge` needs the project's `lavaflow.merge` capability.
+ Without it, a save that sets `autonomy` to `merge`, or changes
+ `merge_policy`, answers `400` with code `feature_unavailable`. A save
+ that sends the saved values again passes this check, though it can
+ still need the owner's check below, and a project at `merge` can
+ still change to another autonomy. The save doesn't read the
+ repository's branch rules: LavaFlow merges only into a base branch
+ that requires at least one status check, and holds every fix with
+ `no_required_checks` on any other.
+
+ Changing `autonomy` to `merge` lets LavaFlow merge with no one else
+ looking. So does turning `enabled` on while `autonomy` stays `merge`,
+ and changing `merge_policy`, `custom_context` or `system_prompt`, to
+ any value, while `autonomy` is, or becomes, `merge`. Under settings
+ saved with automatic runs off before this API, the runs LavaFlow
+ starts on its own stop at a draft pull request. Sending `enabled:
+ true` or `autonomy: merge` again, while LavaFlow is on and `autonomy`
+ is `merge`, lets them merge, so it needs the same check. Turning
+ `allow_ungated_workflows` on lets LavaFlow open a fix
+ where a workflow could run it with the repository's secrets before a
+ person approves it. Turning `skill_learning` up, from `off` to
+ `review` or `auto` or from `review` to `auto`, lets what LavaFlow
+ learns steer later runs with less review. Only the owner can make
+ these changes, with a
+ credential of their own that expires: a `volcano
+ login` token whose sign-in is live, or a platform token with an
+ expiry. The owner's GitHub account must also be able to push to the
+ project's repository. A project access token, MCP, a platform token
+ that never expires, a sign-in that ended, an owner who can't push, and
+ a project with no repository get `403` with code `person_required`,
+ and nothing is saved. Turning LavaFlow or `allow_ungated_workflows`
+ off, and turning `skill_learning` down or off, needs no check.
+ Nothing is saved either when the push check can't be answered (`429`
+ or `503`, with `Retry-After`). When the project points at another
+ repository, reaches its repository through another Volcano GitHub App
+ installation, or points at none, `autonomy` changes from `merge` to
+ `open_pr`; pointing back doesn't change it back. Reconnecting after a
+ reinstall of the App counts as another installation.
+
+ Turning LavaFlow on needs a plan that includes it (`403`, code
+ `plan_required`). LavaFlow is available where the project's
+ `lavaflow` capability is, which includes the owner's plan. Where it is
+ not, a project with LavaFlow records can still turn LavaFlow, Code
+ Quality or skill learning off, or several of them: a save that sends
+ `enabled: false`, `code_quality: {enabled: false}`,
+ `skill_learning: off` or several of them, and otherwise only
+ `allow_ungated_workflows: false` sent with `enabled` or
+ `skill_learning`. Any other save,
+ and any save for a project without records, answers `404` with code
+ `feature_unavailable` while LavaFlow is not offered to the project, and
+ `403` with code `plan_required` when it is but the owner's plan does
+ not include it.
+
+ Args:
+ body (LavaflowSettingsUpdate): The project, and at least one field to change. An omitted
+ field keeps its saved value.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowSettings]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowSettingsUpdate,
+
+) -> Error | LavaflowSettings | None:
+ """ Update LavaFlow settings (deprecated)
+
+ Deprecated: use `PATCH /lavaflow/settings`, which takes the same body.
+ This operation keeps working, and refuses every project access token
+ before it reads the body.
+
+ Changes the fields the request names for the project `project_id`
+ names; an omitted field keeps its saved value, or its default when
+ nothing is saved. `{"project_id": "…", "enabled": true}` turns LavaFlow
+ on for every function, frontend and durable function in the project,
+ and records the repository the project points at as the one LavaFlow
+ works in. A request carrying `"enabled": true` is a turn-on, even while
+ LavaFlow is on. When the project points at no repository at a turn-on,
+ the first repository it connects afterwards is recorded. A request
+ that omits `enabled` never changes which repository is recorded.
+ LavaFlow sends this project's logs
+ and source code to an AI service that Volcano operates.
+
+ Turning LavaFlow on, from off, also starts runs for up to 5 open issues
+ with `exception: true` and an `event_count` of at least 2, last seen in
+ the past 7 days, most recently seen first, leaving out any issue
+ LavaFlow already ran; runs LavaFlow queued on its own and hasn't
+ started count toward the 5. They start like any run LavaFlow starts on
+ its own, one at a time per project. Only the owner's save with a
+ `volcano login` token whose sign-in is live, or a platform token that
+ expires, starts them; any other save turns LavaFlow on without them. A save while LavaFlow is on
+ starts none, and neither
+ does LavaFlow becoming available to the project.
+
+ Only the project's owner can save, with a platform token, while their
+ account is active. A full-scope project access token, its save that
+ turns skill learning off included, or a request made through MCP,
+ gets `403` with code `person_required`; a token sends that save with
+ `PATCH`. A read-only project access token is refused as read-only
+ first, without a code, and so is the owner of a read-only account.
+
+ `autonomy: merge` needs the project's `lavaflow.merge` capability.
+ Without it, a save that sets `autonomy` to `merge`, or changes
+ `merge_policy`, answers `400` with code `feature_unavailable`. A save
+ that sends the saved values again passes this check, though it can
+ still need the owner's check below, and a project at `merge` can
+ still change to another autonomy. The save doesn't read the
+ repository's branch rules: LavaFlow merges only into a base branch
+ that requires at least one status check, and holds every fix with
+ `no_required_checks` on any other.
+
+ Changing `autonomy` to `merge` lets LavaFlow merge with no one else
+ looking. So does turning `enabled` on while `autonomy` stays `merge`,
+ and changing `merge_policy`, `custom_context` or `system_prompt`, to
+ any value, while `autonomy` is, or becomes, `merge`. Under settings
+ saved with automatic runs off before this API, the runs LavaFlow
+ starts on its own stop at a draft pull request. Sending `enabled:
+ true` or `autonomy: merge` again, while LavaFlow is on and `autonomy`
+ is `merge`, lets them merge, so it needs the same check. Turning
+ `allow_ungated_workflows` on lets LavaFlow open a fix
+ where a workflow could run it with the repository's secrets before a
+ person approves it. Turning `skill_learning` up, from `off` to
+ `review` or `auto` or from `review` to `auto`, lets what LavaFlow
+ learns steer later runs with less review. Only the owner can make
+ these changes, with a
+ credential of their own that expires: a `volcano
+ login` token whose sign-in is live, or a platform token with an
+ expiry. The owner's GitHub account must also be able to push to the
+ project's repository. A project access token, MCP, a platform token
+ that never expires, a sign-in that ended, an owner who can't push, and
+ a project with no repository get `403` with code `person_required`,
+ and nothing is saved. Turning LavaFlow or `allow_ungated_workflows`
+ off, and turning `skill_learning` down or off, needs no check.
+ Nothing is saved either when the push check can't be answered (`429`
+ or `503`, with `Retry-After`). When the project points at another
+ repository, reaches its repository through another Volcano GitHub App
+ installation, or points at none, `autonomy` changes from `merge` to
+ `open_pr`; pointing back doesn't change it back. Reconnecting after a
+ reinstall of the App counts as another installation.
+
+ Turning LavaFlow on needs a plan that includes it (`403`, code
+ `plan_required`). LavaFlow is available where the project's
+ `lavaflow` capability is, which includes the owner's plan. Where it is
+ not, a project with LavaFlow records can still turn LavaFlow, Code
+ Quality or skill learning off, or several of them: a save that sends
+ `enabled: false`, `code_quality: {enabled: false}`,
+ `skill_learning: off` or several of them, and otherwise only
+ `allow_ungated_workflows: false` sent with `enabled` or
+ `skill_learning`. Any other save,
+ and any save for a project without records, answers `404` with code
+ `feature_unavailable` while LavaFlow is not offered to the project, and
+ `403` with code `plan_required` when it is but the owner's plan does
+ not include it.
+
+ Args:
+ body (LavaflowSettingsUpdate): The project, and at least one field to change. An omitted
+ field keeps its saved value.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowSettings
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/lava_flow/update_lavaflow_skill.py b/src/volcano_sdk/_generated/api/lava_flow/update_lavaflow_skill.py
new file mode 100644
index 00000000..de3b860c
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/lava_flow/update_lavaflow_skill.py
@@ -0,0 +1,406 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.lavaflow_skill import LavaflowSkill
+from ...models.lavaflow_skill_error import LavaflowSkillError
+from ...models.lavaflow_skill_update import LavaflowSkillUpdate
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ skill_id: UUID | str,
+ *,
+ body: LavaflowSkillUpdate,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+ params: dict[str, Any] = {}
+
+ json_project_id: str | Unset = UNSET
+ if not isinstance(project_id, Unset):
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "patch",
+ "url": "/lavaflow/skills/{skill_id}".format(skill_id=quote(str(skill_id), safe=""),),
+ "params": params,
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | LavaflowSkill | LavaflowSkillError | None:
+ if response.status_code == 200:
+ response_200 = LavaflowSkill.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = LavaflowSkillError.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 413:
+ response_413 = Error.from_dict(response.json())
+
+
+
+ return response_413
+
+ if response.status_code == 429:
+ response_429 = Error.from_dict(response.json())
+
+
+
+ return response_429
+
+ if response.status_code == 503:
+ response_503 = Error.from_dict(response.json())
+
+
+
+ return response_503
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | LavaflowSkill | LavaflowSkillError]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ skill_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowSkillUpdate,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Response[Error | LavaflowSkill | LavaflowSkillError]:
+ """ Change a LavaFlow skill
+
+ Changes only the fields you send: a skill's `description`, `body` or
+ `applies_to`, or its `status`: `active` activates a proposed skill or
+ restores a retired one, and `retired` retires it. `applies_to` merges
+ member by member: an omitted member keeps its value, and a list you
+ send replaces it, so `[]` clears it. Citations can't be changed.
+ A skill is a standing instruction to LavaFlow, so only the project's
+ owner changes one, signed in as a person: with a
+ `volcano login` token whose sign-in is live, or a platform token with
+ an expiry. A change other than retiring also needs the owner's GitHub
+ account to be able to push to the project's repository. A project
+ access token, MCP, a platform token that never expires, a sign-in
+ that ended, an owner who can't push, and a project with no repository
+ get `403` with code `person_required`, and nothing is saved. Retiring
+ needs no repository. Nothing is saved either when the push check
+ can't be answered (`429` or `503`, with `Retry-After`).
+
+ A project keeps its 200 most recently retired skills: retiring
+ another deletes the oldest retired skill and its versions.
+
+ Every change but retiring passes the skill check. Only a change to
+ the text adds a version; activating or restoring doesn't. Text that
+ holds a credential, a project secret value, an email address, a link
+ or a host name, an invisible or control character, a CI-skip
+ directive, or an instruction to skip or weaken tests, CI or
+ LavaFlow's rules answers `400` with code `skill_refused` and the
+ `rules` it failed; nothing is saved, and the text is not kept. When
+ the check can't run, the change answers `503` with code
+ `scan_unavailable` and `Retry-After`.
+
+ Retiring works while the project's `lavaflow.skills` capability is
+ unavailable. Any other change answers `400` with code
+ `feature_unavailable` then.
+
+ Args:
+ skill_id (UUID):
+ project_id (UUID | Unset):
+ body (LavaflowSkillUpdate): The fields to change. An omitted field keeps its value.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowSkill | LavaflowSkillError]
+ """
+
+
+ kwargs = request_kwargs(
+ skill_id=skill_id,
+body=body,
+project_id=project_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ skill_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowSkillUpdate,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Error | LavaflowSkill | LavaflowSkillError | None:
+ """ Change a LavaFlow skill
+
+ Changes only the fields you send: a skill's `description`, `body` or
+ `applies_to`, or its `status`: `active` activates a proposed skill or
+ restores a retired one, and `retired` retires it. `applies_to` merges
+ member by member: an omitted member keeps its value, and a list you
+ send replaces it, so `[]` clears it. Citations can't be changed.
+ A skill is a standing instruction to LavaFlow, so only the project's
+ owner changes one, signed in as a person: with a
+ `volcano login` token whose sign-in is live, or a platform token with
+ an expiry. A change other than retiring also needs the owner's GitHub
+ account to be able to push to the project's repository. A project
+ access token, MCP, a platform token that never expires, a sign-in
+ that ended, an owner who can't push, and a project with no repository
+ get `403` with code `person_required`, and nothing is saved. Retiring
+ needs no repository. Nothing is saved either when the push check
+ can't be answered (`429` or `503`, with `Retry-After`).
+
+ A project keeps its 200 most recently retired skills: retiring
+ another deletes the oldest retired skill and its versions.
+
+ Every change but retiring passes the skill check. Only a change to
+ the text adds a version; activating or restoring doesn't. Text that
+ holds a credential, a project secret value, an email address, a link
+ or a host name, an invisible or control character, a CI-skip
+ directive, or an instruction to skip or weaken tests, CI or
+ LavaFlow's rules answers `400` with code `skill_refused` and the
+ `rules` it failed; nothing is saved, and the text is not kept. When
+ the check can't run, the change answers `503` with code
+ `scan_unavailable` and `Retry-After`.
+
+ Retiring works while the project's `lavaflow.skills` capability is
+ unavailable. Any other change answers `400` with code
+ `feature_unavailable` then.
+
+ Args:
+ skill_id (UUID):
+ project_id (UUID | Unset):
+ body (LavaflowSkillUpdate): The fields to change. An omitted field keeps its value.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowSkill | LavaflowSkillError
+ """
+
+
+ return sync_detailed(
+ skill_id=skill_id,
+client=client,
+body=body,
+project_id=project_id,
+
+ ).parsed
+
+async def asyncio_detailed(
+ skill_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowSkillUpdate,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Response[Error | LavaflowSkill | LavaflowSkillError]:
+ """ Change a LavaFlow skill
+
+ Changes only the fields you send: a skill's `description`, `body` or
+ `applies_to`, or its `status`: `active` activates a proposed skill or
+ restores a retired one, and `retired` retires it. `applies_to` merges
+ member by member: an omitted member keeps its value, and a list you
+ send replaces it, so `[]` clears it. Citations can't be changed.
+ A skill is a standing instruction to LavaFlow, so only the project's
+ owner changes one, signed in as a person: with a
+ `volcano login` token whose sign-in is live, or a platform token with
+ an expiry. A change other than retiring also needs the owner's GitHub
+ account to be able to push to the project's repository. A project
+ access token, MCP, a platform token that never expires, a sign-in
+ that ended, an owner who can't push, and a project with no repository
+ get `403` with code `person_required`, and nothing is saved. Retiring
+ needs no repository. Nothing is saved either when the push check
+ can't be answered (`429` or `503`, with `Retry-After`).
+
+ A project keeps its 200 most recently retired skills: retiring
+ another deletes the oldest retired skill and its versions.
+
+ Every change but retiring passes the skill check. Only a change to
+ the text adds a version; activating or restoring doesn't. Text that
+ holds a credential, a project secret value, an email address, a link
+ or a host name, an invisible or control character, a CI-skip
+ directive, or an instruction to skip or weaken tests, CI or
+ LavaFlow's rules answers `400` with code `skill_refused` and the
+ `rules` it failed; nothing is saved, and the text is not kept. When
+ the check can't run, the change answers `503` with code
+ `scan_unavailable` and `Retry-After`.
+
+ Retiring works while the project's `lavaflow.skills` capability is
+ unavailable. Any other change answers `400` with code
+ `feature_unavailable` then.
+
+ Args:
+ skill_id (UUID):
+ project_id (UUID | Unset):
+ body (LavaflowSkillUpdate): The fields to change. An omitted field keeps its value.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | LavaflowSkill | LavaflowSkillError]
+ """
+
+
+ kwargs = request_kwargs(
+ skill_id=skill_id,
+body=body,
+project_id=project_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ skill_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: LavaflowSkillUpdate,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Error | LavaflowSkill | LavaflowSkillError | None:
+ """ Change a LavaFlow skill
+
+ Changes only the fields you send: a skill's `description`, `body` or
+ `applies_to`, or its `status`: `active` activates a proposed skill or
+ restores a retired one, and `retired` retires it. `applies_to` merges
+ member by member: an omitted member keeps its value, and a list you
+ send replaces it, so `[]` clears it. Citations can't be changed.
+ A skill is a standing instruction to LavaFlow, so only the project's
+ owner changes one, signed in as a person: with a
+ `volcano login` token whose sign-in is live, or a platform token with
+ an expiry. A change other than retiring also needs the owner's GitHub
+ account to be able to push to the project's repository. A project
+ access token, MCP, a platform token that never expires, a sign-in
+ that ended, an owner who can't push, and a project with no repository
+ get `403` with code `person_required`, and nothing is saved. Retiring
+ needs no repository. Nothing is saved either when the push check
+ can't be answered (`429` or `503`, with `Retry-After`).
+
+ A project keeps its 200 most recently retired skills: retiring
+ another deletes the oldest retired skill and its versions.
+
+ Every change but retiring passes the skill check. Only a change to
+ the text adds a version; activating or restoring doesn't. Text that
+ holds a credential, a project secret value, an email address, a link
+ or a host name, an invisible or control character, a CI-skip
+ directive, or an instruction to skip or weaken tests, CI or
+ LavaFlow's rules answers `400` with code `skill_refused` and the
+ `rules` it failed; nothing is saved, and the text is not kept. When
+ the check can't run, the change answers `503` with code
+ `scan_unavailable` and `Retry-After`.
+
+ Retiring works while the project's `lavaflow.skills` capability is
+ unavailable. Any other change answers `400` with code
+ `feature_unavailable` then.
+
+ Args:
+ skill_id (UUID):
+ project_id (UUID | Unset):
+ body (LavaflowSkillUpdate): The fields to change. An omitted field keeps its value.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | LavaflowSkill | LavaflowSkillError
+ """
+
+
+ return (await asyncio_detailed(
+ skill_id=skill_id,
+client=client,
+body=body,
+project_id=project_id,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/notifications/__init__.py b/src/volcano_sdk/_generated/api/notifications/__init__.py
new file mode 100644
index 00000000..c9921b5f
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/notifications/__init__.py
@@ -0,0 +1 @@
+""" Contains endpoint functions for accessing the API """
diff --git a/src/volcano_sdk/_generated/api/notifications/get_notification_settings.py b/src/volcano_sdk/_generated/api/notifications/get_notification_settings.py
new file mode 100644
index 00000000..d7ff57b0
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/notifications/get_notification_settings.py
@@ -0,0 +1,223 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.notification_settings import NotificationSettings
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/projects/{id}/notifications".format(id=quote(str(id), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | NotificationSettings | None:
+ if response.status_code == 200:
+ response_200 = NotificationSettings.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | NotificationSettings]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Error | NotificationSettings]:
+ """ Get notification settings
+
+ Returns where the project's alerts go and when a failing scheduler is
+ announced. A project that never saved settings returns the defaults:
+ email to the project owner, no webhook, and an alert after 3 failed
+ runs in a row, followed by one when the scheduler recovers.
+
+ The webhook signing secret is never returned here; `secret_configured`
+ shows whether one is set. A read-only project access token is refused
+ with `403`, because the webhook URL can carry the receiver's token.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | NotificationSettings]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Error | NotificationSettings | None:
+ """ Get notification settings
+
+ Returns where the project's alerts go and when a failing scheduler is
+ announced. A project that never saved settings returns the defaults:
+ email to the project owner, no webhook, and an alert after 3 failed
+ runs in a row, followed by one when the scheduler recovers.
+
+ The webhook signing secret is never returned here; `secret_configured`
+ shows whether one is set. A read-only project access token is refused
+ with `403`, because the webhook URL can carry the receiver's token.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | NotificationSettings
+ """
+
+
+ return sync_detailed(
+ id=id,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Error | NotificationSettings]:
+ """ Get notification settings
+
+ Returns where the project's alerts go and when a failing scheduler is
+ announced. A project that never saved settings returns the defaults:
+ email to the project owner, no webhook, and an alert after 3 failed
+ runs in a row, followed by one when the scheduler recovers.
+
+ The webhook signing secret is never returned here; `secret_configured`
+ shows whether one is set. A read-only project access token is refused
+ with `403`, because the webhook URL can carry the receiver's token.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | NotificationSettings]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Error | NotificationSettings | None:
+ """ Get notification settings
+
+ Returns where the project's alerts go and when a failing scheduler is
+ announced. A project that never saved settings returns the defaults:
+ email to the project owner, no webhook, and an alert after 3 failed
+ runs in a row, followed by one when the scheduler recovers.
+
+ The webhook signing secret is never returned here; `secret_configured`
+ shows whether one is set. A read-only project access token is refused
+ with `403`, because the webhook URL can carry the receiver's token.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | NotificationSettings
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/notifications/rotate_notification_webhook_secret.py b/src/volcano_sdk/_generated/api/notifications/rotate_notification_webhook_secret.py
new file mode 100644
index 00000000..41bff906
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/notifications/rotate_notification_webhook_secret.py
@@ -0,0 +1,210 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.notification_settings import NotificationSettings
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/projects/{id}/notifications/webhook-secret".format(id=quote(str(id), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | NotificationSettings | None:
+ if response.status_code == 200:
+ response_200 = NotificationSettings.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | NotificationSettings]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Error | NotificationSettings]:
+ """ Rotate the webhook signing secret
+
+ Replaces the webhook signing secret and returns the settings with the
+ new one in `webhook.secret`, this once. Every delivery from now on is
+ signed with the new secret, including retries of earlier alerts.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | NotificationSettings]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Error | NotificationSettings | None:
+ """ Rotate the webhook signing secret
+
+ Replaces the webhook signing secret and returns the settings with the
+ new one in `webhook.secret`, this once. Every delivery from now on is
+ signed with the new secret, including retries of earlier alerts.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | NotificationSettings
+ """
+
+
+ return sync_detailed(
+ id=id,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Error | NotificationSettings]:
+ """ Rotate the webhook signing secret
+
+ Replaces the webhook signing secret and returns the settings with the
+ new one in `webhook.secret`, this once. Every delivery from now on is
+ signed with the new secret, including retries of earlier alerts.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | NotificationSettings]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Error | NotificationSettings | None:
+ """ Rotate the webhook signing secret
+
+ Replaces the webhook signing secret and returns the settings with the
+ new one in `webhook.secret`, this once. Every delivery from now on is
+ signed with the new secret, including retries of earlier alerts.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | NotificationSettings
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/notifications/send_test_notification.py b/src/volcano_sdk/_generated/api/notifications/send_test_notification.py
new file mode 100644
index 00000000..193121c3
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/notifications/send_test_notification.py
@@ -0,0 +1,225 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.notification_test_result import NotificationTestResult
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/projects/{id}/notifications/test".format(id=quote(str(id), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | NotificationTestResult | None:
+ if response.status_code == 200:
+ response_200 = NotificationTestResult.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 429:
+ response_429 = Error.from_dict(response.json())
+
+
+
+ return response_429
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | NotificationTestResult]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Error | NotificationTestResult]:
+ """ Send a test notification
+
+ Sends a `notification.test` event on every channel that delivers
+ right away and reports how each delivery went. A webhook delivery is
+ signed like an alert. Enabled email is reported undelivered, without
+ sending, while the project owner has no verified account email
+ address. One test per project per minute.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | NotificationTestResult]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Error | NotificationTestResult | None:
+ """ Send a test notification
+
+ Sends a `notification.test` event on every channel that delivers
+ right away and reports how each delivery went. A webhook delivery is
+ signed like an alert. Enabled email is reported undelivered, without
+ sending, while the project owner has no verified account email
+ address. One test per project per minute.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | NotificationTestResult
+ """
+
+
+ return sync_detailed(
+ id=id,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Error | NotificationTestResult]:
+ """ Send a test notification
+
+ Sends a `notification.test` event on every channel that delivers
+ right away and reports how each delivery went. A webhook delivery is
+ signed like an alert. Enabled email is reported undelivered, without
+ sending, while the project owner has no verified account email
+ address. One test per project per minute.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | NotificationTestResult]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Error | NotificationTestResult | None:
+ """ Send a test notification
+
+ Sends a `notification.test` event on every channel that delivers
+ right away and reports how each delivery went. A webhook delivery is
+ signed like an alert. Enabled email is reported undelivered, without
+ sending, while the project owner has no verified account email
+ address. One test per project per minute.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | NotificationTestResult
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/notifications/update_notification_settings.py b/src/volcano_sdk/_generated/api/notifications/update_notification_settings.py
new file mode 100644
index 00000000..b92f1ac2
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/notifications/update_notification_settings.py
@@ -0,0 +1,286 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.notification_settings import NotificationSettings
+from ...models.update_notification_settings_request import UpdateNotificationSettingsRequest
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ *,
+ body: UpdateNotificationSettingsRequest,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "put",
+ "url": "/projects/{id}/notifications".format(id=quote(str(id), safe=""),),
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | NotificationSettings | None:
+ if response.status_code == 200:
+ response_200 = NotificationSettings.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | NotificationSettings]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: UpdateNotificationSettingsRequest,
+
+) -> Response[Error | NotificationSettings]:
+ """ Update notification settings
+
+ Changes the project's notification settings. Omitted fields keep their
+ current values, so `{"email": {"enabled": false}}` only turns email off.
+
+ Alert emails go only to the project owner's verified account email
+ address. `email.recipients` may be empty or name that address; any
+ other list is refused with `400`, and so is any non-empty list while
+ the owner has no verified address. `email.status` in the response
+ says whether alerts are being emailed.
+
+ Setting `webhook.url` on a project without a webhook generates its
+ signing secret, returned in `webhook.secret` in this response only.
+ Changing the URL keeps the secret. An empty `webhook.url` removes the
+ webhook and its secret.
+
+ Outside local mode the webhook must be reachable on the public
+ internet; a URL naming a private or loopback address is refused, and
+ so is a delivery to a host name that resolves to one.
+
+ Args:
+ id (UUID):
+ body (UpdateNotificationSettingsRequest): Omitted fields keep their current values.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | NotificationSettings]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: UpdateNotificationSettingsRequest,
+
+) -> Error | NotificationSettings | None:
+ """ Update notification settings
+
+ Changes the project's notification settings. Omitted fields keep their
+ current values, so `{"email": {"enabled": false}}` only turns email off.
+
+ Alert emails go only to the project owner's verified account email
+ address. `email.recipients` may be empty or name that address; any
+ other list is refused with `400`, and so is any non-empty list while
+ the owner has no verified address. `email.status` in the response
+ says whether alerts are being emailed.
+
+ Setting `webhook.url` on a project without a webhook generates its
+ signing secret, returned in `webhook.secret` in this response only.
+ Changing the URL keeps the secret. An empty `webhook.url` removes the
+ webhook and its secret.
+
+ Outside local mode the webhook must be reachable on the public
+ internet; a URL naming a private or loopback address is refused, and
+ so is a delivery to a host name that resolves to one.
+
+ Args:
+ id (UUID):
+ body (UpdateNotificationSettingsRequest): Omitted fields keep their current values.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | NotificationSettings
+ """
+
+
+ return sync_detailed(
+ id=id,
+client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: UpdateNotificationSettingsRequest,
+
+) -> Response[Error | NotificationSettings]:
+ """ Update notification settings
+
+ Changes the project's notification settings. Omitted fields keep their
+ current values, so `{"email": {"enabled": false}}` only turns email off.
+
+ Alert emails go only to the project owner's verified account email
+ address. `email.recipients` may be empty or name that address; any
+ other list is refused with `400`, and so is any non-empty list while
+ the owner has no verified address. `email.status` in the response
+ says whether alerts are being emailed.
+
+ Setting `webhook.url` on a project without a webhook generates its
+ signing secret, returned in `webhook.secret` in this response only.
+ Changing the URL keeps the secret. An empty `webhook.url` removes the
+ webhook and its secret.
+
+ Outside local mode the webhook must be reachable on the public
+ internet; a URL naming a private or loopback address is refused, and
+ so is a delivery to a host name that resolves to one.
+
+ Args:
+ id (UUID):
+ body (UpdateNotificationSettingsRequest): Omitted fields keep their current values.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | NotificationSettings]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: UpdateNotificationSettingsRequest,
+
+) -> Error | NotificationSettings | None:
+ """ Update notification settings
+
+ Changes the project's notification settings. Omitted fields keep their
+ current values, so `{"email": {"enabled": false}}` only turns email off.
+
+ Alert emails go only to the project owner's verified account email
+ address. `email.recipients` may be empty or name that address; any
+ other list is refused with `400`, and so is any non-empty list while
+ the owner has no verified address. `email.status` in the response
+ says whether alerts are being emailed.
+
+ Setting `webhook.url` on a project without a webhook generates its
+ signing secret, returned in `webhook.secret` in this response only.
+ Changing the URL keeps the secret. An empty `webhook.url` removes the
+ webhook and its secret.
+
+ Outside local mode the webhook must be reachable on the public
+ internet; a URL naming a private or loopback address is refused, and
+ so is a delivery to a host name that resolves to one.
+
+ Args:
+ id (UUID):
+ body (UpdateNotificationSettingsRequest): Omitted fields keep their current values.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | NotificationSettings
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/o_auth_authentication/auth_list_o_auth_providers.py b/src/volcano_sdk/_generated/api/o_auth_authentication/auth_list_o_auth_providers.py
index e0b63e04..b3311c1a 100644
--- a/src/volcano_sdk/_generated/api/o_auth_authentication/auth_list_o_auth_providers.py
+++ b/src/volcano_sdk/_generated/api/o_auth_authentication/auth_list_o_auth_providers.py
@@ -70,7 +70,11 @@ def sync_detailed(
) -> Response[AuthListOAuthProvidersResponse200 | Error]:
""" List user's linked providers
- Get list of OAuth providers linked to current user
+ Lists the OAuth providers linked to the signed-in user, with the
+ user's own account ID at each provider. Match on `provider_user_id`,
+ which never changes, rather than on the login or email. For
+ GitHub, it is the numeric user ID that GitHub reports elsewhere, such
+ as a webhook's `sender.id`.
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -98,7 +102,11 @@ def sync(
) -> AuthListOAuthProvidersResponse200 | Error | None:
""" List user's linked providers
- Get list of OAuth providers linked to current user
+ Lists the OAuth providers linked to the signed-in user, with the
+ user's own account ID at each provider. Match on `provider_user_id`,
+ which never changes, rather than on the login or email. For
+ GitHub, it is the numeric user ID that GitHub reports elsewhere, such
+ as a webhook's `sender.id`.
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -121,7 +129,11 @@ async def asyncio_detailed(
) -> Response[AuthListOAuthProvidersResponse200 | Error]:
""" List user's linked providers
- Get list of OAuth providers linked to current user
+ Lists the OAuth providers linked to the signed-in user, with the
+ user's own account ID at each provider. Match on `provider_user_id`,
+ which never changes, rather than on the login or email. For
+ GitHub, it is the numeric user ID that GitHub reports elsewhere, such
+ as a webhook's `sender.id`.
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -149,7 +161,11 @@ async def asyncio(
) -> AuthListOAuthProvidersResponse200 | Error | None:
""" List user's linked providers
- Get list of OAuth providers linked to current user
+ Lists the OAuth providers linked to the signed-in user, with the
+ user's own account ID at each provider. Match on `provider_user_id`,
+ which never changes, rather than on the login or email. For
+ GitHub, it is the numeric user ID that GitHub reports elsewhere, such
+ as a webhook's `sender.id`.
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
diff --git a/src/volcano_sdk/_generated/api/o_auth_authentication/auth_o_auth_callback.py b/src/volcano_sdk/_generated/api/o_auth_authentication/auth_o_auth_callback.py
index 01e3b448..a4e87286 100644
--- a/src/volcano_sdk/_generated/api/o_auth_authentication/auth_o_auth_callback.py
+++ b/src/volcano_sdk/_generated/api/o_auth_authentication/auth_o_auth_callback.py
@@ -78,6 +78,10 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
response_403 = cast(Any, None)
return response_403
+ if response.status_code == 404:
+ response_404 = cast(Any, None)
+ return response_404
+
if response.status_code == 409:
response_409 = cast(Any, None)
return response_409
diff --git a/src/volcano_sdk/_generated/api/o_auth_authentication/auth_unlink_o_auth_provider.py b/src/volcano_sdk/_generated/api/o_auth_authentication/auth_unlink_o_auth_provider.py
index 54011edc..3adfc702 100644
--- a/src/volcano_sdk/_generated/api/o_auth_authentication/auth_unlink_o_auth_provider.py
+++ b/src/volcano_sdk/_generated/api/o_auth_authentication/auth_unlink_o_auth_provider.py
@@ -84,8 +84,10 @@ def sync_detailed(
) -> Response[Any | Error]:
""" Unlink OAuth provider
- Remove OAuth provider from user's account.
- Cannot unlink if it's the only authentication method.
+ Remove OAuth provider from user's account. Refused when the account would
+ have no other way to sign in: another linked OAuth provider that's enabled
+ for the project, or a password while email/password sign-in is on for the
+ project (`enable_email_password`).
Args:
provider (AuthUnlinkOAuthProviderProvider):
@@ -118,8 +120,10 @@ def sync(
) -> Any | Error | None:
""" Unlink OAuth provider
- Remove OAuth provider from user's account.
- Cannot unlink if it's the only authentication method.
+ Remove OAuth provider from user's account. Refused when the account would
+ have no other way to sign in: another linked OAuth provider that's enabled
+ for the project, or a password while email/password sign-in is on for the
+ project (`enable_email_password`).
Args:
provider (AuthUnlinkOAuthProviderProvider):
@@ -147,8 +151,10 @@ async def asyncio_detailed(
) -> Response[Any | Error]:
""" Unlink OAuth provider
- Remove OAuth provider from user's account.
- Cannot unlink if it's the only authentication method.
+ Remove OAuth provider from user's account. Refused when the account would
+ have no other way to sign in: another linked OAuth provider that's enabled
+ for the project, or a password while email/password sign-in is on for the
+ project (`enable_email_password`).
Args:
provider (AuthUnlinkOAuthProviderProvider):
@@ -181,8 +187,10 @@ async def asyncio(
) -> Any | Error | None:
""" Unlink OAuth provider
- Remove OAuth provider from user's account.
- Cannot unlink if it's the only authentication method.
+ Remove OAuth provider from user's account. Refused when the account would
+ have no other way to sign in: another linked OAuth provider that's enabled
+ for the project, or a password while email/password sign-in is on for the
+ project (`enable_email_password`).
Args:
provider (AuthUnlinkOAuthProviderProvider):
diff --git a/src/volcano_sdk/_generated/api/projects/connect_project_git.py b/src/volcano_sdk/_generated/api/projects/connect_project_git.py
index 16856243..3b8dcad6 100644
--- a/src/volcano_sdk/_generated/api/projects/connect_project_git.py
+++ b/src/volcano_sdk/_generated/api/projects/connect_project_git.py
@@ -133,6 +133,26 @@ def sync_detailed(
user token, then persists repository metadata only from that validated
GitHub response.
+ Omitting production_branch follows the repository's default and
+ discards a pinned branch. To keep a pin when rebinding the same
+ repository, read the connection first and send production_branch back
+ when `production_branch_follows_default` is false. The response reports
+ the result in the same field.
+
+ Project access tokens are refused. Which repository a project deploys
+ from is a person's decision, made with a platform token or in the
+ dashboard. A project access token can still change the root directory
+ and production branch through PUT
+ /projects/{id}/git-connection/root-directory and PUT
+ /projects/{id}/git-connection/production-branch.
+
+ Connecting a repository to a project with none, while LavaFlow is on
+ and was turned on with no repository, makes it the one LavaFlow works
+ in, unless the LavaFlow settings' `fix_blocker` asks to turn it on
+ again after the link. Any later change of repository pauses LavaFlow until the owner
+ turns it on again; binding the repository LavaFlow works in again
+ resumes it with no new turn-on.
+
Args:
id (UUID):
body (ConnectProjectGitRequest):
@@ -176,6 +196,26 @@ def sync(
user token, then persists repository metadata only from that validated
GitHub response.
+ Omitting production_branch follows the repository's default and
+ discards a pinned branch. To keep a pin when rebinding the same
+ repository, read the connection first and send production_branch back
+ when `production_branch_follows_default` is false. The response reports
+ the result in the same field.
+
+ Project access tokens are refused. Which repository a project deploys
+ from is a person's decision, made with a platform token or in the
+ dashboard. A project access token can still change the root directory
+ and production branch through PUT
+ /projects/{id}/git-connection/root-directory and PUT
+ /projects/{id}/git-connection/production-branch.
+
+ Connecting a repository to a project with none, while LavaFlow is on
+ and was turned on with no repository, makes it the one LavaFlow works
+ in, unless the LavaFlow settings' `fix_blocker` asks to turn it on
+ again after the link. Any later change of repository pauses LavaFlow until the owner
+ turns it on again; binding the repository LavaFlow works in again
+ resumes it with no new turn-on.
+
Args:
id (UUID):
body (ConnectProjectGitRequest):
@@ -214,6 +254,26 @@ async def asyncio_detailed(
user token, then persists repository metadata only from that validated
GitHub response.
+ Omitting production_branch follows the repository's default and
+ discards a pinned branch. To keep a pin when rebinding the same
+ repository, read the connection first and send production_branch back
+ when `production_branch_follows_default` is false. The response reports
+ the result in the same field.
+
+ Project access tokens are refused. Which repository a project deploys
+ from is a person's decision, made with a platform token or in the
+ dashboard. A project access token can still change the root directory
+ and production branch through PUT
+ /projects/{id}/git-connection/root-directory and PUT
+ /projects/{id}/git-connection/production-branch.
+
+ Connecting a repository to a project with none, while LavaFlow is on
+ and was turned on with no repository, makes it the one LavaFlow works
+ in, unless the LavaFlow settings' `fix_blocker` asks to turn it on
+ again after the link. Any later change of repository pauses LavaFlow until the owner
+ turns it on again; binding the repository LavaFlow works in again
+ resumes it with no new turn-on.
+
Args:
id (UUID):
body (ConnectProjectGitRequest):
@@ -257,6 +317,26 @@ async def asyncio(
user token, then persists repository metadata only from that validated
GitHub response.
+ Omitting production_branch follows the repository's default and
+ discards a pinned branch. To keep a pin when rebinding the same
+ repository, read the connection first and send production_branch back
+ when `production_branch_follows_default` is false. The response reports
+ the result in the same field.
+
+ Project access tokens are refused. Which repository a project deploys
+ from is a person's decision, made with a platform token or in the
+ dashboard. A project access token can still change the root directory
+ and production branch through PUT
+ /projects/{id}/git-connection/root-directory and PUT
+ /projects/{id}/git-connection/production-branch.
+
+ Connecting a repository to a project with none, while LavaFlow is on
+ and was turned on with no repository, makes it the one LavaFlow works
+ in, unless the LavaFlow settings' `fix_blocker` asks to turn it on
+ again after the link. Any later change of repository pauses LavaFlow until the owner
+ turns it on again; binding the repository LavaFlow works in again
+ resumes it with no new turn-on.
+
Args:
id (UUID):
body (ConnectProjectGitRequest):
diff --git a/src/volcano_sdk/_generated/api/projects/create_project.py b/src/volcano_sdk/_generated/api/projects/create_project.py
index b210e651..5a59da7f 100644
--- a/src/volcano_sdk/_generated/api/projects/create_project.py
+++ b/src/volcano_sdk/_generated/api/projects/create_project.py
@@ -94,7 +94,9 @@ def sync_detailed(
""" Create a new project
Creates a project for the authenticated user.
- Each user can create up to 1,000 projects. Requests over this cap return 403.
+ Projects have no plan limit; usage allowances apply across all of a user's projects.
+ Accounts on an older paid pricing revision keep the project cap that revision set, and
+ requests over it return 403.
Args:
body (CreateProjectRequest): Request to create a new project
@@ -128,7 +130,9 @@ def sync(
""" Create a new project
Creates a project for the authenticated user.
- Each user can create up to 1,000 projects. Requests over this cap return 403.
+ Projects have no plan limit; usage allowances apply across all of a user's projects.
+ Accounts on an older paid pricing revision keep the project cap that revision set, and
+ requests over it return 403.
Args:
body (CreateProjectRequest): Request to create a new project
@@ -157,7 +161,9 @@ async def asyncio_detailed(
""" Create a new project
Creates a project for the authenticated user.
- Each user can create up to 1,000 projects. Requests over this cap return 403.
+ Projects have no plan limit; usage allowances apply across all of a user's projects.
+ Accounts on an older paid pricing revision keep the project cap that revision set, and
+ requests over it return 403.
Args:
body (CreateProjectRequest): Request to create a new project
@@ -191,7 +197,9 @@ async def asyncio(
""" Create a new project
Creates a project for the authenticated user.
- Each user can create up to 1,000 projects. Requests over this cap return 403.
+ Projects have no plan limit; usage allowances apply across all of a user's projects.
+ Accounts on an older paid pricing revision keep the project cap that revision set, and
+ requests over it return 403.
Args:
body (CreateProjectRequest): Request to create a new project
diff --git a/src/volcano_sdk/_generated/api/projects/export_project_source.py b/src/volcano_sdk/_generated/api/projects/export_project_source.py
index f577e835..412eea02 100644
--- a/src/volcano_sdk/_generated/api/projects/export_project_source.py
+++ b/src/volcano_sdk/_generated/api/projects/export_project_source.py
@@ -150,11 +150,12 @@ def sync_detailed(
ordinary Git auto-deploy flow. Direct source writes remain frozen until
that deployment succeeds and the repository becomes the source of truth.
- The caller confirms the production branch shown before export. Starting
- export pins that branch: later GitHub default-branch changes do not
- repoint the project. If the configured branch changed after the caller
- read it, the request fails without exporting so the caller can show and
- confirm the new value.
+ The caller confirms the production branch shown before export, and
+ optionally the repository by its `repo_id`. Starting export pins that
+ branch: later GitHub default-branch changes do not repoint the project.
+ If the connected repository or the configured branch changed after the
+ caller read it, the request fails without exporting so the caller can
+ show and confirm the new value.
The response lists what the export could not carry: resources with no
successful deployment to take source from (`skipped`), and things no
@@ -206,11 +207,12 @@ def sync(
ordinary Git auto-deploy flow. Direct source writes remain frozen until
that deployment succeeds and the repository becomes the source of truth.
- The caller confirms the production branch shown before export. Starting
- export pins that branch: later GitHub default-branch changes do not
- repoint the project. If the configured branch changed after the caller
- read it, the request fails without exporting so the caller can show and
- confirm the new value.
+ The caller confirms the production branch shown before export, and
+ optionally the repository by its `repo_id`. Starting export pins that
+ branch: later GitHub default-branch changes do not repoint the project.
+ If the connected repository or the configured branch changed after the
+ caller read it, the request fails without exporting so the caller can
+ show and confirm the new value.
The response lists what the export could not carry: resources with no
successful deployment to take source from (`skipped`), and things no
@@ -257,11 +259,12 @@ async def asyncio_detailed(
ordinary Git auto-deploy flow. Direct source writes remain frozen until
that deployment succeeds and the repository becomes the source of truth.
- The caller confirms the production branch shown before export. Starting
- export pins that branch: later GitHub default-branch changes do not
- repoint the project. If the configured branch changed after the caller
- read it, the request fails without exporting so the caller can show and
- confirm the new value.
+ The caller confirms the production branch shown before export, and
+ optionally the repository by its `repo_id`. Starting export pins that
+ branch: later GitHub default-branch changes do not repoint the project.
+ If the connected repository or the configured branch changed after the
+ caller read it, the request fails without exporting so the caller can
+ show and confirm the new value.
The response lists what the export could not carry: resources with no
successful deployment to take source from (`skipped`), and things no
@@ -313,11 +316,12 @@ async def asyncio(
ordinary Git auto-deploy flow. Direct source writes remain frozen until
that deployment succeeds and the repository becomes the source of truth.
- The caller confirms the production branch shown before export. Starting
- export pins that branch: later GitHub default-branch changes do not
- repoint the project. If the configured branch changed after the caller
- read it, the request fails without exporting so the caller can show and
- confirm the new value.
+ The caller confirms the production branch shown before export, and
+ optionally the repository by its `repo_id`. Starting export pins that
+ branch: later GitHub default-branch changes do not repoint the project.
+ If the connected repository or the configured branch changed after the
+ caller read it, the request fails without exporting so the caller can
+ show and confirm the new value.
The response lists what the export could not carry: resources with no
successful deployment to take source from (`skipped`), and things no
diff --git a/src/volcano_sdk/_generated/api/autofix/get_autofix_run.py b/src/volcano_sdk/_generated/api/projects/get_git_deployment_run.py
similarity index 69%
rename from src/volcano_sdk/_generated/api/autofix/get_autofix_run.py
rename to src/volcano_sdk/_generated/api/projects/get_git_deployment_run.py
index d79f218c..64d6bc1b 100644
--- a/src/volcano_sdk/_generated/api/autofix/get_autofix_run.py
+++ b/src/volcano_sdk/_generated/api/projects/get_git_deployment_run.py
@@ -8,8 +8,8 @@
from ...types import Response, UNSET
from ... import errors
-from ...models.autofix_run import AutofixRun
from ...models.error import Error
+from ...models.git_deployment_run import GitDeploymentRun
from typing import cast
from uuid import UUID
@@ -28,7 +28,7 @@ def request_kwargs(
_kwargs: dict[str, Any] = {
"method": "get",
- "url": "/projects/{id}/autofix-runs/{run_id}".format(id=quote(str(id), safe=""),run_id=quote(str(run_id), safe=""),),
+ "url": "/projects/{id}/git-deployment-runs/{run_id}".format(id=quote(str(id), safe=""),run_id=quote(str(run_id), safe=""),),
}
@@ -36,27 +36,34 @@ def request_kwargs(
-def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> AutofixRun | Error | None:
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | GitDeploymentRun | None:
if response.status_code == 200:
- response_200 = AutofixRun.from_dict(response.json())
+ response_200 = GitDeploymentRun.from_dict(response.json())
return response_200
- if response.status_code == 404:
- response_404 = Error.from_dict(response.json())
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
- return response_404
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
- if response.status_code == 501:
- response_501 = Error.from_dict(response.json())
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
- return response_501
+
+ return response_404
if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
@@ -64,7 +71,7 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return None
-def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[AutofixRun | Error]:
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | GitDeploymentRun]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
@@ -79,12 +86,11 @@ def sync_detailed(
*,
client: AuthenticatedClient,
-) -> Response[AutofixRun | Error]:
- """ Get an autofix run
+) -> Response[Error | GitDeploymentRun]:
+ """ Get a Git deployment run
- Returns one run: its status, the diagnosis once it succeeds, why it
- failed or was canceled, and the model tokens it used. Runs stay readable
- where autofix is not available.
+ Returns one deployment run: the commit it deployed, its status, the
+ migration runs it started, and why it failed or was skipped.
Project access tokens can read runs, including read-only ones.
@@ -97,7 +103,7 @@ def sync_detailed(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[AutofixRun | Error]
+ Response[Error | GitDeploymentRun]
"""
@@ -119,12 +125,11 @@ def sync(
*,
client: AuthenticatedClient,
-) -> AutofixRun | Error | None:
- """ Get an autofix run
+) -> Error | GitDeploymentRun | None:
+ """ Get a Git deployment run
- Returns one run: its status, the diagnosis once it succeeds, why it
- failed or was canceled, and the model tokens it used. Runs stay readable
- where autofix is not available.
+ Returns one deployment run: the commit it deployed, its status, the
+ migration runs it started, and why it failed or was skipped.
Project access tokens can read runs, including read-only ones.
@@ -137,7 +142,7 @@ def sync(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- AutofixRun | Error
+ Error | GitDeploymentRun
"""
@@ -154,12 +159,11 @@ async def asyncio_detailed(
*,
client: AuthenticatedClient,
-) -> Response[AutofixRun | Error]:
- """ Get an autofix run
+) -> Response[Error | GitDeploymentRun]:
+ """ Get a Git deployment run
- Returns one run: its status, the diagnosis once it succeeds, why it
- failed or was canceled, and the model tokens it used. Runs stay readable
- where autofix is not available.
+ Returns one deployment run: the commit it deployed, its status, the
+ migration runs it started, and why it failed or was skipped.
Project access tokens can read runs, including read-only ones.
@@ -172,7 +176,7 @@ async def asyncio_detailed(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[AutofixRun | Error]
+ Response[Error | GitDeploymentRun]
"""
@@ -194,12 +198,11 @@ async def asyncio(
*,
client: AuthenticatedClient,
-) -> AutofixRun | Error | None:
- """ Get an autofix run
+) -> Error | GitDeploymentRun | None:
+ """ Get a Git deployment run
- Returns one run: its status, the diagnosis once it succeeds, why it
- failed or was canceled, and the model tokens it used. Runs stay readable
- where autofix is not available.
+ Returns one deployment run: the commit it deployed, its status, the
+ migration runs it started, and why it failed or was skipped.
Project access tokens can read runs, including read-only ones.
@@ -212,7 +215,7 @@ async def asyncio(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- AutofixRun | Error
+ Error | GitDeploymentRun
"""
diff --git a/src/volcano_sdk/_generated/api/projects/get_project_git_connection.py b/src/volcano_sdk/_generated/api/projects/get_project_git_connection.py
index f53f7d48..307fdbde 100644
--- a/src/volcano_sdk/_generated/api/projects/get_project_git_connection.py
+++ b/src/volcano_sdk/_generated/api/projects/get_project_git_connection.py
@@ -94,6 +94,11 @@ def sync_detailed(
) -> Response[Error | ProjectGitConnection]:
""" Get a project's repo connection
+ Returns the repository binding. `production_branch_follows_default`
+ tells a branch that tracks the repository's default from one the
+ project pinned: a client rebinding the same repository sends a pinned
+ branch back to keep it.
+
Args:
id (UUID):
@@ -125,6 +130,11 @@ def sync(
) -> Error | ProjectGitConnection | None:
""" Get a project's repo connection
+ Returns the repository binding. `production_branch_follows_default`
+ tells a branch that tracks the repository's default from one the
+ project pinned: a client rebinding the same repository sends a pinned
+ branch back to keep it.
+
Args:
id (UUID):
@@ -151,6 +161,11 @@ async def asyncio_detailed(
) -> Response[Error | ProjectGitConnection]:
""" Get a project's repo connection
+ Returns the repository binding. `production_branch_follows_default`
+ tells a branch that tracks the repository's default from one the
+ project pinned: a client rebinding the same repository sends a pinned
+ branch back to keep it.
+
Args:
id (UUID):
@@ -182,6 +197,11 @@ async def asyncio(
) -> Error | ProjectGitConnection | None:
""" Get a project's repo connection
+ Returns the repository binding. `production_branch_follows_default`
+ tells a branch that tracks the repository's default from one the
+ project pinned: a client rebinding the same repository sends a pinned
+ branch back to keep it.
+
Args:
id (UUID):
diff --git a/src/volcano_sdk/_generated/api/projects/get_project_git_owner_push.py b/src/volcano_sdk/_generated/api/projects/get_project_git_owner_push.py
new file mode 100644
index 00000000..39973931
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/projects/get_project_git_owner_push.py
@@ -0,0 +1,267 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.project_git_owner_push import ProjectGitOwnerPush
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/projects/{id}/git-connection/owner-push".format(id=quote(str(id), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | ProjectGitOwnerPush | None:
+ if response.status_code == 200:
+ response_200 = ProjectGitOwnerPush.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 429:
+ response_429 = Error.from_dict(response.json())
+
+
+
+ return response_429
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if response.status_code == 503:
+ response_503 = Error.from_dict(response.json())
+
+
+
+ return response_503
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | ProjectGitOwnerPush]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Error | ProjectGitOwnerPush]:
+ """ Check whether the project owner can push to the connected repository
+
+ Answers whether the project owner's GitHub account can push to the
+ repository the project is connected to. Volcano makes the same check
+ before it writes to that repository for the project. The repository is
+ always the project's connected one; the route takes no repository.
+
+ When `can_push` is false, `reason` says why. The answer can be a few
+ seconds old: repeated checks within that time are answered without
+ asking GitHub again.
+
+ Checks that ask GitHub draw on an hourly budget for the project and
+ another for its owner, shared by all of the owner's projects. Over
+ either, the route answers `429` with `Retry-After`.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | ProjectGitOwnerPush]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Error | ProjectGitOwnerPush | None:
+ """ Check whether the project owner can push to the connected repository
+
+ Answers whether the project owner's GitHub account can push to the
+ repository the project is connected to. Volcano makes the same check
+ before it writes to that repository for the project. The repository is
+ always the project's connected one; the route takes no repository.
+
+ When `can_push` is false, `reason` says why. The answer can be a few
+ seconds old: repeated checks within that time are answered without
+ asking GitHub again.
+
+ Checks that ask GitHub draw on an hourly budget for the project and
+ another for its owner, shared by all of the owner's projects. Over
+ either, the route answers `429` with `Retry-After`.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | ProjectGitOwnerPush
+ """
+
+
+ return sync_detailed(
+ id=id,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Error | ProjectGitOwnerPush]:
+ """ Check whether the project owner can push to the connected repository
+
+ Answers whether the project owner's GitHub account can push to the
+ repository the project is connected to. Volcano makes the same check
+ before it writes to that repository for the project. The repository is
+ always the project's connected one; the route takes no repository.
+
+ When `can_push` is false, `reason` says why. The answer can be a few
+ seconds old: repeated checks within that time are answered without
+ asking GitHub again.
+
+ Checks that ask GitHub draw on an hourly budget for the project and
+ another for its owner, shared by all of the owner's projects. Over
+ either, the route answers `429` with `Retry-After`.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | ProjectGitOwnerPush]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Error | ProjectGitOwnerPush | None:
+ """ Check whether the project owner can push to the connected repository
+
+ Answers whether the project owner's GitHub account can push to the
+ repository the project is connected to. Volcano makes the same check
+ before it writes to that repository for the project. The repository is
+ always the project's connected one; the route takes no repository.
+
+ When `can_push` is false, `reason` says why. The answer can be a few
+ seconds old: repeated checks within that time are answered without
+ asking GitHub again.
+
+ Checks that ask GitHub draw on an hourly budget for the project and
+ another for its owner, shared by all of the owner's projects. Over
+ either, the route answers `429` with `Retry-After`.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | ProjectGitOwnerPush
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/projects/list_git_deployment_runs.py b/src/volcano_sdk/_generated/api/projects/list_git_deployment_runs.py
new file mode 100644
index 00000000..d9bb0e0d
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/projects/list_git_deployment_runs.py
@@ -0,0 +1,334 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.git_deployment_run_status import check_git_deployment_run_status
+from ...models.git_deployment_run_status import GitDeploymentRunStatus
+from ...models.paginated_git_deployment_runs import PaginatedGitDeploymentRuns
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ *,
+ limit: int | Unset = 10,
+ cursor: str | Unset = UNSET,
+ status: GitDeploymentRunStatus | Unset = UNSET,
+ branch: str | Unset = UNSET,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ params["limit"] = limit
+
+ params["cursor"] = cursor
+
+ json_status: str | Unset = UNSET
+ if not isinstance(status, Unset):
+ json_status = status
+
+ params["status"] = json_status
+
+ params["branch"] = branch
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/projects/{id}/git-deployment-runs".format(id=quote(str(id), safe=""),),
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | PaginatedGitDeploymentRuns | None:
+ if response.status_code == 200:
+ response_200 = PaginatedGitDeploymentRuns.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | PaginatedGitDeploymentRuns]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ limit: int | Unset = 10,
+ cursor: str | Unset = UNSET,
+ status: GitDeploymentRunStatus | Unset = UNSET,
+ branch: str | Unset = UNSET,
+
+) -> Response[Error | PaginatedGitDeploymentRuns]:
+ """ List a project's Git deployment runs
+
+ Lists the deployment runs Git auto deploy recorded for the project,
+ newest push first. Each push to the production branch records one run,
+ which says whether the push deployed and, when it failed or was
+ skipped, why.
+
+ A run that applied migrations names the migration run it started on
+ each database. Get one at
+ `GET /projects/{id}/databases/{databaseName}/migration-runs/{runId}`
+ for its files.
+
+ Project access tokens can list runs, including read-only ones.
+
+ Args:
+ id (UUID):
+ limit (int | Unset): Default: 10.
+ cursor (str | Unset):
+ status (GitDeploymentRunStatus | Unset): Where a run is. `pending` and `running` have not
+ ended. `succeeded`: every deployment the run dispatched succeeded, or the commit only had
+ migrations to apply. `failed`: `error` says why. `superseded`: a newer push replaced the
+ run before it started. `skipped`: there was nothing to deploy; `error` says why.
+ branch (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | PaginatedGitDeploymentRuns]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+limit=limit,
+cursor=cursor,
+status=status,
+branch=branch,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ limit: int | Unset = 10,
+ cursor: str | Unset = UNSET,
+ status: GitDeploymentRunStatus | Unset = UNSET,
+ branch: str | Unset = UNSET,
+
+) -> Error | PaginatedGitDeploymentRuns | None:
+ """ List a project's Git deployment runs
+
+ Lists the deployment runs Git auto deploy recorded for the project,
+ newest push first. Each push to the production branch records one run,
+ which says whether the push deployed and, when it failed or was
+ skipped, why.
+
+ A run that applied migrations names the migration run it started on
+ each database. Get one at
+ `GET /projects/{id}/databases/{databaseName}/migration-runs/{runId}`
+ for its files.
+
+ Project access tokens can list runs, including read-only ones.
+
+ Args:
+ id (UUID):
+ limit (int | Unset): Default: 10.
+ cursor (str | Unset):
+ status (GitDeploymentRunStatus | Unset): Where a run is. `pending` and `running` have not
+ ended. `succeeded`: every deployment the run dispatched succeeded, or the commit only had
+ migrations to apply. `failed`: `error` says why. `superseded`: a newer push replaced the
+ run before it started. `skipped`: there was nothing to deploy; `error` says why.
+ branch (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | PaginatedGitDeploymentRuns
+ """
+
+
+ return sync_detailed(
+ id=id,
+client=client,
+limit=limit,
+cursor=cursor,
+status=status,
+branch=branch,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ limit: int | Unset = 10,
+ cursor: str | Unset = UNSET,
+ status: GitDeploymentRunStatus | Unset = UNSET,
+ branch: str | Unset = UNSET,
+
+) -> Response[Error | PaginatedGitDeploymentRuns]:
+ """ List a project's Git deployment runs
+
+ Lists the deployment runs Git auto deploy recorded for the project,
+ newest push first. Each push to the production branch records one run,
+ which says whether the push deployed and, when it failed or was
+ skipped, why.
+
+ A run that applied migrations names the migration run it started on
+ each database. Get one at
+ `GET /projects/{id}/databases/{databaseName}/migration-runs/{runId}`
+ for its files.
+
+ Project access tokens can list runs, including read-only ones.
+
+ Args:
+ id (UUID):
+ limit (int | Unset): Default: 10.
+ cursor (str | Unset):
+ status (GitDeploymentRunStatus | Unset): Where a run is. `pending` and `running` have not
+ ended. `succeeded`: every deployment the run dispatched succeeded, or the commit only had
+ migrations to apply. `failed`: `error` says why. `superseded`: a newer push replaced the
+ run before it started. `skipped`: there was nothing to deploy; `error` says why.
+ branch (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | PaginatedGitDeploymentRuns]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+limit=limit,
+cursor=cursor,
+status=status,
+branch=branch,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ limit: int | Unset = 10,
+ cursor: str | Unset = UNSET,
+ status: GitDeploymentRunStatus | Unset = UNSET,
+ branch: str | Unset = UNSET,
+
+) -> Error | PaginatedGitDeploymentRuns | None:
+ """ List a project's Git deployment runs
+
+ Lists the deployment runs Git auto deploy recorded for the project,
+ newest push first. Each push to the production branch records one run,
+ which says whether the push deployed and, when it failed or was
+ skipped, why.
+
+ A run that applied migrations names the migration run it started on
+ each database. Get one at
+ `GET /projects/{id}/databases/{databaseName}/migration-runs/{runId}`
+ for its files.
+
+ Project access tokens can list runs, including read-only ones.
+
+ Args:
+ id (UUID):
+ limit (int | Unset): Default: 10.
+ cursor (str | Unset):
+ status (GitDeploymentRunStatus | Unset): Where a run is. `pending` and `running` have not
+ ended. `succeeded`: every deployment the run dispatched succeeded, or the commit only had
+ migrations to apply. `failed`: `error` says why. `superseded`: a newer push replaced the
+ run before it started. `skipped`: there was nothing to deploy; `error` says why.
+ branch (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | PaginatedGitDeploymentRuns
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+client=client,
+limit=limit,
+cursor=cursor,
+status=status,
+branch=branch,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/projects/list_project_capabilities.py b/src/volcano_sdk/_generated/api/projects/list_project_capabilities.py
new file mode 100644
index 00000000..401fee01
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/projects/list_project_capabilities.py
@@ -0,0 +1,287 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.capability_list import CapabilityList
+from ...models.error import Error
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/projects/{id}/capabilities".format(id=quote(str(id), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> CapabilityList | Error | None:
+ if response.status_code == 200:
+ response_200 = CapabilityList.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[CapabilityList | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[CapabilityList | Error]:
+ """ List a project's capabilities
+
+ Lists which product capabilities accept new work for this project. It
+ has the same entries as `GET /capabilities`, and answers each one as it
+ does, except for capabilities a project can have when another can't:
+
+ | ID | Available for this project when |
+ | --- | --- |
+ | `lavaflow` | LavaFlow is released, offered to the project's owner, and included in the owner's
+ plan |
+ | `lavaflow.merge` | `lavaflow` is, and LavaFlow's merging is released in this environment |
+ | `lavaflow.lineage` | `lavaflow` is, and fix lineage is released in this environment |
+ | `lavaflow.code_quality` | `lavaflow` is, Code Quality is released in this environment, and the
+ owner's plan allows Code Quality findings; with an allowance of 0 it is `unavailable` with `code`
+ `plan_required` |
+ | `lavaflow.slack` | `lavaflow` is, the Volcano Slack app is set up in this environment, and Slack
+ reports have launched in it |
+
+ Where `lavaflow` isn't available, a project with LavaFlow settings or
+ runs lists it `read_only`: its LavaFlow reads answer, and its owner can
+ turn LavaFlow off. A project without them lists it `unavailable`, with
+ `code` `plan_required` when the owner's plan leaves LavaFlow out.
+
+ Check it to decide what to offer for a project, instead of calling a
+ route to see whether it fails. Project access tokens can read it,
+ including read-only ones.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[CapabilityList | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> CapabilityList | Error | None:
+ """ List a project's capabilities
+
+ Lists which product capabilities accept new work for this project. It
+ has the same entries as `GET /capabilities`, and answers each one as it
+ does, except for capabilities a project can have when another can't:
+
+ | ID | Available for this project when |
+ | --- | --- |
+ | `lavaflow` | LavaFlow is released, offered to the project's owner, and included in the owner's
+ plan |
+ | `lavaflow.merge` | `lavaflow` is, and LavaFlow's merging is released in this environment |
+ | `lavaflow.lineage` | `lavaflow` is, and fix lineage is released in this environment |
+ | `lavaflow.code_quality` | `lavaflow` is, Code Quality is released in this environment, and the
+ owner's plan allows Code Quality findings; with an allowance of 0 it is `unavailable` with `code`
+ `plan_required` |
+ | `lavaflow.slack` | `lavaflow` is, the Volcano Slack app is set up in this environment, and Slack
+ reports have launched in it |
+
+ Where `lavaflow` isn't available, a project with LavaFlow settings or
+ runs lists it `read_only`: its LavaFlow reads answer, and its owner can
+ turn LavaFlow off. A project without them lists it `unavailable`, with
+ `code` `plan_required` when the owner's plan leaves LavaFlow out.
+
+ Check it to decide what to offer for a project, instead of calling a
+ route to see whether it fails. Project access tokens can read it,
+ including read-only ones.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ CapabilityList | Error
+ """
+
+
+ return sync_detailed(
+ id=id,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[CapabilityList | Error]:
+ """ List a project's capabilities
+
+ Lists which product capabilities accept new work for this project. It
+ has the same entries as `GET /capabilities`, and answers each one as it
+ does, except for capabilities a project can have when another can't:
+
+ | ID | Available for this project when |
+ | --- | --- |
+ | `lavaflow` | LavaFlow is released, offered to the project's owner, and included in the owner's
+ plan |
+ | `lavaflow.merge` | `lavaflow` is, and LavaFlow's merging is released in this environment |
+ | `lavaflow.lineage` | `lavaflow` is, and fix lineage is released in this environment |
+ | `lavaflow.code_quality` | `lavaflow` is, Code Quality is released in this environment, and the
+ owner's plan allows Code Quality findings; with an allowance of 0 it is `unavailable` with `code`
+ `plan_required` |
+ | `lavaflow.slack` | `lavaflow` is, the Volcano Slack app is set up in this environment, and Slack
+ reports have launched in it |
+
+ Where `lavaflow` isn't available, a project with LavaFlow settings or
+ runs lists it `read_only`: its LavaFlow reads answer, and its owner can
+ turn LavaFlow off. A project without them lists it `unavailable`, with
+ `code` `plan_required` when the owner's plan leaves LavaFlow out.
+
+ Check it to decide what to offer for a project, instead of calling a
+ route to see whether it fails. Project access tokens can read it,
+ including read-only ones.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[CapabilityList | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> CapabilityList | Error | None:
+ """ List a project's capabilities
+
+ Lists which product capabilities accept new work for this project. It
+ has the same entries as `GET /capabilities`, and answers each one as it
+ does, except for capabilities a project can have when another can't:
+
+ | ID | Available for this project when |
+ | --- | --- |
+ | `lavaflow` | LavaFlow is released, offered to the project's owner, and included in the owner's
+ plan |
+ | `lavaflow.merge` | `lavaflow` is, and LavaFlow's merging is released in this environment |
+ | `lavaflow.lineage` | `lavaflow` is, and fix lineage is released in this environment |
+ | `lavaflow.code_quality` | `lavaflow` is, Code Quality is released in this environment, and the
+ owner's plan allows Code Quality findings; with an allowance of 0 it is `unavailable` with `code`
+ `plan_required` |
+ | `lavaflow.slack` | `lavaflow` is, the Volcano Slack app is set up in this environment, and Slack
+ reports have launched in it |
+
+ Where `lavaflow` isn't available, a project with LavaFlow settings or
+ runs lists it `read_only`: its LavaFlow reads answer, and its owner can
+ turn LavaFlow off. A project without them lists it `unavailable`, with
+ `code` `plan_required` when the owner's plan leaves LavaFlow out.
+
+ Check it to decide what to offer for a project, instead of calling a
+ route to see whether it fails. Project access tokens can read it,
+ including read-only ones.
+
+ Args:
+ id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ CapabilityList | Error
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/projects/set_project_git_production_branch.py b/src/volcano_sdk/_generated/api/projects/set_project_git_production_branch.py
index 9701fe74..0c737bc8 100644
--- a/src/volcano_sdk/_generated/api/projects/set_project_git_production_branch.py
+++ b/src/volcano_sdk/_generated/api/projects/set_project_git_production_branch.py
@@ -86,6 +86,13 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return response_409
+ if response.status_code == 429:
+ response_429 = Error.from_dict(response.json())
+
+
+
+ return response_429
+
if response.status_code == 500:
response_500 = Error.from_dict(response.json())
@@ -128,9 +135,16 @@ def sync_detailed(
to be pushed — the case a repository created empty depends on.
Setting the branch here marks it as the project's own choice, so a later
- default-branch rename on GitHub no longer moves it. Projects that never
+ default-branch rename on GitHub no longer moves it, and the response
+ reports `production_branch_follows_default: false`. Projects that never
set one keep following the repository's default branch.
+ An empty string undoes that choice: the project deploys from the
+ repository's default branch again and follows later renames. Volcano
+ reads the default branch from GitHub through the project owner's
+ connection, and the response carries it with
+ `production_branch_follows_default: true`.
+
Args:
id (UUID):
body (SetProjectGitProductionBranchRequest):
@@ -176,9 +190,16 @@ def sync(
to be pushed — the case a repository created empty depends on.
Setting the branch here marks it as the project's own choice, so a later
- default-branch rename on GitHub no longer moves it. Projects that never
+ default-branch rename on GitHub no longer moves it, and the response
+ reports `production_branch_follows_default: false`. Projects that never
set one keep following the repository's default branch.
+ An empty string undoes that choice: the project deploys from the
+ repository's default branch again and follows later renames. Volcano
+ reads the default branch from GitHub through the project owner's
+ connection, and the response carries it with
+ `production_branch_follows_default: true`.
+
Args:
id (UUID):
body (SetProjectGitProductionBranchRequest):
@@ -219,9 +240,16 @@ async def asyncio_detailed(
to be pushed — the case a repository created empty depends on.
Setting the branch here marks it as the project's own choice, so a later
- default-branch rename on GitHub no longer moves it. Projects that never
+ default-branch rename on GitHub no longer moves it, and the response
+ reports `production_branch_follows_default: false`. Projects that never
set one keep following the repository's default branch.
+ An empty string undoes that choice: the project deploys from the
+ repository's default branch again and follows later renames. Volcano
+ reads the default branch from GitHub through the project owner's
+ connection, and the response carries it with
+ `production_branch_follows_default: true`.
+
Args:
id (UUID):
body (SetProjectGitProductionBranchRequest):
@@ -267,9 +295,16 @@ async def asyncio(
to be pushed — the case a repository created empty depends on.
Setting the branch here marks it as the project's own choice, so a later
- default-branch rename on GitHub no longer moves it. Projects that never
+ default-branch rename on GitHub no longer moves it, and the response
+ reports `production_branch_follows_default: false`. Projects that never
set one keep following the repository's default branch.
+ An empty string undoes that choice: the project deploys from the
+ repository's default branch again and follows later renames. Volcano
+ reads the default branch from GitHub through the project owner's
+ connection, and the response carries it with
+ `production_branch_follows_default: true`.
+
Args:
id (UUID):
body (SetProjectGitProductionBranchRequest):
diff --git a/src/volcano_sdk/_generated/api/projects/set_project_git_root_directory.py b/src/volcano_sdk/_generated/api/projects/set_project_git_root_directory.py
new file mode 100644
index 00000000..2827bb20
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/projects/set_project_git_root_directory.py
@@ -0,0 +1,275 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.project_git_connection import ProjectGitConnection
+from ...models.set_project_git_root_directory_request import SetProjectGitRootDirectoryRequest
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ id: UUID | str,
+ *,
+ body: SetProjectGitRootDirectoryRequest,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "put",
+ "url": "/projects/{id}/git-connection/root-directory".format(id=quote(str(id), safe=""),),
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | ProjectGitConnection | None:
+ if response.status_code == 200:
+ response_200 = ProjectGitConnection.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | ProjectGitConnection]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: SetProjectGitRootDirectoryRequest,
+
+) -> Response[Error | ProjectGitConnection]:
+ """ Set the directory a project builds from
+
+ Changes only the root directory, leaving the repository, the production
+ branch and `production_branch_follows_default` alone. Unlike PUT /projects/{id}/git-connection, this
+ accepts a
+ project access token, so CI or an agent can move a project within its
+ repository without being able to change the repository.
+
+ The directory is a path relative to the repository root. An empty
+ string, `.` or `/` means the repository root. The response carries it in
+ the form a deploy reads it: `./apps/web/` comes back as `apps/web`.
+
+ Args:
+ id (UUID):
+ body (SetProjectGitRootDirectoryRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | ProjectGitConnection]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: SetProjectGitRootDirectoryRequest,
+
+) -> Error | ProjectGitConnection | None:
+ """ Set the directory a project builds from
+
+ Changes only the root directory, leaving the repository, the production
+ branch and `production_branch_follows_default` alone. Unlike PUT /projects/{id}/git-connection, this
+ accepts a
+ project access token, so CI or an agent can move a project within its
+ repository without being able to change the repository.
+
+ The directory is a path relative to the repository root. An empty
+ string, `.` or `/` means the repository root. The response carries it in
+ the form a deploy reads it: `./apps/web/` comes back as `apps/web`.
+
+ Args:
+ id (UUID):
+ body (SetProjectGitRootDirectoryRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | ProjectGitConnection
+ """
+
+
+ return sync_detailed(
+ id=id,
+client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: SetProjectGitRootDirectoryRequest,
+
+) -> Response[Error | ProjectGitConnection]:
+ """ Set the directory a project builds from
+
+ Changes only the root directory, leaving the repository, the production
+ branch and `production_branch_follows_default` alone. Unlike PUT /projects/{id}/git-connection, this
+ accepts a
+ project access token, so CI or an agent can move a project within its
+ repository without being able to change the repository.
+
+ The directory is a path relative to the repository root. An empty
+ string, `.` or `/` means the repository root. The response carries it in
+ the form a deploy reads it: `./apps/web/` comes back as `apps/web`.
+
+ Args:
+ id (UUID):
+ body (SetProjectGitRootDirectoryRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | ProjectGitConnection]
+ """
+
+
+ kwargs = request_kwargs(
+ id=id,
+body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+ body: SetProjectGitRootDirectoryRequest,
+
+) -> Error | ProjectGitConnection | None:
+ """ Set the directory a project builds from
+
+ Changes only the root directory, leaving the repository, the production
+ branch and `production_branch_follows_default` alone. Unlike PUT /projects/{id}/git-connection, this
+ accepts a
+ project access token, so CI or an agent can move a project within its
+ repository without being able to change the repository.
+
+ The directory is a path relative to the repository root. An empty
+ string, `.` or `/` means the repository root. The response carries it in
+ the form a deploy reads it: `./apps/web/` comes back as `apps/web`.
+
+ Args:
+ id (UUID):
+ body (SetProjectGitRootDirectoryRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | ProjectGitConnection
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/projects/update_project_git_deploy_settings.py b/src/volcano_sdk/_generated/api/projects/update_project_git_deploy_settings.py
index b3e1721f..8da2197a 100644
--- a/src/volcano_sdk/_generated/api/projects/update_project_git_deploy_settings.py
+++ b/src/volcano_sdk/_generated/api/projects/update_project_git_deploy_settings.py
@@ -129,10 +129,13 @@ def sync_detailed(
until set here; the frontend need not exist when they are saved, since
frontend_name is resolved at deploy time.
+ apply_migrations is the exception to the full replace: omitting it
+ leaves the saved value unchanged. It is off until set here.
+
Args:
id (UUID):
body (UpdateProjectGitDeploySettingsRequest): Full replace of a project's Git auto-deploy
- settings.
+ settings, except apply_migrations, which keeps its saved value when omitted.
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -176,10 +179,13 @@ def sync(
until set here; the frontend need not exist when they are saved, since
frontend_name is resolved at deploy time.
+ apply_migrations is the exception to the full replace: omitting it
+ leaves the saved value unchanged. It is off until set here.
+
Args:
id (UUID):
body (UpdateProjectGitDeploySettingsRequest): Full replace of a project's Git auto-deploy
- settings.
+ settings, except apply_migrations, which keeps its saved value when omitted.
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -218,10 +224,13 @@ async def asyncio_detailed(
until set here; the frontend need not exist when they are saved, since
frontend_name is resolved at deploy time.
+ apply_migrations is the exception to the full replace: omitting it
+ leaves the saved value unchanged. It is off until set here.
+
Args:
id (UUID):
body (UpdateProjectGitDeploySettingsRequest): Full replace of a project's Git auto-deploy
- settings.
+ settings, except apply_migrations, which keeps its saved value when omitted.
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -265,10 +274,13 @@ async def asyncio(
until set here; the frontend need not exist when they are saved, since
frontend_name is resolved at deploy time.
+ apply_migrations is the exception to the full replace: omitting it
+ leaves the saved value unchanged. It is off until set here.
+
Args:
id (UUID):
body (UpdateProjectGitDeploySettingsRequest): Full replace of a project's Git auto-deploy
- settings.
+ settings, except apply_migrations, which keeps its saved value when omitted.
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
diff --git a/src/volcano_sdk/_generated/api/sandboxes/create_sandbox_file_archive.py b/src/volcano_sdk/_generated/api/sandboxes/create_sandbox_file_archive.py
new file mode 100644
index 00000000..283923de
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/sandboxes/create_sandbox_file_archive.py
@@ -0,0 +1,329 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.sandbox_file_archive import SandboxFileArchive
+from ...models.sandbox_file_archive_form import SandboxFileArchiveForm
+from typing import cast
+
+
+
+def request_kwargs(
+ *,
+ body: SandboxFileArchiveForm,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/sandbox-file-archives",
+ }
+
+ _kwargs["files"] = body.to_multipart()
+
+ headers["Content-Type"] = "multipart/form-data; boundary=+++"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | SandboxFileArchive:
+ if response.status_code == 201:
+ response_201 = SandboxFileArchive.from_dict(response.json())
+
+
+
+ return response_201
+
+ response_default = Error.from_dict(response.json())
+
+
+
+ return response_default
+
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | SandboxFileArchive]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: SandboxFileArchiveForm,
+
+) -> Response[Error | SandboxFileArchive]:
+ """ Extract a tar archive into a session's workspace
+
+ Extracts a tar archive into a directory of a session's workspace. Send `multipart/form-data`
+ with `project_id`, `session_id` and `path`, in any order, then the archive as the file part
+ `archive`. The archive may be gzip-compressed; Volcano detects compression from its first bytes.
+ The request streams to the session, so the archive is never held whole in memory.
+
+ Each call accepts at most 32 MiB of archive, 10,000 files and directories, and 256 MiB of
+ uncompressed archive, counting tar headers, and has 2 minutes to send its archive; a slower
+ call fails and writes nothing. Split larger trees into several archives and create one after
+ another. For a single file larger than 8 MiB, use `POST /sandbox-file-parts`.
+
+ `path` must name a directory below the workspace root; a path that resolves to the root or to
+ `/`, such as `.`, `./`, `/`, `/workspace` or `/workspace/.`, is refused with
+ `sandbox_archive_invalid`. The archive may contain only regular files and directories. Entry
+ names are relative to `path`, which is created when missing; an absolute name, a `..`
+ component, a symbolic link, a
+ hard link, a sparse file, or a device refuses the whole archive. File and directory modes keep their
+ permission bits; setuid, setgid and sticky bits are dropped. A file replaces an existing file or
+ symbolic link at its path. Existing directories keep their modes. A symbolic link in the
+ destination is never followed.
+
+ The archive is checked and staged before the workspace changes, so a refused archive writes
+ nothing, and one that fails part way is undone. If a session process moves or removes a
+ directory while the archive is written, the call answers `409`, a file the archive replaced
+ there is kept in a `.sandbox-archive-*` directory at the workspace root, and files the
+ archive already placed can stay. Read-only directories the session user
+ owns still take new entries and keep their modes. Code `sandbox_archive_invalid` (400) means the
+ archive or form is malformed or holds an
+ entry that is not allowed. Code `sandbox_archive_too_large` (413) means it exceeds a limit
+ above. Code `sandbox_path_conflict` (409) means the destination has a symbolic link or a file
+ where the archive needs a directory, a directory where it has a file, or a directory the
+ session user cannot write. Code
+ `sandbox_disk_full` (409) means the session's disk has no room for it; free space and retry. Code
+ `sandbox_image_outdated` (409) means the session started from an image that predates archive
+ writes; start a new session from a current preset, or redeploy the template. A session outside
+ `project_id`, or a project the caller cannot reach, answers 404 like an unknown session.
+
+ Args:
+ body (SandboxFileArchiveForm): Send `project_id`, `session_id` and `path`, in any order,
+ then the `archive` part.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | SandboxFileArchive]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ body: SandboxFileArchiveForm,
+
+) -> Error | SandboxFileArchive | None:
+ """ Extract a tar archive into a session's workspace
+
+ Extracts a tar archive into a directory of a session's workspace. Send `multipart/form-data`
+ with `project_id`, `session_id` and `path`, in any order, then the archive as the file part
+ `archive`. The archive may be gzip-compressed; Volcano detects compression from its first bytes.
+ The request streams to the session, so the archive is never held whole in memory.
+
+ Each call accepts at most 32 MiB of archive, 10,000 files and directories, and 256 MiB of
+ uncompressed archive, counting tar headers, and has 2 minutes to send its archive; a slower
+ call fails and writes nothing. Split larger trees into several archives and create one after
+ another. For a single file larger than 8 MiB, use `POST /sandbox-file-parts`.
+
+ `path` must name a directory below the workspace root; a path that resolves to the root or to
+ `/`, such as `.`, `./`, `/`, `/workspace` or `/workspace/.`, is refused with
+ `sandbox_archive_invalid`. The archive may contain only regular files and directories. Entry
+ names are relative to `path`, which is created when missing; an absolute name, a `..`
+ component, a symbolic link, a
+ hard link, a sparse file, or a device refuses the whole archive. File and directory modes keep their
+ permission bits; setuid, setgid and sticky bits are dropped. A file replaces an existing file or
+ symbolic link at its path. Existing directories keep their modes. A symbolic link in the
+ destination is never followed.
+
+ The archive is checked and staged before the workspace changes, so a refused archive writes
+ nothing, and one that fails part way is undone. If a session process moves or removes a
+ directory while the archive is written, the call answers `409`, a file the archive replaced
+ there is kept in a `.sandbox-archive-*` directory at the workspace root, and files the
+ archive already placed can stay. Read-only directories the session user
+ owns still take new entries and keep their modes. Code `sandbox_archive_invalid` (400) means the
+ archive or form is malformed or holds an
+ entry that is not allowed. Code `sandbox_archive_too_large` (413) means it exceeds a limit
+ above. Code `sandbox_path_conflict` (409) means the destination has a symbolic link or a file
+ where the archive needs a directory, a directory where it has a file, or a directory the
+ session user cannot write. Code
+ `sandbox_disk_full` (409) means the session's disk has no room for it; free space and retry. Code
+ `sandbox_image_outdated` (409) means the session started from an image that predates archive
+ writes; start a new session from a current preset, or redeploy the template. A session outside
+ `project_id`, or a project the caller cannot reach, answers 404 like an unknown session.
+
+ Args:
+ body (SandboxFileArchiveForm): Send `project_id`, `session_id` and `path`, in any order,
+ then the `archive` part.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | SandboxFileArchive
+ """
+
+
+ return sync_detailed(
+ client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: SandboxFileArchiveForm,
+
+) -> Response[Error | SandboxFileArchive]:
+ """ Extract a tar archive into a session's workspace
+
+ Extracts a tar archive into a directory of a session's workspace. Send `multipart/form-data`
+ with `project_id`, `session_id` and `path`, in any order, then the archive as the file part
+ `archive`. The archive may be gzip-compressed; Volcano detects compression from its first bytes.
+ The request streams to the session, so the archive is never held whole in memory.
+
+ Each call accepts at most 32 MiB of archive, 10,000 files and directories, and 256 MiB of
+ uncompressed archive, counting tar headers, and has 2 minutes to send its archive; a slower
+ call fails and writes nothing. Split larger trees into several archives and create one after
+ another. For a single file larger than 8 MiB, use `POST /sandbox-file-parts`.
+
+ `path` must name a directory below the workspace root; a path that resolves to the root or to
+ `/`, such as `.`, `./`, `/`, `/workspace` or `/workspace/.`, is refused with
+ `sandbox_archive_invalid`. The archive may contain only regular files and directories. Entry
+ names are relative to `path`, which is created when missing; an absolute name, a `..`
+ component, a symbolic link, a
+ hard link, a sparse file, or a device refuses the whole archive. File and directory modes keep their
+ permission bits; setuid, setgid and sticky bits are dropped. A file replaces an existing file or
+ symbolic link at its path. Existing directories keep their modes. A symbolic link in the
+ destination is never followed.
+
+ The archive is checked and staged before the workspace changes, so a refused archive writes
+ nothing, and one that fails part way is undone. If a session process moves or removes a
+ directory while the archive is written, the call answers `409`, a file the archive replaced
+ there is kept in a `.sandbox-archive-*` directory at the workspace root, and files the
+ archive already placed can stay. Read-only directories the session user
+ owns still take new entries and keep their modes. Code `sandbox_archive_invalid` (400) means the
+ archive or form is malformed or holds an
+ entry that is not allowed. Code `sandbox_archive_too_large` (413) means it exceeds a limit
+ above. Code `sandbox_path_conflict` (409) means the destination has a symbolic link or a file
+ where the archive needs a directory, a directory where it has a file, or a directory the
+ session user cannot write. Code
+ `sandbox_disk_full` (409) means the session's disk has no room for it; free space and retry. Code
+ `sandbox_image_outdated` (409) means the session started from an image that predates archive
+ writes; start a new session from a current preset, or redeploy the template. A session outside
+ `project_id`, or a project the caller cannot reach, answers 404 like an unknown session.
+
+ Args:
+ body (SandboxFileArchiveForm): Send `project_id`, `session_id` and `path`, in any order,
+ then the `archive` part.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | SandboxFileArchive]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ body: SandboxFileArchiveForm,
+
+) -> Error | SandboxFileArchive | None:
+ """ Extract a tar archive into a session's workspace
+
+ Extracts a tar archive into a directory of a session's workspace. Send `multipart/form-data`
+ with `project_id`, `session_id` and `path`, in any order, then the archive as the file part
+ `archive`. The archive may be gzip-compressed; Volcano detects compression from its first bytes.
+ The request streams to the session, so the archive is never held whole in memory.
+
+ Each call accepts at most 32 MiB of archive, 10,000 files and directories, and 256 MiB of
+ uncompressed archive, counting tar headers, and has 2 minutes to send its archive; a slower
+ call fails and writes nothing. Split larger trees into several archives and create one after
+ another. For a single file larger than 8 MiB, use `POST /sandbox-file-parts`.
+
+ `path` must name a directory below the workspace root; a path that resolves to the root or to
+ `/`, such as `.`, `./`, `/`, `/workspace` or `/workspace/.`, is refused with
+ `sandbox_archive_invalid`. The archive may contain only regular files and directories. Entry
+ names are relative to `path`, which is created when missing; an absolute name, a `..`
+ component, a symbolic link, a
+ hard link, a sparse file, or a device refuses the whole archive. File and directory modes keep their
+ permission bits; setuid, setgid and sticky bits are dropped. A file replaces an existing file or
+ symbolic link at its path. Existing directories keep their modes. A symbolic link in the
+ destination is never followed.
+
+ The archive is checked and staged before the workspace changes, so a refused archive writes
+ nothing, and one that fails part way is undone. If a session process moves or removes a
+ directory while the archive is written, the call answers `409`, a file the archive replaced
+ there is kept in a `.sandbox-archive-*` directory at the workspace root, and files the
+ archive already placed can stay. Read-only directories the session user
+ owns still take new entries and keep their modes. Code `sandbox_archive_invalid` (400) means the
+ archive or form is malformed or holds an
+ entry that is not allowed. Code `sandbox_archive_too_large` (413) means it exceeds a limit
+ above. Code `sandbox_path_conflict` (409) means the destination has a symbolic link or a file
+ where the archive needs a directory, a directory where it has a file, or a directory the
+ session user cannot write. Code
+ `sandbox_disk_full` (409) means the session's disk has no room for it; free space and retry. Code
+ `sandbox_image_outdated` (409) means the session started from an image that predates archive
+ writes; start a new session from a current preset, or redeploy the template. A session outside
+ `project_id`, or a project the caller cannot reach, answers 404 like an unknown session.
+
+ Args:
+ body (SandboxFileArchiveForm): Send `project_id`, `session_id` and `path`, in any order,
+ then the `archive` part.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | SandboxFileArchive
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/sandboxes/create_sandbox_file_part.py b/src/volcano_sdk/_generated/api/sandboxes/create_sandbox_file_part.py
new file mode 100644
index 00000000..7101db43
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/sandboxes/create_sandbox_file_part.py
@@ -0,0 +1,285 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.sandbox_file_part import SandboxFilePart
+from ...models.sandbox_file_part_request import SandboxFilePartRequest
+from typing import cast
+
+
+
+def request_kwargs(
+ *,
+ body: SandboxFilePartRequest,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/sandbox-file-parts",
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | SandboxFilePart:
+ if response.status_code == 201:
+ response_201 = SandboxFilePart.from_dict(response.json())
+
+
+
+ return response_201
+
+ response_default = Error.from_dict(response.json())
+
+
+
+ return response_default
+
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | SandboxFilePart]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: SandboxFilePartRequest,
+
+) -> Response[Error | SandboxFilePart]:
+ """ Write one part of a large workspace file
+
+ Writes a file of up to 1 GiB into a session's workspace in parts of at most 8 MiB. Each part
+ names its `offset` in the file, the whole file's `size`, and the whole file's lowercase hex
+ `sha256`. Parts collect in a hidden staging file beside `path`; nothing appears at `path` until
+ the part that ends at `size` arrives. That part checks the whole file's size and SHA-256, then
+ moves the file into place in one step, so a partial file is never visible at `path`. The
+ response's `complete` says which part finished the file. Missing parent directories are created,
+ and a symbolic link among them is never followed. The finished file is readable and writable
+ only by the session user.
+
+ A part may start anywhere up to the bytes already received, so a failed part can be resent. A
+ part at offset 0 starts the file again. Resending the part that finished the file answers the
+ same completion while the file at `path` still matches `size` and `sha256`. Code
+ `sandbox_file_part_out_of_order` (409) means the
+ part starts past the bytes received; resend from the last part that succeeded. Code
+ `sandbox_file_part_mismatch` (409) means the finished file differs from `size` or `sha256`; its
+ parts are discarded, so start again at offset 0. Code `sandbox_path_conflict` (409) means a
+ directory is at `path`, a file or symbolic link is where a parent directory belongs, or the
+ session user cannot write the parent directory, or, when parents are missing, the nearest
+ one that exists. Read-only directories the session user owns still take new entries and
+ keep their modes. Code
+ `sandbox_disk_full` (409) means the session's disk has no room; free space and retry. Code
+ `sandbox_image_outdated` (409) means the session started from an image that predates parted
+ writes. A staging file stays until its file completes, a part at offset 0 restarts it, or the
+ session ends. A session outside `project_id`, or a project the caller cannot reach, answers 404
+ like an unknown session.
+
+ Args:
+ body (SandboxFilePartRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | SandboxFilePart]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ body: SandboxFilePartRequest,
+
+) -> Error | SandboxFilePart | None:
+ """ Write one part of a large workspace file
+
+ Writes a file of up to 1 GiB into a session's workspace in parts of at most 8 MiB. Each part
+ names its `offset` in the file, the whole file's `size`, and the whole file's lowercase hex
+ `sha256`. Parts collect in a hidden staging file beside `path`; nothing appears at `path` until
+ the part that ends at `size` arrives. That part checks the whole file's size and SHA-256, then
+ moves the file into place in one step, so a partial file is never visible at `path`. The
+ response's `complete` says which part finished the file. Missing parent directories are created,
+ and a symbolic link among them is never followed. The finished file is readable and writable
+ only by the session user.
+
+ A part may start anywhere up to the bytes already received, so a failed part can be resent. A
+ part at offset 0 starts the file again. Resending the part that finished the file answers the
+ same completion while the file at `path` still matches `size` and `sha256`. Code
+ `sandbox_file_part_out_of_order` (409) means the
+ part starts past the bytes received; resend from the last part that succeeded. Code
+ `sandbox_file_part_mismatch` (409) means the finished file differs from `size` or `sha256`; its
+ parts are discarded, so start again at offset 0. Code `sandbox_path_conflict` (409) means a
+ directory is at `path`, a file or symbolic link is where a parent directory belongs, or the
+ session user cannot write the parent directory, or, when parents are missing, the nearest
+ one that exists. Read-only directories the session user owns still take new entries and
+ keep their modes. Code
+ `sandbox_disk_full` (409) means the session's disk has no room; free space and retry. Code
+ `sandbox_image_outdated` (409) means the session started from an image that predates parted
+ writes. A staging file stays until its file completes, a part at offset 0 restarts it, or the
+ session ends. A session outside `project_id`, or a project the caller cannot reach, answers 404
+ like an unknown session.
+
+ Args:
+ body (SandboxFilePartRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | SandboxFilePart
+ """
+
+
+ return sync_detailed(
+ client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: SandboxFilePartRequest,
+
+) -> Response[Error | SandboxFilePart]:
+ """ Write one part of a large workspace file
+
+ Writes a file of up to 1 GiB into a session's workspace in parts of at most 8 MiB. Each part
+ names its `offset` in the file, the whole file's `size`, and the whole file's lowercase hex
+ `sha256`. Parts collect in a hidden staging file beside `path`; nothing appears at `path` until
+ the part that ends at `size` arrives. That part checks the whole file's size and SHA-256, then
+ moves the file into place in one step, so a partial file is never visible at `path`. The
+ response's `complete` says which part finished the file. Missing parent directories are created,
+ and a symbolic link among them is never followed. The finished file is readable and writable
+ only by the session user.
+
+ A part may start anywhere up to the bytes already received, so a failed part can be resent. A
+ part at offset 0 starts the file again. Resending the part that finished the file answers the
+ same completion while the file at `path` still matches `size` and `sha256`. Code
+ `sandbox_file_part_out_of_order` (409) means the
+ part starts past the bytes received; resend from the last part that succeeded. Code
+ `sandbox_file_part_mismatch` (409) means the finished file differs from `size` or `sha256`; its
+ parts are discarded, so start again at offset 0. Code `sandbox_path_conflict` (409) means a
+ directory is at `path`, a file or symbolic link is where a parent directory belongs, or the
+ session user cannot write the parent directory, or, when parents are missing, the nearest
+ one that exists. Read-only directories the session user owns still take new entries and
+ keep their modes. Code
+ `sandbox_disk_full` (409) means the session's disk has no room; free space and retry. Code
+ `sandbox_image_outdated` (409) means the session started from an image that predates parted
+ writes. A staging file stays until its file completes, a part at offset 0 restarts it, or the
+ session ends. A session outside `project_id`, or a project the caller cannot reach, answers 404
+ like an unknown session.
+
+ Args:
+ body (SandboxFilePartRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | SandboxFilePart]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ body: SandboxFilePartRequest,
+
+) -> Error | SandboxFilePart | None:
+ """ Write one part of a large workspace file
+
+ Writes a file of up to 1 GiB into a session's workspace in parts of at most 8 MiB. Each part
+ names its `offset` in the file, the whole file's `size`, and the whole file's lowercase hex
+ `sha256`. Parts collect in a hidden staging file beside `path`; nothing appears at `path` until
+ the part that ends at `size` arrives. That part checks the whole file's size and SHA-256, then
+ moves the file into place in one step, so a partial file is never visible at `path`. The
+ response's `complete` says which part finished the file. Missing parent directories are created,
+ and a symbolic link among them is never followed. The finished file is readable and writable
+ only by the session user.
+
+ A part may start anywhere up to the bytes already received, so a failed part can be resent. A
+ part at offset 0 starts the file again. Resending the part that finished the file answers the
+ same completion while the file at `path` still matches `size` and `sha256`. Code
+ `sandbox_file_part_out_of_order` (409) means the
+ part starts past the bytes received; resend from the last part that succeeded. Code
+ `sandbox_file_part_mismatch` (409) means the finished file differs from `size` or `sha256`; its
+ parts are discarded, so start again at offset 0. Code `sandbox_path_conflict` (409) means a
+ directory is at `path`, a file or symbolic link is where a parent directory belongs, or the
+ session user cannot write the parent directory, or, when parents are missing, the nearest
+ one that exists. Read-only directories the session user owns still take new entries and
+ keep their modes. Code
+ `sandbox_disk_full` (409) means the session's disk has no room; free space and retry. Code
+ `sandbox_image_outdated` (409) means the session started from an image that predates parted
+ writes. A staging file stays until its file completes, a part at offset 0 restarts it, or the
+ session ends. A session outside `project_id`, or a project the caller cannot reach, answers 404
+ like an unknown session.
+
+ Args:
+ body (SandboxFilePartRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | SandboxFilePart
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/sandboxes/list_sandbox_session_files.py b/src/volcano_sdk/_generated/api/sandboxes/list_sandbox_session_files.py
new file mode 100644
index 00000000..ca7cd44c
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/sandboxes/list_sandbox_session_files.py
@@ -0,0 +1,296 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.sandbox_file_list_result import SandboxFileListResult
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ *,
+ project_id: UUID | str,
+ session_id: UUID | str,
+ path: str | Unset = UNSET,
+ recursive: bool | Unset = True,
+ include_sha256: bool | Unset = False,
+ limit: int | Unset = 10000,
+ cursor: str | Unset = UNSET,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+ json_session_id = str(session_id)
+ params["session_id"] = json_session_id
+
+ params["path"] = path
+
+ params["recursive"] = recursive
+
+ params["include_sha256"] = include_sha256
+
+ params["limit"] = limit
+
+ params["cursor"] = cursor
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/sandbox-session-files",
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | SandboxFileListResult:
+ if response.status_code == 200:
+ response_200 = SandboxFileListResult.from_dict(response.json())
+
+
+
+ return response_200
+
+ response_default = Error.from_dict(response.json())
+
+
+
+ return response_default
+
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | SandboxFileListResult]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ session_id: UUID | str,
+ path: str | Unset = UNSET,
+ recursive: bool | Unset = True,
+ include_sha256: bool | Unset = False,
+ limit: int | Unset = 10000,
+ cursor: str | Unset = UNSET,
+
+) -> Response[Error | SandboxFileListResult]:
+ """ List workspace files
+
+ Lists a directory in a Sandbox session's workspace, one page at a time. The listing never follows a
+ symlink and never leaves the workspace. It is not a snapshot: a file that changes while it runs can
+ appear before or after the change. Sessions started on an image built before file listing answer 409
+ with code `sandbox_image_outdated`; start a new session, after redeploying a custom template.
+
+ Args:
+ project_id (UUID):
+ session_id (UUID):
+ path (str | Unset):
+ recursive (bool | Unset): Default: True.
+ include_sha256 (bool | Unset): Default: False.
+ limit (int | Unset): Default: 10000.
+ cursor (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | SandboxFileListResult]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+session_id=session_id,
+path=path,
+recursive=recursive,
+include_sha256=include_sha256,
+limit=limit,
+cursor=cursor,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ session_id: UUID | str,
+ path: str | Unset = UNSET,
+ recursive: bool | Unset = True,
+ include_sha256: bool | Unset = False,
+ limit: int | Unset = 10000,
+ cursor: str | Unset = UNSET,
+
+) -> Error | SandboxFileListResult | None:
+ """ List workspace files
+
+ Lists a directory in a Sandbox session's workspace, one page at a time. The listing never follows a
+ symlink and never leaves the workspace. It is not a snapshot: a file that changes while it runs can
+ appear before or after the change. Sessions started on an image built before file listing answer 409
+ with code `sandbox_image_outdated`; start a new session, after redeploying a custom template.
+
+ Args:
+ project_id (UUID):
+ session_id (UUID):
+ path (str | Unset):
+ recursive (bool | Unset): Default: True.
+ include_sha256 (bool | Unset): Default: False.
+ limit (int | Unset): Default: 10000.
+ cursor (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | SandboxFileListResult
+ """
+
+
+ return sync_detailed(
+ client=client,
+project_id=project_id,
+session_id=session_id,
+path=path,
+recursive=recursive,
+include_sha256=include_sha256,
+limit=limit,
+cursor=cursor,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ session_id: UUID | str,
+ path: str | Unset = UNSET,
+ recursive: bool | Unset = True,
+ include_sha256: bool | Unset = False,
+ limit: int | Unset = 10000,
+ cursor: str | Unset = UNSET,
+
+) -> Response[Error | SandboxFileListResult]:
+ """ List workspace files
+
+ Lists a directory in a Sandbox session's workspace, one page at a time. The listing never follows a
+ symlink and never leaves the workspace. It is not a snapshot: a file that changes while it runs can
+ appear before or after the change. Sessions started on an image built before file listing answer 409
+ with code `sandbox_image_outdated`; start a new session, after redeploying a custom template.
+
+ Args:
+ project_id (UUID):
+ session_id (UUID):
+ path (str | Unset):
+ recursive (bool | Unset): Default: True.
+ include_sha256 (bool | Unset): Default: False.
+ limit (int | Unset): Default: 10000.
+ cursor (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | SandboxFileListResult]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+session_id=session_id,
+path=path,
+recursive=recursive,
+include_sha256=include_sha256,
+limit=limit,
+cursor=cursor,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+ session_id: UUID | str,
+ path: str | Unset = UNSET,
+ recursive: bool | Unset = True,
+ include_sha256: bool | Unset = False,
+ limit: int | Unset = 10000,
+ cursor: str | Unset = UNSET,
+
+) -> Error | SandboxFileListResult | None:
+ """ List workspace files
+
+ Lists a directory in a Sandbox session's workspace, one page at a time. The listing never follows a
+ symlink and never leaves the workspace. It is not a snapshot: a file that changes while it runs can
+ appear before or after the change. Sessions started on an image built before file listing answer 409
+ with code `sandbox_image_outdated`; start a new session, after redeploying a custom template.
+
+ Args:
+ project_id (UUID):
+ session_id (UUID):
+ path (str | Unset):
+ recursive (bool | Unset): Default: True.
+ include_sha256 (bool | Unset): Default: False.
+ limit (int | Unset): Default: 10000.
+ cursor (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | SandboxFileListResult
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+project_id=project_id,
+session_id=session_id,
+path=path,
+recursive=recursive,
+include_sha256=include_sha256,
+limit=limit,
+cursor=cursor,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/service_keys/create_service_key.py b/src/volcano_sdk/_generated/api/service_keys/create_service_key.py
index 138d753a..d247f78f 100644
--- a/src/volcano_sdk/_generated/api/service_keys/create_service_key.py
+++ b/src/volcano_sdk/_generated/api/service_keys/create_service_key.py
@@ -9,6 +9,7 @@
from ... import errors
from ...models.create_service_key_body import CreateServiceKeyBody
+from ...models.error import Error
from ...models.service_key import ServiceKey
from typing import cast
from uuid import UUID
@@ -42,7 +43,7 @@ def request_kwargs(
-def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | ServiceKey | None:
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | ServiceKey | None:
if response.status_code == 201:
response_201 = ServiceKey.from_dict(response.json())
@@ -50,8 +51,18 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return response_201
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
if response.status_code == 409:
- response_409 = cast(Any, None)
+ response_409 = Error.from_dict(response.json())
+
+
+
return response_409
if client.raise_on_unexpected_status:
@@ -60,7 +71,7 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return None
-def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | ServiceKey]:
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | ServiceKey]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
@@ -75,7 +86,7 @@ def sync_detailed(
client: AuthenticatedClient,
body: CreateServiceKeyBody,
-) -> Response[Any | ServiceKey]:
+) -> Response[Error | ServiceKey]:
""" Create service key
Create a new service role key for admin operations.
@@ -92,7 +103,7 @@ def sync_detailed(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[Any | ServiceKey]
+ Response[Error | ServiceKey]
"""
@@ -114,7 +125,7 @@ def sync(
client: AuthenticatedClient,
body: CreateServiceKeyBody,
-) -> Any | ServiceKey | None:
+) -> Error | ServiceKey | None:
""" Create service key
Create a new service role key for admin operations.
@@ -131,7 +142,7 @@ def sync(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Any | ServiceKey
+ Error | ServiceKey
"""
@@ -148,7 +159,7 @@ async def asyncio_detailed(
client: AuthenticatedClient,
body: CreateServiceKeyBody,
-) -> Response[Any | ServiceKey]:
+) -> Response[Error | ServiceKey]:
""" Create service key
Create a new service role key for admin operations.
@@ -165,7 +176,7 @@ async def asyncio_detailed(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[Any | ServiceKey]
+ Response[Error | ServiceKey]
"""
@@ -187,7 +198,7 @@ async def asyncio(
client: AuthenticatedClient,
body: CreateServiceKeyBody,
-) -> Any | ServiceKey | None:
+) -> Error | ServiceKey | None:
""" Create service key
Create a new service role key for admin operations.
@@ -204,7 +215,7 @@ async def asyncio(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Any | ServiceKey
+ Error | ServiceKey
"""
diff --git a/src/volcano_sdk/_generated/api/service_keys/get_service_key.py b/src/volcano_sdk/_generated/api/service_keys/get_service_key.py
index 0ce830c2..f90bf724 100644
--- a/src/volcano_sdk/_generated/api/service_keys/get_service_key.py
+++ b/src/volcano_sdk/_generated/api/service_keys/get_service_key.py
@@ -8,6 +8,7 @@
from ...types import Response, UNSET
from ... import errors
+from ...models.error import Error
from ...models.service_key import ServiceKey
from typing import cast
from uuid import UUID
@@ -35,7 +36,7 @@ def request_kwargs(
-def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | ServiceKey | None:
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | Error | ServiceKey | None:
if response.status_code == 200:
response_200 = ServiceKey.from_dict(response.json())
@@ -43,6 +44,13 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return response_200
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
if response.status_code == 404:
response_404 = cast(Any, None)
return response_404
@@ -53,7 +61,7 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return None
-def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | ServiceKey]:
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | Error | ServiceKey]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
@@ -68,7 +76,7 @@ def sync_detailed(
*,
client: AuthenticatedClient,
-) -> Response[Any | ServiceKey]:
+) -> Response[Any | Error | ServiceKey]:
""" Get service key
Get details of a specific service key
@@ -82,7 +90,7 @@ def sync_detailed(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[Any | ServiceKey]
+ Response[Any | Error | ServiceKey]
"""
@@ -104,7 +112,7 @@ def sync(
*,
client: AuthenticatedClient,
-) -> Any | ServiceKey | None:
+) -> Any | Error | ServiceKey | None:
""" Get service key
Get details of a specific service key
@@ -118,7 +126,7 @@ def sync(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Any | ServiceKey
+ Any | Error | ServiceKey
"""
@@ -135,7 +143,7 @@ async def asyncio_detailed(
*,
client: AuthenticatedClient,
-) -> Response[Any | ServiceKey]:
+) -> Response[Any | Error | ServiceKey]:
""" Get service key
Get details of a specific service key
@@ -149,7 +157,7 @@ async def asyncio_detailed(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[Any | ServiceKey]
+ Response[Any | Error | ServiceKey]
"""
@@ -171,7 +179,7 @@ async def asyncio(
*,
client: AuthenticatedClient,
-) -> Any | ServiceKey | None:
+) -> Any | Error | ServiceKey | None:
""" Get service key
Get details of a specific service key
@@ -185,7 +193,7 @@ async def asyncio(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Any | ServiceKey
+ Any | Error | ServiceKey
"""
diff --git a/src/volcano_sdk/_generated/api/service_keys/regenerate_service_key.py b/src/volcano_sdk/_generated/api/service_keys/regenerate_service_key.py
index 25705f10..e17f59f7 100644
--- a/src/volcano_sdk/_generated/api/service_keys/regenerate_service_key.py
+++ b/src/volcano_sdk/_generated/api/service_keys/regenerate_service_key.py
@@ -8,6 +8,7 @@
from ...types import Response, UNSET
from ... import errors
+from ...models.error import Error
from ...models.service_key import ServiceKey
from typing import cast
from uuid import UUID
@@ -35,7 +36,7 @@ def request_kwargs(
-def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> ServiceKey | None:
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | ServiceKey | None:
if response.status_code == 200:
response_200 = ServiceKey.from_dict(response.json())
@@ -43,13 +44,20 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return response_200
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
else:
return None
-def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[ServiceKey]:
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | ServiceKey]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
@@ -64,7 +72,7 @@ def sync_detailed(
*,
client: AuthenticatedClient,
-) -> Response[ServiceKey]:
+) -> Response[Error | ServiceKey]:
""" Regenerate service key
Generate new JWT value for existing key.
@@ -80,7 +88,7 @@ def sync_detailed(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[ServiceKey]
+ Response[Error | ServiceKey]
"""
@@ -102,7 +110,7 @@ def sync(
*,
client: AuthenticatedClient,
-) -> ServiceKey | None:
+) -> Error | ServiceKey | None:
""" Regenerate service key
Generate new JWT value for existing key.
@@ -118,7 +126,7 @@ def sync(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- ServiceKey
+ Error | ServiceKey
"""
@@ -135,7 +143,7 @@ async def asyncio_detailed(
*,
client: AuthenticatedClient,
-) -> Response[ServiceKey]:
+) -> Response[Error | ServiceKey]:
""" Regenerate service key
Generate new JWT value for existing key.
@@ -151,7 +159,7 @@ async def asyncio_detailed(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[ServiceKey]
+ Response[Error | ServiceKey]
"""
@@ -173,7 +181,7 @@ async def asyncio(
*,
client: AuthenticatedClient,
-) -> ServiceKey | None:
+) -> Error | ServiceKey | None:
""" Regenerate service key
Generate new JWT value for existing key.
@@ -189,7 +197,7 @@ async def asyncio(
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- ServiceKey
+ Error | ServiceKey
"""
diff --git a/src/volcano_sdk/_generated/api/shares/__init__.py b/src/volcano_sdk/_generated/api/shares/__init__.py
new file mode 100644
index 00000000..c9921b5f
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/shares/__init__.py
@@ -0,0 +1 @@
+""" Contains endpoint functions for accessing the API """
diff --git a/src/volcano_sdk/_generated/api/shares/create_share.py b/src/volcano_sdk/_generated/api/shares/create_share.py
new file mode 100644
index 00000000..1fc93133
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/shares/create_share.py
@@ -0,0 +1,241 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.share import Share
+from ...models.share_create_request import ShareCreateRequest
+from typing import cast
+
+
+
+def request_kwargs(
+ *,
+ body: ShareCreateRequest,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/shares",
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | Share | None:
+ if response.status_code == 201:
+ response_201 = Share.from_dict(response.json())
+
+
+
+ return response_201
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = Error.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | Share]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: ShareCreateRequest,
+
+) -> Response[Error | Share]:
+ """ Create a deploy link
+
+ Creates a draft link for the project. It offers nothing to visitors, and its
+ preview answers `404`, until its owner publishes a release to it with
+ `POST /share-releases`. Any project can have
+ links, whether it deploys from the CLI, the dashboard or Git.
+
+ Args:
+ body (ShareCreateRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | Share]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ body: ShareCreateRequest,
+
+) -> Error | Share | None:
+ """ Create a deploy link
+
+ Creates a draft link for the project. It offers nothing to visitors, and its
+ preview answers `404`, until its owner publishes a release to it with
+ `POST /share-releases`. Any project can have
+ links, whether it deploys from the CLI, the dashboard or Git.
+
+ Args:
+ body (ShareCreateRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | Share
+ """
+
+
+ return sync_detailed(
+ client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: ShareCreateRequest,
+
+) -> Response[Error | Share]:
+ """ Create a deploy link
+
+ Creates a draft link for the project. It offers nothing to visitors, and its
+ preview answers `404`, until its owner publishes a release to it with
+ `POST /share-releases`. Any project can have
+ links, whether it deploys from the CLI, the dashboard or Git.
+
+ Args:
+ body (ShareCreateRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | Share]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ body: ShareCreateRequest,
+
+) -> Error | Share | None:
+ """ Create a deploy link
+
+ Creates a draft link for the project. It offers nothing to visitors, and its
+ preview answers `404`, until its owner publishes a release to it with
+ `POST /share-releases`. Any project can have
+ links, whether it deploys from the CLI, the dashboard or Git.
+
+ Args:
+ body (ShareCreateRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | Share
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/shares/delete_share.py b/src/volcano_sdk/_generated/api/shares/delete_share.py
new file mode 100644
index 00000000..9dd675e2
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/shares/delete_share.py
@@ -0,0 +1,257 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ share_id: str,
+ *,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ json_project_id: str | Unset = UNSET
+ if not isinstance(project_id, Unset):
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "delete",
+ "url": "/shares/{share_id}".format(share_id=quote(str(share_id), safe=""),),
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | Error | None:
+ if response.status_code == 204:
+ response_204 = cast(Any, None)
+ return response_204
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ share_id: str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Response[Any | Error]:
+ """ Delete a deploy link
+
+ Deletes the link, its releases and its recorded events. The address stops
+ working. Installs the link started that have not finished, including ones
+ still queued, fail at their next step. The visitor keeps the project, with
+ its installation failed. A link Volcano took down (`disabled_reason`
+ `operator`) cannot be deleted until that is lifted; deleting its project
+ still removes it.
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ share_id=share_id,
+project_id=project_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ share_id: str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Any | Error | None:
+ """ Delete a deploy link
+
+ Deletes the link, its releases and its recorded events. The address stops
+ working. Installs the link started that have not finished, including ones
+ still queued, fail at their next step. The visitor keeps the project, with
+ its installation failed. A link Volcano took down (`disabled_reason`
+ `operator`) cannot be deleted until that is lifted; deleting its project
+ still removes it.
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return sync_detailed(
+ share_id=share_id,
+client=client,
+project_id=project_id,
+
+ ).parsed
+
+async def asyncio_detailed(
+ share_id: str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Response[Any | Error]:
+ """ Delete a deploy link
+
+ Deletes the link, its releases and its recorded events. The address stops
+ working. Installs the link started that have not finished, including ones
+ still queued, fail at their next step. The visitor keeps the project, with
+ its installation failed. A link Volcano took down (`disabled_reason`
+ `operator`) cannot be deleted until that is lifted; deleting its project
+ still removes it.
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ share_id=share_id,
+project_id=project_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ share_id: str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Any | Error | None:
+ """ Delete a deploy link
+
+ Deletes the link, its releases and its recorded events. The address stops
+ working. Installs the link started that have not finished, including ones
+ still queued, fail at their next step. The visitor keeps the project, with
+ its installation failed. A link Volcano took down (`disabled_reason`
+ `operator`) cannot be deleted until that is lifted; deleting its project
+ still removes it.
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return (await asyncio_detailed(
+ share_id=share_id,
+client=client,
+project_id=project_id,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/shares/get_share.py b/src/volcano_sdk/_generated/api/shares/get_share.py
new file mode 100644
index 00000000..ef18a6ee
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/shares/get_share.py
@@ -0,0 +1,226 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.share import Share
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ share_id: str,
+ *,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ json_project_id: str | Unset = UNSET
+ if not isinstance(project_id, Unset):
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/shares/{share_id}".format(share_id=quote(str(share_id), safe=""),),
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | Share | None:
+ if response.status_code == 200:
+ response_200 = Share.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | Share]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ share_id: str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Response[Error | Share]:
+ """ Get a deploy link
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | Share]
+ """
+
+
+ kwargs = request_kwargs(
+ share_id=share_id,
+project_id=project_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ share_id: str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Error | Share | None:
+ """ Get a deploy link
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | Share
+ """
+
+
+ return sync_detailed(
+ share_id=share_id,
+client=client,
+project_id=project_id,
+
+ ).parsed
+
+async def asyncio_detailed(
+ share_id: str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Response[Error | Share]:
+ """ Get a deploy link
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | Share]
+ """
+
+
+ kwargs = request_kwargs(
+ share_id=share_id,
+project_id=project_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ share_id: str,
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Error | Share | None:
+ """ Get a deploy link
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | Share
+ """
+
+
+ return (await asyncio_detailed(
+ share_id=share_id,
+client=client,
+project_id=project_id,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/shares/get_share_preview.py b/src/volcano_sdk/_generated/api/shares/get_share_preview.py
new file mode 100644
index 00000000..c2e710d6
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/shares/get_share_preview.py
@@ -0,0 +1,265 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.share_preview import SharePreview
+from typing import cast
+
+
+
+def request_kwargs(
+ share_id: str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/share-previews/{share_id}".format(share_id=quote(str(share_id), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | SharePreview | None:
+ if response.status_code == 200:
+ response_200 = SharePreview.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 429:
+ response_429 = Error.from_dict(response.json())
+
+
+
+ return response_429
+
+ if response.status_code == 451:
+ response_451 = Error.from_dict(response.json())
+
+
+
+ return response_451
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if response.status_code == 503:
+ response_503 = Error.from_dict(response.json())
+
+
+
+ return response_503
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | SharePreview]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ share_id: str,
+ *,
+ client: AuthenticatedClient | Client,
+
+) -> Response[Error | SharePreview]:
+ """ Preview what a deploy link deploys
+
+ Public: needs no credential, because the link id is the credential. Answers
+ the link's current release: when it was published, its digest, the functions
+ and frontends installing it creates, the variables the visitor supplies, and
+ the functions that receive the new project's service key. Show it to a
+ visitor before they confirm, and send its `release.id` when creating the
+ project.
+
+ Counts the visit for the link's owner, unless the request comes from a
+ crawler or link preview. A link that does not exist, was switched off, or has
+ not been published yet all answer the same `404`.
+
+ Args:
+ share_id (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | SharePreview]
+ """
+
+
+ kwargs = request_kwargs(
+ share_id=share_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ share_id: str,
+ *,
+ client: AuthenticatedClient | Client,
+
+) -> Error | SharePreview | None:
+ """ Preview what a deploy link deploys
+
+ Public: needs no credential, because the link id is the credential. Answers
+ the link's current release: when it was published, its digest, the functions
+ and frontends installing it creates, the variables the visitor supplies, and
+ the functions that receive the new project's service key. Show it to a
+ visitor before they confirm, and send its `release.id` when creating the
+ project.
+
+ Counts the visit for the link's owner, unless the request comes from a
+ crawler or link preview. A link that does not exist, was switched off, or has
+ not been published yet all answer the same `404`.
+
+ Args:
+ share_id (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | SharePreview
+ """
+
+
+ return sync_detailed(
+ share_id=share_id,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ share_id: str,
+ *,
+ client: AuthenticatedClient | Client,
+
+) -> Response[Error | SharePreview]:
+ """ Preview what a deploy link deploys
+
+ Public: needs no credential, because the link id is the credential. Answers
+ the link's current release: when it was published, its digest, the functions
+ and frontends installing it creates, the variables the visitor supplies, and
+ the functions that receive the new project's service key. Show it to a
+ visitor before they confirm, and send its `release.id` when creating the
+ project.
+
+ Counts the visit for the link's owner, unless the request comes from a
+ crawler or link preview. A link that does not exist, was switched off, or has
+ not been published yet all answer the same `404`.
+
+ Args:
+ share_id (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | SharePreview]
+ """
+
+
+ kwargs = request_kwargs(
+ share_id=share_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ share_id: str,
+ *,
+ client: AuthenticatedClient | Client,
+
+) -> Error | SharePreview | None:
+ """ Preview what a deploy link deploys
+
+ Public: needs no credential, because the link id is the credential. Answers
+ the link's current release: when it was published, its digest, the functions
+ and frontends installing it creates, the variables the visitor supplies, and
+ the functions that receive the new project's service key. Show it to a
+ visitor before they confirm, and send its `release.id` when creating the
+ project.
+
+ Counts the visit for the link's owner, unless the request comes from a
+ crawler or link preview. A link that does not exist, was switched off, or has
+ not been published yet all answer the same `404`.
+
+ Args:
+ share_id (str):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | SharePreview
+ """
+
+
+ return (await asyncio_detailed(
+ share_id=share_id,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/shares/get_share_release_draft.py b/src/volcano_sdk/_generated/api/shares/get_share_release_draft.py
new file mode 100644
index 00000000..0f451153
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/shares/get_share_release_draft.py
@@ -0,0 +1,308 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.share_release_draft import ShareReleaseDraft
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ *,
+ share_id: str,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ params["share_id"] = share_id
+
+ json_project_id: str | Unset = UNSET
+ if not isinstance(project_id, Unset):
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/share-release-drafts",
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | ShareReleaseDraft | None:
+ if response.status_code == 200:
+ response_200 = ShareReleaseDraft.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 422:
+ response_422 = Error.from_dict(response.json())
+
+
+
+ return response_422
+
+ if response.status_code == 429:
+ response_429 = Error.from_dict(response.json())
+
+
+
+ return response_429
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if response.status_code == 503:
+ response_503 = Error.from_dict(response.json())
+
+
+
+ return response_503
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | ShareReleaseDraft]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ share_id: str,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Response[Error | ShareReleaseDraft]:
+ """ Show what publishing a deploy link would release
+
+ Builds the project's deployed functions and frontends the way a release
+ would, without storing anything, and reports what it would carry: the
+ functions and frontends, the project variables every project created from
+ the release gets (empty unless the visitor gives a value), the functions
+ whose code reads `VOLCANO_SERVICE_KEY`, and what is left out (resources with
+ no stored source, databases, sandboxes, dotenv and key files). Review it,
+ then publish with its `draft_id`, and its variables and service key
+ functions confirmed.
+
+ Every call runs a full build and counts against the account's hourly
+ release build budget, which drafts and publishes share. Fetch it when the
+ owner opens the publish step, not on every focus or poll.
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | ShareReleaseDraft]
+ """
+
+
+ kwargs = request_kwargs(
+ share_id=share_id,
+project_id=project_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ share_id: str,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Error | ShareReleaseDraft | None:
+ """ Show what publishing a deploy link would release
+
+ Builds the project's deployed functions and frontends the way a release
+ would, without storing anything, and reports what it would carry: the
+ functions and frontends, the project variables every project created from
+ the release gets (empty unless the visitor gives a value), the functions
+ whose code reads `VOLCANO_SERVICE_KEY`, and what is left out (resources with
+ no stored source, databases, sandboxes, dotenv and key files). Review it,
+ then publish with its `draft_id`, and its variables and service key
+ functions confirmed.
+
+ Every call runs a full build and counts against the account's hourly
+ release build budget, which drafts and publishes share. Fetch it when the
+ owner opens the publish step, not on every focus or poll.
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | ShareReleaseDraft
+ """
+
+
+ return sync_detailed(
+ client=client,
+share_id=share_id,
+project_id=project_id,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ share_id: str,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Response[Error | ShareReleaseDraft]:
+ """ Show what publishing a deploy link would release
+
+ Builds the project's deployed functions and frontends the way a release
+ would, without storing anything, and reports what it would carry: the
+ functions and frontends, the project variables every project created from
+ the release gets (empty unless the visitor gives a value), the functions
+ whose code reads `VOLCANO_SERVICE_KEY`, and what is left out (resources with
+ no stored source, databases, sandboxes, dotenv and key files). Review it,
+ then publish with its `draft_id`, and its variables and service key
+ functions confirmed.
+
+ Every call runs a full build and counts against the account's hourly
+ release build budget, which drafts and publishes share. Fetch it when the
+ owner opens the publish step, not on every focus or poll.
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | ShareReleaseDraft]
+ """
+
+
+ kwargs = request_kwargs(
+ share_id=share_id,
+project_id=project_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ share_id: str,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Error | ShareReleaseDraft | None:
+ """ Show what publishing a deploy link would release
+
+ Builds the project's deployed functions and frontends the way a release
+ would, without storing anything, and reports what it would carry: the
+ functions and frontends, the project variables every project created from
+ the release gets (empty unless the visitor gives a value), the functions
+ whose code reads `VOLCANO_SERVICE_KEY`, and what is left out (resources with
+ no stored source, databases, sandboxes, dotenv and key files). Review it,
+ then publish with its `draft_id`, and its variables and service key
+ functions confirmed.
+
+ Every call runs a full build and counts against the account's hourly
+ release build budget, which drafts and publishes share. Fetch it when the
+ owner opens the publish step, not on every focus or poll.
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | ShareReleaseDraft
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+share_id=share_id,
+project_id=project_id,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/shares/get_share_stats.py b/src/volcano_sdk/_generated/api/shares/get_share_stats.py
new file mode 100644
index 00000000..11ab1da4
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/shares/get_share_stats.py
@@ -0,0 +1,263 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.share_stats import ShareStats
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ *,
+ share_id: str,
+ project_id: UUID | str | Unset = UNSET,
+ days: int | Unset = 30,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ params["share_id"] = share_id
+
+ json_project_id: str | Unset = UNSET
+ if not isinstance(project_id, Unset):
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+ params["days"] = days
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/share-stats",
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | ShareStats | None:
+ if response.status_code == 200:
+ response_200 = ShareStats.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | ShareStats]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ share_id: str,
+ project_id: UUID | str | Unset = UNSET,
+ days: int | Unset = 30,
+
+) -> Response[Error | ShareStats]:
+ """ Get a deploy link's click and deploy counts
+
+ Counts what happened at the link: clicks, previews, confirmations, projects
+ created, and how many became ready or failed. Informational only. Visitors
+ are counted from a salted hash and no address is stored. Events are kept
+ for 90 days, so a `days` above 90 is rejected with `400`.
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+ days (int | Unset): Default: 30.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | ShareStats]
+ """
+
+
+ kwargs = request_kwargs(
+ share_id=share_id,
+project_id=project_id,
+days=days,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ share_id: str,
+ project_id: UUID | str | Unset = UNSET,
+ days: int | Unset = 30,
+
+) -> Error | ShareStats | None:
+ """ Get a deploy link's click and deploy counts
+
+ Counts what happened at the link: clicks, previews, confirmations, projects
+ created, and how many became ready or failed. Informational only. Visitors
+ are counted from a salted hash and no address is stored. Events are kept
+ for 90 days, so a `days` above 90 is rejected with `400`.
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+ days (int | Unset): Default: 30.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | ShareStats
+ """
+
+
+ return sync_detailed(
+ client=client,
+share_id=share_id,
+project_id=project_id,
+days=days,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ share_id: str,
+ project_id: UUID | str | Unset = UNSET,
+ days: int | Unset = 30,
+
+) -> Response[Error | ShareStats]:
+ """ Get a deploy link's click and deploy counts
+
+ Counts what happened at the link: clicks, previews, confirmations, projects
+ created, and how many became ready or failed. Informational only. Visitors
+ are counted from a salted hash and no address is stored. Events are kept
+ for 90 days, so a `days` above 90 is rejected with `400`.
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+ days (int | Unset): Default: 30.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | ShareStats]
+ """
+
+
+ kwargs = request_kwargs(
+ share_id=share_id,
+project_id=project_id,
+days=days,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ share_id: str,
+ project_id: UUID | str | Unset = UNSET,
+ days: int | Unset = 30,
+
+) -> Error | ShareStats | None:
+ """ Get a deploy link's click and deploy counts
+
+ Counts what happened at the link: clicks, previews, confirmations, projects
+ created, and how many became ready or failed. Informational only. Visitors
+ are counted from a salted hash and no address is stored. Events are kept
+ for 90 days, so a `days` above 90 is rejected with `400`.
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+ days (int | Unset): Default: 30.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | ShareStats
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+share_id=share_id,
+project_id=project_id,
+days=days,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/autofix/list_autofix_runs.py b/src/volcano_sdk/_generated/api/shares/list_share_releases.py
similarity index 50%
rename from src/volcano_sdk/_generated/api/autofix/list_autofix_runs.py
rename to src/volcano_sdk/_generated/api/shares/list_share_releases.py
index 0d90897a..0fbc4384 100644
--- a/src/volcano_sdk/_generated/api/autofix/list_autofix_runs.py
+++ b/src/volcano_sdk/_generated/api/shares/list_share_releases.py
@@ -8,10 +8,8 @@
from ...types import Response, UNSET
from ... import errors
-from ...models.autofix_run_status import AutofixRunStatus
-from ...models.autofix_run_status import check_autofix_run_status
from ...models.error import Error
-from ...models.paginated_autofix_runs import PaginatedAutofixRuns
+from ...models.paginated_share_releases import PaginatedShareReleases
from ...types import UNSET, Unset
from typing import cast
from uuid import UUID
@@ -19,12 +17,11 @@
def request_kwargs(
- id: UUID | str,
*,
+ share_id: str,
+ project_id: UUID | str | Unset = UNSET,
limit: int | Unset = 10,
cursor: str | Unset = UNSET,
- issue_id: UUID | str | Unset = UNSET,
- status: AutofixRunStatus | Unset = UNSET,
) -> dict[str, Any]:
@@ -33,20 +30,16 @@ def request_kwargs(
params: dict[str, Any] = {}
- params["limit"] = limit
-
- params["cursor"] = cursor
+ params["share_id"] = share_id
- json_issue_id: str | Unset = UNSET
- if not isinstance(issue_id, Unset):
- json_issue_id = str(issue_id)
- params["issue_id"] = json_issue_id
+ json_project_id: str | Unset = UNSET
+ if not isinstance(project_id, Unset):
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
- json_status: str | Unset = UNSET
- if not isinstance(status, Unset):
- json_status = status
+ params["limit"] = limit
- params["status"] = json_status
+ params["cursor"] = cursor
params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
@@ -54,7 +47,7 @@ def request_kwargs(
_kwargs: dict[str, Any] = {
"method": "get",
- "url": "/projects/{id}/autofix-runs".format(id=quote(str(id), safe=""),),
+ "url": "/share-releases",
"params": params,
}
@@ -63,9 +56,9 @@ def request_kwargs(
-def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | PaginatedAutofixRuns | None:
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | PaginatedShareReleases | None:
if response.status_code == 200:
- response_200 = PaginatedAutofixRuns.from_dict(response.json())
+ response_200 = PaginatedShareReleases.from_dict(response.json())
@@ -78,6 +71,13 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return response_400
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
if response.status_code == 404:
response_404 = Error.from_dict(response.json())
@@ -85,12 +85,12 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return response_404
- if response.status_code == 501:
- response_501 = Error.from_dict(response.json())
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
- return response_501
+ return response_500
if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
@@ -98,7 +98,7 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return None
-def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | PaginatedAutofixRuns]:
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | PaginatedShareReleases]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
@@ -108,45 +108,39 @@ def build_response(*, client: AuthenticatedClient | Client, response: httpx.Resp
def sync_detailed(
- id: UUID | str,
*,
client: AuthenticatedClient,
+ share_id: str,
+ project_id: UUID | str | Unset = UNSET,
limit: int | Unset = 10,
cursor: str | Unset = UNSET,
- issue_id: UUID | str | Unset = UNSET,
- status: AutofixRunStatus | Unset = UNSET,
-
-) -> Response[Error | PaginatedAutofixRuns]:
- """ List autofix runs
- Lists the project's autofix runs, newest first. Runs stay readable after
- autofix is turned off, and where autofix is not available.
+) -> Response[Error | PaginatedShareReleases]:
+ """ List a deploy link's releases
- Project access tokens can list runs, including read-only ones.
+ Pages the link's releases, newest first. Follow `next_cursor` while
+ `has_more` is true.
Args:
- id (UUID):
+ share_id (str):
+ project_id (UUID | Unset):
limit (int | Unset): Default: 10.
cursor (str | Unset):
- issue_id (UUID | Unset):
- status (AutofixRunStatus | Unset): Where a run is. `canceled` means the project's settings
- or plan stopped allowing the run before it finished; `failure_code` says which.
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[Error | PaginatedAutofixRuns]
+ Response[Error | PaginatedShareReleases]
"""
kwargs = request_kwargs(
- id=id,
+ share_id=share_id,
+project_id=project_id,
limit=limit,
cursor=cursor,
-issue_id=issue_id,
-status=status,
)
@@ -157,89 +151,77 @@ def sync_detailed(
return build_response(client=client, response=response)
def sync(
- id: UUID | str,
*,
client: AuthenticatedClient,
+ share_id: str,
+ project_id: UUID | str | Unset = UNSET,
limit: int | Unset = 10,
cursor: str | Unset = UNSET,
- issue_id: UUID | str | Unset = UNSET,
- status: AutofixRunStatus | Unset = UNSET,
-) -> Error | PaginatedAutofixRuns | None:
- """ List autofix runs
+) -> Error | PaginatedShareReleases | None:
+ """ List a deploy link's releases
- Lists the project's autofix runs, newest first. Runs stay readable after
- autofix is turned off, and where autofix is not available.
-
- Project access tokens can list runs, including read-only ones.
+ Pages the link's releases, newest first. Follow `next_cursor` while
+ `has_more` is true.
Args:
- id (UUID):
+ share_id (str):
+ project_id (UUID | Unset):
limit (int | Unset): Default: 10.
cursor (str | Unset):
- issue_id (UUID | Unset):
- status (AutofixRunStatus | Unset): Where a run is. `canceled` means the project's settings
- or plan stopped allowing the run before it finished; `failure_code` says which.
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Error | PaginatedAutofixRuns
+ Error | PaginatedShareReleases
"""
return sync_detailed(
- id=id,
-client=client,
+ client=client,
+share_id=share_id,
+project_id=project_id,
limit=limit,
cursor=cursor,
-issue_id=issue_id,
-status=status,
).parsed
async def asyncio_detailed(
- id: UUID | str,
*,
client: AuthenticatedClient,
+ share_id: str,
+ project_id: UUID | str | Unset = UNSET,
limit: int | Unset = 10,
cursor: str | Unset = UNSET,
- issue_id: UUID | str | Unset = UNSET,
- status: AutofixRunStatus | Unset = UNSET,
-
-) -> Response[Error | PaginatedAutofixRuns]:
- """ List autofix runs
- Lists the project's autofix runs, newest first. Runs stay readable after
- autofix is turned off, and where autofix is not available.
+) -> Response[Error | PaginatedShareReleases]:
+ """ List a deploy link's releases
- Project access tokens can list runs, including read-only ones.
+ Pages the link's releases, newest first. Follow `next_cursor` while
+ `has_more` is true.
Args:
- id (UUID):
+ share_id (str):
+ project_id (UUID | Unset):
limit (int | Unset): Default: 10.
cursor (str | Unset):
- issue_id (UUID | Unset):
- status (AutofixRunStatus | Unset): Where a run is. `canceled` means the project's settings
- or plan stopped allowing the run before it finished; `failure_code` says which.
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Response[Error | PaginatedAutofixRuns]
+ Response[Error | PaginatedShareReleases]
"""
kwargs = request_kwargs(
- id=id,
+ share_id=share_id,
+project_id=project_id,
limit=limit,
cursor=cursor,
-issue_id=issue_id,
-status=status,
)
@@ -250,45 +232,39 @@ async def asyncio_detailed(
return build_response(client=client, response=response)
async def asyncio(
- id: UUID | str,
*,
client: AuthenticatedClient,
+ share_id: str,
+ project_id: UUID | str | Unset = UNSET,
limit: int | Unset = 10,
cursor: str | Unset = UNSET,
- issue_id: UUID | str | Unset = UNSET,
- status: AutofixRunStatus | Unset = UNSET,
-
-) -> Error | PaginatedAutofixRuns | None:
- """ List autofix runs
- Lists the project's autofix runs, newest first. Runs stay readable after
- autofix is turned off, and where autofix is not available.
+) -> Error | PaginatedShareReleases | None:
+ """ List a deploy link's releases
- Project access tokens can list runs, including read-only ones.
+ Pages the link's releases, newest first. Follow `next_cursor` while
+ `has_more` is true.
Args:
- id (UUID):
+ share_id (str):
+ project_id (UUID | Unset):
limit (int | Unset): Default: 10.
cursor (str | Unset):
- issue_id (UUID | Unset):
- status (AutofixRunStatus | Unset): Where a run is. `canceled` means the project's settings
- or plan stopped allowing the run before it finished; `failure_code` says which.
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
- Error | PaginatedAutofixRuns
+ Error | PaginatedShareReleases
"""
return (await asyncio_detailed(
- id=id,
-client=client,
+ client=client,
+share_id=share_id,
+project_id=project_id,
limit=limit,
cursor=cursor,
-issue_id=issue_id,
-status=status,
)).parsed
diff --git a/src/volcano_sdk/_generated/api/shares/list_shares.py b/src/volcano_sdk/_generated/api/shares/list_shares.py
new file mode 100644
index 00000000..2f2a74d4
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/shares/list_shares.py
@@ -0,0 +1,230 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.shares_response import SharesResponse
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ *,
+ project_id: UUID | str,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/shares",
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | SharesResponse | None:
+ if response.status_code == 200:
+ response_200 = SharesResponse.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | SharesResponse]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+
+) -> Response[Error | SharesResponse]:
+ """ List a project's deploy links
+
+ Deploy links let anyone deploy a release the project's owner published as
+ their own new project. A link's public address is
+ `https://volcano.dev/deploy/`; the address carries no release, so it
+ cannot be edited to point at other code.
+
+ Args:
+ project_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | SharesResponse]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+
+) -> Error | SharesResponse | None:
+ """ List a project's deploy links
+
+ Deploy links let anyone deploy a release the project's owner published as
+ their own new project. A link's public address is
+ `https://volcano.dev/deploy/`; the address carries no release, so it
+ cannot be edited to point at other code.
+
+ Args:
+ project_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | SharesResponse
+ """
+
+
+ return sync_detailed(
+ client=client,
+project_id=project_id,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+
+) -> Response[Error | SharesResponse]:
+ """ List a project's deploy links
+
+ Deploy links let anyone deploy a release the project's owner published as
+ their own new project. A link's public address is
+ `https://volcano.dev/deploy/`; the address carries no release, so it
+ cannot be edited to point at other code.
+
+ Args:
+ project_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | SharesResponse]
+ """
+
+
+ kwargs = request_kwargs(
+ project_id=project_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ project_id: UUID | str,
+
+) -> Error | SharesResponse | None:
+ """ List a project's deploy links
+
+ Deploy links let anyone deploy a release the project's owner published as
+ their own new project. A link's public address is
+ `https://volcano.dev/deploy/`; the address carries no release, so it
+ cannot be edited to point at other code.
+
+ Args:
+ project_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | SharesResponse
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+project_id=project_id,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/shares/publish_share_release.py b/src/volcano_sdk/_generated/api/shares/publish_share_release.py
new file mode 100644
index 00000000..777b20c9
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/shares/publish_share_release.py
@@ -0,0 +1,311 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.share_draft_changed_error import ShareDraftChangedError
+from ...models.share_release import ShareRelease
+from ...models.share_release_create_request import ShareReleaseCreateRequest
+from typing import cast
+
+
+
+def request_kwargs(
+ *,
+ body: ShareReleaseCreateRequest,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/share-releases",
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | ShareDraftChangedError | ShareRelease | None:
+ if response.status_code == 201:
+ response_201 = ShareRelease.from_dict(response.json())
+
+
+
+ return response_201
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 409:
+ response_409 = ShareDraftChangedError.from_dict(response.json())
+
+
+
+ return response_409
+
+ if response.status_code == 422:
+ response_422 = Error.from_dict(response.json())
+
+
+
+ return response_422
+
+ if response.status_code == 429:
+ response_429 = Error.from_dict(response.json())
+
+
+
+ return response_429
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if response.status_code == 503:
+ response_503 = Error.from_dict(response.json())
+
+
+
+ return response_503
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | ShareDraftChangedError | ShareRelease]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: ShareReleaseCreateRequest,
+
+) -> Response[Error | ShareDraftChangedError | ShareRelease]:
+ """ Publish a deploy link release
+
+ Snapshots the project's deployed functions and frontends into an immutable
+ release and makes it the link's current release in one step, so visitors see
+ either the previous release or this one. Visitors install exactly the stored
+ release; later deploys to the project change nothing until the owner
+ publishes again.
+
+ Send the reviewed draft's `draft_id`, its variables and the functions that
+ receive the new project's `VOLCANO_SERVICE_KEY`, as confirmed from the
+ draft. Both lists must be exactly the draft's: a release carries every
+ variable, since leaving one out would only break the code that reads it. If
+ a fresh build is not the reviewed draft, because the project was redeployed
+ or changed since, or the lists differ from it, nothing is published and the
+ answer is `409` with code `draft_changed` and the new draft. A
+ release carries variable names, never values, and no database. A publish is
+ a full build and counts against the account's hourly release build budget,
+ which it shares with the draft.
+
+ Args:
+ body (ShareReleaseCreateRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | ShareDraftChangedError | ShareRelease]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ body: ShareReleaseCreateRequest,
+
+) -> Error | ShareDraftChangedError | ShareRelease | None:
+ """ Publish a deploy link release
+
+ Snapshots the project's deployed functions and frontends into an immutable
+ release and makes it the link's current release in one step, so visitors see
+ either the previous release or this one. Visitors install exactly the stored
+ release; later deploys to the project change nothing until the owner
+ publishes again.
+
+ Send the reviewed draft's `draft_id`, its variables and the functions that
+ receive the new project's `VOLCANO_SERVICE_KEY`, as confirmed from the
+ draft. Both lists must be exactly the draft's: a release carries every
+ variable, since leaving one out would only break the code that reads it. If
+ a fresh build is not the reviewed draft, because the project was redeployed
+ or changed since, or the lists differ from it, nothing is published and the
+ answer is `409` with code `draft_changed` and the new draft. A
+ release carries variable names, never values, and no database. A publish is
+ a full build and counts against the account's hourly release build budget,
+ which it shares with the draft.
+
+ Args:
+ body (ShareReleaseCreateRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | ShareDraftChangedError | ShareRelease
+ """
+
+
+ return sync_detailed(
+ client=client,
+body=body,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ body: ShareReleaseCreateRequest,
+
+) -> Response[Error | ShareDraftChangedError | ShareRelease]:
+ """ Publish a deploy link release
+
+ Snapshots the project's deployed functions and frontends into an immutable
+ release and makes it the link's current release in one step, so visitors see
+ either the previous release or this one. Visitors install exactly the stored
+ release; later deploys to the project change nothing until the owner
+ publishes again.
+
+ Send the reviewed draft's `draft_id`, its variables and the functions that
+ receive the new project's `VOLCANO_SERVICE_KEY`, as confirmed from the
+ draft. Both lists must be exactly the draft's: a release carries every
+ variable, since leaving one out would only break the code that reads it. If
+ a fresh build is not the reviewed draft, because the project was redeployed
+ or changed since, or the lists differ from it, nothing is published and the
+ answer is `409` with code `draft_changed` and the new draft. A
+ release carries variable names, never values, and no database. A publish is
+ a full build and counts against the account's hourly release build budget,
+ which it shares with the draft.
+
+ Args:
+ body (ShareReleaseCreateRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | ShareDraftChangedError | ShareRelease]
+ """
+
+
+ kwargs = request_kwargs(
+ body=body,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ body: ShareReleaseCreateRequest,
+
+) -> Error | ShareDraftChangedError | ShareRelease | None:
+ """ Publish a deploy link release
+
+ Snapshots the project's deployed functions and frontends into an immutable
+ release and makes it the link's current release in one step, so visitors see
+ either the previous release or this one. Visitors install exactly the stored
+ release; later deploys to the project change nothing until the owner
+ publishes again.
+
+ Send the reviewed draft's `draft_id`, its variables and the functions that
+ receive the new project's `VOLCANO_SERVICE_KEY`, as confirmed from the
+ draft. Both lists must be exactly the draft's: a release carries every
+ variable, since leaving one out would only break the code that reads it. If
+ a fresh build is not the reviewed draft, because the project was redeployed
+ or changed since, or the lists differ from it, nothing is published and the
+ answer is `409` with code `draft_changed` and the new draft. A
+ release carries variable names, never values, and no database. A publish is
+ a full build and counts against the account's hourly release build budget,
+ which it shares with the draft.
+
+ Args:
+ body (ShareReleaseCreateRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | ShareDraftChangedError | ShareRelease
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+body=body,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/shares/update_share.py b/src/volcano_sdk/_generated/api/shares/update_share.py
new file mode 100644
index 00000000..8cd3010b
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/shares/update_share.py
@@ -0,0 +1,372 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.share import Share
+from ...models.share_update_request import ShareUpdateRequest
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ share_id: str,
+ *,
+ body: ShareUpdateRequest,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> dict[str, Any]:
+ headers: dict[str, Any] = {}
+
+
+
+
+ params: dict[str, Any] = {}
+
+ json_project_id: str | Unset = UNSET
+ if not isinstance(project_id, Unset):
+ json_project_id = str(project_id)
+ params["project_id"] = json_project_id
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "patch",
+ "url": "/shares/{share_id}".format(share_id=quote(str(share_id), safe=""),),
+ "params": params,
+ }
+
+ _kwargs["json"] = body.to_dict()
+
+ headers["Content-Type"] = "application/json"
+
+ _kwargs["headers"] = headers
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | Share | None:
+ if response.status_code == 200:
+ response_200 = Share.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 403:
+ response_403 = Error.from_dict(response.json())
+
+
+
+ return response_403
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 500:
+ response_500 = Error.from_dict(response.json())
+
+
+
+ return response_500
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | Share]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ share_id: str,
+ *,
+ client: AuthenticatedClient,
+ body: ShareUpdateRequest,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Response[Error | Share]:
+ """ Edit or switch a deploy link on or off
+
+ Changes the suggested name, the status, or both. An owner can always switch a
+ link off: it works even while deploy links are not available in this
+ environment, and while the owner's account is read-only. Setting
+ `allow_reshare` to false also works in both cases, alone or with a
+ switch-off, since like a switch-off it only shares less; for a read-only
+ account these are the only changes allowed. While deploy links are not
+ available, a request that sends back the values the link already has,
+ including `status` `active` on an active link, changes nothing and answers
+ `200`.
+
+ Switching a link off also stops the installs it started that have not
+ finished, including ones still queued: each fails at its next step. The
+ visitor keeps the project, with its installation failed. Switching the link
+ back on lets only installs that have not failed yet go ahead.
+
+ A link Volcano took down (`disabled_reason` `operator`) cannot be switched
+ back on; other edits still work, and it stays down. While any of the
+ project's links is taken down, no link of the project can be switched on or
+ allowed to be re-shared.
+
+ A request that switches the link off together with an edit while deploy links
+ are not available, or that also allows re-sharing on a copy whose source does
+ not allow it, still switches the link off, but answers `400` with code
+ `edit_dropped`: the link is off and the edit was not applied. While the
+ account is read-only, a request that switches the link off or sets
+ `allow_reshare` to false together with another edit is answered the same way:
+ the switch-off and the re-sharing change are saved, and the other edit is not.
+ A `status` the link already has is no edit, so sending the fetched link back
+ with `allow_reshare` false answers `200`; a switch-on is such another edit.
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+ body (ShareUpdateRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | Share]
+ """
+
+
+ kwargs = request_kwargs(
+ share_id=share_id,
+body=body,
+project_id=project_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ share_id: str,
+ *,
+ client: AuthenticatedClient,
+ body: ShareUpdateRequest,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Error | Share | None:
+ """ Edit or switch a deploy link on or off
+
+ Changes the suggested name, the status, or both. An owner can always switch a
+ link off: it works even while deploy links are not available in this
+ environment, and while the owner's account is read-only. Setting
+ `allow_reshare` to false also works in both cases, alone or with a
+ switch-off, since like a switch-off it only shares less; for a read-only
+ account these are the only changes allowed. While deploy links are not
+ available, a request that sends back the values the link already has,
+ including `status` `active` on an active link, changes nothing and answers
+ `200`.
+
+ Switching a link off also stops the installs it started that have not
+ finished, including ones still queued: each fails at its next step. The
+ visitor keeps the project, with its installation failed. Switching the link
+ back on lets only installs that have not failed yet go ahead.
+
+ A link Volcano took down (`disabled_reason` `operator`) cannot be switched
+ back on; other edits still work, and it stays down. While any of the
+ project's links is taken down, no link of the project can be switched on or
+ allowed to be re-shared.
+
+ A request that switches the link off together with an edit while deploy links
+ are not available, or that also allows re-sharing on a copy whose source does
+ not allow it, still switches the link off, but answers `400` with code
+ `edit_dropped`: the link is off and the edit was not applied. While the
+ account is read-only, a request that switches the link off or sets
+ `allow_reshare` to false together with another edit is answered the same way:
+ the switch-off and the re-sharing change are saved, and the other edit is not.
+ A `status` the link already has is no edit, so sending the fetched link back
+ with `allow_reshare` false answers `200`; a switch-on is such another edit.
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+ body (ShareUpdateRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | Share
+ """
+
+
+ return sync_detailed(
+ share_id=share_id,
+client=client,
+body=body,
+project_id=project_id,
+
+ ).parsed
+
+async def asyncio_detailed(
+ share_id: str,
+ *,
+ client: AuthenticatedClient,
+ body: ShareUpdateRequest,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Response[Error | Share]:
+ """ Edit or switch a deploy link on or off
+
+ Changes the suggested name, the status, or both. An owner can always switch a
+ link off: it works even while deploy links are not available in this
+ environment, and while the owner's account is read-only. Setting
+ `allow_reshare` to false also works in both cases, alone or with a
+ switch-off, since like a switch-off it only shares less; for a read-only
+ account these are the only changes allowed. While deploy links are not
+ available, a request that sends back the values the link already has,
+ including `status` `active` on an active link, changes nothing and answers
+ `200`.
+
+ Switching a link off also stops the installs it started that have not
+ finished, including ones still queued: each fails at its next step. The
+ visitor keeps the project, with its installation failed. Switching the link
+ back on lets only installs that have not failed yet go ahead.
+
+ A link Volcano took down (`disabled_reason` `operator`) cannot be switched
+ back on; other edits still work, and it stays down. While any of the
+ project's links is taken down, no link of the project can be switched on or
+ allowed to be re-shared.
+
+ A request that switches the link off together with an edit while deploy links
+ are not available, or that also allows re-sharing on a copy whose source does
+ not allow it, still switches the link off, but answers `400` with code
+ `edit_dropped`: the link is off and the edit was not applied. While the
+ account is read-only, a request that switches the link off or sets
+ `allow_reshare` to false together with another edit is answered the same way:
+ the switch-off and the re-sharing change are saved, and the other edit is not.
+ A `status` the link already has is no edit, so sending the fetched link back
+ with `allow_reshare` false answers `200`; a switch-on is such another edit.
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+ body (ShareUpdateRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | Share]
+ """
+
+
+ kwargs = request_kwargs(
+ share_id=share_id,
+body=body,
+project_id=project_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ share_id: str,
+ *,
+ client: AuthenticatedClient,
+ body: ShareUpdateRequest,
+ project_id: UUID | str | Unset = UNSET,
+
+) -> Error | Share | None:
+ """ Edit or switch a deploy link on or off
+
+ Changes the suggested name, the status, or both. An owner can always switch a
+ link off: it works even while deploy links are not available in this
+ environment, and while the owner's account is read-only. Setting
+ `allow_reshare` to false also works in both cases, alone or with a
+ switch-off, since like a switch-off it only shares less; for a read-only
+ account these are the only changes allowed. While deploy links are not
+ available, a request that sends back the values the link already has,
+ including `status` `active` on an active link, changes nothing and answers
+ `200`.
+
+ Switching a link off also stops the installs it started that have not
+ finished, including ones still queued: each fails at its next step. The
+ visitor keeps the project, with its installation failed. Switching the link
+ back on lets only installs that have not failed yet go ahead.
+
+ A link Volcano took down (`disabled_reason` `operator`) cannot be switched
+ back on; other edits still work, and it stays down. While any of the
+ project's links is taken down, no link of the project can be switched on or
+ allowed to be re-shared.
+
+ A request that switches the link off together with an edit while deploy links
+ are not available, or that also allows re-sharing on a copy whose source does
+ not allow it, still switches the link off, but answers `400` with code
+ `edit_dropped`: the link is off and the edit was not applied. While the
+ account is read-only, a request that switches the link off or sets
+ `allow_reshare` to false together with another edit is answered the same way:
+ the switch-off and the re-sharing change are saved, and the other edit is not.
+ A `status` the link already has is no edit, so sending the fetched link back
+ with `allow_reshare` false answers `200`; a switch-on is such another edit.
+
+ Args:
+ share_id (str):
+ project_id (UUID | Unset):
+ body (ShareUpdateRequest):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | Share
+ """
+
+
+ return (await asyncio_detailed(
+ share_id=share_id,
+client=client,
+body=body,
+project_id=project_id,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/slack_connections/__init__.py b/src/volcano_sdk/_generated/api/slack_connections/__init__.py
new file mode 100644
index 00000000..c9921b5f
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/slack_connections/__init__.py
@@ -0,0 +1 @@
+""" Contains endpoint functions for accessing the API """
diff --git a/src/volcano_sdk/_generated/api/slack_connections/delete_slack_connection.py b/src/volcano_sdk/_generated/api/slack_connections/delete_slack_connection.py
new file mode 100644
index 00000000..f28ed9b2
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/slack_connections/delete_slack_connection.py
@@ -0,0 +1,210 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from typing import cast
+from uuid import UUID
+
+
+
+def request_kwargs(
+ connection_id: UUID | str,
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "delete",
+ "url": "/user/slack/connections/{connection_id}".format(connection_id=quote(str(connection_id), safe=""),),
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | Error | None:
+ if response.status_code == 204:
+ response_204 = cast(Any, None)
+ return response_204
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ connection_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Any | Error]:
+ """ Disconnect a Slack identity
+
+ Disconnects one Slack identity from the caller's account. LavaFlow
+ stops acting on its mentions for the account's projects at its next
+ check, which also cancels reports still queued. It works whether or not
+ reporting problems from Slack is available in this environment.
+
+ Args:
+ connection_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ connection_id=connection_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ connection_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Any | Error | None:
+ """ Disconnect a Slack identity
+
+ Disconnects one Slack identity from the caller's account. LavaFlow
+ stops acting on its mentions for the account's projects at its next
+ check, which also cancels reports still queued. It works whether or not
+ reporting problems from Slack is available in this environment.
+
+ Args:
+ connection_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return sync_detailed(
+ connection_id=connection_id,
+client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ connection_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Any | Error]:
+ """ Disconnect a Slack identity
+
+ Disconnects one Slack identity from the caller's account. LavaFlow
+ stops acting on its mentions for the account's projects at its next
+ check, which also cancels reports still queued. It works whether or not
+ reporting problems from Slack is available in this environment.
+
+ Args:
+ connection_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ connection_id=connection_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ connection_id: UUID | str,
+ *,
+ client: AuthenticatedClient,
+
+) -> Any | Error | None:
+ """ Disconnect a Slack identity
+
+ Disconnects one Slack identity from the caller's account. LavaFlow
+ stops acting on its mentions for the account's projects at its next
+ check, which also cancels reports still queued. It works whether or not
+ reporting problems from Slack is available in this environment.
+
+ Args:
+ connection_id (UUID):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return (await asyncio_detailed(
+ connection_id=connection_id,
+client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/slack_connections/list_slack_channels.py b/src/volcano_sdk/_generated/api/slack_connections/list_slack_channels.py
new file mode 100644
index 00000000..f1b5138c
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/slack_connections/list_slack_channels.py
@@ -0,0 +1,232 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.slack_channels_response import SlackChannelsResponse
+from typing import cast
+
+
+
+def request_kwargs(
+ *,
+ team_id: str,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ params["team_id"] = team_id
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/user/slack/channels",
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | SlackChannelsResponse | None:
+ if response.status_code == 200:
+ response_200 = SlackChannelsResponse.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 502:
+ response_502 = Error.from_dict(response.json())
+
+
+
+ return response_502
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | SlackChannelsResponse]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ team_id: str,
+
+) -> Response[Error | SlackChannelsResponse]:
+ """ List a workspace's channels for binding
+
+ Lists the channels in a workspace, public and private, that the Volcano
+ app and one of the Slack identities the caller's sign-in session signed
+ in as are both in, to choose which ones report problems to LavaFlow.
+ Invite the app to a channel in Slack to list it. Slack Connect, shared
+ and archived channels are left out.
+
+ Args:
+ team_id (str): A Slack workspace ID, such as `T0123ABCD`.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | SlackChannelsResponse]
+ """
+
+
+ kwargs = request_kwargs(
+ team_id=team_id,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ team_id: str,
+
+) -> Error | SlackChannelsResponse | None:
+ """ List a workspace's channels for binding
+
+ Lists the channels in a workspace, public and private, that the Volcano
+ app and one of the Slack identities the caller's sign-in session signed
+ in as are both in, to choose which ones report problems to LavaFlow.
+ Invite the app to a channel in Slack to list it. Slack Connect, shared
+ and archived channels are left out.
+
+ Args:
+ team_id (str): A Slack workspace ID, such as `T0123ABCD`.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | SlackChannelsResponse
+ """
+
+
+ return sync_detailed(
+ client=client,
+team_id=team_id,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ team_id: str,
+
+) -> Response[Error | SlackChannelsResponse]:
+ """ List a workspace's channels for binding
+
+ Lists the channels in a workspace, public and private, that the Volcano
+ app and one of the Slack identities the caller's sign-in session signed
+ in as are both in, to choose which ones report problems to LavaFlow.
+ Invite the app to a channel in Slack to list it. Slack Connect, shared
+ and archived channels are left out.
+
+ Args:
+ team_id (str): A Slack workspace ID, such as `T0123ABCD`.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | SlackChannelsResponse]
+ """
+
+
+ kwargs = request_kwargs(
+ team_id=team_id,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ team_id: str,
+
+) -> Error | SlackChannelsResponse | None:
+ """ List a workspace's channels for binding
+
+ Lists the channels in a workspace, public and private, that the Volcano
+ app and one of the Slack identities the caller's sign-in session signed
+ in as are both in, to choose which ones report problems to LavaFlow.
+ Invite the app to a channel in Slack to list it. Slack Connect, shared
+ and archived channels are left out.
+
+ Args:
+ team_id (str): A Slack workspace ID, such as `T0123ABCD`.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | SlackChannelsResponse
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+team_id=team_id,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/slack_connections/list_slack_connections.py b/src/volcano_sdk/_generated/api/slack_connections/list_slack_connections.py
new file mode 100644
index 00000000..e142164f
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/slack_connections/list_slack_connections.py
@@ -0,0 +1,174 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.slack_connections_response import SlackConnectionsResponse
+from typing import cast
+
+
+
+def request_kwargs(
+
+) -> dict[str, Any]:
+
+
+
+
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/user/slack/connections",
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | SlackConnectionsResponse | None:
+ if response.status_code == 200:
+ response_200 = SlackConnectionsResponse.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | SlackConnectionsResponse]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Error | SlackConnectionsResponse]:
+ """ List connected Slack identities
+
+ Lists the caller's connected Slack identities. It answers whether or
+ not reporting problems from Slack is available in this environment, so
+ turning it off strands no connection.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | SlackConnectionsResponse]
+ """
+
+
+ kwargs = request_kwargs(
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+
+) -> Error | SlackConnectionsResponse | None:
+ """ List connected Slack identities
+
+ Lists the caller's connected Slack identities. It answers whether or
+ not reporting problems from Slack is available in this environment, so
+ turning it off strands no connection.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | SlackConnectionsResponse
+ """
+
+
+ return sync_detailed(
+ client=client,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+
+) -> Response[Error | SlackConnectionsResponse]:
+ """ List connected Slack identities
+
+ Lists the caller's connected Slack identities. It answers whether or
+ not reporting problems from Slack is available in this environment, so
+ turning it off strands no connection.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | SlackConnectionsResponse]
+ """
+
+
+ kwargs = request_kwargs(
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+
+) -> Error | SlackConnectionsResponse | None:
+ """ List connected Slack identities
+
+ Lists the caller's connected Slack identities. It answers whether or
+ not reporting problems from Slack is available in this environment, so
+ turning it off strands no connection.
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | SlackConnectionsResponse
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/slack_connections/slack_callback.py b/src/volcano_sdk/_generated/api/slack_connections/slack_callback.py
new file mode 100644
index 00000000..4b25cfd3
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/slack_connections/slack_callback.py
@@ -0,0 +1,252 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...types import UNSET, Unset
+from typing import cast
+
+
+
+def request_kwargs(
+ *,
+ code: str | Unset = UNSET,
+ state: str,
+ error: str | Unset = UNSET,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ params["code"] = code
+
+ params["state"] = state
+
+ params["error"] = error
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/slack/callback",
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | Error | None:
+ if response.status_code == 303:
+ response_303 = cast(Any, None)
+ return response_303
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if response.status_code == 429:
+ response_429 = Error.from_dict(response.json())
+
+
+
+ return response_429
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | Error]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient | Client,
+ code: str | Unset = UNSET,
+ state: str,
+ error: str | Unset = UNSET,
+
+) -> Response[Any | Error]:
+ """ Complete a Slack install or connection
+
+ Public callback Slack sends the browser to after Add to Slack or Sign
+ in with Slack. The signed `state` names the flow and the Volcano user
+ who started it, and the callback cookie binds it to the browser that
+ started it. Redirects to the flow's `redirect`, or to the dashboard,
+ adding `slack_connect_error=1` when the flow failed.
+
+ Args:
+ code (str | Unset):
+ state (str):
+ error (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ code=code,
+state=state,
+error=error,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient | Client,
+ code: str | Unset = UNSET,
+ state: str,
+ error: str | Unset = UNSET,
+
+) -> Any | Error | None:
+ """ Complete a Slack install or connection
+
+ Public callback Slack sends the browser to after Add to Slack or Sign
+ in with Slack. The signed `state` names the flow and the Volcano user
+ who started it, and the callback cookie binds it to the browser that
+ started it. Redirects to the flow's `redirect`, or to the dashboard,
+ adding `slack_connect_error=1` when the flow failed.
+
+ Args:
+ code (str | Unset):
+ state (str):
+ error (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return sync_detailed(
+ client=client,
+code=code,
+state=state,
+error=error,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient | Client,
+ code: str | Unset = UNSET,
+ state: str,
+ error: str | Unset = UNSET,
+
+) -> Response[Any | Error]:
+ """ Complete a Slack install or connection
+
+ Public callback Slack sends the browser to after Add to Slack or Sign
+ in with Slack. The signed `state` names the flow and the Volcano user
+ who started it, and the callback cookie binds it to the browser that
+ started it. Redirects to the flow's `redirect`, or to the dashboard,
+ adding `slack_connect_error=1` when the flow failed.
+
+ Args:
+ code (str | Unset):
+ state (str):
+ error (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Any | Error]
+ """
+
+
+ kwargs = request_kwargs(
+ code=code,
+state=state,
+error=error,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient | Client,
+ code: str | Unset = UNSET,
+ state: str,
+ error: str | Unset = UNSET,
+
+) -> Any | Error | None:
+ """ Complete a Slack install or connection
+
+ Public callback Slack sends the browser to after Add to Slack or Sign
+ in with Slack. The signed `state` names the flow and the Volcano user
+ who started it, and the callback cookie binds it to the browser that
+ started it. Redirects to the flow's `redirect`, or to the dashboard,
+ adding `slack_connect_error=1` when the flow failed.
+
+ Args:
+ code (str | Unset):
+ state (str):
+ error (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Any | Error
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+code=code,
+state=state,
+error=error,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/slack_connections/start_slack_connect.py b/src/volcano_sdk/_generated/api/slack_connections/start_slack_connect.py
new file mode 100644
index 00000000..4348bd6c
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/slack_connections/start_slack_connect.py
@@ -0,0 +1,274 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.slack_authorization_response import SlackAuthorizationResponse
+from ...types import UNSET, Unset
+from typing import cast
+
+
+
+def request_kwargs(
+ *,
+ redirect: str | Unset = UNSET,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ params["redirect"] = redirect
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/user/slack/connections",
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | SlackAuthorizationResponse | None:
+ if response.status_code == 200:
+ response_200 = SlackAuthorizationResponse.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | SlackAuthorizationResponse]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ redirect: str | Unset = UNSET,
+
+) -> Response[Error | SlackAuthorizationResponse]:
+ """ Start connecting a Slack identity
+
+ Starts connecting the caller's Slack identity to their Volcano account
+ and returns its Sign in with Slack URL. LavaFlow acts on a person's
+ Slack mention only for projects owned by an account their identity is
+ connected to. The callback finishes only in the browser that started
+ the connection, so a link forwarded to anyone else connects no one.
+ One Slack identity may connect to several accounts, and one account may
+ have several identities connected. The identity is also tied to the
+ caller's sign-in session: the channel picker and binding act only as
+ the identities this session signed in as, so on an account several
+ people share, nobody picks or binds as another person's identity. An
+ API token has no session, so it can connect an identity that reports,
+ but not pick or bind channels with it. Volcano stores the workspace and
+ user IDs, and no Slack token.
+
+ The response also sets a short-lived HttpOnly cookie that binds the
+ callback to this browser. Installing and connecting each set their
+ own, so starting one leaves the other's callback working.
+
+ Args:
+ redirect (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | SlackAuthorizationResponse]
+ """
+
+
+ kwargs = request_kwargs(
+ redirect=redirect,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ redirect: str | Unset = UNSET,
+
+) -> Error | SlackAuthorizationResponse | None:
+ """ Start connecting a Slack identity
+
+ Starts connecting the caller's Slack identity to their Volcano account
+ and returns its Sign in with Slack URL. LavaFlow acts on a person's
+ Slack mention only for projects owned by an account their identity is
+ connected to. The callback finishes only in the browser that started
+ the connection, so a link forwarded to anyone else connects no one.
+ One Slack identity may connect to several accounts, and one account may
+ have several identities connected. The identity is also tied to the
+ caller's sign-in session: the channel picker and binding act only as
+ the identities this session signed in as, so on an account several
+ people share, nobody picks or binds as another person's identity. An
+ API token has no session, so it can connect an identity that reports,
+ but not pick or bind channels with it. Volcano stores the workspace and
+ user IDs, and no Slack token.
+
+ The response also sets a short-lived HttpOnly cookie that binds the
+ callback to this browser. Installing and connecting each set their
+ own, so starting one leaves the other's callback working.
+
+ Args:
+ redirect (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | SlackAuthorizationResponse
+ """
+
+
+ return sync_detailed(
+ client=client,
+redirect=redirect,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ redirect: str | Unset = UNSET,
+
+) -> Response[Error | SlackAuthorizationResponse]:
+ """ Start connecting a Slack identity
+
+ Starts connecting the caller's Slack identity to their Volcano account
+ and returns its Sign in with Slack URL. LavaFlow acts on a person's
+ Slack mention only for projects owned by an account their identity is
+ connected to. The callback finishes only in the browser that started
+ the connection, so a link forwarded to anyone else connects no one.
+ One Slack identity may connect to several accounts, and one account may
+ have several identities connected. The identity is also tied to the
+ caller's sign-in session: the channel picker and binding act only as
+ the identities this session signed in as, so on an account several
+ people share, nobody picks or binds as another person's identity. An
+ API token has no session, so it can connect an identity that reports,
+ but not pick or bind channels with it. Volcano stores the workspace and
+ user IDs, and no Slack token.
+
+ The response also sets a short-lived HttpOnly cookie that binds the
+ callback to this browser. Installing and connecting each set their
+ own, so starting one leaves the other's callback working.
+
+ Args:
+ redirect (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | SlackAuthorizationResponse]
+ """
+
+
+ kwargs = request_kwargs(
+ redirect=redirect,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ redirect: str | Unset = UNSET,
+
+) -> Error | SlackAuthorizationResponse | None:
+ """ Start connecting a Slack identity
+
+ Starts connecting the caller's Slack identity to their Volcano account
+ and returns its Sign in with Slack URL. LavaFlow acts on a person's
+ Slack mention only for projects owned by an account their identity is
+ connected to. The callback finishes only in the browser that started
+ the connection, so a link forwarded to anyone else connects no one.
+ One Slack identity may connect to several accounts, and one account may
+ have several identities connected. The identity is also tied to the
+ caller's sign-in session: the channel picker and binding act only as
+ the identities this session signed in as, so on an account several
+ people share, nobody picks or binds as another person's identity. An
+ API token has no session, so it can connect an identity that reports,
+ but not pick or bind channels with it. Volcano stores the workspace and
+ user IDs, and no Slack token.
+
+ The response also sets a short-lived HttpOnly cookie that binds the
+ callback to this browser. Installing and connecting each set their
+ own, so starting one leaves the other's callback working.
+
+ Args:
+ redirect (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | SlackAuthorizationResponse
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+redirect=redirect,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/slack_connections/start_slack_install.py b/src/volcano_sdk/_generated/api/slack_connections/start_slack_install.py
new file mode 100644
index 00000000..067f4cb1
--- /dev/null
+++ b/src/volcano_sdk/_generated/api/slack_connections/start_slack_install.py
@@ -0,0 +1,250 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.error import Error
+from ...models.slack_authorization_response import SlackAuthorizationResponse
+from ...types import UNSET, Unset
+from typing import cast
+
+
+
+def request_kwargs(
+ *,
+ redirect: str | Unset = UNSET,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ params["redirect"] = redirect
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "post",
+ "url": "/user/slack/installations",
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | SlackAuthorizationResponse | None:
+ if response.status_code == 200:
+ response_200 = SlackAuthorizationResponse.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = Error.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = Error.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 404:
+ response_404 = Error.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Error | SlackAuthorizationResponse]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ *,
+ client: AuthenticatedClient,
+ redirect: str | Unset = UNSET,
+
+) -> Response[Error | SlackAuthorizationResponse]:
+ """ Start installing the Volcano Slack app
+
+ Starts an installation of the Volcano app in a Slack workspace, so
+ LavaFlow can take problems reported there, and returns its Add to Slack
+ URL. Send the browser to it; Slack returns it to `GET /slack/callback`,
+ which saves the installation as a `slack` connector (`GET /connectors`).
+ Installing again replaces the workspace's installation. Enterprise Grid org-wide installs are
+ refused. The
+ callback finishes only in the browser that started the installation.
+
+ The response also sets a short-lived HttpOnly cookie that binds the
+ callback to this browser. Installing and connecting each set their
+ own, so starting one leaves the other's callback working.
+
+ Args:
+ redirect (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | SlackAuthorizationResponse]
+ """
+
+
+ kwargs = request_kwargs(
+ redirect=redirect,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return build_response(client=client, response=response)
+
+def sync(
+ *,
+ client: AuthenticatedClient,
+ redirect: str | Unset = UNSET,
+
+) -> Error | SlackAuthorizationResponse | None:
+ """ Start installing the Volcano Slack app
+
+ Starts an installation of the Volcano app in a Slack workspace, so
+ LavaFlow can take problems reported there, and returns its Add to Slack
+ URL. Send the browser to it; Slack returns it to `GET /slack/callback`,
+ which saves the installation as a `slack` connector (`GET /connectors`).
+ Installing again replaces the workspace's installation. Enterprise Grid org-wide installs are
+ refused. The
+ callback finishes only in the browser that started the installation.
+
+ The response also sets a short-lived HttpOnly cookie that binds the
+ callback to this browser. Installing and connecting each set their
+ own, so starting one leaves the other's callback working.
+
+ Args:
+ redirect (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | SlackAuthorizationResponse
+ """
+
+
+ return sync_detailed(
+ client=client,
+redirect=redirect,
+
+ ).parsed
+
+async def asyncio_detailed(
+ *,
+ client: AuthenticatedClient,
+ redirect: str | Unset = UNSET,
+
+) -> Response[Error | SlackAuthorizationResponse]:
+ """ Start installing the Volcano Slack app
+
+ Starts an installation of the Volcano app in a Slack workspace, so
+ LavaFlow can take problems reported there, and returns its Add to Slack
+ URL. Send the browser to it; Slack returns it to `GET /slack/callback`,
+ which saves the installation as a `slack` connector (`GET /connectors`).
+ Installing again replaces the workspace's installation. Enterprise Grid org-wide installs are
+ refused. The
+ callback finishes only in the browser that started the installation.
+
+ The response also sets a short-lived HttpOnly cookie that binds the
+ callback to this browser. Installing and connecting each set their
+ own, so starting one leaves the other's callback working.
+
+ Args:
+ redirect (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[Error | SlackAuthorizationResponse]
+ """
+
+
+ kwargs = request_kwargs(
+ redirect=redirect,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return build_response(client=client, response=response)
+
+async def asyncio(
+ *,
+ client: AuthenticatedClient,
+ redirect: str | Unset = UNSET,
+
+) -> Error | SlackAuthorizationResponse | None:
+ """ Start installing the Volcano Slack app
+
+ Starts an installation of the Volcano app in a Slack workspace, so
+ LavaFlow can take problems reported there, and returns its Add to Slack
+ URL. Send the browser to it; Slack returns it to `GET /slack/callback`,
+ which saves the installation as a `slack` connector (`GET /connectors`).
+ Installing again replaces the workspace's installation. Enterprise Grid org-wide installs are
+ refused. The
+ callback finishes only in the browser that started the installation.
+
+ The response also sets a short-lived HttpOnly cookie that binds the
+ callback to this browser. Installing and connecting each set their
+ own, so starting one leaves the other's callback working.
+
+ Args:
+ redirect (str | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Error | SlackAuthorizationResponse
+ """
+
+
+ return (await asyncio_detailed(
+ client=client,
+redirect=redirect,
+
+ )).parsed
diff --git a/src/volcano_sdk/_generated/api/storage_objects/download_public_file.py b/src/volcano_sdk/_generated/api/storage_objects/download_public_file.py
index b51c2764..c99c7ffd 100644
--- a/src/volcano_sdk/_generated/api/storage_objects/download_public_file.py
+++ b/src/volcano_sdk/_generated/api/storage_objects/download_public_file.py
@@ -56,6 +56,13 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
response_404 = cast(Any, None)
return response_404
+ if response.status_code == 416:
+ response_416 = Error.from_dict(response.json())
+
+
+
+ return response_416
+
if response.status_code == 429:
response_429 = Error.from_dict(response.json())
diff --git a/src/volcano_sdk/_generated/api/storage_objects/download_storage_object.py b/src/volcano_sdk/_generated/api/storage_objects/download_storage_object.py
index 30647e4f..011b9cbc 100644
--- a/src/volcano_sdk/_generated/api/storage_objects/download_storage_object.py
+++ b/src/volcano_sdk/_generated/api/storage_objects/download_storage_object.py
@@ -74,6 +74,13 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
response_404 = cast(Any, None)
return response_404
+ if response.status_code == 416:
+ response_416 = Error.from_dict(response.json())
+
+
+
+ return response_416
+
if response.status_code == 429:
response_429 = Error.from_dict(response.json())
diff --git a/src/volcano_sdk/_generated/api/system/list_capabilities.py b/src/volcano_sdk/_generated/api/system/list_capabilities.py
index 32aeb7ad..8a3220c3 100644
--- a/src/volcano_sdk/_generated/api/system/list_capabilities.py
+++ b/src/volcano_sdk/_generated/api/system/list_capabilities.py
@@ -71,10 +71,37 @@ def sync_detailed(
| `sandboxes.sessions` | Starting and resuming sessions, and one-shot executions |
| `sandboxes.custom_templates` | Deploying a custom template; its validation waits while
`sandboxes.sessions` is unavailable |
+ | `sandboxes.network_isolation` | Creating sessions and one-shot executions with `network.egress`
+ `deny_all`; existing `deny_all` sessions work either way |
+ | `sandboxes.output_not_kept` | Commands that keep no output: `keep_output: false` on a command, and
+ `executions.keep_output: false` on a session; commands that keep output work either way |
| `issues` | The Issues API: listing, reading, and updating grouped runtime errors |
- | `autofix` | The Autofix API: a project's AI diagnosis and fix settings |
- | `autofix.managed_models` | Turning autofix on with Volcano-managed models instead of your own API
- key |
+ | `lavaflow` | LavaFlow, which diagnoses a project's issues and opens pull requests that fix them.
+ Here it reports only whether LavaFlow is released in this environment; whether a project has it
+ comes from `GET /projects/{id}/capabilities` |
+ | `lavaflow.merge` | LavaFlow merging its fixes, with `autonomy: merge`. Here it reports only
+ whether merging is released in this environment; whether a project has it comes from `GET
+ /projects/{id}/capabilities` |
+ | `lavaflow.lineage` | LavaFlow following up its fixes: linking a fix's recurrence or a new issue
+ its deploy caused to the fix, the follow-up runs, and the lineage holds. Here it reports only
+ whether fix lineage is released in this environment; whether a project has it comes from `GET
+ /projects/{id}/capabilities` |
+ | `lavaflow.code_quality` | LavaFlow Code Quality, which reviews the code each frontend production
+ deploy changes. Here it reports only whether Code Quality is released in this environment; whether a
+ project has it comes from `GET /projects/{id}/capabilities` |
+ | `lavaflow.slack` | Reporting problems to LavaFlow from Slack: installing the Volcano Slack app,
+ connecting Slack identities, and binding channels to projects. Here it reports whether LavaFlow is
+ released, the Slack app is set up, and Slack reports have launched in this environment; whether a
+ project has it comes from `GET /projects/{id}/capabilities` |
+ | `functions.response_streaming` | Streaming an HTTP-mode function's response on its own URL as the
+ function writes it |
+ | `frontend_routes` | Creating and changing Frontend routes; listing, deleting, and serving existing
+ ones work either way |
+ | `frontends.candidates` | Creating, redeploying, promoting and rolling back to a frontend
+ Candidate; reading, deleting and rolling back to the frontend's own runtime always work |
+ | `databases.migrations` | Starting migration runs and recording a baseline; reading history and
+ runs works either way |
+ | `shares` | Creating, switching on and publishing shares, and forking one |
A capability missing from the list is unavailable, and a capability under
another, such as `sandboxes.sessions`, is unavailable whenever its parent is.
@@ -82,7 +109,13 @@ def sync_detailed(
or `400` with code `feature_unavailable`; refresh this list when you receive
that code. Reading, deleting, and terminating what already exists keep
working unless the whole feature is absent from the environment. Every caller
- in an environment gets the same answer.
+ in an environment gets the same answer; `GET /projects/{id}/capabilities`
+ answers for one project.
+
+ `functions.response_streaming` refuses nothing: while it is unavailable, a
+ function's own URL still answers and sends a streamed response whole, once
+ the function finishes, up to 6 MiB with headers; a larger one fails the
+ invocation. Frontend Function routes stream either way.
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -119,10 +152,37 @@ def sync(
| `sandboxes.sessions` | Starting and resuming sessions, and one-shot executions |
| `sandboxes.custom_templates` | Deploying a custom template; its validation waits while
`sandboxes.sessions` is unavailable |
+ | `sandboxes.network_isolation` | Creating sessions and one-shot executions with `network.egress`
+ `deny_all`; existing `deny_all` sessions work either way |
+ | `sandboxes.output_not_kept` | Commands that keep no output: `keep_output: false` on a command, and
+ `executions.keep_output: false` on a session; commands that keep output work either way |
| `issues` | The Issues API: listing, reading, and updating grouped runtime errors |
- | `autofix` | The Autofix API: a project's AI diagnosis and fix settings |
- | `autofix.managed_models` | Turning autofix on with Volcano-managed models instead of your own API
- key |
+ | `lavaflow` | LavaFlow, which diagnoses a project's issues and opens pull requests that fix them.
+ Here it reports only whether LavaFlow is released in this environment; whether a project has it
+ comes from `GET /projects/{id}/capabilities` |
+ | `lavaflow.merge` | LavaFlow merging its fixes, with `autonomy: merge`. Here it reports only
+ whether merging is released in this environment; whether a project has it comes from `GET
+ /projects/{id}/capabilities` |
+ | `lavaflow.lineage` | LavaFlow following up its fixes: linking a fix's recurrence or a new issue
+ its deploy caused to the fix, the follow-up runs, and the lineage holds. Here it reports only
+ whether fix lineage is released in this environment; whether a project has it comes from `GET
+ /projects/{id}/capabilities` |
+ | `lavaflow.code_quality` | LavaFlow Code Quality, which reviews the code each frontend production
+ deploy changes. Here it reports only whether Code Quality is released in this environment; whether a
+ project has it comes from `GET /projects/{id}/capabilities` |
+ | `lavaflow.slack` | Reporting problems to LavaFlow from Slack: installing the Volcano Slack app,
+ connecting Slack identities, and binding channels to projects. Here it reports whether LavaFlow is
+ released, the Slack app is set up, and Slack reports have launched in this environment; whether a
+ project has it comes from `GET /projects/{id}/capabilities` |
+ | `functions.response_streaming` | Streaming an HTTP-mode function's response on its own URL as the
+ function writes it |
+ | `frontend_routes` | Creating and changing Frontend routes; listing, deleting, and serving existing
+ ones work either way |
+ | `frontends.candidates` | Creating, redeploying, promoting and rolling back to a frontend
+ Candidate; reading, deleting and rolling back to the frontend's own runtime always work |
+ | `databases.migrations` | Starting migration runs and recording a baseline; reading history and
+ runs works either way |
+ | `shares` | Creating, switching on and publishing shares, and forking one |
A capability missing from the list is unavailable, and a capability under
another, such as `sandboxes.sessions`, is unavailable whenever its parent is.
@@ -130,7 +190,13 @@ def sync(
or `400` with code `feature_unavailable`; refresh this list when you receive
that code. Reading, deleting, and terminating what already exists keep
working unless the whole feature is absent from the environment. Every caller
- in an environment gets the same answer.
+ in an environment gets the same answer; `GET /projects/{id}/capabilities`
+ answers for one project.
+
+ `functions.response_streaming` refuses nothing: while it is unavailable, a
+ function's own URL still answers and sends a streamed response whole, once
+ the function finishes, up to 6 MiB with headers; a larger one fails the
+ invocation. Frontend Function routes stream either way.
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -162,10 +228,37 @@ async def asyncio_detailed(
| `sandboxes.sessions` | Starting and resuming sessions, and one-shot executions |
| `sandboxes.custom_templates` | Deploying a custom template; its validation waits while
`sandboxes.sessions` is unavailable |
+ | `sandboxes.network_isolation` | Creating sessions and one-shot executions with `network.egress`
+ `deny_all`; existing `deny_all` sessions work either way |
+ | `sandboxes.output_not_kept` | Commands that keep no output: `keep_output: false` on a command, and
+ `executions.keep_output: false` on a session; commands that keep output work either way |
| `issues` | The Issues API: listing, reading, and updating grouped runtime errors |
- | `autofix` | The Autofix API: a project's AI diagnosis and fix settings |
- | `autofix.managed_models` | Turning autofix on with Volcano-managed models instead of your own API
- key |
+ | `lavaflow` | LavaFlow, which diagnoses a project's issues and opens pull requests that fix them.
+ Here it reports only whether LavaFlow is released in this environment; whether a project has it
+ comes from `GET /projects/{id}/capabilities` |
+ | `lavaflow.merge` | LavaFlow merging its fixes, with `autonomy: merge`. Here it reports only
+ whether merging is released in this environment; whether a project has it comes from `GET
+ /projects/{id}/capabilities` |
+ | `lavaflow.lineage` | LavaFlow following up its fixes: linking a fix's recurrence or a new issue
+ its deploy caused to the fix, the follow-up runs, and the lineage holds. Here it reports only
+ whether fix lineage is released in this environment; whether a project has it comes from `GET
+ /projects/{id}/capabilities` |
+ | `lavaflow.code_quality` | LavaFlow Code Quality, which reviews the code each frontend production
+ deploy changes. Here it reports only whether Code Quality is released in this environment; whether a
+ project has it comes from `GET /projects/{id}/capabilities` |
+ | `lavaflow.slack` | Reporting problems to LavaFlow from Slack: installing the Volcano Slack app,
+ connecting Slack identities, and binding channels to projects. Here it reports whether LavaFlow is
+ released, the Slack app is set up, and Slack reports have launched in this environment; whether a
+ project has it comes from `GET /projects/{id}/capabilities` |
+ | `functions.response_streaming` | Streaming an HTTP-mode function's response on its own URL as the
+ function writes it |
+ | `frontend_routes` | Creating and changing Frontend routes; listing, deleting, and serving existing
+ ones work either way |
+ | `frontends.candidates` | Creating, redeploying, promoting and rolling back to a frontend
+ Candidate; reading, deleting and rolling back to the frontend's own runtime always work |
+ | `databases.migrations` | Starting migration runs and recording a baseline; reading history and
+ runs works either way |
+ | `shares` | Creating, switching on and publishing shares, and forking one |
A capability missing from the list is unavailable, and a capability under
another, such as `sandboxes.sessions`, is unavailable whenever its parent is.
@@ -173,7 +266,13 @@ async def asyncio_detailed(
or `400` with code `feature_unavailable`; refresh this list when you receive
that code. Reading, deleting, and terminating what already exists keep
working unless the whole feature is absent from the environment. Every caller
- in an environment gets the same answer.
+ in an environment gets the same answer; `GET /projects/{id}/capabilities`
+ answers for one project.
+
+ `functions.response_streaming` refuses nothing: while it is unavailable, a
+ function's own URL still answers and sends a streamed response whole, once
+ the function finishes, up to 6 MiB with headers; a larger one fails the
+ invocation. Frontend Function routes stream either way.
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -210,10 +309,37 @@ async def asyncio(
| `sandboxes.sessions` | Starting and resuming sessions, and one-shot executions |
| `sandboxes.custom_templates` | Deploying a custom template; its validation waits while
`sandboxes.sessions` is unavailable |
+ | `sandboxes.network_isolation` | Creating sessions and one-shot executions with `network.egress`
+ `deny_all`; existing `deny_all` sessions work either way |
+ | `sandboxes.output_not_kept` | Commands that keep no output: `keep_output: false` on a command, and
+ `executions.keep_output: false` on a session; commands that keep output work either way |
| `issues` | The Issues API: listing, reading, and updating grouped runtime errors |
- | `autofix` | The Autofix API: a project's AI diagnosis and fix settings |
- | `autofix.managed_models` | Turning autofix on with Volcano-managed models instead of your own API
- key |
+ | `lavaflow` | LavaFlow, which diagnoses a project's issues and opens pull requests that fix them.
+ Here it reports only whether LavaFlow is released in this environment; whether a project has it
+ comes from `GET /projects/{id}/capabilities` |
+ | `lavaflow.merge` | LavaFlow merging its fixes, with `autonomy: merge`. Here it reports only
+ whether merging is released in this environment; whether a project has it comes from `GET
+ /projects/{id}/capabilities` |
+ | `lavaflow.lineage` | LavaFlow following up its fixes: linking a fix's recurrence or a new issue
+ its deploy caused to the fix, the follow-up runs, and the lineage holds. Here it reports only
+ whether fix lineage is released in this environment; whether a project has it comes from `GET
+ /projects/{id}/capabilities` |
+ | `lavaflow.code_quality` | LavaFlow Code Quality, which reviews the code each frontend production
+ deploy changes. Here it reports only whether Code Quality is released in this environment; whether a
+ project has it comes from `GET /projects/{id}/capabilities` |
+ | `lavaflow.slack` | Reporting problems to LavaFlow from Slack: installing the Volcano Slack app,
+ connecting Slack identities, and binding channels to projects. Here it reports whether LavaFlow is
+ released, the Slack app is set up, and Slack reports have launched in this environment; whether a
+ project has it comes from `GET /projects/{id}/capabilities` |
+ | `functions.response_streaming` | Streaming an HTTP-mode function's response on its own URL as the
+ function writes it |
+ | `frontend_routes` | Creating and changing Frontend routes; listing, deleting, and serving existing
+ ones work either way |
+ | `frontends.candidates` | Creating, redeploying, promoting and rolling back to a frontend
+ Candidate; reading, deleting and rolling back to the frontend's own runtime always work |
+ | `databases.migrations` | Starting migration runs and recording a baseline; reading history and
+ runs works either way |
+ | `shares` | Creating, switching on and publishing shares, and forking one |
A capability missing from the list is unavailable, and a capability under
another, such as `sandboxes.sessions`, is unavailable whenever its parent is.
@@ -221,7 +347,13 @@ async def asyncio(
or `400` with code `feature_unavailable`; refresh this list when you receive
that code. Reading, deleting, and terminating what already exists keep
working unless the whole feature is absent from the environment. Every caller
- in an environment gets the same answer.
+ in an environment gets the same answer; `GET /projects/{id}/capabilities`
+ answers for one project.
+
+ `functions.response_streaming` refuses nothing: while it is unavailable, a
+ function's own URL still answers and sends a streamed response whole, once
+ the function finishes, up to 6 MiB with headers; a larger one fails the
+ invocation. Frontend Function routes stream either way.
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
diff --git a/src/volcano_sdk/_generated/models/__init__.py b/src/volcano_sdk/_generated/models/__init__.py
index 31ee40ce..36997852 100644
--- a/src/volcano_sdk/_generated/models/__init__.py
+++ b/src/volcano_sdk/_generated/models/__init__.py
@@ -1,5 +1,8 @@
""" Contains all the data models used in inputs/outputs """
+from .account_session import AccountSession
+from .account_session_kind import AccountSessionKind
+from .account_session_list import AccountSessionList
from .anon_key import AnonKey
from .auth_cancel_email_change_response_200 import AuthCancelEmailChangeResponse200
from .auth_config import AuthConfig
@@ -90,23 +93,6 @@
from .auth_user_app_metadata import AuthUserAppMetadata
from .auth_user_status import AuthUserStatus
from .auth_user_user_metadata import AuthUserUserMetadata
-from .autofix_diagnosis import AutofixDiagnosis
-from .autofix_diagnosis_confidence import AutofixDiagnosisConfidence
-from .autofix_edit import AutofixEdit
-from .autofix_evidence import AutofixEvidence
-from .autofix_evidence_kind import AutofixEvidenceKind
-from .autofix_model import AutofixModel
-from .autofix_patch import AutofixPatch
-from .autofix_provider import AutofixProvider
-from .autofix_pull_request import AutofixPullRequest
-from .autofix_pull_request_skipped import AutofixPullRequestSkipped
-from .autofix_pull_request_state import AutofixPullRequestState
-from .autofix_run import AutofixRun
-from .autofix_run_status import AutofixRunStatus
-from .autofix_run_trigger import AutofixRunTrigger
-from .autofix_run_usage import AutofixRunUsage
-from .autofix_settings import AutofixSettings
-from .autofix_stage import AutofixStage
from .ban_auth_user_body import BanAuthUserBody
from .ban_user_response import BanUserResponse
from .ban_user_response_status import BanUserResponseStatus
@@ -135,6 +121,9 @@
from .configure_auth_methods_body import ConfigureAuthMethodsBody
from .configure_auth_methods_body_oauth_providers_item import ConfigureAuthMethodsBodyOauthProvidersItem
from .connect_project_git_request import ConnectProjectGitRequest
+from .connector import Connector
+from .connector_type import ConnectorType
+from .connectors_response import ConnectorsResponse
from .create_anon_key_body import CreateAnonKeyBody
from .create_anon_key_body_permissions_item import CreateAnonKeyBodyPermissionsItem
from .create_database_backup_request import CreateDatabaseBackupRequest
@@ -151,8 +140,12 @@
from .create_frontend_body import CreateFrontendBody
from .create_frontend_body_framework import CreateFrontendBodyFramework
from .create_frontend_body_variable_scope import CreateFrontendBodyVariableScope
+from .create_frontend_candidate_body import CreateFrontendCandidateBody
from .create_frontend_custom_domain_request import CreateFrontendCustomDomainRequest
+from .create_frontend_deployment_request import CreateFrontendDeploymentRequest
+from .create_frontend_domain_request import CreateFrontendDomainRequest
from .create_frontend_function_route_request import CreateFrontendFunctionRouteRequest
+from .create_frontend_route_request import CreateFrontendRouteRequest
from .create_function_body import CreateFunctionBody
from .create_function_body_runtime import CreateFunctionBodyRuntime
from .create_function_body_variable_scope import CreateFunctionBodyVariableScope
@@ -190,6 +183,25 @@
from .database_delete_request import DatabaseDeleteRequest
from .database_insert_request import DatabaseInsertRequest
from .database_insert_request_values import DatabaseInsertRequestValues
+from .database_migration_baseline import DatabaseMigrationBaseline
+from .database_migration_conflict_error import DatabaseMigrationConflictError
+from .database_migration_file import DatabaseMigrationFile
+from .database_migration_file_error import DatabaseMigrationFileError
+from .database_migration_files_request import DatabaseMigrationFilesRequest
+from .database_migration_history_entry import DatabaseMigrationHistoryEntry
+from .database_migration_history_entry_status import DatabaseMigrationHistoryEntryStatus
+from .database_migration_run import DatabaseMigrationRun
+from .database_migration_run_error import DatabaseMigrationRunError
+from .database_migration_run_error_code import DatabaseMigrationRunErrorCode
+from .database_migration_run_file import DatabaseMigrationRunFile
+from .database_migration_run_file_outcome import DatabaseMigrationRunFileOutcome
+from .database_migration_run_list import DatabaseMigrationRunList
+from .database_migration_run_phase import DatabaseMigrationRunPhase
+from .database_migration_run_source import DatabaseMigrationRunSource
+from .database_migration_run_status import DatabaseMigrationRunStatus
+from .database_migration_warning import DatabaseMigrationWarning
+from .database_migration_warning_code import DatabaseMigrationWarningCode
+from .database_migrations import DatabaseMigrations
from .database_query_filter import DatabaseQueryFilter
from .database_query_filter_operator import DatabaseQueryFilterOperator
from .database_query_order import DatabaseQueryOrder
@@ -199,6 +211,7 @@
from .database_query_result import DatabaseQueryResult
from .database_query_result_data_item import DatabaseQueryResultDataItem
from .database_restore import DatabaseRestore
+from .database_restore_conflict_error import DatabaseRestoreConflictError
from .database_restore_kind import DatabaseRestoreKind
from .database_restore_list import DatabaseRestoreList
from .database_restore_status import DatabaseRestoreStatus
@@ -209,6 +222,8 @@
from .database_status import DatabaseStatus
from .database_update_request import DatabaseUpdateRequest
from .database_update_request_values import DatabaseUpdateRequestValues
+from .default_email_template import DefaultEmailTemplate
+from .default_email_template_type import DefaultEmailTemplateType
from .delete_database_backup_response_200 import DeleteDatabaseBackupResponse200
from .delete_database_branch_response_202 import DeleteDatabaseBranchResponse202
from .delete_database_response_202 import DeleteDatabaseResponse202
@@ -216,6 +231,8 @@
from .delete_o_auth_config_provider import DeleteOAuthConfigProvider
from .deploy_sandbox_body import DeploySandboxBody
from .deploy_sandbox_body_memory_mb import DeploySandboxBodyMemoryMb
+from .deployment_commit import DeploymentCommit
+from .deployment_commit_verification import DeploymentCommitVerification
from .deployment_phase import DeploymentPhase
from .deployment_phase_name import DeploymentPhaseName
from .deployment_phase_status import DeploymentPhaseStatus
@@ -269,8 +286,21 @@
from .error import Error
from .export_project_source_request import ExportProjectSourceRequest
from .fail_durable_callback_request import FailDurableCallbackRequest
+from .fork_create_request import ForkCreateRequest
+from .fork_create_request_variables import ForkCreateRequestVariables
from .frontend import Frontend
+from .frontend_candidate import FrontendCandidate
+from .frontend_candidate_configuration_status import FrontendCandidateConfigurationStatus
+from .frontend_candidate_deployment import FrontendCandidateDeployment
+from .frontend_candidate_deployment_status import FrontendCandidateDeploymentStatus
+from .frontend_candidate_list import FrontendCandidateList
+from .frontend_candidate_status import FrontendCandidateStatus
from .frontend_custom_domain_conflict_error import FrontendCustomDomainConflictError
+from .frontend_custom_domain_list import FrontendCustomDomainList
+from .frontend_custom_domain_redirect import FrontendCustomDomainRedirect
+from .frontend_custom_domain_redirect_request import FrontendCustomDomainRedirectRequest
+from .frontend_custom_domain_redirect_request_status import FrontendCustomDomainRedirectRequestStatus
+from .frontend_custom_domain_redirect_status import FrontendCustomDomainRedirectStatus
from .frontend_custom_domain_response import FrontendCustomDomainResponse
from .frontend_custom_domain_response_domain_status import FrontendCustomDomainResponseDomainStatus
from .frontend_custom_domain_response_serving_certificate import FrontendCustomDomainResponseServingCertificate
@@ -289,6 +319,9 @@
from .frontend_framework import FrontendFramework
from .frontend_function_route import FrontendFunctionRoute
from .frontend_function_route_list import FrontendFunctionRouteList
+from .frontend_route import FrontendRoute
+from .frontend_route_list import FrontendRouteList
+from .frontend_serving import FrontendServing
from .frontend_status import FrontendStatus
from .frontend_usage_daily_entry import FrontendUsageDailyEntry
from .frontend_usage_data import FrontendUsageData
@@ -312,6 +345,8 @@
from .function_runtime_option import FunctionRuntimeOption
from .function_runtimes_response import FunctionRuntimesResponse
from .function_scheduler import FunctionScheduler
+from .function_scheduler_health import FunctionSchedulerHealth
+from .function_scheduler_last_run_status import FunctionSchedulerLastRunStatus
from .function_scheduler_list_response import FunctionSchedulerListResponse
from .function_scheduler_payload import FunctionSchedulerPayload
from .function_scheduler_schedule_kind import FunctionSchedulerScheduleKind
@@ -325,6 +360,7 @@
from .get_default_email_template_type import GetDefaultEmailTemplateType
from .get_default_email_templates_response_200 import GetDefaultEmailTemplatesResponse200
from .get_email_template_type import GetEmailTemplateType
+from .get_lavaflow_stats_category import GetLavaflowStatsCategory
from .get_o_auth_config_provider import GetOAuthConfigProvider
from .get_o_auth_provider_token_provider import GetOAuthProviderTokenProvider
from .get_o_auth_provider_token_response_200 import GetOAuthProviderTokenResponse200
@@ -332,10 +368,15 @@
from .git_connect_start_response import GitConnectStartResponse
from .git_connection import GitConnection
from .git_connections_response import GitConnectionsResponse
+from .git_deployment_migration_run import GitDeploymentMigrationRun
+from .git_deployment_run import GitDeploymentRun
+from .git_deployment_run_error import GitDeploymentRunError
+from .git_deployment_run_status import GitDeploymentRunStatus
from .git_installation import GitInstallation
from .git_installations_response import GitInstallationsResponse
from .git_repositories_response import GitRepositoriesResponse
from .git_repository import GitRepository
+from .git_repository_reference import GitRepositoryReference
from .heartbeat_durable_callback_request import HeartbeatDurableCallbackRequest
from .hosted_auth_page_type import HostedAuthPageType
from .hosted_login_email_check_request import HostedLoginEmailCheckRequest
@@ -349,7 +390,116 @@
from .import_source import ImportSource
from .import_sources_response import ImportSourcesResponse
from .issue import Issue
+from .issue_finding import IssueFinding
+from .issue_finding_severity import IssueFindingSeverity
+from .issue_source import IssueSource
from .issue_status import IssueStatus
+from .lavaflow_allowed_workflow import LavaflowAllowedWorkflow
+from .lavaflow_anomaly import LavaflowAnomaly
+from .lavaflow_autonomy import LavaflowAutonomy
+from .lavaflow_category_counts import LavaflowCategoryCounts
+from .lavaflow_code_quality_settings import LavaflowCodeQualitySettings
+from .lavaflow_code_quality_update import LavaflowCodeQualityUpdate
+from .lavaflow_commit_origin import LavaflowCommitOrigin
+from .lavaflow_connector_binding import LavaflowConnectorBinding
+from .lavaflow_connector_binding_create import LavaflowConnectorBindingCreate
+from .lavaflow_connector_bindings_response import LavaflowConnectorBindingsResponse
+from .lavaflow_day_counts import LavaflowDayCounts
+from .lavaflow_diagnosis import LavaflowDiagnosis
+from .lavaflow_draft_reason import LavaflowDraftReason
+from .lavaflow_failure import LavaflowFailure
+from .lavaflow_fix_outcome import LavaflowFixOutcome
+from .lavaflow_fix_outcome_state import LavaflowFixOutcomeState
+from .lavaflow_global_skill import LavaflowGlobalSkill
+from .lavaflow_global_skill_applies_to import LavaflowGlobalSkillAppliesTo
+from .lavaflow_global_skill_list import LavaflowGlobalSkillList
+from .lavaflow_held_fix_open import LavaflowHeldFixOpen
+from .lavaflow_held_workflows import LavaflowHeldWorkflows
+from .lavaflow_hold_reason import LavaflowHoldReason
+from .lavaflow_involved_resource import LavaflowInvolvedResource
+from .lavaflow_involved_resource_count import LavaflowInvolvedResourceCount
+from .lavaflow_involved_resource_roles_item import LavaflowInvolvedResourceRolesItem
+from .lavaflow_issue_summary import LavaflowIssueSummary
+from .lavaflow_issue_summary_severity import LavaflowIssueSummarySeverity
+from .lavaflow_lineage import LavaflowLineage
+from .lavaflow_lineage_confidence import LavaflowLineageConfidence
+from .lavaflow_lineage_evidence import LavaflowLineageEvidence
+from .lavaflow_lineage_evidence_confidence import LavaflowLineageEvidenceConfidence
+from .lavaflow_lineage_evidence_deployment import LavaflowLineageEvidenceDeployment
+from .lavaflow_lineage_relation import LavaflowLineageRelation
+from .lavaflow_lineage_remedy import LavaflowLineageRemedy
+from .lavaflow_lineage_state import LavaflowLineageState
+from .lavaflow_log_line import LavaflowLogLine
+from .lavaflow_merge import LavaflowMerge
+from .lavaflow_merge_policy import LavaflowMergePolicy
+from .lavaflow_merge_policy_update import LavaflowMergePolicyUpdate
+from .lavaflow_merge_status import LavaflowMergeStatus
+from .lavaflow_pull_request import LavaflowPullRequest
+from .lavaflow_pull_request_state import LavaflowPullRequestState
+from .lavaflow_pull_request_state_counts import LavaflowPullRequestStateCounts
+from .lavaflow_repository_check_command import LavaflowRepositoryCheckCommand
+from .lavaflow_repository_checks import LavaflowRepositoryChecks
+from .lavaflow_resource import LavaflowResource
+from .lavaflow_resource_list import LavaflowResourceList
+from .lavaflow_resource_reference import LavaflowResourceReference
+from .lavaflow_resource_reference_type import LavaflowResourceReferenceType
+from .lavaflow_review import LavaflowReview
+from .lavaflow_review_finding import LavaflowReviewFinding
+from .lavaflow_review_finding_severity import LavaflowReviewFindingSeverity
+from .lavaflow_review_person_reason import LavaflowReviewPersonReason
+from .lavaflow_review_stop import LavaflowReviewStop
+from .lavaflow_review_verdict import LavaflowReviewVerdict
+from .lavaflow_run import LavaflowRun
+from .lavaflow_run_category import LavaflowRunCategory
+from .lavaflow_run_counts import LavaflowRunCounts
+from .lavaflow_run_create import LavaflowRunCreate
+from .lavaflow_run_mode import LavaflowRunMode
+from .lavaflow_run_progress import LavaflowRunProgress
+from .lavaflow_run_progress_stage import LavaflowRunProgressStage
+from .lavaflow_run_reference import LavaflowRunReference
+from .lavaflow_run_status import LavaflowRunStatus
+from .lavaflow_run_status_counts import LavaflowRunStatusCounts
+from .lavaflow_run_summary import LavaflowRunSummary
+from .lavaflow_scan import LavaflowScan
+from .lavaflow_scan_billed_finding import LavaflowScanBilledFinding
+from .lavaflow_scan_billed_finding_billable_events import LavaflowScanBilledFindingBillableEvents
+from .lavaflow_scan_counts import LavaflowScanCounts
+from .lavaflow_scan_resource import LavaflowScanResource
+from .lavaflow_scan_resource_resource_type import LavaflowScanResourceResourceType
+from .lavaflow_scan_source import LavaflowScanSource
+from .lavaflow_scan_status import LavaflowScanStatus
+from .lavaflow_settings import LavaflowSettings
+from .lavaflow_settings_update import LavaflowSettingsUpdate
+from .lavaflow_skill import LavaflowSkill
+from .lavaflow_skill_applies_to import LavaflowSkillAppliesTo
+from .lavaflow_skill_applies_to_update import LavaflowSkillAppliesToUpdate
+from .lavaflow_skill_citation import LavaflowSkillCitation
+from .lavaflow_skill_counts import LavaflowSkillCounts
+from .lavaflow_skill_error import LavaflowSkillError
+from .lavaflow_skill_error_rules_item import LavaflowSkillErrorRulesItem
+from .lavaflow_skill_learning import LavaflowSkillLearning
+from .lavaflow_skill_list import LavaflowSkillList
+from .lavaflow_skill_retired_reason import LavaflowSkillRetiredReason
+from .lavaflow_skill_scope import LavaflowSkillScope
+from .lavaflow_skill_source import LavaflowSkillSource
+from .lavaflow_skill_source_act import LavaflowSkillSourceAct
+from .lavaflow_skill_source_kind import LavaflowSkillSourceKind
+from .lavaflow_skill_status import LavaflowSkillStatus
+from .lavaflow_skill_update import LavaflowSkillUpdate
+from .lavaflow_skill_update_status import LavaflowSkillUpdateStatus
+from .lavaflow_skill_version import LavaflowSkillVersion
+from .lavaflow_skill_version_list import LavaflowSkillVersionList
+from .lavaflow_skip_reason import LavaflowSkipReason
+from .lavaflow_slack_binding import LavaflowSlackBinding
+from .lavaflow_slack_binding_target import LavaflowSlackBindingTarget
+from .lavaflow_source_commit import LavaflowSourceCommit
+from .lavaflow_source_unavailable import LavaflowSourceUnavailable
+from .lavaflow_source_unavailable_reason import LavaflowSourceUnavailableReason
+from .lavaflow_stats import LavaflowStats
+from .lavaflow_stats_totals import LavaflowStatsTotals
+from .lavaflow_workflow_source import LavaflowWorkflowSource
+from .list_account_sessions_sort import ListAccountSessionsSort
+from .list_account_sessions_status import ListAccountSessionsStatus
from .list_anon_keys_response_200 import ListAnonKeysResponse200
from .list_auth_users_status import ListAuthUsersStatus
from .list_available_o_auth_providers_response_200 import ListAvailableOAuthProvidersResponse200
@@ -361,6 +511,11 @@
from .list_deployments_resource_type import ListDeploymentsResourceType
from .list_deployments_status import ListDeploymentsStatus
from .list_email_templates_response_200 import ListEmailTemplatesResponse200
+from .list_lavaflow_resources_category import ListLavaflowResourcesCategory
+from .list_lavaflow_runs_category import ListLavaflowRunsCategory
+from .list_lavaflow_runs_include_item import ListLavaflowRunsIncludeItem
+from .list_lavaflow_runs_order import ListLavaflowRunsOrder
+from .list_lavaflow_runs_pull_request_state import ListLavaflowRunsPullRequestState
from .list_o_auth_configs_response_200 import ListOAuthConfigsResponse200
from .list_postgres_versions_response_200_item import ListPostgresVersionsResponse200Item
from .list_project_deployments_resource_type import ListProjectDeploymentsResourceType
@@ -397,13 +552,19 @@
from .managed_project_config_frontend_custom_domain_tls_config import ManagedProjectConfigFrontendCustomDomainTLSConfig
from .managed_project_config_frontend_custom_domain_tls_config_mode import ManagedProjectConfigFrontendCustomDomainTLSConfigMode
from .metric_usage_data import MetricUsageData
+from .notification_email_settings import NotificationEmailSettings
+from .notification_email_status import NotificationEmailStatus
+from .notification_settings import NotificationSettings
+from .notification_test_delivery import NotificationTestDelivery
+from .notification_test_delivery_channel import NotificationTestDeliveryChannel
+from .notification_test_result import NotificationTestResult
+from .notification_webhook_settings import NotificationWebhookSettings
from .o_auth_config import OAuthConfig
from .o_auth_config_provider import OAuthConfigProvider
from .o_auth_error_response import OAuthErrorResponse
from .open_api_spec_document import OpenAPISpecDocument
from .open_durable_message_session_request import OpenDurableMessageSessionRequest
from .paginated_auth_users import PaginatedAuthUsers
-from .paginated_autofix_runs import PaginatedAutofixRuns
from .paginated_databases import PaginatedDatabases
from .paginated_durable_approvals import PaginatedDurableApprovals
from .paginated_durable_executions import PaginatedDurableExecutions
@@ -412,13 +573,17 @@
from .paginated_frontends import PaginatedFrontends
from .paginated_function_deployments import PaginatedFunctionDeployments
from .paginated_functions import PaginatedFunctions
+from .paginated_git_deployment_runs import PaginatedGitDeploymentRuns
from .paginated_issues import PaginatedIssues
+from .paginated_lavaflow_runs import PaginatedLavaflowRuns
+from .paginated_lavaflow_scans import PaginatedLavaflowScans
from .paginated_project_access_tokens import PaginatedProjectAccessTokens
from .paginated_project_custom_domains import PaginatedProjectCustomDomains
from .paginated_project_deployments import PaginatedProjectDeployments
from .paginated_projects import PaginatedProjects
from .paginated_projects_status import PaginatedProjectsStatus
from .paginated_service_keys import PaginatedServiceKeys
+from .paginated_share_releases import PaginatedShareReleases
from .paginated_storage_buckets import PaginatedStorageBuckets
from .paginated_variables import PaginatedVariables
from .platform_exchange_response import PlatformExchangeResponse
@@ -455,26 +620,31 @@
from .project_config_auth_signup import ProjectConfigAuthSignup
from .project_config_auth_signup_allowed_email_domains_mode import ProjectConfigAuthSignupAllowedEmailDomainsMode
from .project_config_auth_tokens import ProjectConfigAuthTokens
-from .project_config_autofix import ProjectConfigAutofix
from .project_config_bucket import ProjectConfigBucket
from .project_config_bucket_policy import ProjectConfigBucketPolicy
from .project_config_bucket_policy_operation import ProjectConfigBucketPolicyOperation
from .project_config_custom_domain import ProjectConfigCustomDomain
+from .project_config_custom_domain_redirect import ProjectConfigCustomDomainRedirect
+from .project_config_custom_domain_redirect_status import ProjectConfigCustomDomainRedirectStatus
from .project_config_database import ProjectConfigDatabase
from .project_config_database_database_type import ProjectConfigDatabaseDatabaseType
from .project_config_database_pg_version import ProjectConfigDatabasePgVersion
from .project_config_email_template import ProjectConfigEmailTemplate
from .project_config_email_templates import ProjectConfigEmailTemplates
from .project_config_frontend import ProjectConfigFrontend
+from .project_config_frontend_custom_domain import ProjectConfigFrontendCustomDomain
from .project_config_frontend_function_route import ProjectConfigFrontendFunctionRoute
+from .project_config_frontend_route import ProjectConfigFrontendRoute
from .project_config_frontend_variable_scope import ProjectConfigFrontendVariableScope
from .project_config_function import ProjectConfigFunction
from .project_config_function_openapi_spec_type_0 import ProjectConfigFunctionOpenapiSpecType0
from .project_config_function_variable_scope import ProjectConfigFunctionVariableScope
from .project_config_hosted_page import ProjectConfigHostedPage
from .project_config_hosted_pages import ProjectConfigHostedPages
+from .project_config_lava_flow import ProjectConfigLavaFlow
from .project_config_missing_resource import ProjectConfigMissingResource
from .project_config_missing_resource_type import ProjectConfigMissingResourceType
+from .project_config_notifications import ProjectConfigNotifications
from .project_config_o_auth_provider import ProjectConfigOAuthProvider
from .project_config_o_auth_provider_provider import ProjectConfigOAuthProviderProvider
from .project_config_project import ProjectConfigProject
@@ -501,6 +671,8 @@
from .project_git_connection import ProjectGitConnection
from .project_git_connection_summary import ProjectGitConnectionSummary
from .project_git_deploy_settings import ProjectGitDeploySettings
+from .project_git_owner_push import ProjectGitOwnerPush
+from .project_git_owner_push_reason import ProjectGitOwnerPushReason
from .project_health_category import ProjectHealthCategory
from .project_health_check import ProjectHealthCheck
from .project_health_data_status import ProjectHealthDataStatus
@@ -554,8 +726,11 @@
from .project_status import ProjectStatus
from .project_template_installation import ProjectTemplateInstallation
from .project_template_installation_phase import ProjectTemplateInstallationPhase
+from .project_template_installation_source import ProjectTemplateInstallationSource
+from .project_template_installation_source_kind import ProjectTemplateInstallationSourceKind
from .project_template_installation_status import ProjectTemplateInstallationStatus
from .project_usage_response import ProjectUsageResponse
+from .promote_frontend_candidate_body import PromoteFrontendCandidateBody
from .publish_durable_message_request import PublishDurableMessageRequest
from .publish_sandbox_preset_request import PublishSandboxPresetRequest
from .publish_sandbox_preset_request_memory_mb import PublishSandboxPresetRequestMemoryMb
@@ -563,6 +738,7 @@
from .realtime_config import RealtimeConfig
from .realtime_plan_limits import RealtimePlanLimits
from .realtime_stats import RealtimeStats
+from .redeploy_frontend_candidate_body import RedeployFrontendCandidateBody
from .refresh_o_auth_provider_token_provider import RefreshOAuthProviderTokenProvider
from .refresh_o_auth_provider_token_response_200 import RefreshOAuthProviderTokenResponse200
from .register_durable_callback_request import RegisterDurableCallbackRequest
@@ -576,6 +752,7 @@
from .resolve_function_response import ResolveFunctionResponse
from .resource_reference import ResourceReference
from .resource_reference_type import ResourceReferenceType
+from .rollback_frontend_serving_body import RollbackFrontendServingBody
from .sandbox_access import SandboxAccess
from .sandbox_access_request import SandboxAccessRequest
from .sandbox_build_log_page import SandboxBuildLogPage
@@ -588,15 +765,32 @@
from .sandbox_deployment import SandboxDeployment
from .sandbox_deployment_page import SandboxDeploymentPage
from .sandbox_execution_result import SandboxExecutionResult
+from .sandbox_file_archive import SandboxFileArchive
+from .sandbox_file_archive_form import SandboxFileArchiveForm
+from .sandbox_file_entry import SandboxFileEntry
+from .sandbox_file_entry_sha_256_skipped import SandboxFileEntrySha256Skipped
+from .sandbox_file_entry_type import SandboxFileEntryType
+from .sandbox_file_list_result import SandboxFileListResult
+from .sandbox_file_part import SandboxFilePart
+from .sandbox_file_part_request import SandboxFilePartRequest
from .sandbox_file_read_request import SandboxFileReadRequest
from .sandbox_file_result import SandboxFileResult
from .sandbox_file_write_request import SandboxFileWriteRequest
+from .sandbox_limits_applied import SandboxLimitsApplied
from .sandbox_pagination import SandboxPagination
from .sandbox_preset import SandboxPreset
from .sandbox_preset_list import SandboxPresetList
from .sandbox_preset_memory_mb import SandboxPresetMemoryMb
from .sandbox_session import SandboxSession
+from .sandbox_session_applied_limits import SandboxSessionAppliedLimits
from .sandbox_session_desired_state import SandboxSessionDesiredState
+from .sandbox_session_executions import SandboxSessionExecutions
+from .sandbox_session_limits import SandboxSessionLimits
+from .sandbox_session_network import SandboxSessionNetwork
+from .sandbox_session_network_applied import SandboxSessionNetworkApplied
+from .sandbox_session_network_egress import SandboxSessionNetworkEgress
+from .sandbox_session_network_request import SandboxSessionNetworkRequest
+from .sandbox_session_network_request_egress import SandboxSessionNetworkRequestEgress
from .sandbox_session_page import SandboxSessionPage
from .sandbox_session_state import SandboxSessionState
from .sandbox_subject_grant_request import SandboxSubjectGrantRequest
@@ -605,9 +799,44 @@
from .sandbox_template_status import SandboxTemplateStatus
from .schedule_request import ScheduleRequest
from .schedule_request_kind import ScheduleRequestKind
+from .scheduler_failure_alert_policy import SchedulerFailureAlertPolicy
+from .scheduler_failure_notify_on import SchedulerFailureNotifyOn
from .send_durable_message_request import SendDurableMessageRequest
from .service_key import ServiceKey
from .set_project_git_production_branch_request import SetProjectGitProductionBranchRequest
+from .set_project_git_root_directory_request import SetProjectGitRootDirectoryRequest
+from .share import Share
+from .share_create_request import ShareCreateRequest
+from .share_daily_count import ShareDailyCount
+from .share_daily_count_kind import ShareDailyCountKind
+from .share_draft_changed_error import ShareDraftChangedError
+from .share_draft_changed_error_code import ShareDraftChangedErrorCode
+from .share_kind_count import ShareKindCount
+from .share_kind_count_kind import ShareKindCountKind
+from .share_preview import SharePreview
+from .share_preview_release import SharePreviewRelease
+from .share_release import ShareRelease
+from .share_release_create_request import ShareReleaseCreateRequest
+from .share_release_draft import ShareReleaseDraft
+from .share_release_draft_frontend_variables import ShareReleaseDraftFrontendVariables
+from .share_release_function import ShareReleaseFunction
+from .share_release_function_kind import ShareReleaseFunctionKind
+from .share_release_function_variable_scope import ShareReleaseFunctionVariableScope
+from .share_release_omission import ShareReleaseOmission
+from .share_release_omission_kind import ShareReleaseOmissionKind
+from .share_release_ref import ShareReleaseRef
+from .share_stats import ShareStats
+from .share_status import ShareStatus
+from .share_update_request import ShareUpdateRequest
+from .share_update_request_status import ShareUpdateRequestStatus
+from .share_variable import ShareVariable
+from .shares_response import SharesResponse
+from .slack_authorization_response import SlackAuthorizationResponse
+from .slack_channel import SlackChannel
+from .slack_channels_response import SlackChannelsResponse
+from .slack_connection import SlackConnection
+from .slack_connections_response import SlackConnectionsResponse
+from .slack_connector import SlackConnector
from .start_git_connect_provider import StartGitConnectProvider
from .storage_bucket import StorageBucket
from .storage_copy_request import StorageCopyRequest
@@ -632,23 +861,27 @@
from .update_auth_hosted_page_request import UpdateAuthHostedPageRequest
from .update_auth_page_layout_request import UpdateAuthPageLayoutRequest
from .update_auth_page_theme_request import UpdateAuthPageThemeRequest
-from .update_autofix_settings_request import UpdateAutofixSettingsRequest
from .update_database_branch_request import UpdateDatabaseBranchRequest
from .update_database_type_request import UpdateDatabaseTypeRequest
from .update_database_type_request_database_type import UpdateDatabaseTypeRequestDatabaseType
from .update_email_template_request import UpdateEmailTemplateRequest
from .update_email_template_type import UpdateEmailTemplateType
+from .update_frontend_custom_domain_request import UpdateFrontendCustomDomainRequest
from .update_function_request import UpdateFunctionRequest
from .update_function_request_openapi_spec_type_0 import UpdateFunctionRequestOpenapiSpecType0
from .update_function_scheduler_request import UpdateFunctionSchedulerRequest
from .update_function_scheduler_request_payload import UpdateFunctionSchedulerRequestPayload
from .update_issue_request import UpdateIssueRequest
+from .update_notification_email import UpdateNotificationEmail
+from .update_notification_settings_request import UpdateNotificationSettingsRequest
+from .update_notification_webhook import UpdateNotificationWebhook
from .update_o_auth_config_provider import UpdateOAuthConfigProvider
from .update_o_auth_config_request import UpdateOAuthConfigRequest
from .update_project_git_deploy_settings_request import UpdateProjectGitDeploySettingsRequest
from .update_project_request import UpdateProjectRequest
from .update_realtime_config_request import UpdateRealtimeConfigRequest
from .update_sandbox_template_request import UpdateSandboxTemplateRequest
+from .update_scheduler_failure_alert_policy import UpdateSchedulerFailureAlertPolicy
from .update_storage_bucket_request import UpdateStorageBucketRequest
from .update_variable_request import UpdateVariableRequest
from .upload_project_logo_body import UploadProjectLogoBody
@@ -668,6 +901,9 @@
from .verify_domain_request import VerifyDomainRequest
__all__ = (
+ "AccountSession",
+ "AccountSessionKind",
+ "AccountSessionList",
"AnonKey",
"AuthCancelEmailChangeResponse200",
"AuthConfig",
@@ -758,23 +994,6 @@
"AuthUserAppMetadata",
"AuthUserStatus",
"AuthUserUserMetadata",
- "AutofixDiagnosis",
- "AutofixDiagnosisConfidence",
- "AutofixEdit",
- "AutofixEvidence",
- "AutofixEvidenceKind",
- "AutofixModel",
- "AutofixPatch",
- "AutofixProvider",
- "AutofixPullRequest",
- "AutofixPullRequestSkipped",
- "AutofixPullRequestState",
- "AutofixRun",
- "AutofixRunStatus",
- "AutofixRunTrigger",
- "AutofixRunUsage",
- "AutofixSettings",
- "AutofixStage",
"BanAuthUserBody",
"BanUserResponse",
"BanUserResponseStatus",
@@ -802,6 +1021,9 @@
"CompleteUploadSessionResponse",
"ConfigureAuthMethodsBody",
"ConfigureAuthMethodsBodyOauthProvidersItem",
+ "Connector",
+ "ConnectorsResponse",
+ "ConnectorType",
"ConnectProjectGitRequest",
"CreateAnonKeyBody",
"CreateAnonKeyBodyPermissionsItem",
@@ -820,8 +1042,12 @@
"CreateFrontendBody",
"CreateFrontendBodyFramework",
"CreateFrontendBodyVariableScope",
+ "CreateFrontendCandidateBody",
"CreateFrontendCustomDomainRequest",
+ "CreateFrontendDeploymentRequest",
+ "CreateFrontendDomainRequest",
"CreateFrontendFunctionRouteRequest",
+ "CreateFrontendRouteRequest",
"CreateFunctionBody",
"CreateFunctionBodyRuntime",
"CreateFunctionBodyVariableScope",
@@ -858,6 +1084,25 @@
"DatabaseDeleteRequest",
"DatabaseInsertRequest",
"DatabaseInsertRequestValues",
+ "DatabaseMigrationBaseline",
+ "DatabaseMigrationConflictError",
+ "DatabaseMigrationFile",
+ "DatabaseMigrationFileError",
+ "DatabaseMigrationFilesRequest",
+ "DatabaseMigrationHistoryEntry",
+ "DatabaseMigrationHistoryEntryStatus",
+ "DatabaseMigrationRun",
+ "DatabaseMigrationRunError",
+ "DatabaseMigrationRunErrorCode",
+ "DatabaseMigrationRunFile",
+ "DatabaseMigrationRunFileOutcome",
+ "DatabaseMigrationRunList",
+ "DatabaseMigrationRunPhase",
+ "DatabaseMigrationRunSource",
+ "DatabaseMigrationRunStatus",
+ "DatabaseMigrations",
+ "DatabaseMigrationWarning",
+ "DatabaseMigrationWarningCode",
"DatabaseQueryFilter",
"DatabaseQueryFilterOperator",
"DatabaseQueryOrder",
@@ -867,6 +1112,7 @@
"DatabaseQueryResult",
"DatabaseQueryResultDataItem",
"DatabaseRestore",
+ "DatabaseRestoreConflictError",
"DatabaseRestoreKind",
"DatabaseRestoreList",
"DatabaseRestoreStatus",
@@ -877,11 +1123,15 @@
"DatabaseStatus",
"DatabaseUpdateRequest",
"DatabaseUpdateRequestValues",
+ "DefaultEmailTemplate",
+ "DefaultEmailTemplateType",
"DeleteDatabaseBackupResponse200",
"DeleteDatabaseBranchResponse202",
"DeleteDatabaseResponse202",
"DeleteEmailTemplateType",
"DeleteOAuthConfigProvider",
+ "DeploymentCommit",
+ "DeploymentCommitVerification",
"DeploymentPhase",
"DeploymentPhaseName",
"DeploymentPhaseStatus",
@@ -937,8 +1187,21 @@
"Error",
"ExportProjectSourceRequest",
"FailDurableCallbackRequest",
+ "ForkCreateRequest",
+ "ForkCreateRequestVariables",
"Frontend",
+ "FrontendCandidate",
+ "FrontendCandidateConfigurationStatus",
+ "FrontendCandidateDeployment",
+ "FrontendCandidateDeploymentStatus",
+ "FrontendCandidateList",
+ "FrontendCandidateStatus",
"FrontendCustomDomainConflictError",
+ "FrontendCustomDomainList",
+ "FrontendCustomDomainRedirect",
+ "FrontendCustomDomainRedirectRequest",
+ "FrontendCustomDomainRedirectRequestStatus",
+ "FrontendCustomDomainRedirectStatus",
"FrontendCustomDomainResponse",
"FrontendCustomDomainResponseDomainStatus",
"FrontendCustomDomainResponseServingCertificate",
@@ -957,6 +1220,9 @@
"FrontendFramework",
"FrontendFunctionRoute",
"FrontendFunctionRouteList",
+ "FrontendRoute",
+ "FrontendRouteList",
+ "FrontendServing",
"FrontendStatus",
"FrontendUsageDailyEntry",
"FrontendUsageData",
@@ -980,6 +1246,8 @@
"FunctionRuntimeOption",
"FunctionRuntimesResponse",
"FunctionScheduler",
+ "FunctionSchedulerHealth",
+ "FunctionSchedulerLastRunStatus",
"FunctionSchedulerListResponse",
"FunctionSchedulerPayload",
"FunctionSchedulerScheduleKind",
@@ -993,6 +1261,7 @@
"GetDefaultEmailTemplatesResponse200",
"GetDefaultEmailTemplateType",
"GetEmailTemplateType",
+ "GetLavaflowStatsCategory",
"GetOAuthConfigProvider",
"GetOAuthProviderTokenProvider",
"GetOAuthProviderTokenResponse200",
@@ -1000,10 +1269,15 @@
"GitConnection",
"GitConnectionsResponse",
"GitConnectStartResponse",
+ "GitDeploymentMigrationRun",
+ "GitDeploymentRun",
+ "GitDeploymentRunError",
+ "GitDeploymentRunStatus",
"GitInstallation",
"GitInstallationsResponse",
"GitRepositoriesResponse",
"GitRepository",
+ "GitRepositoryReference",
"HeartbeatDurableCallbackRequest",
"HostedAuthPageType",
"HostedLoginEmailCheckRequest",
@@ -1017,7 +1291,116 @@
"ImportSource",
"ImportSourcesResponse",
"Issue",
+ "IssueFinding",
+ "IssueFindingSeverity",
+ "IssueSource",
"IssueStatus",
+ "LavaflowAllowedWorkflow",
+ "LavaflowAnomaly",
+ "LavaflowAutonomy",
+ "LavaflowCategoryCounts",
+ "LavaflowCodeQualitySettings",
+ "LavaflowCodeQualityUpdate",
+ "LavaflowCommitOrigin",
+ "LavaflowConnectorBinding",
+ "LavaflowConnectorBindingCreate",
+ "LavaflowConnectorBindingsResponse",
+ "LavaflowDayCounts",
+ "LavaflowDiagnosis",
+ "LavaflowDraftReason",
+ "LavaflowFailure",
+ "LavaflowFixOutcome",
+ "LavaflowFixOutcomeState",
+ "LavaflowGlobalSkill",
+ "LavaflowGlobalSkillAppliesTo",
+ "LavaflowGlobalSkillList",
+ "LavaflowHeldFixOpen",
+ "LavaflowHeldWorkflows",
+ "LavaflowHoldReason",
+ "LavaflowInvolvedResource",
+ "LavaflowInvolvedResourceCount",
+ "LavaflowInvolvedResourceRolesItem",
+ "LavaflowIssueSummary",
+ "LavaflowIssueSummarySeverity",
+ "LavaflowLineage",
+ "LavaflowLineageConfidence",
+ "LavaflowLineageEvidence",
+ "LavaflowLineageEvidenceConfidence",
+ "LavaflowLineageEvidenceDeployment",
+ "LavaflowLineageRelation",
+ "LavaflowLineageRemedy",
+ "LavaflowLineageState",
+ "LavaflowLogLine",
+ "LavaflowMerge",
+ "LavaflowMergePolicy",
+ "LavaflowMergePolicyUpdate",
+ "LavaflowMergeStatus",
+ "LavaflowPullRequest",
+ "LavaflowPullRequestState",
+ "LavaflowPullRequestStateCounts",
+ "LavaflowRepositoryCheckCommand",
+ "LavaflowRepositoryChecks",
+ "LavaflowResource",
+ "LavaflowResourceList",
+ "LavaflowResourceReference",
+ "LavaflowResourceReferenceType",
+ "LavaflowReview",
+ "LavaflowReviewFinding",
+ "LavaflowReviewFindingSeverity",
+ "LavaflowReviewPersonReason",
+ "LavaflowReviewStop",
+ "LavaflowReviewVerdict",
+ "LavaflowRun",
+ "LavaflowRunCategory",
+ "LavaflowRunCounts",
+ "LavaflowRunCreate",
+ "LavaflowRunMode",
+ "LavaflowRunProgress",
+ "LavaflowRunProgressStage",
+ "LavaflowRunReference",
+ "LavaflowRunStatus",
+ "LavaflowRunStatusCounts",
+ "LavaflowRunSummary",
+ "LavaflowScan",
+ "LavaflowScanBilledFinding",
+ "LavaflowScanBilledFindingBillableEvents",
+ "LavaflowScanCounts",
+ "LavaflowScanResource",
+ "LavaflowScanResourceResourceType",
+ "LavaflowScanSource",
+ "LavaflowScanStatus",
+ "LavaflowSettings",
+ "LavaflowSettingsUpdate",
+ "LavaflowSkill",
+ "LavaflowSkillAppliesTo",
+ "LavaflowSkillAppliesToUpdate",
+ "LavaflowSkillCitation",
+ "LavaflowSkillCounts",
+ "LavaflowSkillError",
+ "LavaflowSkillErrorRulesItem",
+ "LavaflowSkillLearning",
+ "LavaflowSkillList",
+ "LavaflowSkillRetiredReason",
+ "LavaflowSkillScope",
+ "LavaflowSkillSource",
+ "LavaflowSkillSourceAct",
+ "LavaflowSkillSourceKind",
+ "LavaflowSkillStatus",
+ "LavaflowSkillUpdate",
+ "LavaflowSkillUpdateStatus",
+ "LavaflowSkillVersion",
+ "LavaflowSkillVersionList",
+ "LavaflowSkipReason",
+ "LavaflowSlackBinding",
+ "LavaflowSlackBindingTarget",
+ "LavaflowSourceCommit",
+ "LavaflowSourceUnavailable",
+ "LavaflowSourceUnavailableReason",
+ "LavaflowStats",
+ "LavaflowStatsTotals",
+ "LavaflowWorkflowSource",
+ "ListAccountSessionsSort",
+ "ListAccountSessionsStatus",
"ListAnonKeysResponse200",
"ListAuthUsersStatus",
"ListAvailableOAuthProvidersResponse200",
@@ -1029,6 +1412,11 @@
"ListDeploymentsResourceType",
"ListDeploymentsStatus",
"ListEmailTemplatesResponse200",
+ "ListLavaflowResourcesCategory",
+ "ListLavaflowRunsCategory",
+ "ListLavaflowRunsIncludeItem",
+ "ListLavaflowRunsOrder",
+ "ListLavaflowRunsPullRequestState",
"ListOAuthConfigsResponse200",
"ListPostgresVersionsResponse200Item",
"ListProjectDeploymentsResourceType",
@@ -1065,13 +1453,19 @@
"ManagedProjectConfigFrontendCustomDomainTLSConfig",
"ManagedProjectConfigFrontendCustomDomainTLSConfigMode",
"MetricUsageData",
+ "NotificationEmailSettings",
+ "NotificationEmailStatus",
+ "NotificationSettings",
+ "NotificationTestDelivery",
+ "NotificationTestDeliveryChannel",
+ "NotificationTestResult",
+ "NotificationWebhookSettings",
"OAuthConfig",
"OAuthConfigProvider",
"OAuthErrorResponse",
"OpenAPISpecDocument",
"OpenDurableMessageSessionRequest",
"PaginatedAuthUsers",
- "PaginatedAutofixRuns",
"PaginatedDatabases",
"PaginatedDurableApprovals",
"PaginatedDurableExecutions",
@@ -1080,13 +1474,17 @@
"PaginatedFrontends",
"PaginatedFunctionDeployments",
"PaginatedFunctions",
+ "PaginatedGitDeploymentRuns",
"PaginatedIssues",
+ "PaginatedLavaflowRuns",
+ "PaginatedLavaflowScans",
"PaginatedProjectAccessTokens",
"PaginatedProjectCustomDomains",
"PaginatedProjectDeployments",
"PaginatedProjects",
"PaginatedProjectsStatus",
"PaginatedServiceKeys",
+ "PaginatedShareReleases",
"PaginatedStorageBuckets",
"PaginatedVariables",
"PlatformExchangeResponse",
@@ -1123,26 +1521,31 @@
"ProjectConfigAuthSignup",
"ProjectConfigAuthSignupAllowedEmailDomainsMode",
"ProjectConfigAuthTokens",
- "ProjectConfigAutofix",
"ProjectConfigBucket",
"ProjectConfigBucketPolicy",
"ProjectConfigBucketPolicyOperation",
"ProjectConfigCustomDomain",
+ "ProjectConfigCustomDomainRedirect",
+ "ProjectConfigCustomDomainRedirectStatus",
"ProjectConfigDatabase",
"ProjectConfigDatabaseDatabaseType",
"ProjectConfigDatabasePgVersion",
"ProjectConfigEmailTemplate",
"ProjectConfigEmailTemplates",
"ProjectConfigFrontend",
+ "ProjectConfigFrontendCustomDomain",
"ProjectConfigFrontendFunctionRoute",
+ "ProjectConfigFrontendRoute",
"ProjectConfigFrontendVariableScope",
"ProjectConfigFunction",
"ProjectConfigFunctionOpenapiSpecType0",
"ProjectConfigFunctionVariableScope",
"ProjectConfigHostedPage",
"ProjectConfigHostedPages",
+ "ProjectConfigLavaFlow",
"ProjectConfigMissingResource",
"ProjectConfigMissingResourceType",
+ "ProjectConfigNotifications",
"ProjectConfigOAuthProvider",
"ProjectConfigOAuthProviderProvider",
"ProjectConfigProject",
@@ -1169,6 +1572,8 @@
"ProjectGitConnection",
"ProjectGitConnectionSummary",
"ProjectGitDeploySettings",
+ "ProjectGitOwnerPush",
+ "ProjectGitOwnerPushReason",
"ProjectHealthCategory",
"ProjectHealthCheck",
"ProjectHealthDataStatus",
@@ -1222,8 +1627,11 @@
"ProjectStatus",
"ProjectTemplateInstallation",
"ProjectTemplateInstallationPhase",
+ "ProjectTemplateInstallationSource",
+ "ProjectTemplateInstallationSourceKind",
"ProjectTemplateInstallationStatus",
"ProjectUsageResponse",
+ "PromoteFrontendCandidateBody",
"PublishDurableMessageRequest",
"PublishSandboxPresetRequest",
"PublishSandboxPresetRequestMemoryMb",
@@ -1231,6 +1639,7 @@
"RealtimeConfig",
"RealtimePlanLimits",
"RealtimeStats",
+ "RedeployFrontendCandidateBody",
"RefreshOAuthProviderTokenProvider",
"RefreshOAuthProviderTokenResponse200",
"RegisterDurableCallbackRequest",
@@ -1244,6 +1653,7 @@
"ResolveFunctionResponse",
"ResourceReference",
"ResourceReferenceType",
+ "RollbackFrontendServingBody",
"SandboxAccess",
"SandboxAccessRequest",
"SandboxBuildLogPage",
@@ -1256,15 +1666,32 @@
"SandboxDeployment",
"SandboxDeploymentPage",
"SandboxExecutionResult",
+ "SandboxFileArchive",
+ "SandboxFileArchiveForm",
+ "SandboxFileEntry",
+ "SandboxFileEntrySha256Skipped",
+ "SandboxFileEntryType",
+ "SandboxFileListResult",
+ "SandboxFilePart",
+ "SandboxFilePartRequest",
"SandboxFileReadRequest",
"SandboxFileResult",
"SandboxFileWriteRequest",
+ "SandboxLimitsApplied",
"SandboxPagination",
"SandboxPreset",
"SandboxPresetList",
"SandboxPresetMemoryMb",
"SandboxSession",
+ "SandboxSessionAppliedLimits",
"SandboxSessionDesiredState",
+ "SandboxSessionExecutions",
+ "SandboxSessionLimits",
+ "SandboxSessionNetwork",
+ "SandboxSessionNetworkApplied",
+ "SandboxSessionNetworkEgress",
+ "SandboxSessionNetworkRequest",
+ "SandboxSessionNetworkRequestEgress",
"SandboxSessionPage",
"SandboxSessionState",
"SandboxSubjectGrantRequest",
@@ -1273,9 +1700,44 @@
"SandboxTemplateStatus",
"ScheduleRequest",
"ScheduleRequestKind",
+ "SchedulerFailureAlertPolicy",
+ "SchedulerFailureNotifyOn",
"SendDurableMessageRequest",
"ServiceKey",
"SetProjectGitProductionBranchRequest",
+ "SetProjectGitRootDirectoryRequest",
+ "Share",
+ "ShareCreateRequest",
+ "ShareDailyCount",
+ "ShareDailyCountKind",
+ "ShareDraftChangedError",
+ "ShareDraftChangedErrorCode",
+ "ShareKindCount",
+ "ShareKindCountKind",
+ "SharePreview",
+ "SharePreviewRelease",
+ "ShareRelease",
+ "ShareReleaseCreateRequest",
+ "ShareReleaseDraft",
+ "ShareReleaseDraftFrontendVariables",
+ "ShareReleaseFunction",
+ "ShareReleaseFunctionKind",
+ "ShareReleaseFunctionVariableScope",
+ "ShareReleaseOmission",
+ "ShareReleaseOmissionKind",
+ "ShareReleaseRef",
+ "SharesResponse",
+ "ShareStats",
+ "ShareStatus",
+ "ShareUpdateRequest",
+ "ShareUpdateRequestStatus",
+ "ShareVariable",
+ "SlackAuthorizationResponse",
+ "SlackChannel",
+ "SlackChannelsResponse",
+ "SlackConnection",
+ "SlackConnectionsResponse",
+ "SlackConnector",
"StartGitConnectProvider",
"StorageBucket",
"StorageCopyRequest",
@@ -1300,23 +1762,27 @@
"UpdateAuthHostedPageRequest",
"UpdateAuthPageLayoutRequest",
"UpdateAuthPageThemeRequest",
- "UpdateAutofixSettingsRequest",
"UpdateDatabaseBranchRequest",
"UpdateDatabaseTypeRequest",
"UpdateDatabaseTypeRequestDatabaseType",
"UpdateEmailTemplateRequest",
"UpdateEmailTemplateType",
+ "UpdateFrontendCustomDomainRequest",
"UpdateFunctionRequest",
"UpdateFunctionRequestOpenapiSpecType0",
"UpdateFunctionSchedulerRequest",
"UpdateFunctionSchedulerRequestPayload",
"UpdateIssueRequest",
+ "UpdateNotificationEmail",
+ "UpdateNotificationSettingsRequest",
+ "UpdateNotificationWebhook",
"UpdateOAuthConfigProvider",
"UpdateOAuthConfigRequest",
"UpdateProjectGitDeploySettingsRequest",
"UpdateProjectRequest",
"UpdateRealtimeConfigRequest",
"UpdateSandboxTemplateRequest",
+ "UpdateSchedulerFailureAlertPolicy",
"UpdateStorageBucketRequest",
"UpdateVariableRequest",
"UploadProjectLogoBody",
diff --git a/src/volcano_sdk/_generated/models/account_session.py b/src/volcano_sdk/_generated/models/account_session.py
new file mode 100644
index 00000000..953e9f69
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/account_session.py
@@ -0,0 +1,254 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.account_session_kind import AccountSessionKind
+from ..models.account_session_kind import check_account_session_kind
+from ..types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+import datetime
+
+
+
+
+
+
+T = TypeVar("T", bound="AccountSession")
+
+
+
+@_attrs_define
+class AccountSession:
+ """ A sign-in to your Volcano account, from the CLI or a browser.
+
+ Attributes:
+ id (UUID): Unique session identifier
+ user_id (UUID): The sign-in identity (auth user) the session belongs to. This is
+ not your account ID: an identity linked to your account has its
+ own ID.
+ provider (str): How the session was created: `email`, `google`, `github`,
+ `microsoft`, `apple`, or `device:` for a device-code
+ login such as the `volcano` CLI. More values may be added; use
+ `kind` to tell CLI logins from browser sign-ins.
+ Example: github.
+ kind (AccountSessionKind): `cli` for a device-code login, such as `volcano login`, and
+ `browser` for every other sign-in.
+ Example: cli.
+ expires_at (datetime.datetime): When this session expires
+ is_active (bool): Whether the session is currently active (not expired)
+ is_current (bool): Whether this is the session making the current request
+ user_agent (str | Unset): Browser/device user agent string
+ ip_address (str | Unset): IP address of the client when the session was created
+ last_ip_address (str | Unset): IP address of the most recent activity (token refresh)
+ last_activity_at (datetime.datetime | Unset): Last activity timestamp
+ session_started_at (datetime.datetime | Unset): When the session was created
+ created_at (datetime.datetime | Unset):
+ updated_at (datetime.datetime | Unset):
+ """
+
+ id: UUID
+ user_id: UUID
+ provider: str
+ kind: AccountSessionKind
+ expires_at: datetime.datetime
+ is_active: bool
+ is_current: bool
+ user_agent: str | Unset = UNSET
+ ip_address: str | Unset = UNSET
+ last_ip_address: str | Unset = UNSET
+ last_activity_at: datetime.datetime | Unset = UNSET
+ session_started_at: datetime.datetime | Unset = UNSET
+ created_at: datetime.datetime | Unset = UNSET
+ updated_at: datetime.datetime | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ id = str(self.id)
+
+ user_id = str(self.user_id)
+
+ provider = self.provider
+
+ kind: str = self.kind
+
+ expires_at = self.expires_at.isoformat()
+
+ is_active = self.is_active
+
+ is_current = self.is_current
+
+ user_agent = self.user_agent
+
+ ip_address = self.ip_address
+
+ last_ip_address = self.last_ip_address
+
+ last_activity_at: str | Unset = UNSET
+ if not isinstance(self.last_activity_at, Unset):
+ last_activity_at = self.last_activity_at.isoformat()
+
+ session_started_at: str | Unset = UNSET
+ if not isinstance(self.session_started_at, Unset):
+ session_started_at = self.session_started_at.isoformat()
+
+ created_at: str | Unset = UNSET
+ if not isinstance(self.created_at, Unset):
+ created_at = self.created_at.isoformat()
+
+ updated_at: str | Unset = UNSET
+ if not isinstance(self.updated_at, Unset):
+ updated_at = self.updated_at.isoformat()
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "user_id": user_id,
+ "provider": provider,
+ "kind": kind,
+ "expires_at": expires_at,
+ "is_active": is_active,
+ "is_current": is_current,
+ })
+ if user_agent is not UNSET:
+ field_dict["user_agent"] = user_agent
+ if ip_address is not UNSET:
+ field_dict["ip_address"] = ip_address
+ if last_ip_address is not UNSET:
+ field_dict["last_ip_address"] = last_ip_address
+ if last_activity_at is not UNSET:
+ field_dict["last_activity_at"] = last_activity_at
+ if session_started_at is not UNSET:
+ field_dict["session_started_at"] = session_started_at
+ if created_at is not UNSET:
+ field_dict["created_at"] = created_at
+ if updated_at is not UNSET:
+ field_dict["updated_at"] = updated_at
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ user_id = UUID(d.pop("user_id"))
+
+
+
+
+ provider = d.pop("provider")
+
+ kind = check_account_session_kind(d.pop("kind"))
+
+
+
+
+ expires_at = datetime.datetime.fromisoformat(d.pop("expires_at"))
+
+
+
+
+ is_active = d.pop("is_active")
+
+ is_current = d.pop("is_current")
+
+ user_agent = d.pop("user_agent", UNSET)
+
+ ip_address = d.pop("ip_address", UNSET)
+
+ last_ip_address = d.pop("last_ip_address", UNSET)
+
+ _last_activity_at = d.pop("last_activity_at", UNSET)
+ last_activity_at: datetime.datetime | Unset
+ if isinstance(_last_activity_at, Unset):
+ last_activity_at = UNSET
+ else:
+ last_activity_at = datetime.datetime.fromisoformat(_last_activity_at)
+
+
+
+
+ _session_started_at = d.pop("session_started_at", UNSET)
+ session_started_at: datetime.datetime | Unset
+ if isinstance(_session_started_at, Unset):
+ session_started_at = UNSET
+ else:
+ session_started_at = datetime.datetime.fromisoformat(_session_started_at)
+
+
+
+
+ _created_at = d.pop("created_at", UNSET)
+ created_at: datetime.datetime | Unset
+ if isinstance(_created_at, Unset):
+ created_at = UNSET
+ else:
+ created_at = datetime.datetime.fromisoformat(_created_at)
+
+
+
+
+ _updated_at = d.pop("updated_at", UNSET)
+ updated_at: datetime.datetime | Unset
+ if isinstance(_updated_at, Unset):
+ updated_at = UNSET
+ else:
+ updated_at = datetime.datetime.fromisoformat(_updated_at)
+
+
+
+
+ account_session = cls(
+ id=id,
+ user_id=user_id,
+ provider=provider,
+ kind=kind,
+ expires_at=expires_at,
+ is_active=is_active,
+ is_current=is_current,
+ user_agent=user_agent,
+ ip_address=ip_address,
+ last_ip_address=last_ip_address,
+ last_activity_at=last_activity_at,
+ session_started_at=session_started_at,
+ created_at=created_at,
+ updated_at=updated_at,
+ )
+
+
+ account_session.additional_properties = d
+ return account_session
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/account_session_kind.py b/src/volcano_sdk/_generated/models/account_session_kind.py
new file mode 100644
index 00000000..1971e75d
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/account_session_kind.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+AccountSessionKind = Literal['browser', 'cli']
+
+ACCOUNT_SESSION_KIND_VALUES: set[AccountSessionKind] = { 'browser', 'cli', }
+
+def check_account_session_kind(value: str) -> AccountSessionKind:
+ if value in ACCOUNT_SESSION_KIND_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {ACCOUNT_SESSION_KIND_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/account_session_list.py b/src/volcano_sdk/_generated/models/account_session_list.py
new file mode 100644
index 00000000..21a80b9c
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/account_session_list.py
@@ -0,0 +1,193 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.account_session import AccountSession
+
+
+
+
+
+T = TypeVar("T", bound="AccountSessionList")
+
+
+
+@_attrs_define
+class AccountSessionList:
+ """ A page of sessions. Without `sort` the body is the legacy
+ `sessions`/`total`/`page`/`limit`/`total_pages` shape; with
+ `sort=created_at` and a cursor it is the shared `data` envelope.
+
+ Attributes:
+ sessions (list[AccountSession] | Unset):
+ total (int | Unset): Total number of sessions
+ page (int | Unset): Current page number
+ limit (int | Unset): Number of sessions per page
+ total_pages (int | Unset): Total number of pages
+ data (list[AccountSession] | Unset): Sessions for this page (cursor pagination only)
+ has_more (bool | Unset): Whether a further page exists (cursor pagination only)
+ next_cursor (str | Unset): Opaque cursor for the next page (cursor pagination only)
+ prev_cursor (str | Unset): Opaque cursor for the previous page (cursor pagination only). Send as
+ `ending_before`.
+ """
+
+ sessions: list[AccountSession] | Unset = UNSET
+ total: int | Unset = UNSET
+ page: int | Unset = UNSET
+ limit: int | Unset = UNSET
+ total_pages: int | Unset = UNSET
+ data: list[AccountSession] | Unset = UNSET
+ has_more: bool | Unset = UNSET
+ next_cursor: str | Unset = UNSET
+ prev_cursor: str | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.account_session import AccountSession # noqa: PLC0415
+ sessions: list[dict[str, Any]] | Unset = UNSET
+ if not isinstance(self.sessions, Unset):
+ sessions = []
+ for sessions_item_data in self.sessions:
+ sessions_item = sessions_item_data.to_dict()
+ sessions.append(sessions_item)
+
+
+
+ total = self.total
+
+ page = self.page
+
+ limit = self.limit
+
+ total_pages = self.total_pages
+
+ data: list[dict[str, Any]] | Unset = UNSET
+ if not isinstance(self.data, Unset):
+ data = []
+ for data_item_data in self.data:
+ data_item = data_item_data.to_dict()
+ data.append(data_item)
+
+
+
+ has_more = self.has_more
+
+ next_cursor = self.next_cursor
+
+ prev_cursor = self.prev_cursor
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ })
+ if sessions is not UNSET:
+ field_dict["sessions"] = sessions
+ if total is not UNSET:
+ field_dict["total"] = total
+ if page is not UNSET:
+ field_dict["page"] = page
+ if limit is not UNSET:
+ field_dict["limit"] = limit
+ if total_pages is not UNSET:
+ field_dict["total_pages"] = total_pages
+ if data is not UNSET:
+ field_dict["data"] = data
+ if has_more is not UNSET:
+ field_dict["has_more"] = has_more
+ if next_cursor is not UNSET:
+ field_dict["next_cursor"] = next_cursor
+ if prev_cursor is not UNSET:
+ field_dict["prev_cursor"] = prev_cursor
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.account_session import AccountSession # noqa: PLC0415
+ d = dict(src_dict)
+ _sessions = d.pop("sessions", UNSET)
+ sessions: list[AccountSession] | Unset = UNSET
+ if _sessions is not UNSET:
+ sessions = []
+ for sessions_item_data in _sessions:
+ sessions_item = AccountSession.from_dict(sessions_item_data)
+
+
+
+ sessions.append(sessions_item)
+
+
+ total = d.pop("total", UNSET)
+
+ page = d.pop("page", UNSET)
+
+ limit = d.pop("limit", UNSET)
+
+ total_pages = d.pop("total_pages", UNSET)
+
+ _data = d.pop("data", UNSET)
+ data: list[AccountSession] | Unset = UNSET
+ if _data is not UNSET:
+ data = []
+ for data_item_data in _data:
+ data_item = AccountSession.from_dict(data_item_data)
+
+
+
+ data.append(data_item)
+
+
+ has_more = d.pop("has_more", UNSET)
+
+ next_cursor = d.pop("next_cursor", UNSET)
+
+ prev_cursor = d.pop("prev_cursor", UNSET)
+
+ account_session_list = cls(
+ sessions=sessions,
+ total=total,
+ page=page,
+ limit=limit,
+ total_pages=total_pages,
+ data=data,
+ has_more=has_more,
+ next_cursor=next_cursor,
+ prev_cursor=prev_cursor,
+ )
+
+
+ account_session_list.additional_properties = d
+ return account_session_list
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/auth_config.py b/src/volcano_sdk/_generated/models/auth_config.py
index f096393d..651f7ee2 100644
--- a/src/volcano_sdk/_generated/models/auth_config.py
+++ b/src/volcano_sdk/_generated/models/auth_config.py
@@ -82,6 +82,12 @@ class AuthConfig:
max_password_history (int | Unset): Number of previous passwords to remember (0=disabled) Default: 0.
cors_allow_credentials (bool | Unset): Allow credentials in CORS requests Default: True.
cors_max_age (int | Unset): CORS preflight cache duration (seconds) Default: 86400.
+ cors_allow_frontend_previews (bool | Unset): Allow the exact origins of the project's own live frontend previews
+ in its CORS checks, in addition to `cors_allowed_origins`. A preview's origin stops being allowed within seconds
+ of the preview being deleted or expiring, with no configuration change. Default: False.
+ frontend_preview_origins (list[str] | Unset): Origins of the project's live frontend previews that its CORS
+ checks currently allow. Empty unless `cors_allow_frontend_previews` is true. Omitted when the live previews
+ could not be read; the rest of the response, and any update it answers, is unaffected.
require_email_confirmation (bool | Unset): Require users to confirm email before sign-in. Can only be true when
email_enabled is true. Default: False.
email_confirmation_timeout (int | Unset): Email confirmation token expiry in seconds. Default: 86400.
@@ -89,8 +95,13 @@ class AuthConfig:
the same email instead of returning a conflict. Requires require_email_confirmation to be true. Default: False.
email_enabled (bool | Unset): Enable transactional email sending (confirmation, reset, change notifications).
Must be true when require_email_confirmation is true. Default: False.
- email_from_address (str | Unset):
- email_from_name (str | Unset):
+ email_from_address (str | Unset): Sender email address. New or changed values containing carriage returns or
+ newlines return 400. Unchanged stored or exported values are preserved. Leading and trailing whitespace in
+ previously saved settings is trimmed in responses and exports, and ignored when sending.
+ email_from_name (str | Unset): Sender display name; supports punctuation and Unicode. New or changed values
+ containing carriage returns or newlines return 400. Unchanged stored or exported values are preserved. Leading
+ and trailing whitespace in previously saved settings is trimmed in responses and exports, and ignored when
+ sending.
smtp_host (str | Unset):
smtp_port (int | Unset): Default: 587.
smtp_username (str | Unset):
@@ -144,6 +155,8 @@ class AuthConfig:
max_password_history: int | Unset = 0
cors_allow_credentials: bool | Unset = True
cors_max_age: int | Unset = 86400
+ cors_allow_frontend_previews: bool | Unset = False
+ frontend_preview_origins: list[str] | Unset = UNSET
require_email_confirmation: bool | Unset = False
email_confirmation_timeout: int | Unset = 86400
auto_link_verified_oauth: bool | Unset = False
@@ -244,6 +257,14 @@ def to_dict(self) -> dict[str, Any]:
cors_max_age = self.cors_max_age
+ cors_allow_frontend_previews = self.cors_allow_frontend_previews
+
+ frontend_preview_origins: list[str] | Unset = UNSET
+ if not isinstance(self.frontend_preview_origins, Unset):
+ frontend_preview_origins = self.frontend_preview_origins
+
+
+
require_email_confirmation = self.require_email_confirmation
email_confirmation_timeout = self.email_confirmation_timeout
@@ -356,6 +377,10 @@ def to_dict(self) -> dict[str, Any]:
field_dict["cors_allow_credentials"] = cors_allow_credentials
if cors_max_age is not UNSET:
field_dict["cors_max_age"] = cors_max_age
+ if cors_allow_frontend_previews is not UNSET:
+ field_dict["cors_allow_frontend_previews"] = cors_allow_frontend_previews
+ if frontend_preview_origins is not UNSET:
+ field_dict["frontend_preview_origins"] = frontend_preview_origins
if require_email_confirmation is not UNSET:
field_dict["require_email_confirmation"] = require_email_confirmation
if email_confirmation_timeout is not UNSET:
@@ -486,6 +511,11 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
cors_max_age = d.pop("cors_max_age", UNSET)
+ cors_allow_frontend_previews = d.pop("cors_allow_frontend_previews", UNSET)
+
+ frontend_preview_origins = cast(list[str], d.pop("frontend_preview_origins", UNSET))
+
+
require_email_confirmation = d.pop("require_email_confirmation", UNSET)
email_confirmation_timeout = d.pop("email_confirmation_timeout", UNSET)
@@ -575,6 +605,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
max_password_history=max_password_history,
cors_allow_credentials=cors_allow_credentials,
cors_max_age=cors_max_age,
+ cors_allow_frontend_previews=cors_allow_frontend_previews,
+ frontend_preview_origins=frontend_preview_origins,
require_email_confirmation=require_email_confirmation,
email_confirmation_timeout=email_confirmation_timeout,
auto_link_verified_oauth=auto_link_verified_oauth,
diff --git a/src/volcano_sdk/_generated/models/auth_list_o_auth_providers_response_200_providers_item.py b/src/volcano_sdk/_generated/models/auth_list_o_auth_providers_response_200_providers_item.py
index 4765141f..ae4ae15e 100644
--- a/src/volcano_sdk/_generated/models/auth_list_o_auth_providers_response_200_providers_item.py
+++ b/src/volcano_sdk/_generated/models/auth_list_o_auth_providers_response_200_providers_item.py
@@ -25,14 +25,24 @@
class AuthListOAuthProvidersResponse200ProvidersItem:
"""
Attributes:
- provider (str | Unset):
- linked_at (datetime.datetime | Unset):
- updated_at (datetime.datetime | Unset):
+ provider (str):
+ provider_user_id (str): The user's account ID at the provider, as a string.
+ It stays the same when the user renames the account.
+ Example: 583231.
+ linked_at (datetime.datetime):
+ updated_at (datetime.datetime):
+ provider_login (str | Unset): The account's login at the provider when it was
+ linked, such as a GitHub username. It isn't updated
+ when the user renames the account. Omitted for
+ providers without logins.
+ Example: octocat.
"""
- provider: str | Unset = UNSET
- linked_at: datetime.datetime | Unset = UNSET
- updated_at: datetime.datetime | Unset = UNSET
+ provider: str
+ provider_user_id: str
+ linked_at: datetime.datetime
+ updated_at: datetime.datetime
+ provider_login: str | Unset = UNSET
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
@@ -42,25 +52,25 @@ class AuthListOAuthProvidersResponse200ProvidersItem:
def to_dict(self) -> dict[str, Any]:
provider = self.provider
- linked_at: str | Unset = UNSET
- if not isinstance(self.linked_at, Unset):
- linked_at = self.linked_at.isoformat()
+ provider_user_id = self.provider_user_id
- updated_at: str | Unset = UNSET
- if not isinstance(self.updated_at, Unset):
- updated_at = self.updated_at.isoformat()
+ linked_at = self.linked_at.isoformat()
+
+ updated_at = self.updated_at.isoformat()
+
+ provider_login = self.provider_login
field_dict: dict[str, Any] = {}
field_dict.update(self.additional_properties)
field_dict.update({
+ "provider": provider,
+ "provider_user_id": provider_user_id,
+ "linked_at": linked_at,
+ "updated_at": updated_at,
})
- if provider is not UNSET:
- field_dict["provider"] = provider
- if linked_at is not UNSET:
- field_dict["linked_at"] = linked_at
- if updated_at is not UNSET:
- field_dict["updated_at"] = updated_at
+ if provider_login is not UNSET:
+ field_dict["provider_login"] = provider_login
return field_dict
@@ -69,32 +79,28 @@ def to_dict(self) -> dict[str, Any]:
@classmethod
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
d = dict(src_dict)
- provider = d.pop("provider", UNSET)
+ provider = d.pop("provider")
+
+ provider_user_id = d.pop("provider_user_id")
+
+ linked_at = datetime.datetime.fromisoformat(d.pop("linked_at"))
- _linked_at = d.pop("linked_at", UNSET)
- linked_at: datetime.datetime | Unset
- if isinstance(_linked_at, Unset):
- linked_at = UNSET
- else:
- linked_at = datetime.datetime.fromisoformat(_linked_at)
+ updated_at = datetime.datetime.fromisoformat(d.pop("updated_at"))
- _updated_at = d.pop("updated_at", UNSET)
- updated_at: datetime.datetime | Unset
- if isinstance(_updated_at, Unset):
- updated_at = UNSET
- else:
- updated_at = datetime.datetime.fromisoformat(_updated_at)
+ provider_login = d.pop("provider_login", UNSET)
auth_list_o_auth_providers_response_200_providers_item = cls(
provider=provider,
+ provider_user_id=provider_user_id,
linked_at=linked_at,
updated_at=updated_at,
+ provider_login=provider_login,
)
diff --git a/src/volcano_sdk/_generated/models/autofix_diagnosis.py b/src/volcano_sdk/_generated/models/autofix_diagnosis.py
deleted file mode 100644
index 26bacf89..00000000
--- a/src/volcano_sdk/_generated/models/autofix_diagnosis.py
+++ /dev/null
@@ -1,132 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Mapping
-from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
-
-from attrs import define as _attrs_define
-from attrs import field as _attrs_field
-
-from ..types import UNSET, Unset
-
-from ..models.autofix_diagnosis_confidence import AutofixDiagnosisConfidence
-from ..models.autofix_diagnosis_confidence import check_autofix_diagnosis_confidence
-from typing import cast
-
-if TYPE_CHECKING:
- from ..models.autofix_evidence import AutofixEvidence
-
-
-
-
-
-T = TypeVar("T", bound="AutofixDiagnosis")
-
-
-
-@_attrs_define
-class AutofixDiagnosis:
- """
- Attributes:
- summary (str): One or two sentences on what goes wrong.
- root_cause (str):
- evidence (list[AutofixEvidence]):
- suggested_fix (str):
- confidence (AutofixDiagnosisConfidence):
- fixable (bool): Whether a change to the project's code would fix the issue.
- files (list[str]): Repository paths a fix would change.
- """
-
- summary: str
- root_cause: str
- evidence: list[AutofixEvidence]
- suggested_fix: str
- confidence: AutofixDiagnosisConfidence
- fixable: bool
- files: list[str]
-
-
-
-
-
- def to_dict(self) -> dict[str, Any]:
- from ..models.autofix_evidence import AutofixEvidence # noqa: PLC0415
- summary = self.summary
-
- root_cause = self.root_cause
-
- evidence = []
- for evidence_item_data in self.evidence:
- evidence_item = evidence_item_data.to_dict()
- evidence.append(evidence_item)
-
-
-
- suggested_fix = self.suggested_fix
-
- confidence: str = self.confidence
-
- fixable = self.fixable
-
- files = self.files
-
-
-
-
- field_dict: dict[str, Any] = {}
-
- field_dict.update({
- "summary": summary,
- "root_cause": root_cause,
- "evidence": evidence,
- "suggested_fix": suggested_fix,
- "confidence": confidence,
- "fixable": fixable,
- "files": files,
- })
-
- return field_dict
-
-
-
- @classmethod
- def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
- from ..models.autofix_evidence import AutofixEvidence # noqa: PLC0415
- d = dict(src_dict)
- summary = d.pop("summary")
-
- root_cause = d.pop("root_cause")
-
- evidence = []
- _evidence = d.pop("evidence")
- for evidence_item_data in (_evidence):
- evidence_item = AutofixEvidence.from_dict(evidence_item_data)
-
-
-
- evidence.append(evidence_item)
-
-
- suggested_fix = d.pop("suggested_fix")
-
- confidence = check_autofix_diagnosis_confidence(d.pop("confidence"))
-
-
-
-
- fixable = d.pop("fixable")
-
- files = cast(list[str], d.pop("files"))
-
-
- autofix_diagnosis = cls(
- summary=summary,
- root_cause=root_cause,
- evidence=evidence,
- suggested_fix=suggested_fix,
- confidence=confidence,
- fixable=fixable,
- files=files,
- )
-
- return autofix_diagnosis
-
diff --git a/src/volcano_sdk/_generated/models/autofix_diagnosis_confidence.py b/src/volcano_sdk/_generated/models/autofix_diagnosis_confidence.py
deleted file mode 100644
index eeec57dd..00000000
--- a/src/volcano_sdk/_generated/models/autofix_diagnosis_confidence.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from typing import Literal
-
-AutofixDiagnosisConfidence = Literal['high', 'low', 'medium']
-
-AUTOFIX_DIAGNOSIS_CONFIDENCE_VALUES: set[AutofixDiagnosisConfidence] = { 'high', 'low', 'medium', }
-
-def check_autofix_diagnosis_confidence(value: str) -> AutofixDiagnosisConfidence:
- if value in AUTOFIX_DIAGNOSIS_CONFIDENCE_VALUES:
- return value
- raise TypeError(f"Unexpected value {value!r}. Expected one of {AUTOFIX_DIAGNOSIS_CONFIDENCE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/autofix_edit.py b/src/volcano_sdk/_generated/models/autofix_edit.py
deleted file mode 100644
index 2bcb071d..00000000
--- a/src/volcano_sdk/_generated/models/autofix_edit.py
+++ /dev/null
@@ -1,75 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Mapping
-from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
-
-from attrs import define as _attrs_define
-from attrs import field as _attrs_field
-
-from ..types import UNSET, Unset
-
-
-
-
-
-
-
-T = TypeVar("T", bound="AutofixEdit")
-
-
-
-@_attrs_define
-class AutofixEdit:
- """ One exact text replacement. An empty `old_text` creates the file.
-
- Attributes:
- path (str):
- old_text (str):
- new_text (str):
- """
-
- path: str
- old_text: str
- new_text: str
-
-
-
-
-
- def to_dict(self) -> dict[str, Any]:
- path = self.path
-
- old_text = self.old_text
-
- new_text = self.new_text
-
-
- field_dict: dict[str, Any] = {}
-
- field_dict.update({
- "path": path,
- "old_text": old_text,
- "new_text": new_text,
- })
-
- return field_dict
-
-
-
- @classmethod
- def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
- d = dict(src_dict)
- path = d.pop("path")
-
- old_text = d.pop("old_text")
-
- new_text = d.pop("new_text")
-
- autofix_edit = cls(
- path=path,
- old_text=old_text,
- new_text=new_text,
- )
-
- return autofix_edit
-
diff --git a/src/volcano_sdk/_generated/models/autofix_evidence.py b/src/volcano_sdk/_generated/models/autofix_evidence.py
deleted file mode 100644
index 4acd5a3d..00000000
--- a/src/volcano_sdk/_generated/models/autofix_evidence.py
+++ /dev/null
@@ -1,82 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Mapping
-from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
-
-from attrs import define as _attrs_define
-from attrs import field as _attrs_field
-
-from ..types import UNSET, Unset
-
-from ..models.autofix_evidence_kind import AutofixEvidenceKind
-from ..models.autofix_evidence_kind import check_autofix_evidence_kind
-from ..types import UNSET, Unset
-from typing import cast
-
-
-
-
-
-
-T = TypeVar("T", bound="AutofixEvidence")
-
-
-
-@_attrs_define
-class AutofixEvidence:
- """
- Attributes:
- kind (AutofixEvidenceKind):
- detail (str):
- location (str | Unset): A file and line, or a log timestamp. Absent when the evidence has none.
- """
-
- kind: AutofixEvidenceKind
- detail: str
- location: str | Unset = UNSET
-
-
-
-
-
- def to_dict(self) -> dict[str, Any]:
- kind: str = self.kind
-
- detail = self.detail
-
- location = self.location
-
-
- field_dict: dict[str, Any] = {}
-
- field_dict.update({
- "kind": kind,
- "detail": detail,
- })
- if location is not UNSET:
- field_dict["location"] = location
-
- return field_dict
-
-
-
- @classmethod
- def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
- d = dict(src_dict)
- kind = check_autofix_evidence_kind(d.pop("kind"))
-
-
-
-
- detail = d.pop("detail")
-
- location = d.pop("location", UNSET)
-
- autofix_evidence = cls(
- kind=kind,
- detail=detail,
- location=location,
- )
-
- return autofix_evidence
-
diff --git a/src/volcano_sdk/_generated/models/autofix_evidence_kind.py b/src/volcano_sdk/_generated/models/autofix_evidence_kind.py
deleted file mode 100644
index 0723fe78..00000000
--- a/src/volcano_sdk/_generated/models/autofix_evidence_kind.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from typing import Literal
-
-AutofixEvidenceKind = Literal['code', 'log', 'other']
-
-AUTOFIX_EVIDENCE_KIND_VALUES: set[AutofixEvidenceKind] = { 'code', 'log', 'other', }
-
-def check_autofix_evidence_kind(value: str) -> AutofixEvidenceKind:
- if value in AUTOFIX_EVIDENCE_KIND_VALUES:
- return value
- raise TypeError(f"Unexpected value {value!r}. Expected one of {AUTOFIX_EVIDENCE_KIND_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/autofix_model.py b/src/volcano_sdk/_generated/models/autofix_model.py
deleted file mode 100644
index 55871e52..00000000
--- a/src/volcano_sdk/_generated/models/autofix_model.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from typing import Literal
-
-AutofixModel = Literal['claude-fable-5-1', 'claude-haiku-4-5', 'claude-haiku-5-5', 'claude-opus-5', 'claude-opus-5-5', 'claude-sonnet-5', 'claude-sonnet-5-5']
-
-AUTOFIX_MODEL_VALUES: set[AutofixModel] = { 'claude-fable-5-1', 'claude-haiku-4-5', 'claude-haiku-5-5', 'claude-opus-5', 'claude-opus-5-5', 'claude-sonnet-5', 'claude-sonnet-5-5', }
-
-def check_autofix_model(value: str) -> AutofixModel:
- if value in AUTOFIX_MODEL_VALUES:
- return value
- raise TypeError(f"Unexpected value {value!r}. Expected one of {AUTOFIX_MODEL_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/autofix_patch.py b/src/volcano_sdk/_generated/models/autofix_patch.py
deleted file mode 100644
index 62ee2b03..00000000
--- a/src/volcano_sdk/_generated/models/autofix_patch.py
+++ /dev/null
@@ -1,86 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Mapping
-from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
-
-from attrs import define as _attrs_define
-from attrs import field as _attrs_field
-
-from ..types import UNSET, Unset
-
-from typing import cast
-
-if TYPE_CHECKING:
- from ..models.autofix_edit import AutofixEdit
-
-
-
-
-
-T = TypeVar("T", bound="AutofixPatch")
-
-
-
-@_attrs_define
-class AutofixPatch:
- """ The fix the model proposed, applied to the deployed commit. Present whenever the run opened a pull request, and when
- a valid fix could not be published.
-
- Attributes:
- title (str):
- edits (list[AutofixEdit]):
- """
-
- title: str
- edits: list[AutofixEdit]
-
-
-
-
-
- def to_dict(self) -> dict[str, Any]:
- from ..models.autofix_edit import AutofixEdit # noqa: PLC0415
- title = self.title
-
- edits = []
- for edits_item_data in self.edits:
- edits_item = edits_item_data.to_dict()
- edits.append(edits_item)
-
-
-
-
- field_dict: dict[str, Any] = {}
-
- field_dict.update({
- "title": title,
- "edits": edits,
- })
-
- return field_dict
-
-
-
- @classmethod
- def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
- from ..models.autofix_edit import AutofixEdit # noqa: PLC0415
- d = dict(src_dict)
- title = d.pop("title")
-
- edits = []
- _edits = d.pop("edits")
- for edits_item_data in (_edits):
- edits_item = AutofixEdit.from_dict(edits_item_data)
-
-
-
- edits.append(edits_item)
-
-
- autofix_patch = cls(
- title=title,
- edits=edits,
- )
-
- return autofix_patch
-
diff --git a/src/volcano_sdk/_generated/models/autofix_provider.py b/src/volcano_sdk/_generated/models/autofix_provider.py
deleted file mode 100644
index a9c25ca7..00000000
--- a/src/volcano_sdk/_generated/models/autofix_provider.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from typing import Literal
-
-AutofixProvider = Literal['anthropic', 'volcano']
-
-AUTOFIX_PROVIDER_VALUES: set[AutofixProvider] = { 'anthropic', 'volcano', }
-
-def check_autofix_provider(value: str) -> AutofixProvider:
- if value in AUTOFIX_PROVIDER_VALUES:
- return value
- raise TypeError(f"Unexpected value {value!r}. Expected one of {AUTOFIX_PROVIDER_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/autofix_pull_request.py b/src/volcano_sdk/_generated/models/autofix_pull_request.py
deleted file mode 100644
index a8b58ae9..00000000
--- a/src/volcano_sdk/_generated/models/autofix_pull_request.py
+++ /dev/null
@@ -1,131 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Mapping
-from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
-
-from attrs import define as _attrs_define
-from attrs import field as _attrs_field
-
-from ..types import UNSET, Unset
-
-from ..models.autofix_pull_request_state import AutofixPullRequestState
-from ..models.autofix_pull_request_state import check_autofix_pull_request_state
-from ..types import UNSET, Unset
-from typing import cast
-import datetime
-
-
-
-
-
-
-T = TypeVar("T", bound="AutofixPullRequest")
-
-
-
-@_attrs_define
-class AutofixPullRequest:
- """ The draft pull request the run opened on the connected repository.
-
- Attributes:
- number (int):
- url (str):
- branch (str): The branch the fix is on, `volcano/autofix/`.
- state (AutofixPullRequestState):
- closed_at (datetime.datetime | Unset): When the pull request was merged or closed.
- deployed_at (datetime.datetime | Unset): When a deployment that includes the merged fix went live. The issue
- resolves then, unless it occurred again since. When more than 20 deployments went live after the merge before
- Volcano checked, it is the merge time instead.
- """
-
- number: int
- url: str
- branch: str
- state: AutofixPullRequestState
- closed_at: datetime.datetime | Unset = UNSET
- deployed_at: datetime.datetime | Unset = UNSET
-
-
-
-
-
- def to_dict(self) -> dict[str, Any]:
- number = self.number
-
- url = self.url
-
- branch = self.branch
-
- state: str = self.state
-
- closed_at: str | Unset = UNSET
- if not isinstance(self.closed_at, Unset):
- closed_at = self.closed_at.isoformat()
-
- deployed_at: str | Unset = UNSET
- if not isinstance(self.deployed_at, Unset):
- deployed_at = self.deployed_at.isoformat()
-
-
- field_dict: dict[str, Any] = {}
-
- field_dict.update({
- "number": number,
- "url": url,
- "branch": branch,
- "state": state,
- })
- if closed_at is not UNSET:
- field_dict["closed_at"] = closed_at
- if deployed_at is not UNSET:
- field_dict["deployed_at"] = deployed_at
-
- return field_dict
-
-
-
- @classmethod
- def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
- d = dict(src_dict)
- number = d.pop("number")
-
- url = d.pop("url")
-
- branch = d.pop("branch")
-
- state = check_autofix_pull_request_state(d.pop("state"))
-
-
-
-
- _closed_at = d.pop("closed_at", UNSET)
- closed_at: datetime.datetime | Unset
- if isinstance(_closed_at, Unset):
- closed_at = UNSET
- else:
- closed_at = datetime.datetime.fromisoformat(_closed_at)
-
-
-
-
- _deployed_at = d.pop("deployed_at", UNSET)
- deployed_at: datetime.datetime | Unset
- if isinstance(_deployed_at, Unset):
- deployed_at = UNSET
- else:
- deployed_at = datetime.datetime.fromisoformat(_deployed_at)
-
-
-
-
- autofix_pull_request = cls(
- number=number,
- url=url,
- branch=branch,
- state=state,
- closed_at=closed_at,
- deployed_at=deployed_at,
- )
-
- return autofix_pull_request
-
diff --git a/src/volcano_sdk/_generated/models/autofix_pull_request_skipped.py b/src/volcano_sdk/_generated/models/autofix_pull_request_skipped.py
deleted file mode 100644
index 81b39fad..00000000
--- a/src/volcano_sdk/_generated/models/autofix_pull_request_skipped.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from typing import Literal
-
-AutofixPullRequestSkipped = Literal['low_confidence', 'no_patch', 'not_fixable', 'permission_missing', 'publish_failed', 'pull_request_open', 'repository_changed', 'source_unavailable']
-
-AUTOFIX_PULL_REQUEST_SKIPPED_VALUES: set[AutofixPullRequestSkipped] = { 'low_confidence', 'no_patch', 'not_fixable', 'permission_missing', 'publish_failed', 'pull_request_open', 'repository_changed', 'source_unavailable', }
-
-def check_autofix_pull_request_skipped(value: str) -> AutofixPullRequestSkipped:
- if value in AUTOFIX_PULL_REQUEST_SKIPPED_VALUES:
- return value
- raise TypeError(f"Unexpected value {value!r}. Expected one of {AUTOFIX_PULL_REQUEST_SKIPPED_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/autofix_pull_request_state.py b/src/volcano_sdk/_generated/models/autofix_pull_request_state.py
deleted file mode 100644
index 5a7764b9..00000000
--- a/src/volcano_sdk/_generated/models/autofix_pull_request_state.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from typing import Literal
-
-AutofixPullRequestState = Literal['closed', 'merged', 'open']
-
-AUTOFIX_PULL_REQUEST_STATE_VALUES: set[AutofixPullRequestState] = { 'closed', 'merged', 'open', }
-
-def check_autofix_pull_request_state(value: str) -> AutofixPullRequestState:
- if value in AUTOFIX_PULL_REQUEST_STATE_VALUES:
- return value
- raise TypeError(f"Unexpected value {value!r}. Expected one of {AUTOFIX_PULL_REQUEST_STATE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/autofix_run.py b/src/volcano_sdk/_generated/models/autofix_run.py
deleted file mode 100644
index 4fb1f1cb..00000000
--- a/src/volcano_sdk/_generated/models/autofix_run.py
+++ /dev/null
@@ -1,362 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Mapping
-from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
-
-from attrs import define as _attrs_define
-from attrs import field as _attrs_field
-
-from ..types import UNSET, Unset
-
-from ..models.autofix_model import AutofixModel
-from ..models.autofix_model import check_autofix_model
-from ..models.autofix_provider import AutofixProvider
-from ..models.autofix_provider import check_autofix_provider
-from ..models.autofix_pull_request_skipped import AutofixPullRequestSkipped
-from ..models.autofix_pull_request_skipped import check_autofix_pull_request_skipped
-from ..models.autofix_run_status import AutofixRunStatus
-from ..models.autofix_run_status import check_autofix_run_status
-from ..models.autofix_run_trigger import AutofixRunTrigger
-from ..models.autofix_run_trigger import check_autofix_run_trigger
-from ..models.autofix_stage import AutofixStage
-from ..models.autofix_stage import check_autofix_stage
-from ..types import UNSET, Unset
-from typing import cast
-from uuid import UUID
-import datetime
-
-if TYPE_CHECKING:
- from ..models.autofix_diagnosis import AutofixDiagnosis
- from ..models.autofix_patch import AutofixPatch
- from ..models.autofix_pull_request import AutofixPullRequest
- from ..models.autofix_run_usage import AutofixRunUsage
-
-
-
-
-
-T = TypeVar("T", bound="AutofixRun")
-
-
-
-@_attrs_define
-class AutofixRun:
- """
- Attributes:
- id (UUID):
- project_id (UUID):
- issue_id (UUID):
- trigger (AutofixRunTrigger): What started the run. `manual` is a request; `new_issue` and `regression` are
- automatic runs for an issue that appeared or reopened.
- status (AutofixRunStatus): Where a run is. `canceled` means the project's settings or plan stopped allowing the
- run before it finished; `failure_code` says which.
- max_stage (AutofixStage): How far a run may go. `diagnose` stops at a root-cause diagnosis. `pull_request` may
- also open a draft pull request with a fix in the project's connected repository.
- provider (AutofixProvider): Who serves the model. `volcano` runs on Volcano's models. `anthropic` runs on your
- own Anthropic API key.
- model (AutofixModel): The Claude model a run uses. `claude-opus-5-5` is the default.
- usage (AutofixRunUsage): Model tokens the run used across every attempt.
- created_at (datetime.datetime):
- stage_reached (AutofixStage | Unset): How far a run may go. `diagnose` stops at a root-cause diagnosis.
- `pull_request` may also open a draft pull request with a fix in the project's connected repository.
- diagnosis (AutofixDiagnosis | Unset):
- patch (AutofixPatch | Unset): The fix the model proposed, applied to the deployed commit. Present whenever the
- run opened a pull request, and when a valid fix could not be published.
- pull_request (AutofixPullRequest | Unset): The draft pull request the run opened on the connected repository.
- pull_request_skipped (AutofixPullRequestSkipped | Unset): Why a run whose `max_stage` is `pull_request` opened
- no pull request. The diagnosis stands either way.
- commit_sha (str | Unset): The commit the diagnosis read, when a push to the connected repository deployed the
- resource. Absent when the run read logs only.
- failure_code (str | Unset): Why the run failed or was canceled, or why its last attempt will be retried. One of
- `api_key_rejected`, `model_request_rejected`, `model_unavailable`, `model_refused`, `no_diagnosis`,
- `budget_exhausted`, `timed_out`, `attempts_exhausted`, `autofix_disabled`, `plan_required`,
- `managed_models_unavailable`, `settings_changed`, `issue_not_found`, or `internal_error`.
- failure_message (str | Unset):
- started_at (datetime.datetime | Unset):
- completed_at (datetime.datetime | Unset):
- """
-
- id: UUID
- project_id: UUID
- issue_id: UUID
- trigger: AutofixRunTrigger
- status: AutofixRunStatus
- max_stage: AutofixStage
- provider: AutofixProvider
- model: AutofixModel
- usage: AutofixRunUsage
- created_at: datetime.datetime
- stage_reached: AutofixStage | Unset = UNSET
- diagnosis: AutofixDiagnosis | Unset = UNSET
- patch: AutofixPatch | Unset = UNSET
- pull_request: AutofixPullRequest | Unset = UNSET
- pull_request_skipped: AutofixPullRequestSkipped | Unset = UNSET
- commit_sha: str | Unset = UNSET
- failure_code: str | Unset = UNSET
- failure_message: str | Unset = UNSET
- started_at: datetime.datetime | Unset = UNSET
- completed_at: datetime.datetime | Unset = UNSET
-
-
-
-
-
- def to_dict(self) -> dict[str, Any]:
- from ..models.autofix_diagnosis import AutofixDiagnosis # noqa: PLC0415
- from ..models.autofix_patch import AutofixPatch # noqa: PLC0415
- from ..models.autofix_pull_request import AutofixPullRequest # noqa: PLC0415
- from ..models.autofix_run_usage import AutofixRunUsage # noqa: PLC0415
- id = str(self.id)
-
- project_id = str(self.project_id)
-
- issue_id = str(self.issue_id)
-
- trigger: str = self.trigger
-
- status: str = self.status
-
- max_stage: str = self.max_stage
-
- provider: str = self.provider
-
- model: str = self.model
-
- usage = self.usage.to_dict()
-
- created_at = self.created_at.isoformat()
-
- stage_reached: str | Unset = UNSET
- if not isinstance(self.stage_reached, Unset):
- stage_reached = self.stage_reached
-
-
- diagnosis: dict[str, Any] | Unset = UNSET
- if not isinstance(self.diagnosis, Unset):
- diagnosis = self.diagnosis.to_dict()
-
- patch: dict[str, Any] | Unset = UNSET
- if not isinstance(self.patch, Unset):
- patch = self.patch.to_dict()
-
- pull_request: dict[str, Any] | Unset = UNSET
- if not isinstance(self.pull_request, Unset):
- pull_request = self.pull_request.to_dict()
-
- pull_request_skipped: str | Unset = UNSET
- if not isinstance(self.pull_request_skipped, Unset):
- pull_request_skipped = self.pull_request_skipped
-
-
- commit_sha = self.commit_sha
-
- failure_code = self.failure_code
-
- failure_message = self.failure_message
-
- started_at: str | Unset = UNSET
- if not isinstance(self.started_at, Unset):
- started_at = self.started_at.isoformat()
-
- completed_at: str | Unset = UNSET
- if not isinstance(self.completed_at, Unset):
- completed_at = self.completed_at.isoformat()
-
-
- field_dict: dict[str, Any] = {}
-
- field_dict.update({
- "id": id,
- "project_id": project_id,
- "issue_id": issue_id,
- "trigger": trigger,
- "status": status,
- "max_stage": max_stage,
- "provider": provider,
- "model": model,
- "usage": usage,
- "created_at": created_at,
- })
- if stage_reached is not UNSET:
- field_dict["stage_reached"] = stage_reached
- if diagnosis is not UNSET:
- field_dict["diagnosis"] = diagnosis
- if patch is not UNSET:
- field_dict["patch"] = patch
- if pull_request is not UNSET:
- field_dict["pull_request"] = pull_request
- if pull_request_skipped is not UNSET:
- field_dict["pull_request_skipped"] = pull_request_skipped
- if commit_sha is not UNSET:
- field_dict["commit_sha"] = commit_sha
- if failure_code is not UNSET:
- field_dict["failure_code"] = failure_code
- if failure_message is not UNSET:
- field_dict["failure_message"] = failure_message
- if started_at is not UNSET:
- field_dict["started_at"] = started_at
- if completed_at is not UNSET:
- field_dict["completed_at"] = completed_at
-
- return field_dict
-
-
-
- @classmethod
- def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
- from ..models.autofix_diagnosis import AutofixDiagnosis # noqa: PLC0415
- from ..models.autofix_patch import AutofixPatch # noqa: PLC0415
- from ..models.autofix_pull_request import AutofixPullRequest # noqa: PLC0415
- from ..models.autofix_run_usage import AutofixRunUsage # noqa: PLC0415
- d = dict(src_dict)
- id = UUID(d.pop("id"))
-
-
-
-
- project_id = UUID(d.pop("project_id"))
-
-
-
-
- issue_id = UUID(d.pop("issue_id"))
-
-
-
-
- trigger = check_autofix_run_trigger(d.pop("trigger"))
-
-
-
-
- status = check_autofix_run_status(d.pop("status"))
-
-
-
-
- max_stage = check_autofix_stage(d.pop("max_stage"))
-
-
-
-
- provider = check_autofix_provider(d.pop("provider"))
-
-
-
-
- model = check_autofix_model(d.pop("model"))
-
-
-
-
- usage = AutofixRunUsage.from_dict(d.pop("usage"))
-
-
-
-
- created_at = datetime.datetime.fromisoformat(d.pop("created_at"))
-
-
-
-
- _stage_reached = d.pop("stage_reached", UNSET)
- stage_reached: AutofixStage | Unset
- if isinstance(_stage_reached, Unset):
- stage_reached = UNSET
- else:
- stage_reached = check_autofix_stage(_stage_reached)
-
-
-
-
- _diagnosis = d.pop("diagnosis", UNSET)
- diagnosis: AutofixDiagnosis | Unset
- if isinstance(_diagnosis, Unset):
- diagnosis = UNSET
- else:
- diagnosis = AutofixDiagnosis.from_dict(_diagnosis)
-
-
-
-
- _patch = d.pop("patch", UNSET)
- patch: AutofixPatch | Unset
- if isinstance(_patch, Unset):
- patch = UNSET
- else:
- patch = AutofixPatch.from_dict(_patch)
-
-
-
-
- _pull_request = d.pop("pull_request", UNSET)
- pull_request: AutofixPullRequest | Unset
- if isinstance(_pull_request, Unset):
- pull_request = UNSET
- else:
- pull_request = AutofixPullRequest.from_dict(_pull_request)
-
-
-
-
- _pull_request_skipped = d.pop("pull_request_skipped", UNSET)
- pull_request_skipped: AutofixPullRequestSkipped | Unset
- if isinstance(_pull_request_skipped, Unset):
- pull_request_skipped = UNSET
- else:
- pull_request_skipped = check_autofix_pull_request_skipped(_pull_request_skipped)
-
-
-
-
- commit_sha = d.pop("commit_sha", UNSET)
-
- failure_code = d.pop("failure_code", UNSET)
-
- failure_message = d.pop("failure_message", UNSET)
-
- _started_at = d.pop("started_at", UNSET)
- started_at: datetime.datetime | Unset
- if isinstance(_started_at, Unset):
- started_at = UNSET
- else:
- started_at = datetime.datetime.fromisoformat(_started_at)
-
-
-
-
- _completed_at = d.pop("completed_at", UNSET)
- completed_at: datetime.datetime | Unset
- if isinstance(_completed_at, Unset):
- completed_at = UNSET
- else:
- completed_at = datetime.datetime.fromisoformat(_completed_at)
-
-
-
-
- autofix_run = cls(
- id=id,
- project_id=project_id,
- issue_id=issue_id,
- trigger=trigger,
- status=status,
- max_stage=max_stage,
- provider=provider,
- model=model,
- usage=usage,
- created_at=created_at,
- stage_reached=stage_reached,
- diagnosis=diagnosis,
- patch=patch,
- pull_request=pull_request,
- pull_request_skipped=pull_request_skipped,
- commit_sha=commit_sha,
- failure_code=failure_code,
- failure_message=failure_message,
- started_at=started_at,
- completed_at=completed_at,
- )
-
- return autofix_run
-
diff --git a/src/volcano_sdk/_generated/models/autofix_run_status.py b/src/volcano_sdk/_generated/models/autofix_run_status.py
deleted file mode 100644
index e74d65c8..00000000
--- a/src/volcano_sdk/_generated/models/autofix_run_status.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from typing import Literal
-
-AutofixRunStatus = Literal['canceled', 'failed', 'queued', 'running', 'succeeded']
-
-AUTOFIX_RUN_STATUS_VALUES: set[AutofixRunStatus] = { 'canceled', 'failed', 'queued', 'running', 'succeeded', }
-
-def check_autofix_run_status(value: str) -> AutofixRunStatus:
- if value in AUTOFIX_RUN_STATUS_VALUES:
- return value
- raise TypeError(f"Unexpected value {value!r}. Expected one of {AUTOFIX_RUN_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/autofix_run_trigger.py b/src/volcano_sdk/_generated/models/autofix_run_trigger.py
deleted file mode 100644
index c4a8be9f..00000000
--- a/src/volcano_sdk/_generated/models/autofix_run_trigger.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from typing import Literal
-
-AutofixRunTrigger = Literal['manual', 'new_issue', 'regression']
-
-AUTOFIX_RUN_TRIGGER_VALUES: set[AutofixRunTrigger] = { 'manual', 'new_issue', 'regression', }
-
-def check_autofix_run_trigger(value: str) -> AutofixRunTrigger:
- if value in AUTOFIX_RUN_TRIGGER_VALUES:
- return value
- raise TypeError(f"Unexpected value {value!r}. Expected one of {AUTOFIX_RUN_TRIGGER_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/autofix_run_usage.py b/src/volcano_sdk/_generated/models/autofix_run_usage.py
deleted file mode 100644
index a93a2e78..00000000
--- a/src/volcano_sdk/_generated/models/autofix_run_usage.py
+++ /dev/null
@@ -1,83 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Mapping
-from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
-
-from attrs import define as _attrs_define
-from attrs import field as _attrs_field
-
-from ..types import UNSET, Unset
-
-
-
-
-
-
-
-T = TypeVar("T", bound="AutofixRunUsage")
-
-
-
-@_attrs_define
-class AutofixRunUsage:
- """ Model tokens the run used across every attempt.
-
- Attributes:
- input_tokens (int):
- output_tokens (int):
- cache_read_input_tokens (int):
- cache_creation_input_tokens (int):
- """
-
- input_tokens: int
- output_tokens: int
- cache_read_input_tokens: int
- cache_creation_input_tokens: int
-
-
-
-
-
- def to_dict(self) -> dict[str, Any]:
- input_tokens = self.input_tokens
-
- output_tokens = self.output_tokens
-
- cache_read_input_tokens = self.cache_read_input_tokens
-
- cache_creation_input_tokens = self.cache_creation_input_tokens
-
-
- field_dict: dict[str, Any] = {}
-
- field_dict.update({
- "input_tokens": input_tokens,
- "output_tokens": output_tokens,
- "cache_read_input_tokens": cache_read_input_tokens,
- "cache_creation_input_tokens": cache_creation_input_tokens,
- })
-
- return field_dict
-
-
-
- @classmethod
- def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
- d = dict(src_dict)
- input_tokens = d.pop("input_tokens")
-
- output_tokens = d.pop("output_tokens")
-
- cache_read_input_tokens = d.pop("cache_read_input_tokens")
-
- cache_creation_input_tokens = d.pop("cache_creation_input_tokens")
-
- autofix_run_usage = cls(
- input_tokens=input_tokens,
- output_tokens=output_tokens,
- cache_read_input_tokens=cache_read_input_tokens,
- cache_creation_input_tokens=cache_creation_input_tokens,
- )
-
- return autofix_run_usage
-
diff --git a/src/volcano_sdk/_generated/models/autofix_settings.py b/src/volcano_sdk/_generated/models/autofix_settings.py
deleted file mode 100644
index 99ff6fbc..00000000
--- a/src/volcano_sdk/_generated/models/autofix_settings.py
+++ /dev/null
@@ -1,190 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Mapping
-from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
-
-from attrs import define as _attrs_define
-from attrs import field as _attrs_field
-
-from ..types import UNSET, Unset
-
-from ..models.autofix_model import AutofixModel
-from ..models.autofix_model import check_autofix_model
-from ..models.autofix_provider import AutofixProvider
-from ..models.autofix_provider import check_autofix_provider
-from ..models.autofix_stage import AutofixStage
-from ..models.autofix_stage import check_autofix_stage
-from ..types import UNSET, Unset
-from typing import cast
-from uuid import UUID
-import datetime
-
-
-
-
-
-
-T = TypeVar("T", bound="AutofixSettings")
-
-
-
-@_attrs_define
-class AutofixSettings:
- """
- Attributes:
- project_id (UUID):
- enabled (bool): Whether Volcano diagnoses the project's issues with AI.
- max_stage (AutofixStage): How far a run may go. `diagnose` stops at a root-cause diagnosis. `pull_request` may
- also open a draft pull request with a fix in the project's connected repository.
- auto_trigger (bool): Whether a new or reopened issue starts a run on its own. When false, runs start only on
- request.
- provider (AutofixProvider): Who serves the model. `volcano` runs on Volcano's models. `anthropic` runs on your
- own Anthropic API key.
- model (AutofixModel): The Claude model a run uses. `claude-opus-5-5` is the default.
- api_key_configured (bool): Whether your own API key is stored. The key itself is never returned.
- api_key_provider (AutofixProvider | Unset): Who serves the model. `volcano` runs on Volcano's models.
- `anthropic` runs on your own Anthropic API key.
- api_key_last4 (str | Unset): The stored key's last four characters, present when one is stored.
- plan_includes_autofix (bool | Unset): Whether the owner's plan includes autofix. When false, saved settings stay
- stored and no run starts. Absent when a save that needed no plan succeeded but the plan could not be resolved.
- updated_at (datetime.datetime | Unset): When the settings were last saved. Absent until the first save.
- """
-
- project_id: UUID
- enabled: bool
- max_stage: AutofixStage
- auto_trigger: bool
- provider: AutofixProvider
- model: AutofixModel
- api_key_configured: bool
- api_key_provider: AutofixProvider | Unset = UNSET
- api_key_last4: str | Unset = UNSET
- plan_includes_autofix: bool | Unset = UNSET
- updated_at: datetime.datetime | Unset = UNSET
-
-
-
-
-
- def to_dict(self) -> dict[str, Any]:
- project_id = str(self.project_id)
-
- enabled = self.enabled
-
- max_stage: str = self.max_stage
-
- auto_trigger = self.auto_trigger
-
- provider: str = self.provider
-
- model: str = self.model
-
- api_key_configured = self.api_key_configured
-
- api_key_provider: str | Unset = UNSET
- if not isinstance(self.api_key_provider, Unset):
- api_key_provider = self.api_key_provider
-
-
- api_key_last4 = self.api_key_last4
-
- plan_includes_autofix = self.plan_includes_autofix
-
- updated_at: str | Unset = UNSET
- if not isinstance(self.updated_at, Unset):
- updated_at = self.updated_at.isoformat()
-
-
- field_dict: dict[str, Any] = {}
-
- field_dict.update({
- "project_id": project_id,
- "enabled": enabled,
- "max_stage": max_stage,
- "auto_trigger": auto_trigger,
- "provider": provider,
- "model": model,
- "api_key_configured": api_key_configured,
- })
- if api_key_provider is not UNSET:
- field_dict["api_key_provider"] = api_key_provider
- if api_key_last4 is not UNSET:
- field_dict["api_key_last4"] = api_key_last4
- if plan_includes_autofix is not UNSET:
- field_dict["plan_includes_autofix"] = plan_includes_autofix
- if updated_at is not UNSET:
- field_dict["updated_at"] = updated_at
-
- return field_dict
-
-
-
- @classmethod
- def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
- d = dict(src_dict)
- project_id = UUID(d.pop("project_id"))
-
-
-
-
- enabled = d.pop("enabled")
-
- max_stage = check_autofix_stage(d.pop("max_stage"))
-
-
-
-
- auto_trigger = d.pop("auto_trigger")
-
- provider = check_autofix_provider(d.pop("provider"))
-
-
-
-
- model = check_autofix_model(d.pop("model"))
-
-
-
-
- api_key_configured = d.pop("api_key_configured")
-
- _api_key_provider = d.pop("api_key_provider", UNSET)
- api_key_provider: AutofixProvider | Unset
- if isinstance(_api_key_provider, Unset):
- api_key_provider = UNSET
- else:
- api_key_provider = check_autofix_provider(_api_key_provider)
-
-
-
-
- api_key_last4 = d.pop("api_key_last4", UNSET)
-
- plan_includes_autofix = d.pop("plan_includes_autofix", UNSET)
-
- _updated_at = d.pop("updated_at", UNSET)
- updated_at: datetime.datetime | Unset
- if isinstance(_updated_at, Unset):
- updated_at = UNSET
- else:
- updated_at = datetime.datetime.fromisoformat(_updated_at)
-
-
-
-
- autofix_settings = cls(
- project_id=project_id,
- enabled=enabled,
- max_stage=max_stage,
- auto_trigger=auto_trigger,
- provider=provider,
- model=model,
- api_key_configured=api_key_configured,
- api_key_provider=api_key_provider,
- api_key_last4=api_key_last4,
- plan_includes_autofix=plan_includes_autofix,
- updated_at=updated_at,
- )
-
- return autofix_settings
-
diff --git a/src/volcano_sdk/_generated/models/autofix_stage.py b/src/volcano_sdk/_generated/models/autofix_stage.py
deleted file mode 100644
index feec56e0..00000000
--- a/src/volcano_sdk/_generated/models/autofix_stage.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from typing import Literal
-
-AutofixStage = Literal['diagnose', 'pull_request']
-
-AUTOFIX_STAGE_VALUES: set[AutofixStage] = { 'diagnose', 'pull_request', }
-
-def check_autofix_stage(value: str) -> AutofixStage:
- if value in AUTOFIX_STAGE_VALUES:
- return value
- raise TypeError(f"Unexpected value {value!r}. Expected one of {AUTOFIX_STAGE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/capability.py b/src/volcano_sdk/_generated/models/capability.py
index da1a7a9d..864773ca 100644
--- a/src/volcano_sdk/_generated/models/capability.py
+++ b/src/volcano_sdk/_generated/models/capability.py
@@ -10,6 +10,7 @@
from ..models.capability_status import CapabilityStatus
from ..models.capability_status import check_capability_status
+from ..types import UNSET, Unset
from typing import cast
@@ -26,15 +27,21 @@ class Capability:
""" A product capability and whether it accepts new work in this environment.
Attributes:
- id (str): Stable capability ID, such as `sandboxes`, `sandboxes.sessions`, `sandboxes.custom_templates`,
- `issues`, or `autofix`. New IDs may appear at any time. Example: sandboxes.sessions.
+ id (str): Stable capability ID, such as `sandboxes`, `sandboxes.sessions`, `sandboxes.custom_templates`, or
+ `issues`. New IDs may appear at any time. Example: sandboxes.sessions.
status (CapabilityStatus): `available` means the capability accepts new work; a temporary outage still answers
- `503`. `unavailable` means requests that start new work answer `404` or `400` with code `feature_unavailable`.
- Treat any other value as `unavailable`.
+ `503`. `unavailable` means requests that start new work answer `404` or `400` with code `feature_unavailable`,
+ or with the capability's `code` when it has one; while the owner's plan can't be read, they answer `403` without
+ a code. `read_only` means the capability takes no new work for the project, but what the project already has
+ stays readable; only a project's list reports it. Treat any other value as `unavailable`.
+ code (str | Unset): Why an `unavailable` capability refuses new work, named like the error code its requests
+ answer with, such as `plan_required`. Absent on any other status, and when requests answer
+ `feature_unavailable`. Treat an unknown code as absent. Example: plan_required.
"""
id: str
status: CapabilityStatus
+ code: str | Unset = UNSET
@@ -45,6 +52,8 @@ def to_dict(self) -> dict[str, Any]:
status: str = self.status
+ code = self.code
+
field_dict: dict[str, Any] = {}
@@ -52,6 +61,8 @@ def to_dict(self) -> dict[str, Any]:
"id": id,
"status": status,
})
+ if code is not UNSET:
+ field_dict["code"] = code
return field_dict
@@ -67,9 +78,12 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ code = d.pop("code", UNSET)
+
capability = cls(
id=id,
status=status,
+ code=code,
)
return capability
diff --git a/src/volcano_sdk/_generated/models/capability_status.py b/src/volcano_sdk/_generated/models/capability_status.py
index c0e99672..d366b7c5 100644
--- a/src/volcano_sdk/_generated/models/capability_status.py
+++ b/src/volcano_sdk/_generated/models/capability_status.py
@@ -1,8 +1,8 @@
from typing import Literal
-CapabilityStatus = Literal['available', 'unavailable']
+CapabilityStatus = Literal['available', 'read_only', 'unavailable']
-CAPABILITY_STATUS_VALUES: set[CapabilityStatus] = { 'available', 'unavailable', }
+CAPABILITY_STATUS_VALUES: set[CapabilityStatus] = { 'available', 'read_only', 'unavailable', }
def check_capability_status(value: str) -> CapabilityStatus:
if value in CAPABILITY_STATUS_VALUES:
diff --git a/src/volcano_sdk/_generated/models/connect_project_git_request.py b/src/volcano_sdk/_generated/models/connect_project_git_request.py
index 63fefff6..a42b7c08 100644
--- a/src/volcano_sdk/_generated/models/connect_project_git_request.py
+++ b/src/volcano_sdk/_generated/models/connect_project_git_request.py
@@ -41,7 +41,9 @@ class ConnectProjectGitRequest:
a Git branch name only: it does not have to exist yet, so a project can be pointed at a branch about to be
pushed. Changing repository and naming a branch other than the new repository's default in one request is
refused with 400, because the branch named is almost always the previous repository's, echoed back — connect
- first, then set the branch.
+ first, then set the branch. A repository that reports no default branch, as one with no commits can, is
+ connected only by naming a branch, and any branch is accepted for it, including on a rebind. An empty repository
+ that still reports a default follows the rule above.
"""
connection_id: UUID
diff --git a/src/volcano_sdk/_generated/models/connector.py b/src/volcano_sdk/_generated/models/connector.py
new file mode 100644
index 00000000..fed5ca3f
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/connector.py
@@ -0,0 +1,149 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.connector_type import check_connector_type
+from ..models.connector_type import ConnectorType
+from ..types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+import datetime
+
+if TYPE_CHECKING:
+ from ..models.slack_connector import SlackConnector
+
+
+
+
+
+T = TypeVar("T", bound="Connector")
+
+
+
+@_attrs_define
+class Connector:
+ """ A link from Volcano to an outside service. A `slack` connector is a Slack workspace the Volcano app is installed in,
+ shared by every Volcano account with a Slack identity connected there.
+
+ Attributes:
+ id (UUID):
+ type_ (ConnectorType): The outside service a connector links to.
+ name (str): The connector's name in its service, such as the Slack workspace's name.
+ removable (bool): Whether the caller can remove the connector. Only the person who installed the Volcano app in
+ a Slack workspace can.
+ created_at (datetime.datetime):
+ slack (SlackConnector | Unset): A `slack` connector's workspace. Present when `type` is `slack`.
+ """
+
+ id: UUID
+ type_: ConnectorType
+ name: str
+ removable: bool
+ created_at: datetime.datetime
+ slack: SlackConnector | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.slack_connector import SlackConnector # noqa: PLC0415
+ id = str(self.id)
+
+ type_: str = self.type_
+
+ name = self.name
+
+ removable = self.removable
+
+ created_at = self.created_at.isoformat()
+
+ slack: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.slack, Unset):
+ slack = self.slack.to_dict()
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "type": type_,
+ "name": name,
+ "removable": removable,
+ "created_at": created_at,
+ })
+ if slack is not UNSET:
+ field_dict["slack"] = slack
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.slack_connector import SlackConnector # noqa: PLC0415
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ type_ = check_connector_type(d.pop("type"))
+
+
+
+
+ name = d.pop("name")
+
+ removable = d.pop("removable")
+
+ created_at = datetime.datetime.fromisoformat(d.pop("created_at"))
+
+
+
+
+ _slack = d.pop("slack", UNSET)
+ slack: SlackConnector | Unset
+ if isinstance(_slack, Unset):
+ slack = UNSET
+ else:
+ slack = SlackConnector.from_dict(_slack)
+
+
+
+
+ connector = cls(
+ id=id,
+ type_=type_,
+ name=name,
+ removable=removable,
+ created_at=created_at,
+ slack=slack,
+ )
+
+
+ connector.additional_properties = d
+ return connector
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/connector_type.py b/src/volcano_sdk/_generated/models/connector_type.py
new file mode 100644
index 00000000..085b755c
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/connector_type.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+ConnectorType = Literal['slack']
+
+CONNECTOR_TYPE_VALUES: set[ConnectorType] = { 'slack', }
+
+def check_connector_type(value: str) -> ConnectorType:
+ if value in CONNECTOR_TYPE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {CONNECTOR_TYPE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/connectors_response.py b/src/volcano_sdk/_generated/models/connectors_response.py
new file mode 100644
index 00000000..440f0b1f
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/connectors_response.py
@@ -0,0 +1,94 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.connector import Connector
+
+
+
+
+
+T = TypeVar("T", bound="ConnectorsResponse")
+
+
+
+@_attrs_define
+class ConnectorsResponse:
+ """
+ Attributes:
+ connectors (list[Connector]):
+ """
+
+ connectors: list[Connector]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.connector import Connector # noqa: PLC0415
+ connectors = []
+ for connectors_item_data in self.connectors:
+ connectors_item = connectors_item_data.to_dict()
+ connectors.append(connectors_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "connectors": connectors,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.connector import Connector # noqa: PLC0415
+ d = dict(src_dict)
+ connectors = []
+ _connectors = d.pop("connectors")
+ for connectors_item_data in (_connectors):
+ connectors_item = Connector.from_dict(connectors_item_data)
+
+
+
+ connectors.append(connectors_item)
+
+
+ connectors_response = cls(
+ connectors=connectors,
+ )
+
+
+ connectors_response.additional_properties = d
+ return connectors_response
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/create_database_backup_request.py b/src/volcano_sdk/_generated/models/create_database_backup_request.py
index dc74b54a..5b0d72cc 100644
--- a/src/volcano_sdk/_generated/models/create_database_backup_request.py
+++ b/src/volcano_sdk/_generated/models/create_database_backup_request.py
@@ -23,7 +23,9 @@ class CreateDatabaseBackupRequest:
"""
Attributes:
name (str): Backup name, unique within the database. Names beginning with
- `volcano-` are reserved for the platform's own snapshots.
+ `volcano-` are reserved for the platform's own snapshots, and names
+ beginning with `before-migration-` for the backups migration runs
+ take.
Example: before_migration.
"""
diff --git a/src/volcano_sdk/_generated/models/create_database_branch_request.py b/src/volcano_sdk/_generated/models/create_database_branch_request.py
index 785c8813..f8408d51 100644
--- a/src/volcano_sdk/_generated/models/create_database_branch_request.py
+++ b/src/volcano_sdk/_generated/models/create_database_branch_request.py
@@ -23,7 +23,10 @@
class CreateDatabaseBranchRequest:
"""
Attributes:
- name (str): Branch name (must be unique within the parent database) Example: feature_checkout.
+ name (str): Branch name, unique within the parent database. Names beginning
+ with `migration_rehearsal_` are reserved for the branches migration
+ runs rehearse on.
+ Example: feature_checkout.
ttl_seconds (int | Unset): How long the branch should live, between one hour and 30 days.
Defaults to 7 days when omitted.
Example: 86400.
diff --git a/src/volcano_sdk/_generated/models/create_durable_function_body.py b/src/volcano_sdk/_generated/models/create_durable_function_body.py
index 9bac550c..caded640 100644
--- a/src/volcano_sdk/_generated/models/create_durable_function_body.py
+++ b/src/volcano_sdk/_generated/models/create_durable_function_body.py
@@ -66,6 +66,14 @@ class CreateDurableFunctionBody:
detected in its source. A declared name the project does not define is rejected with 400; a detected name it
does not define is ignored. Only used when `variable_scope` is `scoped`. Omitting this leaves an existing
function's declared names unchanged.
+ commit (str | Unset): JSON-encoded commit the uploaded source came from: `{"repository": "acme/app", "sha":
+ "<40-character commit ID>", "dirty": false}`. `repository` is `owner/name` or a github.com remote URL
+ (`https://github.com/acme/app.git`, `git@github.com:acme/app.git`, or `ssh://git@github.com/acme/app.git`);
+ Volcano drops any credentials in the URL and records `owner/name`. `dirty` is `true` when the uploaded files
+ differ from the commit. All three fields are required, and fields Volcano does not know are ignored. An empty
+ value, `null`, or `""` reports no commit. A malformed commit, or a repository not on GitHub, returns 400 before
+ anything is deployed. Volcano records a function's commit with `commit.verified: false`; a clean commit of the
+ project's connected repository that its production branch holds gets `commit.verification: repository`.
"""
name: str
@@ -76,6 +84,7 @@ class CreateDurableFunctionBody:
is_public: bool | Unset = UNSET
variable_scope: CreateDurableFunctionBodyVariableScope | Unset = UNSET
variables: str | Unset = UNSET
+ commit: str | Unset = UNSET
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
@@ -106,6 +115,8 @@ def to_dict(self) -> dict[str, Any]:
variables = self.variables
+ commit = self.commit
+
field_dict: dict[str, Any] = {}
field_dict.update(self.additional_properties)
@@ -124,6 +135,8 @@ def to_dict(self) -> dict[str, Any]:
field_dict["variable_scope"] = variable_scope
if variables is not UNSET:
field_dict["variables"] = variables
+ if commit is not UNSET:
+ field_dict["commit"] = commit
return field_dict
@@ -168,6 +181,11 @@ def to_multipart(self) -> types.RequestFiles:
+ if not isinstance(self.commit, Unset):
+ files.append(("commit", (None, str(self.commit).encode(), "text/plain")))
+
+
+
for prop_name, prop in self.additional_properties.items():
files.append((prop_name, (None, str(prop).encode(), "text/plain")))
@@ -220,6 +238,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
variables = d.pop("variables", UNSET)
+ commit = d.pop("commit", UNSET)
+
create_durable_function_body = cls(
name=name,
code=code,
@@ -229,6 +249,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
is_public=is_public,
variable_scope=variable_scope,
variables=variables,
+ commit=commit,
)
diff --git a/src/volcano_sdk/_generated/models/create_email_template_request.py b/src/volcano_sdk/_generated/models/create_email_template_request.py
index 95905f8b..0b5c0a0a 100644
--- a/src/volcano_sdk/_generated/models/create_email_template_request.py
+++ b/src/volcano_sdk/_generated/models/create_email_template_request.py
@@ -26,7 +26,9 @@ class CreateEmailTemplateRequest:
"""
Attributes:
template_type (CreateEmailTemplateRequestTemplateType): Type of email template
- subject (str): Email subject line Example: Confirm your email.
+ subject (str): Subject template. After Go template whitespace trimming, literal interior carriage returns or
+ newlines return 400. Outer whitespace and trailing block-scalar newlines are allowed. Example: Confirm your
+ email.
html_body (str): HTML template body. Available placeholders:
- {{.Token}} - The confirmation/reset token
- {{.ProjectName}} - The project name
diff --git a/src/volcano_sdk/_generated/models/create_frontend_body.py b/src/volcano_sdk/_generated/models/create_frontend_body.py
index 37d542ac..1163826b 100644
--- a/src/volcano_sdk/_generated/models/create_frontend_body.py
+++ b/src/volcano_sdk/_generated/models/create_frontend_body.py
@@ -43,6 +43,18 @@ class CreateFrontendBody:
default to `scoped`; omitting this field for an existing frontend preserves its current selection.
variables (list[str] | Unset): Project variable names selected when `variable_scope` is `scoped`. Submit each
name as a repeated multipart field.
+ commit (str | Unset): JSON-encoded commit the uploaded source came from: `{"repository": "acme/app", "sha":
+ "<40-character commit ID>", "dirty": false, "root": "apps/web"}`. `repository` is `owner/name` or a github.com
+ remote URL (`https://github.com/acme/app.git`, `git@github.com:acme/app.git`, or
+ `ssh://git@github.com/acme/app.git`); Volcano drops any credentials in the URL and records `owner/name`. `dirty`
+ is `true` when the uploaded files differ from the commit. `root` is the uploaded directory's path from the
+ repository root, `""` for the root itself. `repository`, `sha`, and `dirty` are required, and fields Volcano
+ does not know are ignored. An empty value, `null`, or `""` reports no commit. A malformed commit, or a
+ repository not on GitHub, returns 400 before anything is deployed. Volcano checks the commit against the
+ project's connected repository and each uploaded file against the commit's file at `root`, and returns the
+ result in the deployment's `commit.verified`; an uploaded file in the project's root directory that the commit
+ does not hold sets `commit.dirty`, and one outside it leaves the commit unverified. A commit it cannot verify is
+ still recorded and never fails the deploy.
"""
name: str
@@ -51,6 +63,7 @@ class CreateFrontendBody:
app_root: str | Unset = UNSET
variable_scope: CreateFrontendBodyVariableScope | Unset = UNSET
variables: list[str] | Unset = UNSET
+ commit: str | Unset = UNSET
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
@@ -81,6 +94,8 @@ def to_dict(self) -> dict[str, Any]:
+ commit = self.commit
+
field_dict: dict[str, Any] = {}
field_dict.update(self.additional_properties)
@@ -96,6 +111,8 @@ def to_dict(self) -> dict[str, Any]:
field_dict["variable_scope"] = variable_scope
if variables is not UNSET:
field_dict["variables"] = variables
+ if commit is not UNSET:
+ field_dict["commit"] = commit
return field_dict
@@ -133,6 +150,11 @@ def to_multipart(self) -> types.RequestFiles:
+ if not isinstance(self.commit, Unset):
+ files.append(("commit", (None, str(self.commit).encode(), "text/plain")))
+
+
+
for prop_name, prop in self.additional_properties.items():
files.append((prop_name, (None, str(prop).encode(), "text/plain")))
@@ -179,6 +201,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
variables = cast(list[str], d.pop("variables", UNSET))
+ commit = d.pop("commit", UNSET)
+
create_frontend_body = cls(
name=name,
archive=archive,
@@ -186,6 +210,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
app_root=app_root,
variable_scope=variable_scope,
variables=variables,
+ commit=commit,
)
diff --git a/src/volcano_sdk/_generated/models/create_frontend_candidate_body.py b/src/volcano_sdk/_generated/models/create_frontend_candidate_body.py
new file mode 100644
index 00000000..77c8c17b
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/create_frontend_candidate_body.py
@@ -0,0 +1,130 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+import json
+from .. import types
+
+from ..types import UNSET, Unset
+
+from ..types import File, FileTypes
+from ..types import UNSET, Unset
+from io import BytesIO
+
+
+
+
+
+
+T = TypeVar("T", bound="CreateFrontendCandidateBody")
+
+
+
+@_attrs_define
+class CreateFrontendCandidateBody:
+ """
+ Attributes:
+ name (str): Names the Candidate within the frontend. Cannot be `production`.
+ archive (File): ZIP or tar.gz archive of the frontend project, as for creating a frontend. The API enforces
+ SOURCE_ARCHIVE_SIZE_LIMIT_MB.
+ ttl_seconds (int | Unset): Deletes the Candidate this many seconds after it is created, at most 30 days. Omit to
+ keep it until deleted.
+ """
+
+ name: str
+ archive: File
+ ttl_seconds: int | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ name = self.name
+
+ archive = self.archive.to_tuple()
+
+
+ ttl_seconds = self.ttl_seconds
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "name": name,
+ "archive": archive,
+ })
+ if ttl_seconds is not UNSET:
+ field_dict["ttl_seconds"] = ttl_seconds
+
+ return field_dict
+
+
+ def to_multipart(self) -> types.RequestFiles:
+ files: types.RequestFiles = []
+
+ files.append(("name", (None, str(self.name).encode(), "text/plain")))
+
+
+
+ files.append(("archive", self.archive.to_tuple()))
+
+
+
+ if not isinstance(self.ttl_seconds, Unset):
+ files.append(("ttl_seconds", (None, str(self.ttl_seconds).encode(), "text/plain")))
+
+
+
+
+ for prop_name, prop in self.additional_properties.items():
+ files.append((prop_name, (None, str(prop).encode(), "text/plain")))
+
+
+
+ return files
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ name = d.pop("name")
+
+ archive = File(
+ payload = BytesIO(d.pop("archive"))
+ )
+
+
+
+
+ ttl_seconds = d.pop("ttl_seconds", UNSET)
+
+ create_frontend_candidate_body = cls(
+ name=name,
+ archive=archive,
+ ttl_seconds=ttl_seconds,
+ )
+
+
+ create_frontend_candidate_body.additional_properties = d
+ return create_frontend_candidate_body
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/create_frontend_deployment_request.py b/src/volcano_sdk/_generated/models/create_frontend_deployment_request.py
new file mode 100644
index 00000000..efe49b2e
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/create_frontend_deployment_request.py
@@ -0,0 +1,64 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="CreateFrontendDeploymentRequest")
+
+
+
+@_attrs_define
+class CreateFrontendDeploymentRequest:
+ """ Deploys the build of an existing deployment instead of compiling the frontend's source.
+
+ Attributes:
+ source_deployment_id (UUID): An `active` or `degraded` deployment of another frontend in the same project. Its
+ build is copied to this frontend and published without compiling it again.
+ """
+
+ source_deployment_id: UUID
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ source_deployment_id = str(self.source_deployment_id)
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "source_deployment_id": source_deployment_id,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ source_deployment_id = UUID(d.pop("source_deployment_id"))
+
+
+
+
+ create_frontend_deployment_request = cls(
+ source_deployment_id=source_deployment_id,
+ )
+
+ return create_frontend_deployment_request
+
diff --git a/src/volcano_sdk/_generated/models/create_frontend_domain_request.py b/src/volcano_sdk/_generated/models/create_frontend_domain_request.py
new file mode 100644
index 00000000..e69977f4
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/create_frontend_domain_request.py
@@ -0,0 +1,101 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.frontend_custom_domain_redirect_request import FrontendCustomDomainRedirectRequest
+ from ..models.frontend_custom_domain_tls_config import FrontendCustomDomainTLSConfig
+
+
+
+
+
+T = TypeVar("T", bound="CreateFrontendDomainRequest")
+
+
+
+@_attrs_define
+class CreateFrontendDomainRequest:
+ """
+ Attributes:
+ domain (str): Fully-qualified domain name (hostname only, no scheme/path). Managed TLS (`tls.mode: managed`)
+ accepts at most 219 characters; BYOC accepts 253. Example: www.example.com.
+ tls (FrontendCustomDomainTLSConfig): TLS for a new custom domain. With `mode: managed`, Volcano issues and
+ renews the certificate; omit every PEM field. With `mode: byoc`, send both `certificate_pem` and
+ `private_key_pem`, plus an optional `certificate_chain_pem`.
+ redirect (FrontendCustomDomainRedirectRequest | Unset): Redirects every request for the domain to `to`, another
+ active domain of the same frontend that serves it, keeping the path and query string.
+ """
+
+ domain: str
+ tls: FrontendCustomDomainTLSConfig
+ redirect: FrontendCustomDomainRedirectRequest | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.frontend_custom_domain_redirect_request import FrontendCustomDomainRedirectRequest # noqa: PLC0415
+ from ..models.frontend_custom_domain_tls_config import FrontendCustomDomainTLSConfig # noqa: PLC0415
+ domain = self.domain
+
+ tls = self.tls.to_dict()
+
+ redirect: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.redirect, Unset):
+ redirect = self.redirect.to_dict()
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "domain": domain,
+ "tls": tls,
+ })
+ if redirect is not UNSET:
+ field_dict["redirect"] = redirect
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.frontend_custom_domain_redirect_request import FrontendCustomDomainRedirectRequest # noqa: PLC0415
+ from ..models.frontend_custom_domain_tls_config import FrontendCustomDomainTLSConfig # noqa: PLC0415
+ d = dict(src_dict)
+ domain = d.pop("domain")
+
+ tls = FrontendCustomDomainTLSConfig.from_dict(d.pop("tls"))
+
+
+
+
+ _redirect = d.pop("redirect", UNSET)
+ redirect: FrontendCustomDomainRedirectRequest | Unset
+ if isinstance(_redirect, Unset):
+ redirect = UNSET
+ else:
+ redirect = FrontendCustomDomainRedirectRequest.from_dict(_redirect)
+
+
+
+
+ create_frontend_domain_request = cls(
+ domain=domain,
+ tls=tls,
+ redirect=redirect,
+ )
+
+ return create_frontend_domain_request
+
diff --git a/src/volcano_sdk/_generated/models/create_frontend_route_request.py b/src/volcano_sdk/_generated/models/create_frontend_route_request.py
new file mode 100644
index 00000000..617cb674
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/create_frontend_route_request.py
@@ -0,0 +1,70 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="CreateFrontendRouteRequest")
+
+
+
+@_attrs_define
+class CreateFrontendRouteRequest:
+ """
+ Attributes:
+ target_frontend_id (UUID): The Frontend to mount. It must be another Frontend in the Project.
+ path_prefix (str):
+ """
+
+ target_frontend_id: UUID
+ path_prefix: str
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ target_frontend_id = str(self.target_frontend_id)
+
+ path_prefix = self.path_prefix
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "target_frontend_id": target_frontend_id,
+ "path_prefix": path_prefix,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ target_frontend_id = UUID(d.pop("target_frontend_id"))
+
+
+
+
+ path_prefix = d.pop("path_prefix")
+
+ create_frontend_route_request = cls(
+ target_frontend_id=target_frontend_id,
+ path_prefix=path_prefix,
+ )
+
+ return create_frontend_route_request
+
diff --git a/src/volcano_sdk/_generated/models/create_function_body.py b/src/volcano_sdk/_generated/models/create_function_body.py
index b9eac419..30bb0530 100644
--- a/src/volcano_sdk/_generated/models/create_function_body.py
+++ b/src/volcano_sdk/_generated/models/create_function_body.py
@@ -46,10 +46,13 @@ class CreateFunctionBody:
- Node.js: nodejs22.x, nodejs24.x
- Python: python3.10, python3.11, python3.12, python3.13, python3.14
- Ruby: ruby3.3, ruby3.4, ruby4.0
+
+ python3.10 is deprecated: it still deploys, and Volcano will remove it before 2027-08-31.
Example: nodejs24.x.
handler (str | Unset): The name of the function to invoke. Defaults to "handler" if not specified.
Your code must export/define a function with this name:
- - Node.js: exports.handler (in index.js)
+ - Node.js: exports.handler (in index.js, index.mjs or index.cjs, or in TypeScript in index.ts, index.mts or
+ index.cts, which the build compiles without type-checking)
- Python: def handler() (in main.py)
- Ruby: def handler() (in main.rb)
Default: 'handler'. Example: handler.
@@ -80,6 +83,14 @@ class CreateFunctionBody:
detected in its source. A declared name the project does not define is rejected with 400; a detected name it
does not define is ignored. Only used when `variable_scope` is `scoped`. Omitting this leaves an existing
function's declared names unchanged.
+ commit (str | Unset): JSON-encoded commit the uploaded source came from: `{"repository": "acme/app", "sha":
+ "<40-character commit ID>", "dirty": false}`. `repository` is `owner/name` or a github.com remote URL
+ (`https://github.com/acme/app.git`, `git@github.com:acme/app.git`, or `ssh://git@github.com/acme/app.git`);
+ Volcano drops any credentials in the URL and records `owner/name`. `dirty` is `true` when the uploaded files
+ differ from the commit. All three fields are required, and fields Volcano does not know are ignored. An empty
+ value, `null`, or `""` reports no commit. A malformed commit, or a repository not on GitHub, returns 400 before
+ anything is deployed. Volcano records a function's commit with `commit.verified: false`; a clean commit of the
+ project's connected repository that its production branch holds gets `commit.verification: repository`.
"""
name: str
@@ -93,6 +104,7 @@ class CreateFunctionBody:
openapi_spec: str | Unset = UNSET
variable_scope: CreateFunctionBodyVariableScope | Unset = UNSET
variables: str | Unset = UNSET
+ commit: str | Unset = UNSET
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
@@ -135,6 +147,8 @@ def to_dict(self) -> dict[str, Any]:
variables = self.variables
+ commit = self.commit
+
field_dict: dict[str, Any] = {}
field_dict.update(self.additional_properties)
@@ -159,6 +173,8 @@ def to_dict(self) -> dict[str, Any]:
field_dict["variable_scope"] = variable_scope
if variables is not UNSET:
field_dict["variables"] = variables
+ if commit is not UNSET:
+ field_dict["commit"] = commit
return field_dict
@@ -218,6 +234,11 @@ def to_multipart(self) -> types.RequestFiles:
+ if not isinstance(self.commit, Unset):
+ files.append(("commit", (None, str(self.commit).encode(), "text/plain")))
+
+
+
for prop_name, prop in self.additional_properties.items():
files.append((prop_name, (None, str(prop).encode(), "text/plain")))
@@ -292,6 +313,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
variables = d.pop("variables", UNSET)
+ commit = d.pop("commit", UNSET)
+
create_function_body = cls(
name=name,
code=code,
@@ -304,6 +327,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
openapi_spec=openapi_spec,
variable_scope=variable_scope,
variables=variables,
+ commit=commit,
)
diff --git a/src/volcano_sdk/_generated/models/create_functions_batch_body.py b/src/volcano_sdk/_generated/models/create_functions_batch_body.py
index eda92542..f1913b12 100644
--- a/src/volcano_sdk/_generated/models/create_functions_batch_body.py
+++ b/src/volcano_sdk/_generated/models/create_functions_batch_body.py
@@ -40,6 +40,11 @@ class CreateFunctionsBatchBody:
it must not deploy without the variable. The request is rejected with 400 before anything is deployed if a
scoped function declares a variable the project does not define, or if the resulting environment exceeds 4096
bytes.
+
+ Each entry may also carry `commit`, the commit its source came from, as an object: `{"repository": "acme/app",
+ "sha": "<40-character commit ID>", "dirty": false}`. It takes the same values as the `commit` field of a single
+ function upload; `null` or `""` reports no commit. The request is rejected with 400 before anything is deployed
+ if an entry's commit is malformed or names a repository not on GitHub.
code_0 (File | Unset): Function ZIP or tar.gz archive referenced by the first manifest entry's `file_field`;
additional code_N file fields may be included. Each archive is subject to SOURCE_ARCHIVE_SIZE_LIMIT_MB.
"""
diff --git a/src/volcano_sdk/_generated/models/create_project_request.py b/src/volcano_sdk/_generated/models/create_project_request.py
index 1b25095e..9cb3e029 100644
--- a/src/volcano_sdk/_generated/models/create_project_request.py
+++ b/src/volcano_sdk/_generated/models/create_project_request.py
@@ -27,7 +27,8 @@ class CreateProjectRequest:
""" Request to create a new project
Attributes:
- name (str): Project name (must be unique).
+ name (str): Project name. A name you already use is not refused: the project is
+ created with a short random suffix added to it.
Can only contain letters, numbers, underscores, and hyphens.
Example: my-awesome-app.
template_id (CreateProjectRequestTemplateId | Unset): Optional trusted starter template identifier. The server
diff --git a/src/volcano_sdk/_generated/models/create_service_key_body.py b/src/volcano_sdk/_generated/models/create_service_key_body.py
index 875d490a..7554768d 100644
--- a/src/volcano_sdk/_generated/models/create_service_key_body.py
+++ b/src/volcano_sdk/_generated/models/create_service_key_body.py
@@ -32,9 +32,18 @@ class CreateServiceKeyBody:
for backward compatibility. Provide an explicit list (e.g.
["functions.invoke", "locks.manage"]) to restrict the key; "*"
grants everything. Scope enforcement applies to function invocation,
- storage object operations, project locks, and server-side auth proxy
+ storage object operations, project locks, sandboxes, and server-side auth proxy
metadata (auth.signin, auth.signup, auth.refresh, auth.logout,
- auth.password_reset).
+ auth.password_reset). A key scoped to a list without "*" reads, stops,
+ and messages a durable execution only with the `client_token` its
+ start returned. Today the scope doesn't restrict the database API, and
+ restricts realtime only on a durable run's channel: every service key
+ queries every table with RLS bypassed, subscribes to every other channel,
+ and publishes on broadcast channels. Once Volcano applies scopes to the
+ database API and realtime, a key without "*" gets 403 from the database
+ API, needs realtime.subscribe for broadcast and presence channels and
+ realtime.publish to publish, and needs "*" for table changes. `ai.invoke`
+ is reserved: this route refuses it with 400, and "*" doesn't include it.
Example: ['functions.invoke', 'locks.manage'].
"""
diff --git a/src/volcano_sdk/_generated/models/database_backup.py b/src/volcano_sdk/_generated/models/database_backup.py
index 815e688b..1a1a82b7 100644
--- a/src/volcano_sdk/_generated/models/database_backup.py
+++ b/src/volcano_sdk/_generated/models/database_backup.py
@@ -34,9 +34,9 @@ class DatabaseBackup:
Attributes:
name (str): Backup name, unique within the database. Backups you create are
named by you; scheduled backups are named by the storage provider.
- source (DatabaseBackupSource): Whether the backup was requested explicitly or produced by the
- backup schedule. Only `manual` backups count against the plan's
- backup allowance.
+ source (DatabaseBackupSource): Whether the backup was requested explicitly, produced by the backup
+ schedule, or taken before migrations were applied to the database.
+ Only `manual` backups count against the plan's backup allowance.
created_at (datetime.datetime): The point in time the backup captures.
size_bytes (int | Unset): Storage the backup occupies. Absent until the provider has costed
it, which takes a few minutes after the backup is taken; absent is
diff --git a/src/volcano_sdk/_generated/models/database_backup_source.py b/src/volcano_sdk/_generated/models/database_backup_source.py
index dc8e5143..334dbde2 100644
--- a/src/volcano_sdk/_generated/models/database_backup_source.py
+++ b/src/volcano_sdk/_generated/models/database_backup_source.py
@@ -1,8 +1,8 @@
from typing import Literal
-DatabaseBackupSource = Literal['manual', 'scheduled']
+DatabaseBackupSource = Literal['manual', 'migration', 'scheduled']
-DATABASE_BACKUP_SOURCE_VALUES: set[DatabaseBackupSource] = { 'manual', 'scheduled', }
+DATABASE_BACKUP_SOURCE_VALUES: set[DatabaseBackupSource] = { 'manual', 'migration', 'scheduled', }
def check_database_backup_source(value: str) -> DatabaseBackupSource:
if value in DATABASE_BACKUP_SOURCE_VALUES:
diff --git a/src/volcano_sdk/_generated/models/database_migration_baseline.py b/src/volcano_sdk/_generated/models/database_migration_baseline.py
new file mode 100644
index 00000000..7b14d06a
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_migration_baseline.py
@@ -0,0 +1,81 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="DatabaseMigrationBaseline")
+
+
+
+@_attrs_define
+class DatabaseMigrationBaseline:
+ """
+ Attributes:
+ recorded (list[str]): The files this request recorded, in name order. Empty when the
+ history already recorded every file.
+ """
+
+ recorded: list[str]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ recorded = self.recorded
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "recorded": recorded,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ recorded = cast(list[str], d.pop("recorded"))
+
+
+ database_migration_baseline = cls(
+ recorded=recorded,
+ )
+
+
+ database_migration_baseline.additional_properties = d
+ return database_migration_baseline
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/database_migration_conflict_error.py b/src/volcano_sdk/_generated/models/database_migration_conflict_error.py
new file mode 100644
index 00000000..49f69a79
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_migration_conflict_error.py
@@ -0,0 +1,115 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="DatabaseMigrationConflictError")
+
+
+
+@_attrs_define
+class DatabaseMigrationConflictError:
+ """ A migration request refused by the database's state. With code
+ `migration_run_in_progress`, `run_id` names the run that is queued or
+ running.
+
+ Attributes:
+ error (str):
+ code (str | Unset): Stable machine-readable error code when a specific recovery path is available.
+ `plan_required` (403) means the project owner's plan does not include the requested feature or option; upgrading
+ the plan unlocks it. `person_required` (403) means a project access token tried to change LavaFlow settings,
+ which only the project's owner changes, with a platform token, or that the change needs the owner's own
+ credential that expires, a project repository, and an owner whose GitHub account can push to it; `error` says
+ which. A 403 without a code leaves the reason unspecified: it can be an access refusal, a reached limit, or a
+ plan check that could not read the owner's plan. Match on the code, not the message text.
+ run_id (UUID | Unset):
+ """
+
+ error: str
+ code: str | Unset = UNSET
+ run_id: UUID | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ error = self.error
+
+ code = self.code
+
+ run_id: str | Unset = UNSET
+ if not isinstance(self.run_id, Unset):
+ run_id = str(self.run_id)
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "error": error,
+ })
+ if code is not UNSET:
+ field_dict["code"] = code
+ if run_id is not UNSET:
+ field_dict["run_id"] = run_id
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ error = d.pop("error")
+
+ code = d.pop("code", UNSET)
+
+ _run_id = d.pop("run_id", UNSET)
+ run_id: UUID | Unset
+ if isinstance(_run_id, Unset):
+ run_id = UNSET
+ else:
+ run_id = UUID(_run_id)
+
+
+
+
+ database_migration_conflict_error = cls(
+ error=error,
+ code=code,
+ run_id=run_id,
+ )
+
+
+ database_migration_conflict_error.additional_properties = d
+ return database_migration_conflict_error
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/database_migration_file.py b/src/volcano_sdk/_generated/models/database_migration_file.py
new file mode 100644
index 00000000..f5797a23
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_migration_file.py
@@ -0,0 +1,100 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="DatabaseMigrationFile")
+
+
+
+@_attrs_define
+class DatabaseMigrationFile:
+ """ One migration file and its SQL.
+
+ Attributes:
+ name (str): The file's path under `volcano/migrations/`: a file name such as
+ `001_create_users.sql`, or `/001_create_users.sql` in a
+ project with more than one database, where `` must be
+ this database. Every file in a request takes the same form. Files
+ run in byte order of their file name, which the history records.
+ Example: 001_create_users.sql.
+ sql (str): The file's SQL, at most 1 MiB. A file may hold several statements
+ and runs in one transaction. A file cannot commit, roll back, use
+ savepoints, or `COPY` from the client; such a file fails with
+ `migration_failed`. A statement that cannot run in a transaction,
+ such as `CREATE INDEX CONCURRENTLY`, goes alone in a file whose
+ first line is `-- volcano:no-transaction`. That file runs outside a
+ transaction and runs again from its start when a run retries it. A
+ run refuses with `invalid_file`, before anything runs, a file with
+ the marker on any other line, and a marked file that builds an
+ unnamed index with `CREATE INDEX CONCURRENTLY` or starts with
+ `COPY`.
+ """
+
+ name: str
+ sql: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ name = self.name
+
+ sql = self.sql
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "name": name,
+ "sql": sql,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ name = d.pop("name")
+
+ sql = d.pop("sql")
+
+ database_migration_file = cls(
+ name=name,
+ sql=sql,
+ )
+
+
+ database_migration_file.additional_properties = d
+ return database_migration_file
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/database_migration_file_error.py b/src/volcano_sdk/_generated/models/database_migration_file_error.py
new file mode 100644
index 00000000..fb14bcb2
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_migration_file_error.py
@@ -0,0 +1,104 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+T = TypeVar("T", bound="DatabaseMigrationFileError")
+
+
+
+@_attrs_define
+class DatabaseMigrationFileError:
+ """ The database's error for a `failed` file, or for an `unknown` file
+ that runs outside a transaction, when a later attempt failed it after
+ an earlier one may have run it. `message` is the database's own
+ message and can quote values from the file or the data.
+
+ Attributes:
+ message (str): At most 8 KiB (8,192 bytes). A longer message is cut and ends with
+ ` … [truncated]`. Volcano reads each reply the database sends about
+ the file up to 4 MiB, which leaves room for a reply that quotes the
+ whole file twice. A larger reply is not read: the file fails, and
+ this message says so instead.
+ Example: column "email" of relation "users" already exists.
+ sqlstate (str | Unset): The Postgres error code, when the database reported one. Example: 42701.
+ line (int | Unset): The line of the file the database reported, when known.
+ """
+
+ message: str
+ sqlstate: str | Unset = UNSET
+ line: int | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ message = self.message
+
+ sqlstate = self.sqlstate
+
+ line = self.line
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "message": message,
+ })
+ if sqlstate is not UNSET:
+ field_dict["sqlstate"] = sqlstate
+ if line is not UNSET:
+ field_dict["line"] = line
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ message = d.pop("message")
+
+ sqlstate = d.pop("sqlstate", UNSET)
+
+ line = d.pop("line", UNSET)
+
+ database_migration_file_error = cls(
+ message=message,
+ sqlstate=sqlstate,
+ line=line,
+ )
+
+
+ database_migration_file_error.additional_properties = d
+ return database_migration_file_error
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/database_migration_files_request.py b/src/volcano_sdk/_generated/models/database_migration_files_request.py
new file mode 100644
index 00000000..41f6ad0f
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_migration_files_request.py
@@ -0,0 +1,94 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.database_migration_file import DatabaseMigrationFile
+
+
+
+
+
+T = TypeVar("T", bound="DatabaseMigrationFilesRequest")
+
+
+
+@_attrs_define
+class DatabaseMigrationFilesRequest:
+ """
+ Attributes:
+ files (list[DatabaseMigrationFile]):
+ """
+
+ files: list[DatabaseMigrationFile]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.database_migration_file import DatabaseMigrationFile # noqa: PLC0415
+ files = []
+ for files_item_data in self.files:
+ files_item = files_item_data.to_dict()
+ files.append(files_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "files": files,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.database_migration_file import DatabaseMigrationFile # noqa: PLC0415
+ d = dict(src_dict)
+ files = []
+ _files = d.pop("files")
+ for files_item_data in (_files):
+ files_item = DatabaseMigrationFile.from_dict(files_item_data)
+
+
+
+ files.append(files_item)
+
+
+ database_migration_files_request = cls(
+ files=files,
+ )
+
+
+ database_migration_files_request.additional_properties = d
+ return database_migration_files_request
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/database_migration_history_entry.py b/src/volcano_sdk/_generated/models/database_migration_history_entry.py
new file mode 100644
index 00000000..adc60a27
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_migration_history_entry.py
@@ -0,0 +1,136 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.database_migration_history_entry_status import check_database_migration_history_entry_status
+from ..models.database_migration_history_entry_status import DatabaseMigrationHistoryEntryStatus
+from ..types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+import datetime
+
+
+
+
+
+
+T = TypeVar("T", bound="DatabaseMigrationHistoryEntry")
+
+
+
+@_attrs_define
+class DatabaseMigrationHistoryEntry:
+ """ One file the database's migration history records.
+
+ Attributes:
+ name (str): Example: 001_create_users.sql.
+ checksum (str): `sha256:` and the hex digest of the file as recorded, with a leading
+ byte order mark removed and CRLF line endings converted to LF.
+ Example: sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08.
+ status (DatabaseMigrationHistoryEntryStatus): `applied`: a run ran the file and it committed. `baselined`: the
+ file
+ was recorded as applied without running.
+ applied_at (datetime.datetime):
+ run_id (UUID | Unset): The run that recorded the file. Absent for a baseline.
+ """
+
+ name: str
+ checksum: str
+ status: DatabaseMigrationHistoryEntryStatus
+ applied_at: datetime.datetime
+ run_id: UUID | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ name = self.name
+
+ checksum = self.checksum
+
+ status: str = self.status
+
+ applied_at = self.applied_at.isoformat()
+
+ run_id: str | Unset = UNSET
+ if not isinstance(self.run_id, Unset):
+ run_id = str(self.run_id)
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "name": name,
+ "checksum": checksum,
+ "status": status,
+ "applied_at": applied_at,
+ })
+ if run_id is not UNSET:
+ field_dict["run_id"] = run_id
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ name = d.pop("name")
+
+ checksum = d.pop("checksum")
+
+ status = check_database_migration_history_entry_status(d.pop("status"))
+
+
+
+
+ applied_at = datetime.datetime.fromisoformat(d.pop("applied_at"))
+
+
+
+
+ _run_id = d.pop("run_id", UNSET)
+ run_id: UUID | Unset
+ if isinstance(_run_id, Unset):
+ run_id = UNSET
+ else:
+ run_id = UUID(_run_id)
+
+
+
+
+ database_migration_history_entry = cls(
+ name=name,
+ checksum=checksum,
+ status=status,
+ applied_at=applied_at,
+ run_id=run_id,
+ )
+
+
+ database_migration_history_entry.additional_properties = d
+ return database_migration_history_entry
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/database_migration_history_entry_status.py b/src/volcano_sdk/_generated/models/database_migration_history_entry_status.py
new file mode 100644
index 00000000..23c13ca8
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_migration_history_entry_status.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+DatabaseMigrationHistoryEntryStatus = Literal['applied', 'baselined']
+
+DATABASE_MIGRATION_HISTORY_ENTRY_STATUS_VALUES: set[DatabaseMigrationHistoryEntryStatus] = { 'applied', 'baselined', }
+
+def check_database_migration_history_entry_status(value: str) -> DatabaseMigrationHistoryEntryStatus:
+ if value in DATABASE_MIGRATION_HISTORY_ENTRY_STATUS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {DATABASE_MIGRATION_HISTORY_ENTRY_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/database_migration_run.py b/src/volcano_sdk/_generated/models/database_migration_run.py
new file mode 100644
index 00000000..59bb1f3c
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_migration_run.py
@@ -0,0 +1,307 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.database_migration_run_phase import check_database_migration_run_phase
+from ..models.database_migration_run_phase import DatabaseMigrationRunPhase
+from ..models.database_migration_run_source import check_database_migration_run_source
+from ..models.database_migration_run_source import DatabaseMigrationRunSource
+from ..models.database_migration_run_status import check_database_migration_run_status
+from ..models.database_migration_run_status import DatabaseMigrationRunStatus
+from ..types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+import datetime
+
+if TYPE_CHECKING:
+ from ..models.database_migration_run_error import DatabaseMigrationRunError
+ from ..models.database_migration_run_file import DatabaseMigrationRunFile
+ from ..models.database_migration_warning import DatabaseMigrationWarning
+ from ..models.resource_reference import ResourceReference
+
+
+
+
+
+T = TypeVar("T", bound="DatabaseMigrationRun")
+
+
+
+@_attrs_define
+class DatabaseMigrationRun:
+ """ One application of migration files to a database. A run plans the files
+ against the database's history, rehearses the pending ones on a
+ short-lived branch, takes a backup, and applies them.
+
+ Attributes:
+ id (UUID):
+ database (ResourceReference): Stable reference to a Volcano resource.
+ status (DatabaseMigrationRunStatus): `queued` and `running` mean the run has not ended; a run waiting
+ to retry stays `running`. `succeeded`: every pending file was
+ applied, or none was pending. `failed`: `error` says why.
+ phase (DatabaseMigrationRunPhase): The step the run is on, or the one it ended on. `plan` compares the
+ files with the history. `rehearse` applies the pending files to a
+ short-lived branch of the database, which is deleted afterwards.
+ `backup` takes the backup named by `backup_name`. `apply` applies
+ the files to the database.
+ source (DatabaseMigrationRunSource): What started the run.
+ warnings (list[DatabaseMigrationWarning]): A run keeps at most 100 warnings, keeping those about the run, such
+ as a skipped backup, ahead of those about files. A run that raised
+ more ends the list with a `warnings_truncated` warning.
+ created_at (datetime.datetime):
+ updated_at (datetime.datetime):
+ commit_sha (str | Unset): The commit whose files the run applies. Present for `git_deploy` runs.
+ backup_name (str | Unset): The backup the run takes before it applies the files, named once
+ the run starts taking it. It is listed with the database's backups
+ with `source: migration`. A run that ended in its `backup` phase
+ may name a backup that was never created.
+ Example: before-migration-7f3a1c2e-5d4b-4a91-8c6f-2b1e9d0a4c73.
+ files (list[DatabaseMigrationRunFile] | Unset): The run's files, in the order they run, with what became of
+ each.
+ Absent when listing runs.
+ error (DatabaseMigrationRunError | Unset): Why the run failed, or why its last attempt did.
+ started_at (datetime.datetime | Unset): When a worker first picked the run up.
+ completed_at (datetime.datetime | Unset):
+ """
+
+ id: UUID
+ database: ResourceReference
+ status: DatabaseMigrationRunStatus
+ phase: DatabaseMigrationRunPhase
+ source: DatabaseMigrationRunSource
+ warnings: list[DatabaseMigrationWarning]
+ created_at: datetime.datetime
+ updated_at: datetime.datetime
+ commit_sha: str | Unset = UNSET
+ backup_name: str | Unset = UNSET
+ files: list[DatabaseMigrationRunFile] | Unset = UNSET
+ error: DatabaseMigrationRunError | Unset = UNSET
+ started_at: datetime.datetime | Unset = UNSET
+ completed_at: datetime.datetime | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.database_migration_run_error import DatabaseMigrationRunError # noqa: PLC0415
+ from ..models.database_migration_run_file import DatabaseMigrationRunFile # noqa: PLC0415
+ from ..models.database_migration_warning import DatabaseMigrationWarning # noqa: PLC0415
+ from ..models.resource_reference import ResourceReference # noqa: PLC0415
+ id = str(self.id)
+
+ database = self.database.to_dict()
+
+ status: str = self.status
+
+ phase: str = self.phase
+
+ source: str = self.source
+
+ warnings = []
+ for warnings_item_data in self.warnings:
+ warnings_item = warnings_item_data.to_dict()
+ warnings.append(warnings_item)
+
+
+
+ created_at = self.created_at.isoformat()
+
+ updated_at = self.updated_at.isoformat()
+
+ commit_sha = self.commit_sha
+
+ backup_name = self.backup_name
+
+ files: list[dict[str, Any]] | Unset = UNSET
+ if not isinstance(self.files, Unset):
+ files = []
+ for files_item_data in self.files:
+ files_item = files_item_data.to_dict()
+ files.append(files_item)
+
+
+
+ error: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.error, Unset):
+ error = self.error.to_dict()
+
+ started_at: str | Unset = UNSET
+ if not isinstance(self.started_at, Unset):
+ started_at = self.started_at.isoformat()
+
+ completed_at: str | Unset = UNSET
+ if not isinstance(self.completed_at, Unset):
+ completed_at = self.completed_at.isoformat()
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "database": database,
+ "status": status,
+ "phase": phase,
+ "source": source,
+ "warnings": warnings,
+ "created_at": created_at,
+ "updated_at": updated_at,
+ })
+ if commit_sha is not UNSET:
+ field_dict["commit_sha"] = commit_sha
+ if backup_name is not UNSET:
+ field_dict["backup_name"] = backup_name
+ if files is not UNSET:
+ field_dict["files"] = files
+ if error is not UNSET:
+ field_dict["error"] = error
+ if started_at is not UNSET:
+ field_dict["started_at"] = started_at
+ if completed_at is not UNSET:
+ field_dict["completed_at"] = completed_at
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.database_migration_run_error import DatabaseMigrationRunError # noqa: PLC0415
+ from ..models.database_migration_run_file import DatabaseMigrationRunFile # noqa: PLC0415
+ from ..models.database_migration_warning import DatabaseMigrationWarning # noqa: PLC0415
+ from ..models.resource_reference import ResourceReference # noqa: PLC0415
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ database = ResourceReference.from_dict(d.pop("database"))
+
+
+
+
+ status = check_database_migration_run_status(d.pop("status"))
+
+
+
+
+ phase = check_database_migration_run_phase(d.pop("phase"))
+
+
+
+
+ source = check_database_migration_run_source(d.pop("source"))
+
+
+
+
+ warnings = []
+ _warnings = d.pop("warnings")
+ for warnings_item_data in (_warnings):
+ warnings_item = DatabaseMigrationWarning.from_dict(warnings_item_data)
+
+
+
+ warnings.append(warnings_item)
+
+
+ created_at = datetime.datetime.fromisoformat(d.pop("created_at"))
+
+
+
+
+ updated_at = datetime.datetime.fromisoformat(d.pop("updated_at"))
+
+
+
+
+ commit_sha = d.pop("commit_sha", UNSET)
+
+ backup_name = d.pop("backup_name", UNSET)
+
+ _files = d.pop("files", UNSET)
+ files: list[DatabaseMigrationRunFile] | Unset = UNSET
+ if _files is not UNSET:
+ files = []
+ for files_item_data in _files:
+ files_item = DatabaseMigrationRunFile.from_dict(files_item_data)
+
+
+
+ files.append(files_item)
+
+
+ _error = d.pop("error", UNSET)
+ error: DatabaseMigrationRunError | Unset
+ if isinstance(_error, Unset):
+ error = UNSET
+ else:
+ error = DatabaseMigrationRunError.from_dict(_error)
+
+
+
+
+ _started_at = d.pop("started_at", UNSET)
+ started_at: datetime.datetime | Unset
+ if isinstance(_started_at, Unset):
+ started_at = UNSET
+ else:
+ started_at = datetime.datetime.fromisoformat(_started_at)
+
+
+
+
+ _completed_at = d.pop("completed_at", UNSET)
+ completed_at: datetime.datetime | Unset
+ if isinstance(_completed_at, Unset):
+ completed_at = UNSET
+ else:
+ completed_at = datetime.datetime.fromisoformat(_completed_at)
+
+
+
+
+ database_migration_run = cls(
+ id=id,
+ database=database,
+ status=status,
+ phase=phase,
+ source=source,
+ warnings=warnings,
+ created_at=created_at,
+ updated_at=updated_at,
+ commit_sha=commit_sha,
+ backup_name=backup_name,
+ files=files,
+ error=error,
+ started_at=started_at,
+ completed_at=completed_at,
+ )
+
+
+ database_migration_run.additional_properties = d
+ return database_migration_run
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/database_migration_run_error.py b/src/volcano_sdk/_generated/models/database_migration_run_error.py
new file mode 100644
index 00000000..8c169159
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_migration_run_error.py
@@ -0,0 +1,123 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.database_migration_run_error_code import check_database_migration_run_error_code
+from ..models.database_migration_run_error_code import DatabaseMigrationRunErrorCode
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="DatabaseMigrationRunError")
+
+
+
+@_attrs_define
+class DatabaseMigrationRunError:
+ """ Why the run failed, or why its last attempt did.
+
+ Attributes:
+ code (DatabaseMigrationRunErrorCode): Stable machine-readable reason. `migration_failed`: a file's SQL,
+ or its `COMMIT`, failed; `phase` says whether in the rehearsal,
+ leaving the database untouched, or in the database, where the files
+ before it stay applied. `checksum_mismatch`: an applied file changed.
+ `history_missing`: the database's history table is gone though
+ migrations ran there; record a baseline of the files already
+ applied. Dropping the whole `_volcano_migrations` schema is not
+ supported and not detected: the database reads as new, and the run
+ applies every file again. `history_too_large`: the history has
+ more than the 1,000 entries Volcano reads. `invalid_file`: a file
+ Volcano refuses to run. `invalid_layout`: file paths that do not map
+ to the database.
+ `plan_changed`: the history changed after the rehearsal.
+ `branch_limit`: the rehearsal branch would exceed the plan's branch
+ allowance. `backup_failed` and `rehearsal_unavailable`: Volcano
+ could not take the backup or prepare the rehearsal.
+ `restore_in_progress` and `database_unavailable`: the database could
+ not take the run. `owner_not_active`: the project owner's account
+ was not `active` when Volcano picked the run up, or before its
+ `backup` or `apply`, or before a file in `apply` unless held
+ `read_only` only for the plan's limits, so the run applied nothing
+ further; files it already applied stay applied.
+ `locked`: another session held the migration lock,
+ or a file, or Volcano's drop of a failed build's index, waited too
+ long for a lock. `connection_failed`: the
+ database could not be reached, or the connection was lost,
+ including while a file ran. `internal_error`: Volcano failed for a
+ reason of its own, such as its own statements around a file.
+ `timeout` and `attempts_exhausted`: the run could not finish.
+ `operator_failed`: Volcano ended a run that stopped making
+ progress; read the history to see which files were applied, then
+ start a new run.
+ message (str): What happened, naming files and Postgres error codes. The
+ database's own message is on the failed file.
+ """
+
+ code: DatabaseMigrationRunErrorCode
+ message: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ code: str = self.code
+
+ message = self.message
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "code": code,
+ "message": message,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ code = check_database_migration_run_error_code(d.pop("code"))
+
+
+
+
+ message = d.pop("message")
+
+ database_migration_run_error = cls(
+ code=code,
+ message=message,
+ )
+
+
+ database_migration_run_error.additional_properties = d
+ return database_migration_run_error
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/database_migration_run_error_code.py b/src/volcano_sdk/_generated/models/database_migration_run_error_code.py
new file mode 100644
index 00000000..4344ede1
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_migration_run_error_code.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+DatabaseMigrationRunErrorCode = Literal['attempts_exhausted', 'backup_failed', 'branch_limit', 'checksum_mismatch', 'connection_failed', 'database_unavailable', 'history_missing', 'history_too_large', 'internal_error', 'invalid_file', 'invalid_layout', 'locked', 'migration_failed', 'operator_failed', 'owner_not_active', 'plan_changed', 'rehearsal_unavailable', 'restore_in_progress', 'timeout']
+
+DATABASE_MIGRATION_RUN_ERROR_CODE_VALUES: set[DatabaseMigrationRunErrorCode] = { 'attempts_exhausted', 'backup_failed', 'branch_limit', 'checksum_mismatch', 'connection_failed', 'database_unavailable', 'history_missing', 'history_too_large', 'internal_error', 'invalid_file', 'invalid_layout', 'locked', 'migration_failed', 'operator_failed', 'owner_not_active', 'plan_changed', 'rehearsal_unavailable', 'restore_in_progress', 'timeout', }
+
+def check_database_migration_run_error_code(value: str) -> DatabaseMigrationRunErrorCode:
+ if value in DATABASE_MIGRATION_RUN_ERROR_CODE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {DATABASE_MIGRATION_RUN_ERROR_CODE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/database_migration_run_file.py b/src/volcano_sdk/_generated/models/database_migration_run_file.py
new file mode 100644
index 00000000..542fc3a0
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_migration_run_file.py
@@ -0,0 +1,146 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.database_migration_run_file_outcome import check_database_migration_run_file_outcome
+from ..models.database_migration_run_file_outcome import DatabaseMigrationRunFileOutcome
+from ..types import UNSET, Unset
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.database_migration_file_error import DatabaseMigrationFileError
+
+
+
+
+
+T = TypeVar("T", bound="DatabaseMigrationRunFile")
+
+
+
+@_attrs_define
+class DatabaseMigrationRunFile:
+ """
+ Attributes:
+ name (str): Example: 001_create_users.sql.
+ outcome (DatabaseMigrationRunFileOutcome): `pending`: not settled yet, including a file the run will try again
+ on its next attempt. `already_applied`: the history already recorded
+ it, so it did not run; a file can also end this way in `apply`, when
+ another session applied or baselined it after the run planned.
+ `applied`: this run applied it. `failed`: its own SQL failed and
+ its transaction rolled back, in the rehearsal or in the database as
+ the run's `phase` says, including when the run's time limit stopped
+ it; a file whose `COMMIT` failed is `unknown` instead. A file whose
+ first line is `-- volcano:no-transaction` runs outside a
+ transaction, so nothing rolls back what it did before failing, such
+ as the invalid index a failed `CREATE INDEX CONCURRENTLY` leaves.
+ `not_run`: the run ended before the file committed, without its
+ SQL failing: before `apply`, after an earlier file failed or lost
+ its `COMMIT`, or after the connection was lost or Volcano's own
+ statements around the file failed, which rolled it back. `unknown`:
+ the run ended in `apply` without confirming whether the file ran,
+ for example because its attempts ran out, its `COMMIT` failed or
+ was cut short, or it ran outside a transaction and the connection
+ was lost or Volcano's own statements after it failed. The file may
+ have committed. The database's history says whether a file that
+ ran in a transaction committed, and the next run's plan applies a
+ file only if the history does not record it.
+ While the run is `queued` or `running`, each attempt reads the
+ history again before it runs a file, and sets every file the run
+ has not applied from it: `already_applied` if the history holds
+ it, `pending` otherwise. The exception is a file that runs outside
+ a transaction: it is `unknown` from just before Volcano sends it
+ until Volcano confirms what became of it. If it may have run, it
+ stays `unknown` until an attempt applies it or the history holds
+ it, and keeps the `error` of a later attempt that fails it.
+ error (DatabaseMigrationFileError | Unset): The database's error for a `failed` file, or for an `unknown` file
+ that runs outside a transaction, when a later attempt failed it after
+ an earlier one may have run it. `message` is the database's own
+ message and can quote values from the file or the data.
+ """
+
+ name: str
+ outcome: DatabaseMigrationRunFileOutcome
+ error: DatabaseMigrationFileError | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.database_migration_file_error import DatabaseMigrationFileError # noqa: PLC0415
+ name = self.name
+
+ outcome: str = self.outcome
+
+ error: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.error, Unset):
+ error = self.error.to_dict()
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "name": name,
+ "outcome": outcome,
+ })
+ if error is not UNSET:
+ field_dict["error"] = error
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.database_migration_file_error import DatabaseMigrationFileError # noqa: PLC0415
+ d = dict(src_dict)
+ name = d.pop("name")
+
+ outcome = check_database_migration_run_file_outcome(d.pop("outcome"))
+
+
+
+
+ _error = d.pop("error", UNSET)
+ error: DatabaseMigrationFileError | Unset
+ if isinstance(_error, Unset):
+ error = UNSET
+ else:
+ error = DatabaseMigrationFileError.from_dict(_error)
+
+
+
+
+ database_migration_run_file = cls(
+ name=name,
+ outcome=outcome,
+ error=error,
+ )
+
+
+ database_migration_run_file.additional_properties = d
+ return database_migration_run_file
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/database_migration_run_file_outcome.py b/src/volcano_sdk/_generated/models/database_migration_run_file_outcome.py
new file mode 100644
index 00000000..98144a1b
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_migration_run_file_outcome.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+DatabaseMigrationRunFileOutcome = Literal['already_applied', 'applied', 'failed', 'not_run', 'pending', 'unknown']
+
+DATABASE_MIGRATION_RUN_FILE_OUTCOME_VALUES: set[DatabaseMigrationRunFileOutcome] = { 'already_applied', 'applied', 'failed', 'not_run', 'pending', 'unknown', }
+
+def check_database_migration_run_file_outcome(value: str) -> DatabaseMigrationRunFileOutcome:
+ if value in DATABASE_MIGRATION_RUN_FILE_OUTCOME_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {DATABASE_MIGRATION_RUN_FILE_OUTCOME_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/database_migration_run_list.py b/src/volcano_sdk/_generated/models/database_migration_run_list.py
new file mode 100644
index 00000000..19afefaa
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_migration_run_list.py
@@ -0,0 +1,94 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.database_migration_run import DatabaseMigrationRun
+
+
+
+
+
+T = TypeVar("T", bound="DatabaseMigrationRunList")
+
+
+
+@_attrs_define
+class DatabaseMigrationRunList:
+ """
+ Attributes:
+ data (list[DatabaseMigrationRun]):
+ """
+
+ data: list[DatabaseMigrationRun]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.database_migration_run import DatabaseMigrationRun # noqa: PLC0415
+ data = []
+ for data_item_data in self.data:
+ data_item = data_item_data.to_dict()
+ data.append(data_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "data": data,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.database_migration_run import DatabaseMigrationRun # noqa: PLC0415
+ d = dict(src_dict)
+ data = []
+ _data = d.pop("data")
+ for data_item_data in (_data):
+ data_item = DatabaseMigrationRun.from_dict(data_item_data)
+
+
+
+ data.append(data_item)
+
+
+ database_migration_run_list = cls(
+ data=data,
+ )
+
+
+ database_migration_run_list.additional_properties = d
+ return database_migration_run_list
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/database_migration_run_phase.py b/src/volcano_sdk/_generated/models/database_migration_run_phase.py
new file mode 100644
index 00000000..2b47f2fd
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_migration_run_phase.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+DatabaseMigrationRunPhase = Literal['apply', 'backup', 'plan', 'rehearse']
+
+DATABASE_MIGRATION_RUN_PHASE_VALUES: set[DatabaseMigrationRunPhase] = { 'apply', 'backup', 'plan', 'rehearse', }
+
+def check_database_migration_run_phase(value: str) -> DatabaseMigrationRunPhase:
+ if value in DATABASE_MIGRATION_RUN_PHASE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {DATABASE_MIGRATION_RUN_PHASE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/database_migration_run_source.py b/src/volcano_sdk/_generated/models/database_migration_run_source.py
new file mode 100644
index 00000000..8f4a02f2
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_migration_run_source.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+DatabaseMigrationRunSource = Literal['api', 'git_deploy']
+
+DATABASE_MIGRATION_RUN_SOURCE_VALUES: set[DatabaseMigrationRunSource] = { 'api', 'git_deploy', }
+
+def check_database_migration_run_source(value: str) -> DatabaseMigrationRunSource:
+ if value in DATABASE_MIGRATION_RUN_SOURCE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {DATABASE_MIGRATION_RUN_SOURCE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/database_migration_run_status.py b/src/volcano_sdk/_generated/models/database_migration_run_status.py
new file mode 100644
index 00000000..c43390b0
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_migration_run_status.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+DatabaseMigrationRunStatus = Literal['failed', 'queued', 'running', 'succeeded']
+
+DATABASE_MIGRATION_RUN_STATUS_VALUES: set[DatabaseMigrationRunStatus] = { 'failed', 'queued', 'running', 'succeeded', }
+
+def check_database_migration_run_status(value: str) -> DatabaseMigrationRunStatus:
+ if value in DATABASE_MIGRATION_RUN_STATUS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {DATABASE_MIGRATION_RUN_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/database_migration_warning.py b/src/volcano_sdk/_generated/models/database_migration_warning.py
new file mode 100644
index 00000000..8800437e
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_migration_warning.py
@@ -0,0 +1,111 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.database_migration_warning_code import check_database_migration_warning_code
+from ..models.database_migration_warning_code import DatabaseMigrationWarningCode
+from ..types import UNSET, Unset
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="DatabaseMigrationWarning")
+
+
+
+@_attrs_define
+class DatabaseMigrationWarning:
+ """ A condition the run reports that did not stop it.
+
+ Attributes:
+ code (DatabaseMigrationWarningCode): `out_of_order`: a pending file sorts before one the history already
+ records; it still ran. `missing_file`: the history records a file
+ the run did not include. `rehearsal_skipped`: the files were not
+ rehearsed, because branches are not available here or on the plan.
+ `backup_skipped`: no backup was taken, because backups are not
+ available here or on the plan. `backup_prune_failed`: Volcano
+ could not delete older migration backups beyond the 20 it keeps;
+ the run's outcome is unaffected, and the next run that takes a
+ backup tries again. `warnings_truncated`: the run raised more than
+ 100 warnings; it is the last one, and its message says how many
+ more were not kept.
+ message (str):
+ file (str | Unset): The file the warning is about, when it is about one.
+ """
+
+ code: DatabaseMigrationWarningCode
+ message: str
+ file: str | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ code: str = self.code
+
+ message = self.message
+
+ file = self.file
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "code": code,
+ "message": message,
+ })
+ if file is not UNSET:
+ field_dict["file"] = file
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ code = check_database_migration_warning_code(d.pop("code"))
+
+
+
+
+ message = d.pop("message")
+
+ file = d.pop("file", UNSET)
+
+ database_migration_warning = cls(
+ code=code,
+ message=message,
+ file=file,
+ )
+
+
+ database_migration_warning.additional_properties = d
+ return database_migration_warning
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/database_migration_warning_code.py b/src/volcano_sdk/_generated/models/database_migration_warning_code.py
new file mode 100644
index 00000000..c683f008
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_migration_warning_code.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+DatabaseMigrationWarningCode = Literal['backup_prune_failed', 'backup_skipped', 'missing_file', 'out_of_order', 'rehearsal_skipped', 'warnings_truncated']
+
+DATABASE_MIGRATION_WARNING_CODE_VALUES: set[DatabaseMigrationWarningCode] = { 'backup_prune_failed', 'backup_skipped', 'missing_file', 'out_of_order', 'rehearsal_skipped', 'warnings_truncated', }
+
+def check_database_migration_warning_code(value: str) -> DatabaseMigrationWarningCode:
+ if value in DATABASE_MIGRATION_WARNING_CODE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {DATABASE_MIGRATION_WARNING_CODE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/database_migrations.py b/src/volcano_sdk/_generated/models/database_migrations.py
new file mode 100644
index 00000000..31715275
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_migrations.py
@@ -0,0 +1,115 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+if TYPE_CHECKING:
+ from ..models.database_migration_history_entry import DatabaseMigrationHistoryEntry
+
+
+
+
+
+T = TypeVar("T", bound="DatabaseMigrations")
+
+
+
+@_attrs_define
+class DatabaseMigrations:
+ """
+ Attributes:
+ history (list[DatabaseMigrationHistoryEntry]): Every file the history records, in name order.
+ active_run_id (UUID | Unset): The run that is queued or running, if any.
+ """
+
+ history: list[DatabaseMigrationHistoryEntry]
+ active_run_id: UUID | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.database_migration_history_entry import DatabaseMigrationHistoryEntry # noqa: PLC0415
+ history = []
+ for history_item_data in self.history:
+ history_item = history_item_data.to_dict()
+ history.append(history_item)
+
+
+
+ active_run_id: str | Unset = UNSET
+ if not isinstance(self.active_run_id, Unset):
+ active_run_id = str(self.active_run_id)
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "history": history,
+ })
+ if active_run_id is not UNSET:
+ field_dict["active_run_id"] = active_run_id
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.database_migration_history_entry import DatabaseMigrationHistoryEntry # noqa: PLC0415
+ d = dict(src_dict)
+ history = []
+ _history = d.pop("history")
+ for history_item_data in (_history):
+ history_item = DatabaseMigrationHistoryEntry.from_dict(history_item_data)
+
+
+
+ history.append(history_item)
+
+
+ _active_run_id = d.pop("active_run_id", UNSET)
+ active_run_id: UUID | Unset
+ if isinstance(_active_run_id, Unset):
+ active_run_id = UNSET
+ else:
+ active_run_id = UUID(_active_run_id)
+
+
+
+
+ database_migrations = cls(
+ history=history,
+ active_run_id=active_run_id,
+ )
+
+
+ database_migrations.additional_properties = d
+ return database_migrations
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/database_restore_conflict_error.py b/src/volcano_sdk/_generated/models/database_restore_conflict_error.py
new file mode 100644
index 00000000..cd10e2d1
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/database_restore_conflict_error.py
@@ -0,0 +1,115 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="DatabaseRestoreConflictError")
+
+
+
+@_attrs_define
+class DatabaseRestoreConflictError:
+ """ A restore refused by the database's state. With code
+ `migration_run_in_progress`, `run_id` names the migration run backing up
+ or applying to the database.
+
+ Attributes:
+ error (str):
+ code (str | Unset): Stable machine-readable error code when a specific recovery path is available.
+ `plan_required` (403) means the project owner's plan does not include the requested feature or option; upgrading
+ the plan unlocks it. `person_required` (403) means a project access token tried to change LavaFlow settings,
+ which only the project's owner changes, with a platform token, or that the change needs the owner's own
+ credential that expires, a project repository, and an owner whose GitHub account can push to it; `error` says
+ which. A 403 without a code leaves the reason unspecified: it can be an access refusal, a reached limit, or a
+ plan check that could not read the owner's plan. Match on the code, not the message text.
+ run_id (UUID | Unset):
+ """
+
+ error: str
+ code: str | Unset = UNSET
+ run_id: UUID | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ error = self.error
+
+ code = self.code
+
+ run_id: str | Unset = UNSET
+ if not isinstance(self.run_id, Unset):
+ run_id = str(self.run_id)
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "error": error,
+ })
+ if code is not UNSET:
+ field_dict["code"] = code
+ if run_id is not UNSET:
+ field_dict["run_id"] = run_id
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ error = d.pop("error")
+
+ code = d.pop("code", UNSET)
+
+ _run_id = d.pop("run_id", UNSET)
+ run_id: UUID | Unset
+ if isinstance(_run_id, Unset):
+ run_id = UNSET
+ else:
+ run_id = UUID(_run_id)
+
+
+
+
+ database_restore_conflict_error = cls(
+ error=error,
+ code=code,
+ run_id=run_id,
+ )
+
+
+ database_restore_conflict_error.additional_properties = d
+ return database_restore_conflict_error
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/default_email_template.py b/src/volcano_sdk/_generated/models/default_email_template.py
new file mode 100644
index 00000000..725f0050
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/default_email_template.py
@@ -0,0 +1,107 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.default_email_template_type import check_default_email_template_type
+from ..models.default_email_template_type import DefaultEmailTemplateType
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="DefaultEmailTemplate")
+
+
+
+@_attrs_define
+class DefaultEmailTemplate:
+ """ Built-in email template used when no custom template applies.
+
+ Attributes:
+ type_ (DefaultEmailTemplateType):
+ subject (str):
+ html_body (str): HTML template with placeholders
+ text_body (str): Plain text template with placeholders
+ """
+
+ type_: DefaultEmailTemplateType
+ subject: str
+ html_body: str
+ text_body: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ type_: str = self.type_
+
+ subject = self.subject
+
+ html_body = self.html_body
+
+ text_body = self.text_body
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "type": type_,
+ "subject": subject,
+ "html_body": html_body,
+ "text_body": text_body,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ type_ = check_default_email_template_type(d.pop("type"))
+
+
+
+
+ subject = d.pop("subject")
+
+ html_body = d.pop("html_body")
+
+ text_body = d.pop("text_body")
+
+ default_email_template = cls(
+ type_=type_,
+ subject=subject,
+ html_body=html_body,
+ text_body=text_body,
+ )
+
+
+ default_email_template.additional_properties = d
+ return default_email_template
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/default_email_template_type.py b/src/volcano_sdk/_generated/models/default_email_template_type.py
new file mode 100644
index 00000000..8487643a
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/default_email_template_type.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+DefaultEmailTemplateType = Literal['confirmation', 'password_changed', 'password_reset', 'welcome']
+
+DEFAULT_EMAIL_TEMPLATE_TYPE_VALUES: set[DefaultEmailTemplateType] = { 'confirmation', 'password_changed', 'password_reset', 'welcome', }
+
+def check_default_email_template_type(value: str) -> DefaultEmailTemplateType:
+ if value in DEFAULT_EMAIL_TEMPLATE_TYPE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {DEFAULT_EMAIL_TEMPLATE_TYPE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/deployment_commit.py b/src/volcano_sdk/_generated/models/deployment_commit.py
new file mode 100644
index 00000000..a758aeea
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/deployment_commit.py
@@ -0,0 +1,127 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.deployment_commit_verification import check_deployment_commit_verification
+from ..models.deployment_commit_verification import DeploymentCommitVerification
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="DeploymentCommit")
+
+
+
+@_attrs_define
+class DeploymentCommit:
+ """ The commit a deploy client reported for the deployment's source. Absent when the client reported none. A frontend
+ deployment that publishes another deployment's build carries that deployment's commit.
+
+ Attributes:
+ repository (str): GitHub repository as `owner/name`, normalized from what the client sent. Example: acme/app.
+ sha (str): Full commit ID.
+ dirty (bool): `true` when the client reported that the uploaded files differ from the commit, or Volcano found
+ an uploaded file in the project's root directory that the commit does not hold, so the deployed code may differ
+ from the commit.
+ verified (bool): `true` only when `verification` is `files`: Volcano confirmed that the deployed files are the
+ commit's. A commit verified at the `repository` level is not `verified`.
+ verification (DeploymentCommitVerification): What Volcano confirmed about the commit, through the project's
+ GitHub connection, when it recorded the deployment. `files`: `repository` is the project's connected repository,
+ `sha` is on its production branch, every uploaded file is the commit's file at its path, and the upload holds
+ the commit's files under its root but those deploy clients leave out. Only a frontend upload is checked this
+ far. `repository`: `repository` is the project's connected repository and `sha` is on its production branch, but
+ the uploaded files were not compared with the commit, since a function upload holds build output rather than the
+ repository's layout. Only a function upload the client reports clean is checked at this level. `none`: Volcano
+ confirmed nothing, as for a commit the client reports dirty, one from another branch or repository, one from a
+ project without a connection, or one it couldn't check in time.
+ """
+
+ repository: str
+ sha: str
+ dirty: bool
+ verified: bool
+ verification: DeploymentCommitVerification
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ repository = self.repository
+
+ sha = self.sha
+
+ dirty = self.dirty
+
+ verified = self.verified
+
+ verification: str = self.verification
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "repository": repository,
+ "sha": sha,
+ "dirty": dirty,
+ "verified": verified,
+ "verification": verification,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ repository = d.pop("repository")
+
+ sha = d.pop("sha")
+
+ dirty = d.pop("dirty")
+
+ verified = d.pop("verified")
+
+ verification = check_deployment_commit_verification(d.pop("verification"))
+
+
+
+
+ deployment_commit = cls(
+ repository=repository,
+ sha=sha,
+ dirty=dirty,
+ verified=verified,
+ verification=verification,
+ )
+
+
+ deployment_commit.additional_properties = d
+ return deployment_commit
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/deployment_commit_verification.py b/src/volcano_sdk/_generated/models/deployment_commit_verification.py
new file mode 100644
index 00000000..ccad7a58
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/deployment_commit_verification.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+DeploymentCommitVerification = Literal['files', 'none', 'repository']
+
+DEPLOYMENT_COMMIT_VERIFICATION_VALUES: set[DeploymentCommitVerification] = { 'files', 'none', 'repository', }
+
+def check_deployment_commit_verification(value: str) -> DeploymentCommitVerification:
+ if value in DEPLOYMENT_COMMIT_VERIFICATION_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {DEPLOYMENT_COMMIT_VERIFICATION_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/durable_callback_error.py b/src/volcano_sdk/_generated/models/durable_callback_error.py
index 427d4465..a21e0d53 100644
--- a/src/volcano_sdk/_generated/models/durable_callback_error.py
+++ b/src/volcano_sdk/_generated/models/durable_callback_error.py
@@ -26,7 +26,10 @@ class DurableCallbackError:
Attributes:
type_ (str): A name workflows can branch on, such as `PaymentDeclined`. Up to
256 characters, without control characters.
- message (str | Unset): A human-readable explanation, up to 32 KiB.
+ message (str | Unset): A human-readable explanation of up to 32,768 bytes of UTF-8, with
+ tab and newline as its only control characters. A character
+ outside ASCII takes more than one byte, so such text reaches the
+ limit before `maxLength`.
"""
type_: str
diff --git a/src/volcano_sdk/_generated/models/durable_callback_registration.py b/src/volcano_sdk/_generated/models/durable_callback_registration.py
index a34633d6..08684463 100644
--- a/src/volcano_sdk/_generated/models/durable_callback_registration.py
+++ b/src/volcano_sdk/_generated/models/durable_callback_registration.py
@@ -27,9 +27,10 @@ class DurableCallbackRegistration:
Attributes:
token (str): The `vcb_` token the workflow handed out. It is the only credential
the callback operations take, so treat it as a secret.
- expires_at (datetime.datetime | None): When the waiting step times out and the token stops working. Null
- when the workflow set no timeout, in which case the token works
- until the execution ends.
+ expires_at (datetime.datetime | None): When the waiting step's `timeout` passes and the token stops
+ working. Null when the workflow set no `timeout`. A step with a
+ heartbeat timeout also ends once that long passes without a
+ heartbeat, which can be before this time.
"""
token: str
diff --git a/src/volcano_sdk/_generated/models/durable_execution.py b/src/volcano_sdk/_generated/models/durable_execution.py
index c45737cf..e9998a78 100644
--- a/src/volcano_sdk/_generated/models/durable_execution.py
+++ b/src/volcano_sdk/_generated/models/durable_execution.py
@@ -58,7 +58,8 @@ class DurableExecution:
result (Any | Unset): Whatever the function returned, verbatim. Absent while the execution
is still running, absent when the result was too large to return and
was checkpointed instead, and absent once the retention period has
- lapsed.
+ lapsed. A result Volcano has just read can still be returned for up
+ to five minutes after that.
result_expired (bool | Unset): `true` when the execution is terminal but its result is no longer
retained, which distinguishes a discarded result from an empty one.
Shortly after that the execution itself is dropped and reads answer
@@ -68,9 +69,11 @@ class DurableExecution:
unset, so it reads like a function that returned nothing.
error (DurableExecutionError | Unset): Why a failed or timed-out execution ended.
completed_at (datetime.datetime | Unset): Present once the execution has reached a terminal status.
- client_token (str | Unset): Lets a browser read and send the execution's messages. Returned only
- by the start whose input the execution runs, never by a repeat under
- the same name or by a read. Send it as `X-Volcano-Client-Token`.
+ client_token (str | Unset): Lets a browser read the execution, stop it, and read and send its
+ messages, and a service key scoped to a list without `*` do the
+ same. Returned only by the start whose input the execution runs,
+ never by a repeat under the same name or by a read. Send it as
+ `X-Volcano-Client-Token`.
"""
id: UUID
diff --git a/src/volcano_sdk/_generated/models/durable_function_config.py b/src/volcano_sdk/_generated/models/durable_function_config.py
index 989ce72d..b4843c31 100644
--- a/src/volcano_sdk/_generated/models/durable_function_config.py
+++ b/src/volcano_sdk/_generated/models/durable_function_config.py
@@ -36,7 +36,10 @@ class DurableFunctionConfig:
timeout is the plan's own, smaller number.
retention_days (int): How long a finished execution's result and history are retained, for
as long as the function exists. Deleting the function, or its
- project, ends retention early and takes the history with it.
+ project, ends retention early and takes the history with it. A
+ result or error Volcano has just read is kept in memory for up to
+ five minutes, so a read can still return it for up to five minutes
+ after retention ends.
"""
execution_timeout_seconds: int
diff --git a/src/volcano_sdk/_generated/models/email_template.py b/src/volcano_sdk/_generated/models/email_template.py
index cbb01b24..1cfd6f96 100644
--- a/src/volcano_sdk/_generated/models/email_template.py
+++ b/src/volcano_sdk/_generated/models/email_template.py
@@ -30,21 +30,21 @@ class EmailTemplate:
Attributes:
template_type (EmailTemplateTemplateType):
- subject (str): Example: Confirm your email address.
- html_body (str): HTML template with placeholders
- text_body (str): Plain text template with placeholders
id (UUID | Unset):
project_id (UUID | Unset):
+ subject (str | Unset): Example: Confirm your email address.
+ html_body (str | Unset): HTML template with placeholders
+ text_body (str | Unset): Plain text template with placeholders
created_at (datetime.datetime | Unset):
updated_at (datetime.datetime | Unset):
"""
template_type: EmailTemplateTemplateType
- subject: str
- html_body: str
- text_body: str
id: UUID | Unset = UNSET
project_id: UUID | Unset = UNSET
+ subject: str | Unset = UNSET
+ html_body: str | Unset = UNSET
+ text_body: str | Unset = UNSET
created_at: datetime.datetime | Unset = UNSET
updated_at: datetime.datetime | Unset = UNSET
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
@@ -56,12 +56,6 @@ class EmailTemplate:
def to_dict(self) -> dict[str, Any]:
template_type: str = self.template_type
- subject = self.subject
-
- html_body = self.html_body
-
- text_body = self.text_body
-
id: str | Unset = UNSET
if not isinstance(self.id, Unset):
id = str(self.id)
@@ -70,6 +64,12 @@ def to_dict(self) -> dict[str, Any]:
if not isinstance(self.project_id, Unset):
project_id = str(self.project_id)
+ subject = self.subject
+
+ html_body = self.html_body
+
+ text_body = self.text_body
+
created_at: str | Unset = UNSET
if not isinstance(self.created_at, Unset):
created_at = self.created_at.isoformat()
@@ -83,14 +83,17 @@ def to_dict(self) -> dict[str, Any]:
field_dict.update(self.additional_properties)
field_dict.update({
"template_type": template_type,
- "subject": subject,
- "html_body": html_body,
- "text_body": text_body,
})
if id is not UNSET:
field_dict["id"] = id
if project_id is not UNSET:
field_dict["project_id"] = project_id
+ if subject is not UNSET:
+ field_dict["subject"] = subject
+ if html_body is not UNSET:
+ field_dict["html_body"] = html_body
+ if text_body is not UNSET:
+ field_dict["text_body"] = text_body
if created_at is not UNSET:
field_dict["created_at"] = created_at
if updated_at is not UNSET:
@@ -108,12 +111,6 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
- subject = d.pop("subject")
-
- html_body = d.pop("html_body")
-
- text_body = d.pop("text_body")
-
_id = d.pop("id", UNSET)
id: UUID | Unset
if isinstance(_id, Unset):
@@ -134,6 +131,12 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ subject = d.pop("subject", UNSET)
+
+ html_body = d.pop("html_body", UNSET)
+
+ text_body = d.pop("text_body", UNSET)
+
_created_at = d.pop("created_at", UNSET)
created_at: datetime.datetime | Unset
if isinstance(_created_at, Unset):
@@ -156,11 +159,11 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
email_template = cls(
template_type=template_type,
+ id=id,
+ project_id=project_id,
subject=subject,
html_body=html_body,
text_body=text_body,
- id=id,
- project_id=project_id,
created_at=created_at,
updated_at=updated_at,
)
diff --git a/src/volcano_sdk/_generated/models/error.py b/src/volcano_sdk/_generated/models/error.py
index 4595ac6a..fd86f01f 100644
--- a/src/volcano_sdk/_generated/models/error.py
+++ b/src/volcano_sdk/_generated/models/error.py
@@ -25,6 +25,12 @@ class Error:
Attributes:
error (str):
code (str | Unset): Stable machine-readable error code when a specific recovery path is available.
+ `plan_required` (403) means the project owner's plan does not include the requested feature or option; upgrading
+ the plan unlocks it. `person_required` (403) means a project access token tried to change LavaFlow settings,
+ which only the project's owner changes, with a platform token, or that the change needs the owner's own
+ credential that expires, a project repository, and an owner whose GitHub account can push to it; `error` says
+ which. A 403 without a code leaves the reason unspecified: it can be an access refusal, a reached limit, or a
+ plan check that could not read the owner's plan. Match on the code, not the message text.
"""
error: str
diff --git a/src/volcano_sdk/_generated/models/export_project_source_request.py b/src/volcano_sdk/_generated/models/export_project_source_request.py
index 43a0bbcd..b633c071 100644
--- a/src/volcano_sdk/_generated/models/export_project_source_request.py
+++ b/src/volcano_sdk/_generated/models/export_project_source_request.py
@@ -8,6 +8,7 @@
from ..types import UNSET, Unset
+from ..types import UNSET, Unset
@@ -23,9 +24,14 @@ class ExportProjectSourceRequest:
"""
Attributes:
production_branch (str): The currently configured production branch the user confirmed for export.
+ repo_id (int | Unset): The `repo_id` of the connected repository the user confirmed for
+ export, as the git connection reports it. When set, export answers
+ `409` if the project is now connected to a different repository, so
+ source is written only to the repository the user was shown.
"""
production_branch: str
+ repo_id: int | Unset = UNSET
@@ -34,12 +40,16 @@ class ExportProjectSourceRequest:
def to_dict(self) -> dict[str, Any]:
production_branch = self.production_branch
+ repo_id = self.repo_id
+
field_dict: dict[str, Any] = {}
field_dict.update({
"production_branch": production_branch,
})
+ if repo_id is not UNSET:
+ field_dict["repo_id"] = repo_id
return field_dict
@@ -50,8 +60,11 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
d = dict(src_dict)
production_branch = d.pop("production_branch")
+ repo_id = d.pop("repo_id", UNSET)
+
export_project_source_request = cls(
production_branch=production_branch,
+ repo_id=repo_id,
)
return export_project_source_request
diff --git a/src/volcano_sdk/_generated/models/fork_create_request.py b/src/volcano_sdk/_generated/models/fork_create_request.py
new file mode 100644
index 00000000..8a9f29ce
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/fork_create_request.py
@@ -0,0 +1,111 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+if TYPE_CHECKING:
+ from ..models.fork_create_request_variables import ForkCreateRequestVariables
+
+
+
+
+
+T = TypeVar("T", bound="ForkCreateRequest")
+
+
+
+@_attrs_define
+class ForkCreateRequest:
+ """
+ Attributes:
+ share_id (str): The share to fork, the id at the end of its deploy URL.
+ release_id (UUID): The `release.id` the share's preview returned, so only the release the visitor saw is
+ installed.
+ name (str): The new project's name, which may contain only letters, numbers, underscores and hyphens. A name you
+ already use gets a short random suffix. An invalid name answers `400` before anything is counted against the
+ share or your hourly fork limit.
+ variables (ForkCreateRequestVariables | Unset): Values for the variables the preview lists, by name. Any may be
+ left out
+ and is then created empty; only listed names are accepted (`422`
+ otherwise). Each value is at most 4096 bytes of UTF-8, since a function's
+ environment is limited in bytes; a longer one, or one containing a NUL
+ character, answers `400`. Values are never logged, and `Idempotency-Key` compares only the names given a value.
+ """
+
+ share_id: str
+ release_id: UUID
+ name: str
+ variables: ForkCreateRequestVariables | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.fork_create_request_variables import ForkCreateRequestVariables # noqa: PLC0415
+ share_id = self.share_id
+
+ release_id = str(self.release_id)
+
+ name = self.name
+
+ variables: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.variables, Unset):
+ variables = self.variables.to_dict()
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "share_id": share_id,
+ "release_id": release_id,
+ "name": name,
+ })
+ if variables is not UNSET:
+ field_dict["variables"] = variables
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.fork_create_request_variables import ForkCreateRequestVariables # noqa: PLC0415
+ d = dict(src_dict)
+ share_id = d.pop("share_id")
+
+ release_id = UUID(d.pop("release_id"))
+
+
+
+
+ name = d.pop("name")
+
+ _variables = d.pop("variables", UNSET)
+ variables: ForkCreateRequestVariables | Unset
+ if isinstance(_variables, Unset):
+ variables = UNSET
+ else:
+ variables = ForkCreateRequestVariables.from_dict(_variables)
+
+
+
+
+ fork_create_request = cls(
+ share_id=share_id,
+ release_id=release_id,
+ name=name,
+ variables=variables,
+ )
+
+ return fork_create_request
+
diff --git a/src/volcano_sdk/_generated/models/fork_create_request_variables.py b/src/volcano_sdk/_generated/models/fork_create_request_variables.py
new file mode 100644
index 00000000..6ec30ed3
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/fork_create_request_variables.py
@@ -0,0 +1,70 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="ForkCreateRequestVariables")
+
+
+
+@_attrs_define
+class ForkCreateRequestVariables:
+ """ Values for the variables the preview lists, by name. Any may be left out
+ and is then created empty; only listed names are accepted (`422`
+ otherwise). Each value is at most 4096 bytes of UTF-8, since a function's
+ environment is limited in bytes; a longer one, or one containing a NUL
+ character, answers `400`. Values are never logged, and `Idempotency-Key` compares only the names given a value.
+
+ """
+
+ additional_properties: dict[str, str] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ fork_create_request_variables = cls(
+ )
+
+
+ fork_create_request_variables.additional_properties = d
+ return fork_create_request_variables
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> str:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: str) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/frontend.py b/src/volcano_sdk/_generated/models/frontend.py
index dc40a193..e62ed9de 100644
--- a/src/volcano_sdk/_generated/models/frontend.py
+++ b/src/volcano_sdk/_generated/models/frontend.py
@@ -23,6 +23,7 @@
if TYPE_CHECKING:
from ..models.frontend_function_route import FrontendFunctionRoute
+ from ..models.frontend_route import FrontendRoute
@@ -48,9 +49,17 @@ class Frontend:
frontend stays `active` on the previous deployment, so `failed` means no
deployment is serving.
deployed_regions (list[str]):
+ serving_candidate_id (None | UUID): The promoted Candidate whose runtime receives this frontend's traffic, the
+ same as
+ `candidate_id` in `serving`. Null when the frontend serves its own runtime. While it is
+ set, `current_deployment_id` and `status` describe a deployment that receives no traffic,
+ and deploying the frontend is refused until it is rolled back.
function_routes (list[FrontendFunctionRoute]): Paths on this frontend that forward to a public function, ordered
from most to least specific. Anyone who can load the frontend can
reach the target function at these paths without a credential.
+ frontend_routes (list[FrontendRoute]): Paths on this frontend served by another frontend in the project,
+ ordered from most to least specific. Function and Frontend routes
+ share one path namespace and the 64-route limit.
created_at (datetime.datetime):
updated_at (datetime.datetime):
variable_scope (FrontendVariableScope | Unset): All preserves access to all project variables. Shared includes
@@ -78,7 +87,9 @@ class Frontend:
framework: FrontendFramework
status: FrontendStatus
deployed_regions: list[str]
+ serving_candidate_id: None | UUID
function_routes: list[FrontendFunctionRoute]
+ frontend_routes: list[FrontendRoute]
created_at: datetime.datetime
updated_at: datetime.datetime
variable_scope: FrontendVariableScope | Unset = UNSET
@@ -100,6 +111,7 @@ class Frontend:
def to_dict(self) -> dict[str, Any]:
from ..models.frontend_function_route import FrontendFunctionRoute # noqa: PLC0415
+ from ..models.frontend_route import FrontendRoute # noqa: PLC0415
id = str(self.id)
project_id = str(self.project_id)
@@ -114,6 +126,12 @@ def to_dict(self) -> dict[str, Any]:
+ serving_candidate_id: None | str
+ if isinstance(self.serving_candidate_id, UUID):
+ serving_candidate_id = str(self.serving_candidate_id)
+ else:
+ serving_candidate_id = self.serving_candidate_id
+
function_routes = []
for function_routes_item_data in self.function_routes:
function_routes_item = function_routes_item_data.to_dict()
@@ -121,6 +139,13 @@ def to_dict(self) -> dict[str, Any]:
+ frontend_routes = []
+ for frontend_routes_item_data in self.frontend_routes:
+ frontend_routes_item = frontend_routes_item_data.to_dict()
+ frontend_routes.append(frontend_routes_item)
+
+
+
created_at = self.created_at.isoformat()
updated_at = self.updated_at.isoformat()
@@ -177,7 +202,9 @@ def to_dict(self) -> dict[str, Any]:
"framework": framework,
"status": status,
"deployed_regions": deployed_regions,
+ "serving_candidate_id": serving_candidate_id,
"function_routes": function_routes,
+ "frontend_routes": frontend_routes,
"created_at": created_at,
"updated_at": updated_at,
})
@@ -211,6 +238,7 @@ def to_dict(self) -> dict[str, Any]:
@classmethod
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
from ..models.frontend_function_route import FrontendFunctionRoute # noqa: PLC0415
+ from ..models.frontend_route import FrontendRoute # noqa: PLC0415
d = dict(src_dict)
id = UUID(d.pop("id"))
@@ -237,6 +265,24 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
deployed_regions = cast(list[str], d.pop("deployed_regions"))
+ def _parse_serving_candidate_id(data: object) -> None | UUID:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ serving_candidate_id_type_0 = UUID(data)
+
+
+
+ return serving_candidate_id_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(None | UUID, data)
+
+ serving_candidate_id = _parse_serving_candidate_id(d.pop("serving_candidate_id"))
+
+
function_routes = []
_function_routes = d.pop("function_routes")
for function_routes_item_data in (_function_routes):
@@ -247,6 +293,16 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
function_routes.append(function_routes_item)
+ frontend_routes = []
+ _frontend_routes = d.pop("frontend_routes")
+ for frontend_routes_item_data in (_frontend_routes):
+ frontend_routes_item = FrontendRoute.from_dict(frontend_routes_item_data)
+
+
+
+ frontend_routes.append(frontend_routes_item)
+
+
created_at = datetime.datetime.fromisoformat(d.pop("created_at"))
@@ -343,7 +399,9 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
framework=framework,
status=status,
deployed_regions=deployed_regions,
+ serving_candidate_id=serving_candidate_id,
function_routes=function_routes,
+ frontend_routes=frontend_routes,
created_at=created_at,
updated_at=updated_at,
variable_scope=variable_scope,
diff --git a/src/volcano_sdk/_generated/models/frontend_candidate.py b/src/volcano_sdk/_generated/models/frontend_candidate.py
new file mode 100644
index 00000000..7e5b36bc
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/frontend_candidate.py
@@ -0,0 +1,221 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.frontend_candidate_configuration_status import check_frontend_candidate_configuration_status
+from ..models.frontend_candidate_configuration_status import FrontendCandidateConfigurationStatus
+from ..models.frontend_candidate_status import check_frontend_candidate_status
+from ..models.frontend_candidate_status import FrontendCandidateStatus
+from ..types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+import datetime
+
+if TYPE_CHECKING:
+ from ..models.frontend_candidate_deployment import FrontendCandidateDeployment
+
+
+
+
+
+T = TypeVar("T", bound="FrontendCandidate")
+
+
+
+@_attrs_define
+class FrontendCandidate:
+ """ A copy of a frontend built from an uploaded archive with the frontend's own configuration, so
+ it can be checked before anything is promoted. A Candidate is reachable by anyone who holds its
+ URL and is not indexed or listed; it is never public, and it does not claim to be private.
+
+ Attributes:
+ id (UUID):
+ frontend_id (UUID):
+ name (str):
+ status (FrontendCandidateStatus): `creating` until its first deployment succeeds, `ready` while it serves,
+ `deleting` while
+ its runtime is removed, and `error` when its deletion gave up and needs an operator.
+ created_at (datetime.datetime):
+ updated_at (datetime.datetime):
+ url (str | Unset): Where the Candidate is served. Absent until its first deployment succeeds.
+ expires_at (datetime.datetime | Unset): When the Candidate is deleted on its own. Absent when it is kept until
+ deleted.
+ current_deployment_id (UUID | Unset): The deployment the Candidate serves. Absent until its first
+ deployment succeeds. It differs from `deployment` while a redeploy runs or after one failed.
+ deployment (FrontendCandidateDeployment | Unset):
+ configuration_status (FrontendCandidateConfigurationStatus | Unset): Present while the Candidate serves a
+ deployment. `current` means that deployment was built
+ with the variables the frontend selects now; `changed` means they differ, or can no longer
+ be resolved. Promotion refuses a Candidate whose status is `changed`.
+ """
+
+ id: UUID
+ frontend_id: UUID
+ name: str
+ status: FrontendCandidateStatus
+ created_at: datetime.datetime
+ updated_at: datetime.datetime
+ url: str | Unset = UNSET
+ expires_at: datetime.datetime | Unset = UNSET
+ current_deployment_id: UUID | Unset = UNSET
+ deployment: FrontendCandidateDeployment | Unset = UNSET
+ configuration_status: FrontendCandidateConfigurationStatus | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.frontend_candidate_deployment import FrontendCandidateDeployment # noqa: PLC0415
+ id = str(self.id)
+
+ frontend_id = str(self.frontend_id)
+
+ name = self.name
+
+ status: str = self.status
+
+ created_at = self.created_at.isoformat()
+
+ updated_at = self.updated_at.isoformat()
+
+ url = self.url
+
+ expires_at: str | Unset = UNSET
+ if not isinstance(self.expires_at, Unset):
+ expires_at = self.expires_at.isoformat()
+
+ current_deployment_id: str | Unset = UNSET
+ if not isinstance(self.current_deployment_id, Unset):
+ current_deployment_id = str(self.current_deployment_id)
+
+ deployment: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.deployment, Unset):
+ deployment = self.deployment.to_dict()
+
+ configuration_status: str | Unset = UNSET
+ if not isinstance(self.configuration_status, Unset):
+ configuration_status = self.configuration_status
+
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "id": id,
+ "frontend_id": frontend_id,
+ "name": name,
+ "status": status,
+ "created_at": created_at,
+ "updated_at": updated_at,
+ })
+ if url is not UNSET:
+ field_dict["url"] = url
+ if expires_at is not UNSET:
+ field_dict["expires_at"] = expires_at
+ if current_deployment_id is not UNSET:
+ field_dict["current_deployment_id"] = current_deployment_id
+ if deployment is not UNSET:
+ field_dict["deployment"] = deployment
+ if configuration_status is not UNSET:
+ field_dict["configuration_status"] = configuration_status
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.frontend_candidate_deployment import FrontendCandidateDeployment # noqa: PLC0415
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ frontend_id = UUID(d.pop("frontend_id"))
+
+
+
+
+ name = d.pop("name")
+
+ status = check_frontend_candidate_status(d.pop("status"))
+
+
+
+
+ created_at = datetime.datetime.fromisoformat(d.pop("created_at"))
+
+
+
+
+ updated_at = datetime.datetime.fromisoformat(d.pop("updated_at"))
+
+
+
+
+ url = d.pop("url", UNSET)
+
+ _expires_at = d.pop("expires_at", UNSET)
+ expires_at: datetime.datetime | Unset
+ if isinstance(_expires_at, Unset):
+ expires_at = UNSET
+ else:
+ expires_at = datetime.datetime.fromisoformat(_expires_at)
+
+
+
+
+ _current_deployment_id = d.pop("current_deployment_id", UNSET)
+ current_deployment_id: UUID | Unset
+ if isinstance(_current_deployment_id, Unset):
+ current_deployment_id = UNSET
+ else:
+ current_deployment_id = UUID(_current_deployment_id)
+
+
+
+
+ _deployment = d.pop("deployment", UNSET)
+ deployment: FrontendCandidateDeployment | Unset
+ if isinstance(_deployment, Unset):
+ deployment = UNSET
+ else:
+ deployment = FrontendCandidateDeployment.from_dict(_deployment)
+
+
+
+
+ _configuration_status = d.pop("configuration_status", UNSET)
+ configuration_status: FrontendCandidateConfigurationStatus | Unset
+ if isinstance(_configuration_status, Unset):
+ configuration_status = UNSET
+ else:
+ configuration_status = check_frontend_candidate_configuration_status(_configuration_status)
+
+
+
+
+ frontend_candidate = cls(
+ id=id,
+ frontend_id=frontend_id,
+ name=name,
+ status=status,
+ created_at=created_at,
+ updated_at=updated_at,
+ url=url,
+ expires_at=expires_at,
+ current_deployment_id=current_deployment_id,
+ deployment=deployment,
+ configuration_status=configuration_status,
+ )
+
+ return frontend_candidate
+
diff --git a/src/volcano_sdk/_generated/models/frontend_candidate_configuration_status.py b/src/volcano_sdk/_generated/models/frontend_candidate_configuration_status.py
new file mode 100644
index 00000000..d75743c9
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/frontend_candidate_configuration_status.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+FrontendCandidateConfigurationStatus = Literal['changed', 'current']
+
+FRONTEND_CANDIDATE_CONFIGURATION_STATUS_VALUES: set[FrontendCandidateConfigurationStatus] = { 'changed', 'current', }
+
+def check_frontend_candidate_configuration_status(value: str) -> FrontendCandidateConfigurationStatus:
+ if value in FRONTEND_CANDIDATE_CONFIGURATION_STATUS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {FRONTEND_CANDIDATE_CONFIGURATION_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/frontend_candidate_deployment.py b/src/volcano_sdk/_generated/models/frontend_candidate_deployment.py
new file mode 100644
index 00000000..ffa9f602
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/frontend_candidate_deployment.py
@@ -0,0 +1,129 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.frontend_candidate_deployment_status import check_frontend_candidate_deployment_status
+from ..models.frontend_candidate_deployment_status import FrontendCandidateDeploymentStatus
+from ..types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+import datetime
+
+
+
+
+
+
+T = TypeVar("T", bound="FrontendCandidateDeployment")
+
+
+
+@_attrs_define
+class FrontendCandidateDeployment:
+ """
+ Attributes:
+ id (UUID):
+ status (FrontendCandidateDeploymentStatus): `provisioning` while the build and deploy run, `active` once the
+ Candidate serves this
+ deployment, and `failed` when it could not be built or deployed. A failed deployment of a
+ Candidate that already served keeps the previous deployment serving.
+ configuration_digest (str): Identifies the resolved configuration the deployment was built with. It carries no
+ value.
+ created_at (datetime.datetime):
+ error_message (str | Unset): Why a failed deployment failed.
+ completed_at (datetime.datetime | Unset): Set once the deployment is no longer provisioning.
+ """
+
+ id: UUID
+ status: FrontendCandidateDeploymentStatus
+ configuration_digest: str
+ created_at: datetime.datetime
+ error_message: str | Unset = UNSET
+ completed_at: datetime.datetime | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ id = str(self.id)
+
+ status: str = self.status
+
+ configuration_digest = self.configuration_digest
+
+ created_at = self.created_at.isoformat()
+
+ error_message = self.error_message
+
+ completed_at: str | Unset = UNSET
+ if not isinstance(self.completed_at, Unset):
+ completed_at = self.completed_at.isoformat()
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "id": id,
+ "status": status,
+ "configuration_digest": configuration_digest,
+ "created_at": created_at,
+ })
+ if error_message is not UNSET:
+ field_dict["error_message"] = error_message
+ if completed_at is not UNSET:
+ field_dict["completed_at"] = completed_at
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ status = check_frontend_candidate_deployment_status(d.pop("status"))
+
+
+
+
+ configuration_digest = d.pop("configuration_digest")
+
+ created_at = datetime.datetime.fromisoformat(d.pop("created_at"))
+
+
+
+
+ error_message = d.pop("error_message", UNSET)
+
+ _completed_at = d.pop("completed_at", UNSET)
+ completed_at: datetime.datetime | Unset
+ if isinstance(_completed_at, Unset):
+ completed_at = UNSET
+ else:
+ completed_at = datetime.datetime.fromisoformat(_completed_at)
+
+
+
+
+ frontend_candidate_deployment = cls(
+ id=id,
+ status=status,
+ configuration_digest=configuration_digest,
+ created_at=created_at,
+ error_message=error_message,
+ completed_at=completed_at,
+ )
+
+ return frontend_candidate_deployment
+
diff --git a/src/volcano_sdk/_generated/models/frontend_candidate_deployment_status.py b/src/volcano_sdk/_generated/models/frontend_candidate_deployment_status.py
new file mode 100644
index 00000000..86e7bee9
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/frontend_candidate_deployment_status.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+FrontendCandidateDeploymentStatus = Literal['active', 'failed', 'provisioning']
+
+FRONTEND_CANDIDATE_DEPLOYMENT_STATUS_VALUES: set[FrontendCandidateDeploymentStatus] = { 'active', 'failed', 'provisioning', }
+
+def check_frontend_candidate_deployment_status(value: str) -> FrontendCandidateDeploymentStatus:
+ if value in FRONTEND_CANDIDATE_DEPLOYMENT_STATUS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {FRONTEND_CANDIDATE_DEPLOYMENT_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/frontend_candidate_list.py b/src/volcano_sdk/_generated/models/frontend_candidate_list.py
new file mode 100644
index 00000000..4f285561
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/frontend_candidate_list.py
@@ -0,0 +1,76 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.frontend_candidate import FrontendCandidate
+
+
+
+
+
+T = TypeVar("T", bound="FrontendCandidateList")
+
+
+
+@_attrs_define
+class FrontendCandidateList:
+ """
+ Attributes:
+ data (list[FrontendCandidate]):
+ """
+
+ data: list[FrontendCandidate]
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.frontend_candidate import FrontendCandidate # noqa: PLC0415
+ data = []
+ for data_item_data in self.data:
+ data_item = data_item_data.to_dict()
+ data.append(data_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "data": data,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.frontend_candidate import FrontendCandidate # noqa: PLC0415
+ d = dict(src_dict)
+ data = []
+ _data = d.pop("data")
+ for data_item_data in (_data):
+ data_item = FrontendCandidate.from_dict(data_item_data)
+
+
+
+ data.append(data_item)
+
+
+ frontend_candidate_list = cls(
+ data=data,
+ )
+
+ return frontend_candidate_list
+
diff --git a/src/volcano_sdk/_generated/models/frontend_candidate_status.py b/src/volcano_sdk/_generated/models/frontend_candidate_status.py
new file mode 100644
index 00000000..36f1c9c4
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/frontend_candidate_status.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+FrontendCandidateStatus = Literal['creating', 'deleting', 'error', 'ready']
+
+FRONTEND_CANDIDATE_STATUS_VALUES: set[FrontendCandidateStatus] = { 'creating', 'deleting', 'error', 'ready', }
+
+def check_frontend_candidate_status(value: str) -> FrontendCandidateStatus:
+ if value in FRONTEND_CANDIDATE_STATUS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {FRONTEND_CANDIDATE_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/frontend_custom_domain_conflict_error.py b/src/volcano_sdk/_generated/models/frontend_custom_domain_conflict_error.py
index 48324ad0..c4c07e89 100644
--- a/src/volcano_sdk/_generated/models/frontend_custom_domain_conflict_error.py
+++ b/src/volcano_sdk/_generated/models/frontend_custom_domain_conflict_error.py
@@ -33,6 +33,12 @@ class FrontendCustomDomainConflictError:
Attributes:
error (str):
code (str | Unset): Stable machine-readable error code when a specific recovery path is available.
+ `plan_required` (403) means the project owner's plan does not include the requested feature or option; upgrading
+ the plan unlocks it. `person_required` (403) means a project access token tried to change LavaFlow settings,
+ which only the project's owner changes, with a platform token, or that the change needs the owner's own
+ credential that expires, a project repository, and an owner whose GitHub account can push to it; `error` says
+ which. A 403 without a code leaves the reason unspecified: it can be an access refusal, a reached limit, or a
+ plan check that could not read the owner's plan. Match on the code, not the message text.
required_record (FrontendDomainVerificationRecord | Unset): The DNS records currently required. Volcano may
require an account-specific TXT ownership record for the hostname's domain before returning a CNAME that
authorizes managed certificate issuance and renewal. Clients must follow the records returned for the current
diff --git a/src/volcano_sdk/_generated/models/frontend_custom_domain_list.py b/src/volcano_sdk/_generated/models/frontend_custom_domain_list.py
new file mode 100644
index 00000000..3cdafb4b
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/frontend_custom_domain_list.py
@@ -0,0 +1,94 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.frontend_custom_domain_response import FrontendCustomDomainResponse
+
+
+
+
+
+T = TypeVar("T", bound="FrontendCustomDomainList")
+
+
+
+@_attrs_define
+class FrontendCustomDomainList:
+ """
+ Attributes:
+ data (list[FrontendCustomDomainResponse]):
+ """
+
+ data: list[FrontendCustomDomainResponse]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.frontend_custom_domain_response import FrontendCustomDomainResponse # noqa: PLC0415
+ data = []
+ for data_item_data in self.data:
+ data_item = data_item_data.to_dict()
+ data.append(data_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "data": data,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.frontend_custom_domain_response import FrontendCustomDomainResponse # noqa: PLC0415
+ d = dict(src_dict)
+ data = []
+ _data = d.pop("data")
+ for data_item_data in (_data):
+ data_item = FrontendCustomDomainResponse.from_dict(data_item_data)
+
+
+
+ data.append(data_item)
+
+
+ frontend_custom_domain_list = cls(
+ data=data,
+ )
+
+
+ frontend_custom_domain_list.additional_properties = d
+ return frontend_custom_domain_list
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/frontend_custom_domain_redirect.py b/src/volcano_sdk/_generated/models/frontend_custom_domain_redirect.py
new file mode 100644
index 00000000..04146df6
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/frontend_custom_domain_redirect.py
@@ -0,0 +1,90 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.frontend_custom_domain_redirect_status import check_frontend_custom_domain_redirect_status
+from ..models.frontend_custom_domain_redirect_status import FrontendCustomDomainRedirectStatus
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="FrontendCustomDomainRedirect")
+
+
+
+@_attrs_define
+class FrontendCustomDomainRedirect:
+ """
+ Attributes:
+ to (str): Hostname the domain redirects to.
+ status (FrontendCustomDomainRedirectStatus):
+ """
+
+ to: str
+ status: FrontendCustomDomainRedirectStatus
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ to = self.to
+
+ status: int = self.status
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "to": to,
+ "status": status,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ to = d.pop("to")
+
+ status = check_frontend_custom_domain_redirect_status(d.pop("status"))
+
+
+
+
+ frontend_custom_domain_redirect = cls(
+ to=to,
+ status=status,
+ )
+
+
+ frontend_custom_domain_redirect.additional_properties = d
+ return frontend_custom_domain_redirect
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/frontend_custom_domain_redirect_request.py b/src/volcano_sdk/_generated/models/frontend_custom_domain_redirect_request.py
new file mode 100644
index 00000000..4e80b6cc
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/frontend_custom_domain_redirect_request.py
@@ -0,0 +1,85 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.frontend_custom_domain_redirect_request_status import check_frontend_custom_domain_redirect_request_status
+from ..models.frontend_custom_domain_redirect_request_status import FrontendCustomDomainRedirectRequestStatus
+from ..types import UNSET, Unset
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="FrontendCustomDomainRedirectRequest")
+
+
+
+@_attrs_define
+class FrontendCustomDomainRedirectRequest:
+ """ Redirects every request for the domain to `to`, another active domain of the same frontend that serves it, keeping
+ the path and query string.
+
+ Attributes:
+ to (str): Hostname of an active domain of the same frontend that serves it. Example: www.example.com.
+ status (FrontendCustomDomainRedirectRequestStatus | Unset): Redirect status. 301 and 308 are permanent, 302 and
+ 307 temporary; 307 and 308 keep the request method and body. Default: 308.
+ """
+
+ to: str
+ status: FrontendCustomDomainRedirectRequestStatus | Unset = 308
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ to = self.to
+
+ status: int | Unset = UNSET
+ if not isinstance(self.status, Unset):
+ status = self.status
+
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "to": to,
+ })
+ if status is not UNSET:
+ field_dict["status"] = status
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ to = d.pop("to")
+
+ _status = d.pop("status", UNSET)
+ status: FrontendCustomDomainRedirectRequestStatus | Unset
+ if isinstance(_status, Unset):
+ status = UNSET
+ else:
+ status = check_frontend_custom_domain_redirect_request_status(_status)
+
+
+
+
+ frontend_custom_domain_redirect_request = cls(
+ to=to,
+ status=status,
+ )
+
+ return frontend_custom_domain_redirect_request
+
diff --git a/src/volcano_sdk/_generated/models/frontend_custom_domain_redirect_request_status.py b/src/volcano_sdk/_generated/models/frontend_custom_domain_redirect_request_status.py
new file mode 100644
index 00000000..7a118903
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/frontend_custom_domain_redirect_request_status.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+FrontendCustomDomainRedirectRequestStatus = Literal[301, 302, 307, 308]
+
+FRONTEND_CUSTOM_DOMAIN_REDIRECT_REQUEST_STATUS_VALUES: set[FrontendCustomDomainRedirectRequestStatus] = { 301, 302, 307, 308, }
+
+def check_frontend_custom_domain_redirect_request_status(value: int) -> FrontendCustomDomainRedirectRequestStatus:
+ if value in FRONTEND_CUSTOM_DOMAIN_REDIRECT_REQUEST_STATUS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {FRONTEND_CUSTOM_DOMAIN_REDIRECT_REQUEST_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/frontend_custom_domain_redirect_status.py b/src/volcano_sdk/_generated/models/frontend_custom_domain_redirect_status.py
new file mode 100644
index 00000000..ed85622b
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/frontend_custom_domain_redirect_status.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+FrontendCustomDomainRedirectStatus = Literal[301, 302, 307, 308]
+
+FRONTEND_CUSTOM_DOMAIN_REDIRECT_STATUS_VALUES: set[FrontendCustomDomainRedirectStatus] = { 301, 302, 307, 308, }
+
+def check_frontend_custom_domain_redirect_status(value: int) -> FrontendCustomDomainRedirectStatus:
+ if value in FRONTEND_CUSTOM_DOMAIN_REDIRECT_STATUS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {FRONTEND_CUSTOM_DOMAIN_REDIRECT_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/frontend_custom_domain_response.py b/src/volcano_sdk/_generated/models/frontend_custom_domain_response.py
index 7a58f669..b6c12d66 100644
--- a/src/volcano_sdk/_generated/models/frontend_custom_domain_response.py
+++ b/src/volcano_sdk/_generated/models/frontend_custom_domain_response.py
@@ -21,6 +21,7 @@
import datetime
if TYPE_CHECKING:
+ from ..models.frontend_custom_domain_redirect import FrontendCustomDomainRedirect
from ..models.frontend_domain_routing_record import FrontendDomainRoutingRecord
from ..models.frontend_domain_verification_record import FrontendDomainVerificationRecord
@@ -44,6 +45,8 @@ class FrontendCustomDomainResponse:
withdrawn, or Volcano is retrying after a failure. `failed`: a failure left the domain unserved, alongside
`domain_status: failed`; managed domains report the cause in `failure_reason`.
effective_urls (list[str]):
+ redirect (FrontendCustomDomainRedirect | None): Where the domain redirects every request, or null when it serves
+ the frontend.
created_at (datetime.datetime):
updated_at (datetime.datetime):
serving_certificate (FrontendCustomDomainResponseServingCertificate | Unset): Certificate the domain serves,
@@ -69,6 +72,7 @@ class FrontendCustomDomainResponse:
domain_status: FrontendCustomDomainResponseDomainStatus
verification_status: FrontendCustomDomainResponseVerificationStatus
effective_urls: list[str]
+ redirect: FrontendCustomDomainRedirect | None
created_at: datetime.datetime
updated_at: datetime.datetime
serving_certificate: FrontendCustomDomainResponseServingCertificate | Unset = UNSET
@@ -83,6 +87,7 @@ class FrontendCustomDomainResponse:
def to_dict(self) -> dict[str, Any]:
+ from ..models.frontend_custom_domain_redirect import FrontendCustomDomainRedirect # noqa: PLC0415
from ..models.frontend_domain_routing_record import FrontendDomainRoutingRecord # noqa: PLC0415
from ..models.frontend_domain_verification_record import FrontendDomainVerificationRecord # noqa: PLC0415
domain = self.domain
@@ -97,6 +102,12 @@ def to_dict(self) -> dict[str, Any]:
+ redirect: dict[str, Any] | None
+ if isinstance(self.redirect, FrontendCustomDomainRedirect):
+ redirect = self.redirect.to_dict()
+ else:
+ redirect = self.redirect
+
created_at = self.created_at.isoformat()
updated_at = self.updated_at.isoformat()
@@ -132,6 +143,7 @@ def to_dict(self) -> dict[str, Any]:
"domain_status": domain_status,
"verification_status": verification_status,
"effective_urls": effective_urls,
+ "redirect": redirect,
"created_at": created_at,
"updated_at": updated_at,
})
@@ -152,6 +164,7 @@ def to_dict(self) -> dict[str, Any]:
@classmethod
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.frontend_custom_domain_redirect import FrontendCustomDomainRedirect # noqa: PLC0415
from ..models.frontend_domain_routing_record import FrontendDomainRoutingRecord # noqa: PLC0415
from ..models.frontend_domain_verification_record import FrontendDomainVerificationRecord # noqa: PLC0415
d = dict(src_dict)
@@ -175,6 +188,24 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
effective_urls = cast(list[str], d.pop("effective_urls"))
+ def _parse_redirect(data: object) -> FrontendCustomDomainRedirect | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ redirect_type_1 = FrontendCustomDomainRedirect.from_dict(data)
+
+
+
+ return redirect_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(FrontendCustomDomainRedirect | None, data)
+
+ redirect = _parse_redirect(d.pop("redirect"))
+
+
created_at = datetime.datetime.fromisoformat(d.pop("created_at"))
@@ -227,6 +258,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
domain_status=domain_status,
verification_status=verification_status,
effective_urls=effective_urls,
+ redirect=redirect,
created_at=created_at,
updated_at=updated_at,
serving_certificate=serving_certificate,
diff --git a/src/volcano_sdk/_generated/models/frontend_deployment.py b/src/volcano_sdk/_generated/models/frontend_deployment.py
index e1619381..c43f95e3 100644
--- a/src/volcano_sdk/_generated/models/frontend_deployment.py
+++ b/src/volcano_sdk/_generated/models/frontend_deployment.py
@@ -20,6 +20,7 @@
import datetime
if TYPE_CHECKING:
+ from ..models.deployment_commit import DeploymentCommit
from ..models.deployment_progress import DeploymentProgress
@@ -46,6 +47,11 @@ class FrontendDeployment:
updated_at (datetime.datetime):
initiated_by (str | Unset): Platform user that triggered a request-initiated deployment; absent for git and
system deployments.
+ commit (DeploymentCommit | Unset): The commit a deploy client reported for the deployment's source. Absent when
+ the client reported none. A frontend deployment that publishes another deployment's build carries that
+ deployment's commit.
+ source_deployment_id (UUID | Unset): The deployment whose build this deployment published instead of compiling
+ its own source. Absent when the deployment compiled.
site_url (str | Unset):
build_duration_seconds (int | Unset): Total build time recorded for this deployment, in seconds.
build_count (int | Unset): Number of completed builds included in build_duration_seconds.
@@ -64,6 +70,8 @@ class FrontendDeployment:
created_at: datetime.datetime
updated_at: datetime.datetime
initiated_by: str | Unset = UNSET
+ commit: DeploymentCommit | Unset = UNSET
+ source_deployment_id: UUID | Unset = UNSET
site_url: str | Unset = UNSET
build_duration_seconds: int | Unset = UNSET
build_count: int | Unset = UNSET
@@ -77,6 +85,7 @@ class FrontendDeployment:
def to_dict(self) -> dict[str, Any]:
+ from ..models.deployment_commit import DeploymentCommit # noqa: PLC0415
from ..models.deployment_progress import DeploymentProgress # noqa: PLC0415
id = str(self.id)
@@ -96,6 +105,14 @@ def to_dict(self) -> dict[str, Any]:
initiated_by = self.initiated_by
+ commit: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.commit, Unset):
+ commit = self.commit.to_dict()
+
+ source_deployment_id: str | Unset = UNSET
+ if not isinstance(self.source_deployment_id, Unset):
+ source_deployment_id = str(self.source_deployment_id)
+
site_url = self.site_url
build_duration_seconds = self.build_duration_seconds
@@ -127,6 +144,10 @@ def to_dict(self) -> dict[str, Any]:
})
if initiated_by is not UNSET:
field_dict["initiated_by"] = initiated_by
+ if commit is not UNSET:
+ field_dict["commit"] = commit
+ if source_deployment_id is not UNSET:
+ field_dict["source_deployment_id"] = source_deployment_id
if site_url is not UNSET:
field_dict["site_url"] = site_url
if build_duration_seconds is not UNSET:
@@ -146,6 +167,7 @@ def to_dict(self) -> dict[str, Any]:
@classmethod
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.deployment_commit import DeploymentCommit # noqa: PLC0415
from ..models.deployment_progress import DeploymentProgress # noqa: PLC0415
d = dict(src_dict)
id = UUID(d.pop("id"))
@@ -190,6 +212,26 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
initiated_by = d.pop("initiated_by", UNSET)
+ _commit = d.pop("commit", UNSET)
+ commit: DeploymentCommit | Unset
+ if isinstance(_commit, Unset):
+ commit = UNSET
+ else:
+ commit = DeploymentCommit.from_dict(_commit)
+
+
+
+
+ _source_deployment_id = d.pop("source_deployment_id", UNSET)
+ source_deployment_id: UUID | Unset
+ if isinstance(_source_deployment_id, Unset):
+ source_deployment_id = UNSET
+ else:
+ source_deployment_id = UUID(_source_deployment_id)
+
+
+
+
site_url = d.pop("site_url", UNSET)
build_duration_seconds = d.pop("build_duration_seconds", UNSET)
@@ -228,6 +270,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
created_at=created_at,
updated_at=updated_at,
initiated_by=initiated_by,
+ commit=commit,
+ source_deployment_id=source_deployment_id,
site_url=site_url,
build_duration_seconds=build_duration_seconds,
build_count=build_count,
diff --git a/src/volcano_sdk/_generated/models/frontend_route.py b/src/volcano_sdk/_generated/models/frontend_route.py
new file mode 100644
index 00000000..390d2714
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/frontend_route.py
@@ -0,0 +1,130 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+from uuid import UUID
+import datetime
+
+
+
+
+
+
+T = TypeVar("T", bound="FrontendRoute")
+
+
+
+@_attrs_define
+class FrontendRoute:
+ """ A path prefix on this Frontend's hostnames served by another Frontend in the Project, the
+ mounted Frontend. Paths are forwarded unchanged, so the mounted Frontend serves its prefix
+ as real pages (page directories or a matching `basePath`).
+
+ Attributes:
+ id (UUID):
+ project_id (UUID):
+ frontend_id (UUID): The Frontend whose hostnames serve the route
+ target_frontend_id (UUID): The mounted Frontend
+ path_prefix (str):
+ created_at (datetime.datetime):
+ updated_at (datetime.datetime):
+ """
+
+ id: UUID
+ project_id: UUID
+ frontend_id: UUID
+ target_frontend_id: UUID
+ path_prefix: str
+ created_at: datetime.datetime
+ updated_at: datetime.datetime
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ id = str(self.id)
+
+ project_id = str(self.project_id)
+
+ frontend_id = str(self.frontend_id)
+
+ target_frontend_id = str(self.target_frontend_id)
+
+ path_prefix = self.path_prefix
+
+ created_at = self.created_at.isoformat()
+
+ updated_at = self.updated_at.isoformat()
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "id": id,
+ "project_id": project_id,
+ "frontend_id": frontend_id,
+ "target_frontend_id": target_frontend_id,
+ "path_prefix": path_prefix,
+ "created_at": created_at,
+ "updated_at": updated_at,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ frontend_id = UUID(d.pop("frontend_id"))
+
+
+
+
+ target_frontend_id = UUID(d.pop("target_frontend_id"))
+
+
+
+
+ path_prefix = d.pop("path_prefix")
+
+ created_at = datetime.datetime.fromisoformat(d.pop("created_at"))
+
+
+
+
+ updated_at = datetime.datetime.fromisoformat(d.pop("updated_at"))
+
+
+
+
+ frontend_route = cls(
+ id=id,
+ project_id=project_id,
+ frontend_id=frontend_id,
+ target_frontend_id=target_frontend_id,
+ path_prefix=path_prefix,
+ created_at=created_at,
+ updated_at=updated_at,
+ )
+
+ return frontend_route
+
diff --git a/src/volcano_sdk/_generated/models/frontend_route_list.py b/src/volcano_sdk/_generated/models/frontend_route_list.py
new file mode 100644
index 00000000..50975964
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/frontend_route_list.py
@@ -0,0 +1,76 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.frontend_route import FrontendRoute
+
+
+
+
+
+T = TypeVar("T", bound="FrontendRouteList")
+
+
+
+@_attrs_define
+class FrontendRouteList:
+ """
+ Attributes:
+ data (list[FrontendRoute]):
+ """
+
+ data: list[FrontendRoute]
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.frontend_route import FrontendRoute # noqa: PLC0415
+ data = []
+ for data_item_data in self.data:
+ data_item = data_item_data.to_dict()
+ data.append(data_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "data": data,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.frontend_route import FrontendRoute # noqa: PLC0415
+ d = dict(src_dict)
+ data = []
+ _data = d.pop("data")
+ for data_item_data in (_data):
+ data_item = FrontendRoute.from_dict(data_item_data)
+
+
+
+ data.append(data_item)
+
+
+ frontend_route_list = cls(
+ data=data,
+ )
+
+ return frontend_route_list
+
diff --git a/src/volcano_sdk/_generated/models/frontend_serving.py b/src/volcano_sdk/_generated/models/frontend_serving.py
new file mode 100644
index 00000000..2d59fb1a
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/frontend_serving.py
@@ -0,0 +1,125 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="FrontendServing")
+
+
+
+@_attrs_define
+class FrontendServing:
+ """ What a frontend serves. Until a Candidate is promoted it serves its own runtime and
+ `candidate_id` is null. After a promotion, the frontend's traffic is routed to that
+ Candidate's runtime, nothing is rebuilt or copied, and `previous_candidate_id` is the runtime a
+ rollback returns to (null when that is the frontend's own). A Candidate that serves cannot be
+ deleted and does not expire. One kept only as the runtime a rollback returns to does not
+ expire either, but it can be deleted, which gives up that rollback; the frontend's own
+ runtime stays one `to_production` rollback away.
+
+ Attributes:
+ revision (int): Counts changes to what the frontend serves or can roll back to — promotions, rollbacks, and
+ deleting the Candidate kept for a rollback. A promotion or rollback names the revision it read, so one that read
+ before such a change fails with `409` instead of overwriting it; read the serving state again and retry.
+ candidate_id (None | UUID):
+ previous_candidate_id (None | UUID):
+ """
+
+ revision: int
+ candidate_id: None | UUID
+ previous_candidate_id: None | UUID
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ revision = self.revision
+
+ candidate_id: None | str
+ if isinstance(self.candidate_id, UUID):
+ candidate_id = str(self.candidate_id)
+ else:
+ candidate_id = self.candidate_id
+
+ previous_candidate_id: None | str
+ if isinstance(self.previous_candidate_id, UUID):
+ previous_candidate_id = str(self.previous_candidate_id)
+ else:
+ previous_candidate_id = self.previous_candidate_id
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "revision": revision,
+ "candidate_id": candidate_id,
+ "previous_candidate_id": previous_candidate_id,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ revision = d.pop("revision")
+
+ def _parse_candidate_id(data: object) -> None | UUID:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ candidate_id_type_0 = UUID(data)
+
+
+
+ return candidate_id_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(None | UUID, data)
+
+ candidate_id = _parse_candidate_id(d.pop("candidate_id"))
+
+
+ def _parse_previous_candidate_id(data: object) -> None | UUID:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ previous_candidate_id_type_0 = UUID(data)
+
+
+
+ return previous_candidate_id_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(None | UUID, data)
+
+ previous_candidate_id = _parse_previous_candidate_id(d.pop("previous_candidate_id"))
+
+
+ frontend_serving = cls(
+ revision=revision,
+ candidate_id=candidate_id,
+ previous_candidate_id=previous_candidate_id,
+ )
+
+ return frontend_serving
+
diff --git a/src/volcano_sdk/_generated/models/function.py b/src/volcano_sdk/_generated/models/function.py
index bfe46bc2..de1e0005 100644
--- a/src/volcano_sdk/_generated/models/function.py
+++ b/src/volcano_sdk/_generated/models/function.py
@@ -64,9 +64,9 @@ class Function:
updated_at (datetime.datetime):
provisioning_started_at (datetime.datetime | Unset): Timestamp when the current provisioning phase started
invoke_url (str | Unset): Canonical geo-routed HTTPS endpoint for invoking this function. Use it as-is: it does
- not share a domain with the API, so a host derived from the API URL will not reach the function. Omitted when
- the deployment serves no public invocation domain, as in local development, so a client testing for an empty
- string never matches.
+ not share a domain with the API, so a host derived from the API URL will not reach the function. In local
+ development it is `http://{id}.functions.localhost:8000/`, served by the local API. Omitted when the deployment
+ serves no function invocation domain, so a client testing for an empty string never matches.
runtime (str | Unset):
handler (str | Unset):
current_deployment_id (UUID | Unset): Identifier of the latest function deployment operation
diff --git a/src/volcano_sdk/_generated/models/function_deployment.py b/src/volcano_sdk/_generated/models/function_deployment.py
index 7f7c87b2..c3bc84c0 100644
--- a/src/volcano_sdk/_generated/models/function_deployment.py
+++ b/src/volcano_sdk/_generated/models/function_deployment.py
@@ -20,6 +20,7 @@
import datetime
if TYPE_CHECKING:
+ from ..models.deployment_commit import DeploymentCommit
from ..models.deployment_progress import DeploymentProgress
@@ -45,6 +46,9 @@ class FunctionDeployment:
batch_id (UUID | Unset):
initiated_by (str | Unset): Platform user that triggered a request-initiated deployment; absent for git and
system deployments.
+ commit (DeploymentCommit | Unset): The commit a deploy client reported for the deployment's source. Absent when
+ the client reported none. A frontend deployment that publishes another deployment's build carries that
+ deployment's commit.
build_duration_seconds (int | Unset): Total build time recorded for this deployment, in seconds.
build_count (int | Unset): Number of completed builds included in build_duration_seconds.
build_duration_recorded_at (datetime.datetime | Unset): When the build time was last recorded.
@@ -64,6 +68,7 @@ class FunctionDeployment:
updated_at: datetime.datetime
batch_id: UUID | Unset = UNSET
initiated_by: str | Unset = UNSET
+ commit: DeploymentCommit | Unset = UNSET
build_duration_seconds: int | Unset = UNSET
build_count: int | Unset = UNSET
build_duration_recorded_at: datetime.datetime | Unset = UNSET
@@ -77,6 +82,7 @@ class FunctionDeployment:
def to_dict(self) -> dict[str, Any]:
+ from ..models.deployment_commit import DeploymentCommit # noqa: PLC0415
from ..models.deployment_progress import DeploymentProgress # noqa: PLC0415
id = str(self.id)
@@ -100,6 +106,10 @@ def to_dict(self) -> dict[str, Any]:
initiated_by = self.initiated_by
+ commit: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.commit, Unset):
+ commit = self.commit.to_dict()
+
build_duration_seconds = self.build_duration_seconds
build_count = self.build_count
@@ -135,6 +145,8 @@ def to_dict(self) -> dict[str, Any]:
field_dict["batch_id"] = batch_id
if initiated_by is not UNSET:
field_dict["initiated_by"] = initiated_by
+ if commit is not UNSET:
+ field_dict["commit"] = commit
if build_duration_seconds is not UNSET:
field_dict["build_duration_seconds"] = build_duration_seconds
if build_count is not UNSET:
@@ -154,6 +166,7 @@ def to_dict(self) -> dict[str, Any]:
@classmethod
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.deployment_commit import DeploymentCommit # noqa: PLC0415
from ..models.deployment_progress import DeploymentProgress # noqa: PLC0415
d = dict(src_dict)
id = UUID(d.pop("id"))
@@ -208,6 +221,16 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
initiated_by = d.pop("initiated_by", UNSET)
+ _commit = d.pop("commit", UNSET)
+ commit: DeploymentCommit | Unset
+ if isinstance(_commit, Unset):
+ commit = UNSET
+ else:
+ commit = DeploymentCommit.from_dict(_commit)
+
+
+
+
build_duration_seconds = d.pop("build_duration_seconds", UNSET)
build_count = d.pop("build_count", UNSET)
@@ -255,6 +278,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
updated_at=updated_at,
batch_id=batch_id,
initiated_by=initiated_by,
+ commit=commit,
build_duration_seconds=build_duration_seconds,
build_count=build_count,
build_duration_recorded_at=build_duration_recorded_at,
diff --git a/src/volcano_sdk/_generated/models/function_scheduler.py b/src/volcano_sdk/_generated/models/function_scheduler.py
index 54036e1c..ad459fe8 100644
--- a/src/volcano_sdk/_generated/models/function_scheduler.py
+++ b/src/volcano_sdk/_generated/models/function_scheduler.py
@@ -10,6 +10,10 @@
from ..models.function_kind import check_function_kind
from ..models.function_kind import FunctionKind
+from ..models.function_scheduler_health import check_function_scheduler_health
+from ..models.function_scheduler_health import FunctionSchedulerHealth
+from ..models.function_scheduler_last_run_status import check_function_scheduler_last_run_status
+from ..models.function_scheduler_last_run_status import FunctionSchedulerLastRunStatus
from ..models.function_scheduler_schedule_kind import check_function_scheduler_schedule_kind
from ..models.function_scheduler_schedule_kind import FunctionSchedulerScheduleKind
from ..types import UNSET, Unset
@@ -53,6 +57,16 @@ class FunctionScheduler:
last_error (str | Unset):
run_count (int | Unset): Total number of times this scheduler has executed. 0 for a scheduler that has never
run.
+ health (FunctionSchedulerHealth | Unset): `failing` while `consecutive_failures` is above 0; `healthy`
+ otherwise, including before its first run in the region the scheduler runs in now. A run from a region it moved
+ away from does not count. For a durable function a run finishes when its execution does, so a run that starts
+ but then fails counts as failed.
+ consecutive_failures (int | Unset): How many runs in a row have failed in the region the scheduler runs in now.
+ Resets to 0 when a run succeeds, and starts at 0 in a region it moves to.
+ last_run_status (FunctionSchedulerLastRunStatus | Unset): Outcome of the most recent finished run. Absent before
+ the first.
+ last_success_at (datetime.datetime | Unset): When the most recent successful run finished.
+ last_failure_at (datetime.datetime | Unset): When the most recent failed run finished.
created_at (datetime.datetime | Unset):
updated_at (datetime.datetime | Unset):
"""
@@ -73,6 +87,11 @@ class FunctionScheduler:
last_completed_at: datetime.datetime | Unset = UNSET
last_error: str | Unset = UNSET
run_count: int | Unset = UNSET
+ health: FunctionSchedulerHealth | Unset = UNSET
+ consecutive_failures: int | Unset = UNSET
+ last_run_status: FunctionSchedulerLastRunStatus | Unset = UNSET
+ last_success_at: datetime.datetime | Unset = UNSET
+ last_failure_at: datetime.datetime | Unset = UNSET
created_at: datetime.datetime | Unset = UNSET
updated_at: datetime.datetime | Unset = UNSET
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
@@ -139,6 +158,26 @@ def to_dict(self) -> dict[str, Any]:
run_count = self.run_count
+ health: str | Unset = UNSET
+ if not isinstance(self.health, Unset):
+ health = self.health
+
+
+ consecutive_failures = self.consecutive_failures
+
+ last_run_status: str | Unset = UNSET
+ if not isinstance(self.last_run_status, Unset):
+ last_run_status = self.last_run_status
+
+
+ last_success_at: str | Unset = UNSET
+ if not isinstance(self.last_success_at, Unset):
+ last_success_at = self.last_success_at.isoformat()
+
+ last_failure_at: str | Unset = UNSET
+ if not isinstance(self.last_failure_at, Unset):
+ last_failure_at = self.last_failure_at.isoformat()
+
created_at: str | Unset = UNSET
if not isinstance(self.created_at, Unset):
created_at = self.created_at.isoformat()
@@ -184,6 +223,16 @@ def to_dict(self) -> dict[str, Any]:
field_dict["last_error"] = last_error
if run_count is not UNSET:
field_dict["run_count"] = run_count
+ if health is not UNSET:
+ field_dict["health"] = health
+ if consecutive_failures is not UNSET:
+ field_dict["consecutive_failures"] = consecutive_failures
+ if last_run_status is not UNSET:
+ field_dict["last_run_status"] = last_run_status
+ if last_success_at is not UNSET:
+ field_dict["last_success_at"] = last_success_at
+ if last_failure_at is not UNSET:
+ field_dict["last_failure_at"] = last_failure_at
if created_at is not UNSET:
field_dict["created_at"] = created_at
if updated_at is not UNSET:
@@ -302,6 +351,48 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
run_count = d.pop("run_count", UNSET)
+ _health = d.pop("health", UNSET)
+ health: FunctionSchedulerHealth | Unset
+ if isinstance(_health, Unset):
+ health = UNSET
+ else:
+ health = check_function_scheduler_health(_health)
+
+
+
+
+ consecutive_failures = d.pop("consecutive_failures", UNSET)
+
+ _last_run_status = d.pop("last_run_status", UNSET)
+ last_run_status: FunctionSchedulerLastRunStatus | Unset
+ if isinstance(_last_run_status, Unset):
+ last_run_status = UNSET
+ else:
+ last_run_status = check_function_scheduler_last_run_status(_last_run_status)
+
+
+
+
+ _last_success_at = d.pop("last_success_at", UNSET)
+ last_success_at: datetime.datetime | Unset
+ if isinstance(_last_success_at, Unset):
+ last_success_at = UNSET
+ else:
+ last_success_at = datetime.datetime.fromisoformat(_last_success_at)
+
+
+
+
+ _last_failure_at = d.pop("last_failure_at", UNSET)
+ last_failure_at: datetime.datetime | Unset
+ if isinstance(_last_failure_at, Unset):
+ last_failure_at = UNSET
+ else:
+ last_failure_at = datetime.datetime.fromisoformat(_last_failure_at)
+
+
+
+
_created_at = d.pop("created_at", UNSET)
created_at: datetime.datetime | Unset
if isinstance(_created_at, Unset):
@@ -339,6 +430,11 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
last_completed_at=last_completed_at,
last_error=last_error,
run_count=run_count,
+ health=health,
+ consecutive_failures=consecutive_failures,
+ last_run_status=last_run_status,
+ last_success_at=last_success_at,
+ last_failure_at=last_failure_at,
created_at=created_at,
updated_at=updated_at,
)
diff --git a/src/volcano_sdk/_generated/models/function_scheduler_health.py b/src/volcano_sdk/_generated/models/function_scheduler_health.py
new file mode 100644
index 00000000..4b66932a
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/function_scheduler_health.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+FunctionSchedulerHealth = Literal['failing', 'healthy']
+
+FUNCTION_SCHEDULER_HEALTH_VALUES: set[FunctionSchedulerHealth] = { 'failing', 'healthy', }
+
+def check_function_scheduler_health(value: str) -> FunctionSchedulerHealth:
+ if value in FUNCTION_SCHEDULER_HEALTH_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {FUNCTION_SCHEDULER_HEALTH_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/function_scheduler_last_run_status.py b/src/volcano_sdk/_generated/models/function_scheduler_last_run_status.py
new file mode 100644
index 00000000..6f62a935
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/function_scheduler_last_run_status.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+FunctionSchedulerLastRunStatus = Literal['failed', 'succeeded']
+
+FUNCTION_SCHEDULER_LAST_RUN_STATUS_VALUES: set[FunctionSchedulerLastRunStatus] = { 'failed', 'succeeded', }
+
+def check_function_scheduler_last_run_status(value: str) -> FunctionSchedulerLastRunStatus:
+ if value in FUNCTION_SCHEDULER_LAST_RUN_STATUS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {FUNCTION_SCHEDULER_LAST_RUN_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/get_default_email_templates_response_200.py b/src/volcano_sdk/_generated/models/get_default_email_templates_response_200.py
index 7dfeab71..5d4909ec 100644
--- a/src/volcano_sdk/_generated/models/get_default_email_templates_response_200.py
+++ b/src/volcano_sdk/_generated/models/get_default_email_templates_response_200.py
@@ -12,7 +12,7 @@
from typing import cast
if TYPE_CHECKING:
- from ..models.email_template import EmailTemplate
+ from ..models.default_email_template import DefaultEmailTemplate
@@ -26,10 +26,10 @@
class GetDefaultEmailTemplatesResponse200:
"""
Attributes:
- data (list[EmailTemplate] | Unset):
+ data (list[DefaultEmailTemplate] | Unset):
"""
- data: list[EmailTemplate] | Unset = UNSET
+ data: list[DefaultEmailTemplate] | Unset = UNSET
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
@@ -37,7 +37,7 @@ class GetDefaultEmailTemplatesResponse200:
def to_dict(self) -> dict[str, Any]:
- from ..models.email_template import EmailTemplate # noqa: PLC0415
+ from ..models.default_email_template import DefaultEmailTemplate # noqa: PLC0415
data: list[dict[str, Any]] | Unset = UNSET
if not isinstance(self.data, Unset):
data = []
@@ -61,14 +61,14 @@ def to_dict(self) -> dict[str, Any]:
@classmethod
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
- from ..models.email_template import EmailTemplate # noqa: PLC0415
+ from ..models.default_email_template import DefaultEmailTemplate # noqa: PLC0415
d = dict(src_dict)
_data = d.pop("data", UNSET)
- data: list[EmailTemplate] | Unset = UNSET
+ data: list[DefaultEmailTemplate] | Unset = UNSET
if _data is not UNSET:
data = []
for data_item_data in _data:
- data_item = EmailTemplate.from_dict(data_item_data)
+ data_item = DefaultEmailTemplate.from_dict(data_item_data)
diff --git a/src/volcano_sdk/_generated/models/get_lavaflow_stats_category.py b/src/volcano_sdk/_generated/models/get_lavaflow_stats_category.py
new file mode 100644
index 00000000..8d37dec2
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/get_lavaflow_stats_category.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+GetLavaflowStatsCategory = Literal['bug', 'configuration', 'dependency', 'external', 'improvement', 'performance', 'security', 'uncategorized']
+
+GET_LAVAFLOW_STATS_CATEGORY_VALUES: set[GetLavaflowStatsCategory] = { 'bug', 'configuration', 'dependency', 'external', 'improvement', 'performance', 'security', 'uncategorized', }
+
+def check_get_lavaflow_stats_category(value: str) -> GetLavaflowStatsCategory:
+ if value in GET_LAVAFLOW_STATS_CATEGORY_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {GET_LAVAFLOW_STATS_CATEGORY_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/git_deployment_migration_run.py b/src/volcano_sdk/_generated/models/git_deployment_migration_run.py
new file mode 100644
index 00000000..37fcf007
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/git_deployment_migration_run.py
@@ -0,0 +1,98 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+from uuid import UUID
+
+if TYPE_CHECKING:
+ from ..models.resource_reference import ResourceReference
+
+
+
+
+
+T = TypeVar("T", bound="GitDeploymentMigrationRun")
+
+
+
+@_attrs_define
+class GitDeploymentMigrationRun:
+ """ A migration run a deployment run started. Get it at `GET /projects/{id}/databases/{databaseName}/migration-
+ runs/{runId}` with `database.name` and `id`.
+
+ Attributes:
+ id (UUID):
+ database (ResourceReference): Stable reference to a Volcano resource.
+ """
+
+ id: UUID
+ database: ResourceReference
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.resource_reference import ResourceReference # noqa: PLC0415
+ id = str(self.id)
+
+ database = self.database.to_dict()
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "database": database,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.resource_reference import ResourceReference # noqa: PLC0415
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ database = ResourceReference.from_dict(d.pop("database"))
+
+
+
+
+ git_deployment_migration_run = cls(
+ id=id,
+ database=database,
+ )
+
+
+ git_deployment_migration_run.additional_properties = d
+ return git_deployment_migration_run
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/git_deployment_run.py b/src/volcano_sdk/_generated/models/git_deployment_run.py
new file mode 100644
index 00000000..a1d5804f
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/git_deployment_run.py
@@ -0,0 +1,222 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.git_deployment_run_status import check_git_deployment_run_status
+from ..models.git_deployment_run_status import GitDeploymentRunStatus
+from ..types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+import datetime
+
+if TYPE_CHECKING:
+ from ..models.git_deployment_migration_run import GitDeploymentMigrationRun
+ from ..models.git_deployment_run_error import GitDeploymentRunError
+
+
+
+
+
+T = TypeVar("T", bound="GitDeploymentRun")
+
+
+
+@_attrs_define
+class GitDeploymentRun:
+ """ One push's deployment through Git auto deploy.
+
+ Attributes:
+ id (UUID):
+ status (GitDeploymentRunStatus): Where a run is. `pending` and `running` have not ended. `succeeded`: every
+ deployment the run dispatched succeeded, or the commit only had migrations to apply. `failed`: `error` says why.
+ `superseded`: a newer push replaced the run before it started. `skipped`: there was nothing to deploy; `error`
+ says why.
+ branch (str): The branch the push updated, the project's production branch at the time.
+ commit_sha (str): The commit the run deploys.
+ apply_migrations (bool): Whether the run applies the commit's migrations: the project's `apply_migrations` Git
+ deploy setting when the push arrived.
+ migration_runs (list[GitDeploymentMigrationRun]): The migration runs the run started, one per database, ordered
+ by database name. Empty when it started none.
+ created_at (datetime.datetime): When the push was recorded.
+ error (GitDeploymentRunError | Unset): Why a run failed or was skipped.
+ started_at (datetime.datetime | Unset): When a worker first picked the run up.
+ completed_at (datetime.datetime | Unset): When the run ended.
+ """
+
+ id: UUID
+ status: GitDeploymentRunStatus
+ branch: str
+ commit_sha: str
+ apply_migrations: bool
+ migration_runs: list[GitDeploymentMigrationRun]
+ created_at: datetime.datetime
+ error: GitDeploymentRunError | Unset = UNSET
+ started_at: datetime.datetime | Unset = UNSET
+ completed_at: datetime.datetime | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.git_deployment_migration_run import GitDeploymentMigrationRun # noqa: PLC0415
+ from ..models.git_deployment_run_error import GitDeploymentRunError # noqa: PLC0415
+ id = str(self.id)
+
+ status: str = self.status
+
+ branch = self.branch
+
+ commit_sha = self.commit_sha
+
+ apply_migrations = self.apply_migrations
+
+ migration_runs = []
+ for migration_runs_item_data in self.migration_runs:
+ migration_runs_item = migration_runs_item_data.to_dict()
+ migration_runs.append(migration_runs_item)
+
+
+
+ created_at = self.created_at.isoformat()
+
+ error: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.error, Unset):
+ error = self.error.to_dict()
+
+ started_at: str | Unset = UNSET
+ if not isinstance(self.started_at, Unset):
+ started_at = self.started_at.isoformat()
+
+ completed_at: str | Unset = UNSET
+ if not isinstance(self.completed_at, Unset):
+ completed_at = self.completed_at.isoformat()
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "status": status,
+ "branch": branch,
+ "commit_sha": commit_sha,
+ "apply_migrations": apply_migrations,
+ "migration_runs": migration_runs,
+ "created_at": created_at,
+ })
+ if error is not UNSET:
+ field_dict["error"] = error
+ if started_at is not UNSET:
+ field_dict["started_at"] = started_at
+ if completed_at is not UNSET:
+ field_dict["completed_at"] = completed_at
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.git_deployment_migration_run import GitDeploymentMigrationRun # noqa: PLC0415
+ from ..models.git_deployment_run_error import GitDeploymentRunError # noqa: PLC0415
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ status = check_git_deployment_run_status(d.pop("status"))
+
+
+
+
+ branch = d.pop("branch")
+
+ commit_sha = d.pop("commit_sha")
+
+ apply_migrations = d.pop("apply_migrations")
+
+ migration_runs = []
+ _migration_runs = d.pop("migration_runs")
+ for migration_runs_item_data in (_migration_runs):
+ migration_runs_item = GitDeploymentMigrationRun.from_dict(migration_runs_item_data)
+
+
+
+ migration_runs.append(migration_runs_item)
+
+
+ created_at = datetime.datetime.fromisoformat(d.pop("created_at"))
+
+
+
+
+ _error = d.pop("error", UNSET)
+ error: GitDeploymentRunError | Unset
+ if isinstance(_error, Unset):
+ error = UNSET
+ else:
+ error = GitDeploymentRunError.from_dict(_error)
+
+
+
+
+ _started_at = d.pop("started_at", UNSET)
+ started_at: datetime.datetime | Unset
+ if isinstance(_started_at, Unset):
+ started_at = UNSET
+ else:
+ started_at = datetime.datetime.fromisoformat(_started_at)
+
+
+
+
+ _completed_at = d.pop("completed_at", UNSET)
+ completed_at: datetime.datetime | Unset
+ if isinstance(_completed_at, Unset):
+ completed_at = UNSET
+ else:
+ completed_at = datetime.datetime.fromisoformat(_completed_at)
+
+
+
+
+ git_deployment_run = cls(
+ id=id,
+ status=status,
+ branch=branch,
+ commit_sha=commit_sha,
+ apply_migrations=apply_migrations,
+ migration_runs=migration_runs,
+ created_at=created_at,
+ error=error,
+ started_at=started_at,
+ completed_at=completed_at,
+ )
+
+
+ git_deployment_run.additional_properties = d
+ return git_deployment_run
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/git_deployment_run_error.py b/src/volcano_sdk/_generated/models/git_deployment_run_error.py
new file mode 100644
index 00000000..5123a1ea
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/git_deployment_run_error.py
@@ -0,0 +1,95 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="GitDeploymentRunError")
+
+
+
+@_attrs_define
+class GitDeploymentRunError:
+ """ Why a run failed or was skipped.
+
+ Attributes:
+ code (str): Stable machine-readable reason. For a failed run: `migration_failed`, `migration_invalid_layout`,
+ `migration_timeout`, `feature_unavailable`, `source_invalid`, `child_deploy_failed`, `child_deploy_not_started`,
+ `deploy_refused`, `typescript_not_compiled`, `deploy_failed`, `max_attempts_exhausted`, `owner_not_active`, or
+ `project_deleting`. `source_invalid`, `deploy_refused`, and `typescript_not_compiled` fail the same way if the
+ same commit is pushed again; `child_deploy_not_started`, `deploy_failed`, and `max_attempts_exhausted` may
+ succeed on another push; for `owner_not_active`, reactivating the owner's account restores deployment
+ eligibility; push again to deploy. `project_deleting` means the project is being deleted. For a skipped run:
+ `auto_deploy_disabled`, `binding_changed`, `disconnected`, `project_missing`, or `nothing_to_deploy`. Treat a
+ code you do not know as a failure.
+ message (str): What happened. For `migration_failed`, `migration_invalid_layout`, `source_invalid`,
+ `deploy_refused`, `child_deploy_not_started`, and `typescript_not_compiled` it names the database, files,
+ resource, or setting at fault when Volcano has them.
+ """
+
+ code: str
+ message: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ code = self.code
+
+ message = self.message
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "code": code,
+ "message": message,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ code = d.pop("code")
+
+ message = d.pop("message")
+
+ git_deployment_run_error = cls(
+ code=code,
+ message=message,
+ )
+
+
+ git_deployment_run_error.additional_properties = d
+ return git_deployment_run_error
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/git_deployment_run_status.py b/src/volcano_sdk/_generated/models/git_deployment_run_status.py
new file mode 100644
index 00000000..3a41b212
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/git_deployment_run_status.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+GitDeploymentRunStatus = Literal['failed', 'pending', 'running', 'skipped', 'succeeded', 'superseded']
+
+GIT_DEPLOYMENT_RUN_STATUS_VALUES: set[GitDeploymentRunStatus] = { 'failed', 'pending', 'running', 'skipped', 'succeeded', 'superseded', }
+
+def check_git_deployment_run_status(value: str) -> GitDeploymentRunStatus:
+ if value in GIT_DEPLOYMENT_RUN_STATUS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {GIT_DEPLOYMENT_RUN_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/git_repository.py b/src/volcano_sdk/_generated/models/git_repository.py
index b0d3878b..be535f6b 100644
--- a/src/volcano_sdk/_generated/models/git_repository.py
+++ b/src/volcano_sdk/_generated/models/git_repository.py
@@ -22,8 +22,8 @@
class GitRepository:
"""
Attributes:
- id (int): Stable GitHub repository id (repository.id), unchanged by renames.
- full_name (str):
+ id (int): GitHub's repository id. It stays the same through a rename or a transfer.
+ full_name (str): The repository's owner and name, such as `acme/shop`.
default_branch (str):
private (bool):
is_empty (bool): Whether the repository has no commits and can receive an initial source export.
diff --git a/src/volcano_sdk/_generated/models/git_repository_reference.py b/src/volcano_sdk/_generated/models/git_repository_reference.py
new file mode 100644
index 00000000..f60bb8c6
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/git_repository_reference.py
@@ -0,0 +1,85 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="GitRepositoryReference")
+
+
+
+@_attrs_define
+class GitRepositoryReference:
+ """ A GitHub repository, by its stable id and its name.
+
+ Attributes:
+ id (int): GitHub's repository id. It stays the same through a rename or a transfer.
+ full_name (str): The repository's owner and name, such as `acme/shop`.
+ """
+
+ id: int
+ full_name: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ id = self.id
+
+ full_name = self.full_name
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "full_name": full_name,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ id = d.pop("id")
+
+ full_name = d.pop("full_name")
+
+ git_repository_reference = cls(
+ id=id,
+ full_name=full_name,
+ )
+
+
+ git_repository_reference.additional_properties = d
+ return git_repository_reference
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/issue.py b/src/volcano_sdk/_generated/models/issue.py
index 18eddb2d..158254fe 100644
--- a/src/volcano_sdk/_generated/models/issue.py
+++ b/src/volcano_sdk/_generated/models/issue.py
@@ -8,6 +8,8 @@
from ..types import UNSET, Unset
+from ..models.issue_source import check_issue_source
+from ..models.issue_source import IssueSource
from ..models.issue_status import check_issue_status
from ..models.issue_status import IssueStatus
from ..types import UNSET, Unset
@@ -16,6 +18,7 @@
import datetime
if TYPE_CHECKING:
+ from ..models.issue_finding import IssueFinding
from ..models.resource_reference import ResourceReference
@@ -28,7 +31,9 @@
@_attrs_define
class Issue:
- """ Runtime errors from one function or frontend, grouped by error type and stack.
+ """ Runtime errors from one function or frontend, grouped by error type and stack, one LavaFlow Code Quality finding, or
+ a user-reported project problem. A report has a project resource, zero runtime occurrences, and report times as its
+ first and last seen times.
Attributes:
id (UUID):
@@ -37,15 +42,29 @@ class Issue:
title (str): The error type and message, with values such as IDs, numbers, and
URLs replaced by placeholders like `` and ``.
status (IssueStatus): `open` until someone resolves or ignores the issue. A resolved issue
- seen again reopens.
+ seen again reopens. A reported problem resolves when its LavaFlow fix
+ merges. Volcano ignores one whose report it deleted before any fix
+ merged, so it no longer counts toward the project's open issues.
+ source (IssueSource): Where the issue came from: `runtime` for errors your code logged, `code_quality` for a
+ LavaFlow Code Quality finding in code a deploy changed, or `report` for a problem reported for the project, such
+ as through Slack. A `code_quality` issue's `error_type` is the finding's rule, its `culprit` the enclosing
+ function and file, and its `event_count` the scans that found it.
+ exception (bool): Whether the issue holds an exception: one your code threw, or one it
+ logged with `console.error(err)` or Python's `logger.exception()`.
+ `false` for an error logged any other way, such as a structured log
+ line, a logger's error line, or a printed traceback, and for every
+ `code_quality` issue. Once `true`, it stays `true`.
event_count (int): Errors counted in this issue. A retried delivery can count an error twice.
first_seen_at (datetime.datetime):
last_seen_at (datetime.datetime):
created_at (datetime.datetime):
updated_at (datetime.datetime):
error_type (str | Unset): The exception class, such as `TypeError`. Omitted when the error has none.
- culprit (str | Unset): The innermost frame of your code in the stack, as `function (file)`. Omitted without a
- stack.
+ culprit (str | Unset): The innermost frame of your code in the stack, as `function (file)`. For a frontend's
+ Next.js build output, the outermost route or page file of the build in the stack, such as
+ `.next/server/app/checkout/route.js`, or without one, the outermost file of the build. For a minified file of a
+ function's own bundle, the file alone. Omitted without a stack.
+ finding (IssueFinding | Unset): The LavaFlow Code Quality finding behind a `code_quality` issue.
last_region (str | Unset): The region that served the latest error, such as `us-east-1`.
sample_event_id (str | Unset): The ID of the latest error's log event, while logs retain it.
sample_event_at (datetime.datetime | Unset): When the latest error's log event was written.
@@ -58,6 +77,8 @@ class Issue:
resource: ResourceReference
title: str
status: IssueStatus
+ source: IssueSource
+ exception: bool
event_count: int
first_seen_at: datetime.datetime
last_seen_at: datetime.datetime
@@ -65,6 +86,7 @@ class Issue:
updated_at: datetime.datetime
error_type: str | Unset = UNSET
culprit: str | Unset = UNSET
+ finding: IssueFinding | Unset = UNSET
last_region: str | Unset = UNSET
sample_event_id: str | Unset = UNSET
sample_event_at: datetime.datetime | Unset = UNSET
@@ -77,6 +99,7 @@ class Issue:
def to_dict(self) -> dict[str, Any]:
+ from ..models.issue_finding import IssueFinding # noqa: PLC0415
from ..models.resource_reference import ResourceReference # noqa: PLC0415
id = str(self.id)
@@ -88,6 +111,10 @@ def to_dict(self) -> dict[str, Any]:
status: str = self.status
+ source: str = self.source
+
+ exception = self.exception
+
event_count = self.event_count
first_seen_at = self.first_seen_at.isoformat()
@@ -102,6 +129,10 @@ def to_dict(self) -> dict[str, Any]:
culprit = self.culprit
+ finding: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.finding, Unset):
+ finding = self.finding.to_dict()
+
last_region = self.last_region
sample_event_id = self.sample_event_id
@@ -127,6 +158,8 @@ def to_dict(self) -> dict[str, Any]:
"resource": resource,
"title": title,
"status": status,
+ "source": source,
+ "exception": exception,
"event_count": event_count,
"first_seen_at": first_seen_at,
"last_seen_at": last_seen_at,
@@ -137,6 +170,8 @@ def to_dict(self) -> dict[str, Any]:
field_dict["error_type"] = error_type
if culprit is not UNSET:
field_dict["culprit"] = culprit
+ if finding is not UNSET:
+ field_dict["finding"] = finding
if last_region is not UNSET:
field_dict["last_region"] = last_region
if sample_event_id is not UNSET:
@@ -154,6 +189,7 @@ def to_dict(self) -> dict[str, Any]:
@classmethod
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.issue_finding import IssueFinding # noqa: PLC0415
from ..models.resource_reference import ResourceReference # noqa: PLC0415
d = dict(src_dict)
id = UUID(d.pop("id"))
@@ -178,6 +214,13 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ source = check_issue_source(d.pop("source"))
+
+
+
+
+ exception = d.pop("exception")
+
event_count = d.pop("event_count")
first_seen_at = datetime.datetime.fromisoformat(d.pop("first_seen_at"))
@@ -204,6 +247,16 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
culprit = d.pop("culprit", UNSET)
+ _finding = d.pop("finding", UNSET)
+ finding: IssueFinding | Unset
+ if isinstance(_finding, Unset):
+ finding = UNSET
+ else:
+ finding = IssueFinding.from_dict(_finding)
+
+
+
+
last_region = d.pop("last_region", UNSET)
sample_event_id = d.pop("sample_event_id", UNSET)
@@ -244,6 +297,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
resource=resource,
title=title,
status=status,
+ source=source,
+ exception=exception,
event_count=event_count,
first_seen_at=first_seen_at,
last_seen_at=last_seen_at,
@@ -251,6 +306,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
updated_at=updated_at,
error_type=error_type,
culprit=culprit,
+ finding=finding,
last_region=last_region,
sample_event_id=sample_event_id,
sample_event_at=sample_event_at,
diff --git a/src/volcano_sdk/_generated/models/issue_finding.py b/src/volcano_sdk/_generated/models/issue_finding.py
new file mode 100644
index 00000000..4796c6ce
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/issue_finding.py
@@ -0,0 +1,132 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.issue_finding_severity import check_issue_finding_severity
+from ..models.issue_finding_severity import IssueFindingSeverity
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="IssueFinding")
+
+
+
+@_attrs_define
+class IssueFinding:
+ """ The LavaFlow Code Quality finding behind a `code_quality` issue.
+
+ Attributes:
+ rule (str): The rule the finding names, such as `null-dereference`.
+ severity (IssueFindingSeverity): How much the problem matters, as the finding was confirmed.
+ commit_sha (str): The deployed commit the scan found the problem in.
+ path (str): The file, from the repository root.
+ start_line (int): The first line of the problem in that commit, from 1.
+ end_line (int): The last line of the problem in that commit.
+ explanation (str): What fails and on which input, as plain text. When it may contain a credential, LavaFlow
+ withholds it whole, and it reads `LavaFlow left this explanation out because it may contain a credential`.
+ """
+
+ rule: str
+ severity: IssueFindingSeverity
+ commit_sha: str
+ path: str
+ start_line: int
+ end_line: int
+ explanation: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ rule = self.rule
+
+ severity: str = self.severity
+
+ commit_sha = self.commit_sha
+
+ path = self.path
+
+ start_line = self.start_line
+
+ end_line = self.end_line
+
+ explanation = self.explanation
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "rule": rule,
+ "severity": severity,
+ "commit_sha": commit_sha,
+ "path": path,
+ "start_line": start_line,
+ "end_line": end_line,
+ "explanation": explanation,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ rule = d.pop("rule")
+
+ severity = check_issue_finding_severity(d.pop("severity"))
+
+
+
+
+ commit_sha = d.pop("commit_sha")
+
+ path = d.pop("path")
+
+ start_line = d.pop("start_line")
+
+ end_line = d.pop("end_line")
+
+ explanation = d.pop("explanation")
+
+ issue_finding = cls(
+ rule=rule,
+ severity=severity,
+ commit_sha=commit_sha,
+ path=path,
+ start_line=start_line,
+ end_line=end_line,
+ explanation=explanation,
+ )
+
+
+ issue_finding.additional_properties = d
+ return issue_finding
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/issue_finding_severity.py b/src/volcano_sdk/_generated/models/issue_finding_severity.py
new file mode 100644
index 00000000..91b079c5
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/issue_finding_severity.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+IssueFindingSeverity = Literal['critical', 'major', 'minor', 'nit']
+
+ISSUE_FINDING_SEVERITY_VALUES: set[IssueFindingSeverity] = { 'critical', 'major', 'minor', 'nit', }
+
+def check_issue_finding_severity(value: str) -> IssueFindingSeverity:
+ if value in ISSUE_FINDING_SEVERITY_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {ISSUE_FINDING_SEVERITY_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/issue_source.py b/src/volcano_sdk/_generated/models/issue_source.py
new file mode 100644
index 00000000..2abfc7b6
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/issue_source.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+IssueSource = Literal['code_quality', 'report', 'runtime']
+
+ISSUE_SOURCE_VALUES: set[IssueSource] = { 'code_quality', 'report', 'runtime', }
+
+def check_issue_source(value: str) -> IssueSource:
+ if value in ISSUE_SOURCE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {ISSUE_SOURCE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_allowed_workflow.py b/src/volcano_sdk/_generated/models/lavaflow_allowed_workflow.py
new file mode 100644
index 00000000..a306c59d
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_allowed_workflow.py
@@ -0,0 +1,105 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowAllowedWorkflow")
+
+
+
+@_attrs_define
+class LavaflowAllowedWorkflow:
+ """ A workflow job that could run a fix's pull request with the repository's secrets before a person approves it.
+
+ Attributes:
+ source (str): The branch or commit whose workflows run it. Example: main.
+ path (str): Example: .github/workflows/preview.yml.
+ job (str | Unset): The job, absent for a workflow that could not be read. Example: deploy-preview.
+ trigger (str | Unset): The event that runs it, absent for a workflow that could not be read. Example:
+ pull_request_target.
+ """
+
+ source: str
+ path: str
+ job: str | Unset = UNSET
+ trigger: str | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ source = self.source
+
+ path = self.path
+
+ job = self.job
+
+ trigger = self.trigger
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "source": source,
+ "path": path,
+ })
+ if job is not UNSET:
+ field_dict["job"] = job
+ if trigger is not UNSET:
+ field_dict["trigger"] = trigger
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ source = d.pop("source")
+
+ path = d.pop("path")
+
+ job = d.pop("job", UNSET)
+
+ trigger = d.pop("trigger", UNSET)
+
+ lavaflow_allowed_workflow = cls(
+ source=source,
+ path=path,
+ job=job,
+ trigger=trigger,
+ )
+
+
+ lavaflow_allowed_workflow.additional_properties = d
+ return lavaflow_allowed_workflow
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_anomaly.py b/src/volcano_sdk/_generated/models/lavaflow_anomaly.py
new file mode 100644
index 00000000..6f46f88c
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_anomaly.py
@@ -0,0 +1,92 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowAnomaly")
+
+
+
+@_attrs_define
+class LavaflowAnomaly:
+ """
+ Attributes:
+ flagged (bool):
+ reason (None | str): Why the resource is flagged, null when it is not.
+ """
+
+ flagged: bool
+ reason: None | str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ flagged = self.flagged
+
+ reason: None | str
+ reason = self.reason
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "flagged": flagged,
+ "reason": reason,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ flagged = d.pop("flagged")
+
+ def _parse_reason(data: object) -> None | str:
+ if data is None:
+ return data
+ return cast(None | str, data)
+
+ reason = _parse_reason(d.pop("reason"))
+
+
+ lavaflow_anomaly = cls(
+ flagged=flagged,
+ reason=reason,
+ )
+
+
+ lavaflow_anomaly.additional_properties = d
+ return lavaflow_anomaly
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_autonomy.py b/src/volcano_sdk/_generated/models/lavaflow_autonomy.py
new file mode 100644
index 00000000..b3573aa3
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_autonomy.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowAutonomy = Literal['diagnose_only', 'merge', 'open_pr']
+
+LAVAFLOW_AUTONOMY_VALUES: set[LavaflowAutonomy] = { 'diagnose_only', 'merge', 'open_pr', }
+
+def check_lavaflow_autonomy(value: str) -> LavaflowAutonomy:
+ if value in LAVAFLOW_AUTONOMY_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_AUTONOMY_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_category_counts.py b/src/volcano_sdk/_generated/models/lavaflow_category_counts.py
new file mode 100644
index 00000000..642d9ba1
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_category_counts.py
@@ -0,0 +1,133 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowCategoryCounts")
+
+
+
+@_attrs_define
+class LavaflowCategoryCounts:
+ """ Matching runs in each category, zeros included. `uncategorized` counts runs whose `category` is null.
+
+ Attributes:
+ bug (int):
+ performance (int):
+ security (int):
+ improvement (int):
+ configuration (int):
+ dependency (int):
+ external (int):
+ uncategorized (int):
+ """
+
+ bug: int
+ performance: int
+ security: int
+ improvement: int
+ configuration: int
+ dependency: int
+ external: int
+ uncategorized: int
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ bug = self.bug
+
+ performance = self.performance
+
+ security = self.security
+
+ improvement = self.improvement
+
+ configuration = self.configuration
+
+ dependency = self.dependency
+
+ external = self.external
+
+ uncategorized = self.uncategorized
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "bug": bug,
+ "performance": performance,
+ "security": security,
+ "improvement": improvement,
+ "configuration": configuration,
+ "dependency": dependency,
+ "external": external,
+ "uncategorized": uncategorized,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ bug = d.pop("bug")
+
+ performance = d.pop("performance")
+
+ security = d.pop("security")
+
+ improvement = d.pop("improvement")
+
+ configuration = d.pop("configuration")
+
+ dependency = d.pop("dependency")
+
+ external = d.pop("external")
+
+ uncategorized = d.pop("uncategorized")
+
+ lavaflow_category_counts = cls(
+ bug=bug,
+ performance=performance,
+ security=security,
+ improvement=improvement,
+ configuration=configuration,
+ dependency=dependency,
+ external=external,
+ uncategorized=uncategorized,
+ )
+
+
+ lavaflow_category_counts.additional_properties = d
+ return lavaflow_category_counts
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_code_quality_settings.py b/src/volcano_sdk/_generated/models/lavaflow_code_quality_settings.py
new file mode 100644
index 00000000..6f5f4d19
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_code_quality_settings.py
@@ -0,0 +1,79 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowCodeQualitySettings")
+
+
+
+@_attrs_define
+class LavaflowCodeQualitySettings:
+ """ LavaFlow Code Quality: whether LavaFlow reviews the code each production deploy changes and opens pull requests that
+ fix what it confirms.
+
+ Attributes:
+ enabled (bool): Whether Code Quality reviews the project's deploys. Off by default. It reads as off while the
+ project points at another repository than the one it was turned on for, and works only while LavaFlow is on.
+ """
+
+ enabled: bool
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ enabled = self.enabled
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "enabled": enabled,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ enabled = d.pop("enabled")
+
+ lavaflow_code_quality_settings = cls(
+ enabled=enabled,
+ )
+
+
+ lavaflow_code_quality_settings.additional_properties = d
+ return lavaflow_code_quality_settings
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_code_quality_update.py b/src/volcano_sdk/_generated/models/lavaflow_code_quality_update.py
new file mode 100644
index 00000000..25c6277f
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_code_quality_update.py
@@ -0,0 +1,60 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowCodeQualityUpdate")
+
+
+
+@_attrs_define
+class LavaflowCodeQualityUpdate:
+ """ Turns Code Quality on or off. Only the project's owner, signed in, can turn it on; any credential that can save the
+ settings can turn it off.
+
+ Attributes:
+ enabled (bool):
+ """
+
+ enabled: bool
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ enabled = self.enabled
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "enabled": enabled,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ enabled = d.pop("enabled")
+
+ lavaflow_code_quality_update = cls(
+ enabled=enabled,
+ )
+
+ return lavaflow_code_quality_update
+
diff --git a/src/volcano_sdk/_generated/models/lavaflow_commit_origin.py b/src/volcano_sdk/_generated/models/lavaflow_commit_origin.py
new file mode 100644
index 00000000..87ee4947
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_commit_origin.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowCommitOrigin = Literal['client_reported', 'client_reported_repository', 'push', 'repository']
+
+LAVAFLOW_COMMIT_ORIGIN_VALUES: set[LavaflowCommitOrigin] = { 'client_reported', 'client_reported_repository', 'push', 'repository', }
+
+def check_lavaflow_commit_origin(value: str) -> LavaflowCommitOrigin:
+ if value in LAVAFLOW_COMMIT_ORIGIN_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_COMMIT_ORIGIN_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_connector_binding.py b/src/volcano_sdk/_generated/models/lavaflow_connector_binding.py
new file mode 100644
index 00000000..c9c653be
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_connector_binding.py
@@ -0,0 +1,163 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.connector_type import check_connector_type
+from ..models.connector_type import ConnectorType
+from ..types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+import datetime
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_slack_binding import LavaflowSlackBinding
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowConnectorBinding")
+
+
+
+@_attrs_define
+class LavaflowConnectorBinding:
+ """ A place in a connector, such as a Slack channel, that reports problems to LavaFlow for a project.
+
+ Attributes:
+ id (UUID): The binding's ID, which removing it takes.
+ project_id (UUID):
+ connector_type (ConnectorType): The outside service a connector links to.
+ created_at (datetime.datetime):
+ connector_id (UUID | Unset): The connector the binding reports through. Omitted while the Volcano app is not
+ installed in the binding's Slack workspace; the binding reports again once it is.
+ slack (LavaflowSlackBinding | Unset): The Slack channel a binding reports from. Present when `connector_type` is
+ `slack`.
+ """
+
+ id: UUID
+ project_id: UUID
+ connector_type: ConnectorType
+ created_at: datetime.datetime
+ connector_id: UUID | Unset = UNSET
+ slack: LavaflowSlackBinding | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_slack_binding import LavaflowSlackBinding # noqa: PLC0415
+ id = str(self.id)
+
+ project_id = str(self.project_id)
+
+ connector_type: str = self.connector_type
+
+ created_at = self.created_at.isoformat()
+
+ connector_id: str | Unset = UNSET
+ if not isinstance(self.connector_id, Unset):
+ connector_id = str(self.connector_id)
+
+ slack: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.slack, Unset):
+ slack = self.slack.to_dict()
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "project_id": project_id,
+ "connector_type": connector_type,
+ "created_at": created_at,
+ })
+ if connector_id is not UNSET:
+ field_dict["connector_id"] = connector_id
+ if slack is not UNSET:
+ field_dict["slack"] = slack
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_slack_binding import LavaflowSlackBinding # noqa: PLC0415
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ connector_type = check_connector_type(d.pop("connector_type"))
+
+
+
+
+ created_at = datetime.datetime.fromisoformat(d.pop("created_at"))
+
+
+
+
+ _connector_id = d.pop("connector_id", UNSET)
+ connector_id: UUID | Unset
+ if isinstance(_connector_id, Unset):
+ connector_id = UNSET
+ else:
+ connector_id = UUID(_connector_id)
+
+
+
+
+ _slack = d.pop("slack", UNSET)
+ slack: LavaflowSlackBinding | Unset
+ if isinstance(_slack, Unset):
+ slack = UNSET
+ else:
+ slack = LavaflowSlackBinding.from_dict(_slack)
+
+
+
+
+ lavaflow_connector_binding = cls(
+ id=id,
+ project_id=project_id,
+ connector_type=connector_type,
+ created_at=created_at,
+ connector_id=connector_id,
+ slack=slack,
+ )
+
+
+ lavaflow_connector_binding.additional_properties = d
+ return lavaflow_connector_binding
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_connector_binding_create.py b/src/volcano_sdk/_generated/models/lavaflow_connector_binding_create.py
new file mode 100644
index 00000000..9d62b271
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_connector_binding_create.py
@@ -0,0 +1,89 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+from uuid import UUID
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_slack_binding_target import LavaflowSlackBindingTarget
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowConnectorBindingCreate")
+
+
+
+@_attrs_define
+class LavaflowConnectorBindingCreate:
+ """
+ Attributes:
+ project_id (UUID): The project the place reports for.
+ connector_id (UUID): The connector to bind, from `GET /connectors`.
+ slack (LavaflowSlackBindingTarget): The channel to bind, for a `slack` connector.
+ """
+
+ project_id: UUID
+ connector_id: UUID
+ slack: LavaflowSlackBindingTarget
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_slack_binding_target import LavaflowSlackBindingTarget # noqa: PLC0415
+ project_id = str(self.project_id)
+
+ connector_id = str(self.connector_id)
+
+ slack = self.slack.to_dict()
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "project_id": project_id,
+ "connector_id": connector_id,
+ "slack": slack,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_slack_binding_target import LavaflowSlackBindingTarget # noqa: PLC0415
+ d = dict(src_dict)
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ connector_id = UUID(d.pop("connector_id"))
+
+
+
+
+ slack = LavaflowSlackBindingTarget.from_dict(d.pop("slack"))
+
+
+
+
+ lavaflow_connector_binding_create = cls(
+ project_id=project_id,
+ connector_id=connector_id,
+ slack=slack,
+ )
+
+ return lavaflow_connector_binding_create
+
diff --git a/src/volcano_sdk/_generated/models/lavaflow_connector_bindings_response.py b/src/volcano_sdk/_generated/models/lavaflow_connector_bindings_response.py
new file mode 100644
index 00000000..251481ba
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_connector_bindings_response.py
@@ -0,0 +1,94 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_connector_binding import LavaflowConnectorBinding
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowConnectorBindingsResponse")
+
+
+
+@_attrs_define
+class LavaflowConnectorBindingsResponse:
+ """
+ Attributes:
+ bindings (list[LavaflowConnectorBinding]):
+ """
+
+ bindings: list[LavaflowConnectorBinding]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_connector_binding import LavaflowConnectorBinding # noqa: PLC0415
+ bindings = []
+ for bindings_item_data in self.bindings:
+ bindings_item = bindings_item_data.to_dict()
+ bindings.append(bindings_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "bindings": bindings,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_connector_binding import LavaflowConnectorBinding # noqa: PLC0415
+ d = dict(src_dict)
+ bindings = []
+ _bindings = d.pop("bindings")
+ for bindings_item_data in (_bindings):
+ bindings_item = LavaflowConnectorBinding.from_dict(bindings_item_data)
+
+
+
+ bindings.append(bindings_item)
+
+
+ lavaflow_connector_bindings_response = cls(
+ bindings=bindings,
+ )
+
+
+ lavaflow_connector_bindings_response.additional_properties = d
+ return lavaflow_connector_bindings_response
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_day_counts.py b/src/volcano_sdk/_generated/models/lavaflow_day_counts.py
new file mode 100644
index 00000000..8c1ec676
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_day_counts.py
@@ -0,0 +1,97 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+import datetime
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowDayCounts")
+
+
+
+@_attrs_define
+class LavaflowDayCounts:
+ """
+ Attributes:
+ date (datetime.date):
+ issues_opened (int): Issues LavaFlow took on that UTC day.
+ pull_requests_opened (int): Pull requests with a fix LavaFlow opened that UTC day.
+ """
+
+ date: datetime.date
+ issues_opened: int
+ pull_requests_opened: int
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ date = self.date.isoformat()
+
+ issues_opened = self.issues_opened
+
+ pull_requests_opened = self.pull_requests_opened
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "date": date,
+ "issues_opened": issues_opened,
+ "pull_requests_opened": pull_requests_opened,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ date = datetime.date.fromisoformat(d.pop("date"))
+
+
+
+
+ issues_opened = d.pop("issues_opened")
+
+ pull_requests_opened = d.pop("pull_requests_opened")
+
+ lavaflow_day_counts = cls(
+ date=date,
+ issues_opened=issues_opened,
+ pull_requests_opened=pull_requests_opened,
+ )
+
+
+ lavaflow_day_counts.additional_properties = d
+ return lavaflow_day_counts
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_diagnosis.py b/src/volcano_sdk/_generated/models/lavaflow_diagnosis.py
new file mode 100644
index 00000000..bcbc101f
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_diagnosis.py
@@ -0,0 +1,124 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_log_line import LavaflowLogLine
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowDiagnosis")
+
+
+
+@_attrs_define
+class LavaflowDiagnosis:
+ """ Each text reads `LavaFlow left this section out because it may contain a credential` when it may contain a
+ credential, holds one of the project's secret values, or is over 4,000 characters, as the fix's pull request
+ description leaves it out. A log line's `level` reads `""` then.
+
+ Attributes:
+ summary (str):
+ root_cause (str):
+ evidence (list[str]):
+ log_lines (list[LavaflowLogLine]): Empty for now. `evidence` cites the log lines the diagnosis relies on.
+ """
+
+ summary: str
+ root_cause: str
+ evidence: list[str]
+ log_lines: list[LavaflowLogLine]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_log_line import LavaflowLogLine # noqa: PLC0415
+ summary = self.summary
+
+ root_cause = self.root_cause
+
+ evidence = self.evidence
+
+
+
+ log_lines = []
+ for log_lines_item_data in self.log_lines:
+ log_lines_item = log_lines_item_data.to_dict()
+ log_lines.append(log_lines_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "summary": summary,
+ "root_cause": root_cause,
+ "evidence": evidence,
+ "log_lines": log_lines,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_log_line import LavaflowLogLine # noqa: PLC0415
+ d = dict(src_dict)
+ summary = d.pop("summary")
+
+ root_cause = d.pop("root_cause")
+
+ evidence = cast(list[str], d.pop("evidence"))
+
+
+ log_lines = []
+ _log_lines = d.pop("log_lines")
+ for log_lines_item_data in (_log_lines):
+ log_lines_item = LavaflowLogLine.from_dict(log_lines_item_data)
+
+
+
+ log_lines.append(log_lines_item)
+
+
+ lavaflow_diagnosis = cls(
+ summary=summary,
+ root_cause=root_cause,
+ evidence=evidence,
+ log_lines=log_lines,
+ )
+
+
+ lavaflow_diagnosis.additional_properties = d
+ return lavaflow_diagnosis
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_draft_reason.py b/src/volcano_sdk/_generated/models/lavaflow_draft_reason.py
new file mode 100644
index 00000000..e292990b
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_draft_reason.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowDraftReason = Literal['converted_to_draft', 'open_pr', 'review_unresolved']
+
+LAVAFLOW_DRAFT_REASON_VALUES: set[LavaflowDraftReason] = { 'converted_to_draft', 'open_pr', 'review_unresolved', }
+
+def check_lavaflow_draft_reason(value: str) -> LavaflowDraftReason:
+ if value in LAVAFLOW_DRAFT_REASON_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_DRAFT_REASON_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_failure.py b/src/volcano_sdk/_generated/models/lavaflow_failure.py
new file mode 100644
index 00000000..79efb0bd
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_failure.py
@@ -0,0 +1,84 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowFailure")
+
+
+
+@_attrs_define
+class LavaflowFailure:
+ """
+ Attributes:
+ code (str): Stable code, such as `timed_out` or `feature_paused`.
+ message (str): Text to show for the code.
+ """
+
+ code: str
+ message: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ code = self.code
+
+ message = self.message
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "code": code,
+ "message": message,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ code = d.pop("code")
+
+ message = d.pop("message")
+
+ lavaflow_failure = cls(
+ code=code,
+ message=message,
+ )
+
+
+ lavaflow_failure.additional_properties = d
+ return lavaflow_failure
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_fix_outcome.py b/src/volcano_sdk/_generated/models/lavaflow_fix_outcome.py
new file mode 100644
index 00000000..0bd9bd76
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_fix_outcome.py
@@ -0,0 +1,150 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_fix_outcome_state import check_lavaflow_fix_outcome_state
+from ..models.lavaflow_fix_outcome_state import LavaflowFixOutcomeState
+from typing import cast
+import datetime
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowFixOutcome")
+
+
+
+@_attrs_define
+class LavaflowFixOutcome:
+ """ How a merged LavaFlow fix fared once it went live.
+
+ Attributes:
+ state (LavaflowFixOutcomeState): `watching` for 14 days after the fix goes live, then `effective` unless its
+ issue came back (`ineffective`) or a new issue was traced to its deploy (`regressed`). An outcome never moves
+ back. `reverted` is reserved and not produced yet.
+ live_at (datetime.datetime | None):
+ watch_until (datetime.datetime | None):
+ follow_ups (int): Runs linked to this fix.
+ """
+
+ state: LavaflowFixOutcomeState
+ live_at: datetime.datetime | None
+ watch_until: datetime.datetime | None
+ follow_ups: int
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ state: str = self.state
+
+ live_at: None | str
+ if isinstance(self.live_at, datetime.datetime):
+ live_at = self.live_at.isoformat()
+ else:
+ live_at = self.live_at
+
+ watch_until: None | str
+ if isinstance(self.watch_until, datetime.datetime):
+ watch_until = self.watch_until.isoformat()
+ else:
+ watch_until = self.watch_until
+
+ follow_ups = self.follow_ups
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "state": state,
+ "live_at": live_at,
+ "watch_until": watch_until,
+ "follow_ups": follow_ups,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ state = check_lavaflow_fix_outcome_state(d.pop("state"))
+
+
+
+
+ def _parse_live_at(data: object) -> datetime.datetime | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ live_at_type_0 = datetime.datetime.fromisoformat(data)
+
+
+
+ return live_at_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(datetime.datetime | None, data)
+
+ live_at = _parse_live_at(d.pop("live_at"))
+
+
+ def _parse_watch_until(data: object) -> datetime.datetime | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ watch_until_type_0 = datetime.datetime.fromisoformat(data)
+
+
+
+ return watch_until_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(datetime.datetime | None, data)
+
+ watch_until = _parse_watch_until(d.pop("watch_until"))
+
+
+ follow_ups = d.pop("follow_ups")
+
+ lavaflow_fix_outcome = cls(
+ state=state,
+ live_at=live_at,
+ watch_until=watch_until,
+ follow_ups=follow_ups,
+ )
+
+
+ lavaflow_fix_outcome.additional_properties = d
+ return lavaflow_fix_outcome
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_fix_outcome_state.py b/src/volcano_sdk/_generated/models/lavaflow_fix_outcome_state.py
new file mode 100644
index 00000000..ab321fb4
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_fix_outcome_state.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowFixOutcomeState = Literal['awaiting_deploy', 'effective', 'ineffective', 'regressed', 'reverted', 'watching']
+
+LAVAFLOW_FIX_OUTCOME_STATE_VALUES: set[LavaflowFixOutcomeState] = { 'awaiting_deploy', 'effective', 'ineffective', 'regressed', 'reverted', 'watching', }
+
+def check_lavaflow_fix_outcome_state(value: str) -> LavaflowFixOutcomeState:
+ if value in LAVAFLOW_FIX_OUTCOME_STATE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_FIX_OUTCOME_STATE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_global_skill.py b/src/volcano_sdk/_generated/models/lavaflow_global_skill.py
new file mode 100644
index 00000000..058e01e4
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_global_skill.py
@@ -0,0 +1,131 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_skill_scope import check_lavaflow_skill_scope
+from ..models.lavaflow_skill_scope import LavaflowSkillScope
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_global_skill_applies_to import LavaflowGlobalSkillAppliesTo
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowGlobalSkill")
+
+
+
+@_attrs_define
+class LavaflowGlobalSkill:
+ """ A skill Volcano wrote for every project. It holds no customer content.
+
+ Attributes:
+ scope (LavaflowSkillScope): `project` skills belong to this project and never leave it. `volcano` skills are
+ written by Volcano for every project.
+ name (str): Runs list it as `volcano:`.
+ description (str):
+ body (str):
+ applies_to (LavaflowGlobalSkillAppliesTo): Where a global skill applies. Empty lists apply it to every project.
+ content_sha256 (str): The hash of the skill's file, which identifies its version.
+ """
+
+ scope: LavaflowSkillScope
+ name: str
+ description: str
+ body: str
+ applies_to: LavaflowGlobalSkillAppliesTo
+ content_sha256: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_global_skill_applies_to import LavaflowGlobalSkillAppliesTo # noqa: PLC0415
+ scope: str = self.scope
+
+ name = self.name
+
+ description = self.description
+
+ body = self.body
+
+ applies_to = self.applies_to.to_dict()
+
+ content_sha256 = self.content_sha256
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "scope": scope,
+ "name": name,
+ "description": description,
+ "body": body,
+ "applies_to": applies_to,
+ "content_sha256": content_sha256,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_global_skill_applies_to import LavaflowGlobalSkillAppliesTo # noqa: PLC0415
+ d = dict(src_dict)
+ scope = check_lavaflow_skill_scope(d.pop("scope"))
+
+
+
+
+ name = d.pop("name")
+
+ description = d.pop("description")
+
+ body = d.pop("body")
+
+ applies_to = LavaflowGlobalSkillAppliesTo.from_dict(d.pop("applies_to"))
+
+
+
+
+ content_sha256 = d.pop("content_sha256")
+
+ lavaflow_global_skill = cls(
+ scope=scope,
+ name=name,
+ description=description,
+ body=body,
+ applies_to=applies_to,
+ content_sha256=content_sha256,
+ )
+
+
+ lavaflow_global_skill.additional_properties = d
+ return lavaflow_global_skill
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_global_skill_applies_to.py b/src/volcano_sdk/_generated/models/lavaflow_global_skill_applies_to.py
new file mode 100644
index 00000000..8190da7e
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_global_skill_applies_to.py
@@ -0,0 +1,103 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowGlobalSkillAppliesTo")
+
+
+
+@_attrs_define
+class LavaflowGlobalSkillAppliesTo:
+ """ Where a global skill applies. Empty lists apply it to every project.
+
+ Attributes:
+ runtimes (list[str]):
+ frameworks (list[str]):
+ resource_types (list[str]):
+ """
+
+ runtimes: list[str]
+ frameworks: list[str]
+ resource_types: list[str]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ runtimes = self.runtimes
+
+
+
+ frameworks = self.frameworks
+
+
+
+ resource_types = self.resource_types
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "runtimes": runtimes,
+ "frameworks": frameworks,
+ "resource_types": resource_types,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ runtimes = cast(list[str], d.pop("runtimes"))
+
+
+ frameworks = cast(list[str], d.pop("frameworks"))
+
+
+ resource_types = cast(list[str], d.pop("resource_types"))
+
+
+ lavaflow_global_skill_applies_to = cls(
+ runtimes=runtimes,
+ frameworks=frameworks,
+ resource_types=resource_types,
+ )
+
+
+ lavaflow_global_skill_applies_to.additional_properties = d
+ return lavaflow_global_skill_applies_to
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_global_skill_list.py b/src/volcano_sdk/_generated/models/lavaflow_global_skill_list.py
new file mode 100644
index 00000000..41de9de7
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_global_skill_list.py
@@ -0,0 +1,94 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_global_skill import LavaflowGlobalSkill
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowGlobalSkillList")
+
+
+
+@_attrs_define
+class LavaflowGlobalSkillList:
+ """
+ Attributes:
+ data (list[LavaflowGlobalSkill]):
+ """
+
+ data: list[LavaflowGlobalSkill]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_global_skill import LavaflowGlobalSkill # noqa: PLC0415
+ data = []
+ for data_item_data in self.data:
+ data_item = data_item_data.to_dict()
+ data.append(data_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "data": data,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_global_skill import LavaflowGlobalSkill # noqa: PLC0415
+ d = dict(src_dict)
+ data = []
+ _data = d.pop("data")
+ for data_item_data in (_data):
+ data_item = LavaflowGlobalSkill.from_dict(data_item_data)
+
+
+
+ data.append(data_item)
+
+
+ lavaflow_global_skill_list = cls(
+ data=data,
+ )
+
+
+ lavaflow_global_skill_list.additional_properties = d
+ return lavaflow_global_skill_list
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_held_fix_open.py b/src/volcano_sdk/_generated/models/lavaflow_held_fix_open.py
new file mode 100644
index 00000000..cfa4d86a
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_held_fix_open.py
@@ -0,0 +1,92 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowHeldFixOpen")
+
+
+
+@_attrs_define
+class LavaflowHeldFixOpen:
+ """ The project, the run, and the diff and jobs of the held fix you read, by the digests the run served them with.
+
+ Attributes:
+ project_id (UUID): The project the run belongs to.
+ run_id (UUID): The run whose held fix to open.
+ diff_sha256 (str): The run's `diff_sha256`, as it served it. Example:
+ 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08.
+ jobs_sha256 (str): The run's `held_workflows.jobs_sha256`, as it served it. Example:
+ 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae.
+ """
+
+ project_id: UUID
+ run_id: UUID
+ diff_sha256: str
+ jobs_sha256: str
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ project_id = str(self.project_id)
+
+ run_id = str(self.run_id)
+
+ diff_sha256 = self.diff_sha256
+
+ jobs_sha256 = self.jobs_sha256
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "project_id": project_id,
+ "run_id": run_id,
+ "diff_sha256": diff_sha256,
+ "jobs_sha256": jobs_sha256,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ run_id = UUID(d.pop("run_id"))
+
+
+
+
+ diff_sha256 = d.pop("diff_sha256")
+
+ jobs_sha256 = d.pop("jobs_sha256")
+
+ lavaflow_held_fix_open = cls(
+ project_id=project_id,
+ run_id=run_id,
+ diff_sha256=diff_sha256,
+ jobs_sha256=jobs_sha256,
+ )
+
+ return lavaflow_held_fix_open
+
diff --git a/src/volcano_sdk/_generated/models/lavaflow_held_workflows.py b/src/volcano_sdk/_generated/models/lavaflow_held_workflows.py
new file mode 100644
index 00000000..8bbcdf0e
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_held_workflows.py
@@ -0,0 +1,132 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_allowed_workflow import LavaflowAllowedWorkflow
+ from ..models.lavaflow_workflow_source import LavaflowWorkflowSource
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowHeldWorkflows")
+
+
+
+@_attrs_define
+class LavaflowHeldWorkflows:
+ """ Every workflow job that could run a held fix's pull request with the repository's secrets before a person approves
+ it, as LavaFlow found them when it held the fix, and the commits it read the workflows at.
+
+ Attributes:
+ read_at (list[LavaflowWorkflowSource]): Each branch or commit whose workflows LavaFlow read: the project's
+ production branch, the repository's default branch, and the commit the fix is cut from.
+ jobs (list[LavaflowAllowedWorkflow]): Every such job, at most 256, sorted by source, path and job. Empty when
+ LavaFlow read every workflow to the end and found none, such as when they changed between the hold and the read.
+ jobs_sha256 (str): Identifies `read_at` and `jobs` together. Treat it as opaque: it changes when a listed job,
+ or a commit the workflows were read at, does. Example:
+ 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae.
+ """
+
+ read_at: list[LavaflowWorkflowSource]
+ jobs: list[LavaflowAllowedWorkflow]
+ jobs_sha256: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_allowed_workflow import LavaflowAllowedWorkflow # noqa: PLC0415
+ from ..models.lavaflow_workflow_source import LavaflowWorkflowSource # noqa: PLC0415
+ read_at = []
+ for read_at_item_data in self.read_at:
+ read_at_item = read_at_item_data.to_dict()
+ read_at.append(read_at_item)
+
+
+
+ jobs = []
+ for jobs_item_data in self.jobs:
+ jobs_item = jobs_item_data.to_dict()
+ jobs.append(jobs_item)
+
+
+
+ jobs_sha256 = self.jobs_sha256
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "read_at": read_at,
+ "jobs": jobs,
+ "jobs_sha256": jobs_sha256,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_allowed_workflow import LavaflowAllowedWorkflow # noqa: PLC0415
+ from ..models.lavaflow_workflow_source import LavaflowWorkflowSource # noqa: PLC0415
+ d = dict(src_dict)
+ read_at = []
+ _read_at = d.pop("read_at")
+ for read_at_item_data in (_read_at):
+ read_at_item = LavaflowWorkflowSource.from_dict(read_at_item_data)
+
+
+
+ read_at.append(read_at_item)
+
+
+ jobs = []
+ _jobs = d.pop("jobs")
+ for jobs_item_data in (_jobs):
+ jobs_item = LavaflowAllowedWorkflow.from_dict(jobs_item_data)
+
+
+
+ jobs.append(jobs_item)
+
+
+ jobs_sha256 = d.pop("jobs_sha256")
+
+ lavaflow_held_workflows = cls(
+ read_at=read_at,
+ jobs=jobs,
+ jobs_sha256=jobs_sha256,
+ )
+
+
+ lavaflow_held_workflows.additional_properties = d
+ return lavaflow_held_workflows
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_hold_reason.py b/src/volcano_sdk/_generated/models/lavaflow_hold_reason.py
new file mode 100644
index 00000000..29ed31f3
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_hold_reason.py
@@ -0,0 +1,135 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowHoldReason")
+
+
+
+@_attrs_define
+class LavaflowHoldReason:
+ """ One reason LavaFlow holds the fix for a person.
+
+ Attributes:
+ code (str): Why the fix is held. `client_reported_commit`: the fix is built on a commit Volcano can't tie to a
+ push. `path`: it changes a path in `human_review_paths`, or deploy or infrastructure configuration Volcano
+ always holds, such as `volcano-config.yaml`, Terraform files, a YAML or JSON file that declares a resource, a
+ YAML template that mentions `apiVersion` or `kind`, a file in a Helm chart or Kustomize directory, or, in a
+ repository too large to read in full, any file no other path reason holds. `sensitive_path`: it changes another
+ path Volcano always holds: authentication or authorization code, Next.js middleware included; secret, key,
+ certificate or cryptography files; a coding agent's instructions or settings, or Git hook configuration; CI
+ configuration; a dependency manifest or lockfile, or a `package.json` change to what installs or its install
+ scripts; or runtime, container or other configuration files. `label`: the pull request has the `needs-human-
+ review` label. `no_checks`: no CI ran on it. `required_check_skipped`: a required check was skipped.
+ `no_required_checks`: the base branch requires no check, so passing checks alone don't vouch for the fix.
+ `changes_requested`: a reviewer requested changes. `repository_requires_approval`: the repository requires an
+ approving review. `person_commits`: someone other than LavaFlow pushed to the fix's branch. `rules_bypass`: the
+ Volcano GitHub App can bypass a ruleset on the base branch. `unchecked_rules`: the base branch has a rule
+ LavaFlow doesn't check, such as required signatures. `commit_convention`: no title can meet the repository's
+ commit convention. `ungated_workflows`: the fix opened past workflows that can run it with the repository's
+ secrets before a person approves it, as the project's owner allowed, or LavaFlow couldn't check its workflows,
+ or, when LavaFlow was about to start its CI or add it to a merge queue, a workflow could run it with those
+ secrets before a person approves it or couldn't be read, so LavaFlow takes it no further and never merges it. A
+ fix held for another reason before its CI starts lists it too when that check, run without starting CI, finds
+ such a workflow or can't finish. `ci_outside_actions`: when LavaFlow was about to start the fix's CI, the
+ repository could run CI, a build or a preview outside GitHub Actions: the root of the fix's tree or its base
+ branch's holds another service's configuration, such as `.travis.yml`, `.circleci/` or `netlify.toml`, which
+ `paths` names, another app reported checks or statuses on the base branch, or LavaFlow couldn't read them in
+ full. LavaFlow starts CI only when it finds no sign of CI outside GitHub Actions, so it never starts this fix's
+ CI or merges it. `lineage_undoes_parent`: the fix follows up an earlier LavaFlow fix and deletes or changes
+ lines that fix added, which could undo it. `lineage_cap`: the fix's lineage opened as many pull requests as it
+ may. `lineage_held`: an earlier pull request in the fix's lineage was held, stopped or closed.
+ `recent_regressions`: fixes LavaFlow merged in the project recently caused new errors. `no_test`: the fix
+ changes code the repository tests and adds no test, because testing it needs test infrastructure the repository
+ doesn't have or the change has no effect a test can observe. Other codes name a concern LavaFlow's reviewers
+ raised. New codes may appear.
+ question (str): Why LavaFlow holds the fix and what to check before you merge it, in one or two sentences to
+ show as given. A reviewer's reason is a question for you to answer. Reads `LavaFlow left this question out
+ because it may contain a credential` when it holds one of the project's secret values, a value shaped like a
+ credential, or a path `paths` leaves out, or is over 4,000 characters, and, for a question LavaFlow's reviewers
+ wrote, when it may contain a credential. Every question reads so, LavaFlow's fixed sentences too, on a run whose
+ `pull_request_skipped` is `possible_credential`.
+ paths (list[str]): The changed paths that matched, for a path code. For `ci_outside_actions`, the entries at the
+ repository's root that another CI or preview service reads, whether or not the fix changes them. `""` for a path
+ that may contain a credential, holds one of the project's secret values, or is over 4,000 characters.
+ """
+
+ code: str
+ question: str
+ paths: list[str]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ code = self.code
+
+ question = self.question
+
+ paths = self.paths
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "code": code,
+ "question": question,
+ "paths": paths,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ code = d.pop("code")
+
+ question = d.pop("question")
+
+ paths = cast(list[str], d.pop("paths"))
+
+
+ lavaflow_hold_reason = cls(
+ code=code,
+ question=question,
+ paths=paths,
+ )
+
+
+ lavaflow_hold_reason.additional_properties = d
+ return lavaflow_hold_reason
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_involved_resource.py b/src/volcano_sdk/_generated/models/lavaflow_involved_resource.py
new file mode 100644
index 00000000..0b8858a3
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_involved_resource.py
@@ -0,0 +1,111 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_involved_resource_roles_item import check_lavaflow_involved_resource_roles_item
+from ..models.lavaflow_involved_resource_roles_item import LavaflowInvolvedResourceRolesItem
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_resource_reference import LavaflowResourceReference
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowInvolvedResource")
+
+
+
+@_attrs_define
+class LavaflowInvolvedResource:
+ """ A resource a run involves, and how.
+
+ Attributes:
+ resource (LavaflowResourceReference): A function, durable function or frontend in the project, or the project of
+ a user-reported problem.
+ roles (list[LavaflowInvolvedResourceRolesItem]): `issue`: the issue came from it. `cause`: the issue came from
+ it, or code the diagnosis cites as evidence is in its source. `fix`: the diagnosis proposes changing its source,
+ or the fix changes it; a change to code that every function shares involves every function.
+ """
+
+ resource: LavaflowResourceReference
+ roles: list[LavaflowInvolvedResourceRolesItem]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_resource_reference import LavaflowResourceReference # noqa: PLC0415
+ resource = self.resource.to_dict()
+
+ roles = []
+ for roles_item_data in self.roles:
+ roles_item: str = roles_item_data
+ roles.append(roles_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "resource": resource,
+ "roles": roles,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_resource_reference import LavaflowResourceReference # noqa: PLC0415
+ d = dict(src_dict)
+ resource = LavaflowResourceReference.from_dict(d.pop("resource"))
+
+
+
+
+ roles = []
+ _roles = d.pop("roles")
+ for roles_item_data in (_roles):
+ roles_item = check_lavaflow_involved_resource_roles_item(roles_item_data)
+
+
+
+ roles.append(roles_item)
+
+
+ lavaflow_involved_resource = cls(
+ resource=resource,
+ roles=roles,
+ )
+
+
+ lavaflow_involved_resource.additional_properties = d
+ return lavaflow_involved_resource
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_involved_resource_count.py b/src/volcano_sdk/_generated/models/lavaflow_involved_resource_count.py
new file mode 100644
index 00000000..59a6693b
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_involved_resource_count.py
@@ -0,0 +1,94 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_resource_reference import LavaflowResourceReference
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowInvolvedResourceCount")
+
+
+
+@_attrs_define
+class LavaflowInvolvedResourceCount:
+ """ A resource and how many matching runs involve it.
+
+ Attributes:
+ resource (LavaflowResourceReference): A function, durable function or frontend in the project, or the project of
+ a user-reported problem.
+ runs (int):
+ """
+
+ resource: LavaflowResourceReference
+ runs: int
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_resource_reference import LavaflowResourceReference # noqa: PLC0415
+ resource = self.resource.to_dict()
+
+ runs = self.runs
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "resource": resource,
+ "runs": runs,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_resource_reference import LavaflowResourceReference # noqa: PLC0415
+ d = dict(src_dict)
+ resource = LavaflowResourceReference.from_dict(d.pop("resource"))
+
+
+
+
+ runs = d.pop("runs")
+
+ lavaflow_involved_resource_count = cls(
+ resource=resource,
+ runs=runs,
+ )
+
+
+ lavaflow_involved_resource_count.additional_properties = d
+ return lavaflow_involved_resource_count
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_involved_resource_roles_item.py b/src/volcano_sdk/_generated/models/lavaflow_involved_resource_roles_item.py
new file mode 100644
index 00000000..512830b6
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_involved_resource_roles_item.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowInvolvedResourceRolesItem = Literal['cause', 'fix', 'issue']
+
+LAVAFLOW_INVOLVED_RESOURCE_ROLES_ITEM_VALUES: set[LavaflowInvolvedResourceRolesItem] = { 'cause', 'fix', 'issue', }
+
+def check_lavaflow_involved_resource_roles_item(value: str) -> LavaflowInvolvedResourceRolesItem:
+ if value in LAVAFLOW_INVOLVED_RESOURCE_ROLES_ITEM_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_INVOLVED_RESOURCE_ROLES_ITEM_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_issue_summary.py b/src/volcano_sdk/_generated/models/lavaflow_issue_summary.py
new file mode 100644
index 00000000..e57f5d6b
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_issue_summary.py
@@ -0,0 +1,235 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.issue_status import check_issue_status
+from ..models.issue_status import IssueStatus
+from ..models.lavaflow_issue_summary_severity import check_lavaflow_issue_summary_severity
+from ..models.lavaflow_issue_summary_severity import LavaflowIssueSummarySeverity
+from ..types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+import datetime
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowIssueSummary")
+
+
+
+@_attrs_define
+class LavaflowIssueSummary:
+ """ The project issue a run works on.
+
+ Attributes:
+ id (UUID):
+ title (str): The issue's title: the error type and message, a Code Quality finding's title, or a reported
+ problem's title.
+ culprit (None | str): The innermost frame of your code, as `function (file)`; for a Code Quality finding, the
+ symbol and file it is in, as `symbol (file)`, or the file alone. Null for an error without a stack and for a
+ reported problem.
+ status (IssueStatus): `open` until someone resolves or ignores the issue. A resolved issue
+ seen again reopens. A reported problem resolves when its LavaFlow fix
+ merges. Volcano ignores one whose report it deleted before any fix
+ merged, so it no longer counts toward the project's open issues.
+ event_count (int): Errors the issue has grouped so far; for a Code Quality finding, the scans that saw it; 0 for
+ a reported problem.
+ last_seen_at (datetime.datetime):
+ resolved_at (datetime.datetime | None): When the issue was resolved; null unless it is resolved now.
+ regressed_at (datetime.datetime | None): When the issue was last seen again after it was resolved, and reopened;
+ null if it never was.
+ run_count (int): LavaFlow runs on this issue, this one included.
+ severity (LavaflowIssueSummarySeverity | Unset): The confirmed Code Quality finding's recorded severity. Omitted
+ for other issue sources and when no canonical severity is known; absence does not mean the issue has low
+ severity.
+ """
+
+ id: UUID
+ title: str
+ culprit: None | str
+ status: IssueStatus
+ event_count: int
+ last_seen_at: datetime.datetime
+ resolved_at: datetime.datetime | None
+ regressed_at: datetime.datetime | None
+ run_count: int
+ severity: LavaflowIssueSummarySeverity | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ id = str(self.id)
+
+ title = self.title
+
+ culprit: None | str
+ culprit = self.culprit
+
+ status: str = self.status
+
+ event_count = self.event_count
+
+ last_seen_at = self.last_seen_at.isoformat()
+
+ resolved_at: None | str
+ if isinstance(self.resolved_at, datetime.datetime):
+ resolved_at = self.resolved_at.isoformat()
+ else:
+ resolved_at = self.resolved_at
+
+ regressed_at: None | str
+ if isinstance(self.regressed_at, datetime.datetime):
+ regressed_at = self.regressed_at.isoformat()
+ else:
+ regressed_at = self.regressed_at
+
+ run_count = self.run_count
+
+ severity: str | Unset = UNSET
+ if not isinstance(self.severity, Unset):
+ severity = self.severity
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "title": title,
+ "culprit": culprit,
+ "status": status,
+ "event_count": event_count,
+ "last_seen_at": last_seen_at,
+ "resolved_at": resolved_at,
+ "regressed_at": regressed_at,
+ "run_count": run_count,
+ })
+ if severity is not UNSET:
+ field_dict["severity"] = severity
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ title = d.pop("title")
+
+ def _parse_culprit(data: object) -> None | str:
+ if data is None:
+ return data
+ return cast(None | str, data)
+
+ culprit = _parse_culprit(d.pop("culprit"))
+
+
+ status = check_issue_status(d.pop("status"))
+
+
+
+
+ event_count = d.pop("event_count")
+
+ last_seen_at = datetime.datetime.fromisoformat(d.pop("last_seen_at"))
+
+
+
+
+ def _parse_resolved_at(data: object) -> datetime.datetime | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ resolved_at_type_0 = datetime.datetime.fromisoformat(data)
+
+
+
+ return resolved_at_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(datetime.datetime | None, data)
+
+ resolved_at = _parse_resolved_at(d.pop("resolved_at"))
+
+
+ def _parse_regressed_at(data: object) -> datetime.datetime | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ regressed_at_type_0 = datetime.datetime.fromisoformat(data)
+
+
+
+ return regressed_at_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(datetime.datetime | None, data)
+
+ regressed_at = _parse_regressed_at(d.pop("regressed_at"))
+
+
+ run_count = d.pop("run_count")
+
+ _severity = d.pop("severity", UNSET)
+ severity: LavaflowIssueSummarySeverity | Unset
+ if isinstance(_severity, Unset):
+ severity = UNSET
+ else:
+ severity = check_lavaflow_issue_summary_severity(_severity)
+
+
+
+
+ lavaflow_issue_summary = cls(
+ id=id,
+ title=title,
+ culprit=culprit,
+ status=status,
+ event_count=event_count,
+ last_seen_at=last_seen_at,
+ resolved_at=resolved_at,
+ regressed_at=regressed_at,
+ run_count=run_count,
+ severity=severity,
+ )
+
+
+ lavaflow_issue_summary.additional_properties = d
+ return lavaflow_issue_summary
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_issue_summary_severity.py b/src/volcano_sdk/_generated/models/lavaflow_issue_summary_severity.py
new file mode 100644
index 00000000..13bd03b5
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_issue_summary_severity.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowIssueSummarySeverity = Literal['critical', 'major', 'minor', 'nit']
+
+LAVAFLOW_ISSUE_SUMMARY_SEVERITY_VALUES: set[LavaflowIssueSummarySeverity] = { 'critical', 'major', 'minor', 'nit', }
+
+def check_lavaflow_issue_summary_severity(value: str) -> LavaflowIssueSummarySeverity:
+ if value in LAVAFLOW_ISSUE_SUMMARY_SEVERITY_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_ISSUE_SUMMARY_SEVERITY_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_lineage.py b/src/volcano_sdk/_generated/models/lavaflow_lineage.py
new file mode 100644
index 00000000..3bc7cd68
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_lineage.py
@@ -0,0 +1,237 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_lineage_confidence import check_lavaflow_lineage_confidence
+from ..models.lavaflow_lineage_confidence import LavaflowLineageConfidence
+from ..models.lavaflow_lineage_relation import check_lavaflow_lineage_relation
+from ..models.lavaflow_lineage_relation import LavaflowLineageRelation
+from ..models.lavaflow_lineage_remedy import check_lavaflow_lineage_remedy
+from ..models.lavaflow_lineage_remedy import LavaflowLineageRemedy
+from ..models.lavaflow_lineage_state import check_lavaflow_lineage_state
+from ..models.lavaflow_lineage_state import LavaflowLineageState
+from typing import cast
+from uuid import UUID
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_run_reference import LavaflowRunReference
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowLineage")
+
+
+
+@_attrs_define
+class LavaflowLineage:
+ """ A chain of LavaFlow fixes: a merged fix, and the runs that followed up an issue traced to it or to a fix after it.
+
+ Attributes:
+ id (UUID): The lineage's root run.
+ depth (int): 0 for the root fix.
+ relation (LavaflowLineageRelation): `regression` for an issue traced to the parent's deploy, `recurrence` for an
+ issue that came back after the parent went live. Null for the root.
+ confidence (LavaflowLineageConfidence): Null for the root, and otherwise `strong`. `weak` is reserved: nothing
+ writes it.
+ parent (LavaflowRunReference | None): The fix this run follows up. Null for the root.
+ covered_by (LavaflowRunReference | None): The run whose fix also covers this issue, so this run opened nothing.
+ remedy (LavaflowLineageRemedy): How the run follows up its parent. Currently always `fix`: a regression gets a
+ follow-up fix. `revert` and `none` are reserved.
+ state (LavaflowLineageState):
+ hold_reason (None | str): Why the lineage holds: `lineage_cap`, `lineage_held` or `repository_changed`. New
+ values may appear. Null unless `state` is `held`.
+ pull_requests_opened (int): Pull requests the lineage opened, counting the root's.
+ pull_request_cap (int): The most pull requests a lineage opens before it holds.
+ """
+
+ id: UUID
+ depth: int
+ relation: LavaflowLineageRelation
+ confidence: LavaflowLineageConfidence
+ parent: LavaflowRunReference | None
+ covered_by: LavaflowRunReference | None
+ remedy: LavaflowLineageRemedy
+ state: LavaflowLineageState
+ hold_reason: None | str
+ pull_requests_opened: int
+ pull_request_cap: int
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_run_reference import LavaflowRunReference # noqa: PLC0415
+ id = str(self.id)
+
+ depth = self.depth
+
+ relation: str = self.relation
+
+ confidence: str = self.confidence
+
+ parent: dict[str, Any] | None
+ if isinstance(self.parent, LavaflowRunReference):
+ parent = self.parent.to_dict()
+ else:
+ parent = self.parent
+
+ covered_by: dict[str, Any] | None
+ if isinstance(self.covered_by, LavaflowRunReference):
+ covered_by = self.covered_by.to_dict()
+ else:
+ covered_by = self.covered_by
+
+ remedy: str = self.remedy
+
+ state: str = self.state
+
+ hold_reason: None | str
+ hold_reason = self.hold_reason
+
+ pull_requests_opened = self.pull_requests_opened
+
+ pull_request_cap = self.pull_request_cap
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "depth": depth,
+ "relation": relation,
+ "confidence": confidence,
+ "parent": parent,
+ "covered_by": covered_by,
+ "remedy": remedy,
+ "state": state,
+ "hold_reason": hold_reason,
+ "pull_requests_opened": pull_requests_opened,
+ "pull_request_cap": pull_request_cap,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_run_reference import LavaflowRunReference # noqa: PLC0415
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ depth = d.pop("depth")
+
+ relation = check_lavaflow_lineage_relation(d.pop("relation"))
+
+
+
+
+ confidence = check_lavaflow_lineage_confidence(d.pop("confidence"))
+
+
+
+
+ def _parse_parent(data: object) -> LavaflowRunReference | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ parent_type_1 = LavaflowRunReference.from_dict(data)
+
+
+
+ return parent_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowRunReference | None, data)
+
+ parent = _parse_parent(d.pop("parent"))
+
+
+ def _parse_covered_by(data: object) -> LavaflowRunReference | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ covered_by_type_1 = LavaflowRunReference.from_dict(data)
+
+
+
+ return covered_by_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowRunReference | None, data)
+
+ covered_by = _parse_covered_by(d.pop("covered_by"))
+
+
+ remedy = check_lavaflow_lineage_remedy(d.pop("remedy"))
+
+
+
+
+ state = check_lavaflow_lineage_state(d.pop("state"))
+
+
+
+
+ def _parse_hold_reason(data: object) -> None | str:
+ if data is None:
+ return data
+ return cast(None | str, data)
+
+ hold_reason = _parse_hold_reason(d.pop("hold_reason"))
+
+
+ pull_requests_opened = d.pop("pull_requests_opened")
+
+ pull_request_cap = d.pop("pull_request_cap")
+
+ lavaflow_lineage = cls(
+ id=id,
+ depth=depth,
+ relation=relation,
+ confidence=confidence,
+ parent=parent,
+ covered_by=covered_by,
+ remedy=remedy,
+ state=state,
+ hold_reason=hold_reason,
+ pull_requests_opened=pull_requests_opened,
+ pull_request_cap=pull_request_cap,
+ )
+
+
+ lavaflow_lineage.additional_properties = d
+ return lavaflow_lineage
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_lineage_confidence.py b/src/volcano_sdk/_generated/models/lavaflow_lineage_confidence.py
new file mode 100644
index 00000000..fabebb60
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_lineage_confidence.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowLineageConfidence = Literal['strong', 'weak']
+
+LAVAFLOW_LINEAGE_CONFIDENCE_VALUES: set[LavaflowLineageConfidence] = { 'strong', 'weak', }
+
+def check_lavaflow_lineage_confidence(value: str) -> LavaflowLineageConfidence:
+ if value in LAVAFLOW_LINEAGE_CONFIDENCE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_LINEAGE_CONFIDENCE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_lineage_evidence.py b/src/volcano_sdk/_generated/models/lavaflow_lineage_evidence.py
new file mode 100644
index 00000000..5837715f
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_lineage_evidence.py
@@ -0,0 +1,173 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_lineage_evidence_confidence import check_lavaflow_lineage_evidence_confidence
+from ..models.lavaflow_lineage_evidence_confidence import LavaflowLineageEvidenceConfidence
+from typing import cast
+import datetime
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_lineage_evidence_deployment import LavaflowLineageEvidenceDeployment
+ from ..models.lavaflow_run_reference import LavaflowRunReference
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowLineageEvidence")
+
+
+
+@_attrs_define
+class LavaflowLineageEvidence:
+ """ What tied the run's issue to a recent LavaFlow fix. A `display` link rests on less than a strong one and joins no
+ lineage.
+
+ Attributes:
+ confidence (LavaflowLineageEvidenceConfidence): `strong` or `display`. `weak` is reserved: nothing writes it.
+ parent (LavaflowRunReference): Another LavaFlow run of the same project.
+ deployment (LavaflowLineageEvidenceDeployment):
+ previous_commit_sha (None | str): The commit of the deployment before it.
+ fix_live_at (datetime.datetime):
+ opened_at (datetime.datetime): The occurrence attribution judged.
+ overlapping_functions (list[str]):
+ overlapping_files (list[str]):
+ """
+
+ confidence: LavaflowLineageEvidenceConfidence
+ parent: LavaflowRunReference
+ deployment: LavaflowLineageEvidenceDeployment
+ previous_commit_sha: None | str
+ fix_live_at: datetime.datetime
+ opened_at: datetime.datetime
+ overlapping_functions: list[str]
+ overlapping_files: list[str]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_lineage_evidence_deployment import LavaflowLineageEvidenceDeployment # noqa: PLC0415
+ from ..models.lavaflow_run_reference import LavaflowRunReference # noqa: PLC0415
+ confidence: str = self.confidence
+
+ parent = self.parent.to_dict()
+
+ deployment = self.deployment.to_dict()
+
+ previous_commit_sha: None | str
+ previous_commit_sha = self.previous_commit_sha
+
+ fix_live_at = self.fix_live_at.isoformat()
+
+ opened_at = self.opened_at.isoformat()
+
+ overlapping_functions = self.overlapping_functions
+
+
+
+ overlapping_files = self.overlapping_files
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "confidence": confidence,
+ "parent": parent,
+ "deployment": deployment,
+ "previous_commit_sha": previous_commit_sha,
+ "fix_live_at": fix_live_at,
+ "opened_at": opened_at,
+ "overlapping_functions": overlapping_functions,
+ "overlapping_files": overlapping_files,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_lineage_evidence_deployment import LavaflowLineageEvidenceDeployment # noqa: PLC0415
+ from ..models.lavaflow_run_reference import LavaflowRunReference # noqa: PLC0415
+ d = dict(src_dict)
+ confidence = check_lavaflow_lineage_evidence_confidence(d.pop("confidence"))
+
+
+
+
+ parent = LavaflowRunReference.from_dict(d.pop("parent"))
+
+
+
+
+ deployment = LavaflowLineageEvidenceDeployment.from_dict(d.pop("deployment"))
+
+
+
+
+ def _parse_previous_commit_sha(data: object) -> None | str:
+ if data is None:
+ return data
+ return cast(None | str, data)
+
+ previous_commit_sha = _parse_previous_commit_sha(d.pop("previous_commit_sha"))
+
+
+ fix_live_at = datetime.datetime.fromisoformat(d.pop("fix_live_at"))
+
+
+
+
+ opened_at = datetime.datetime.fromisoformat(d.pop("opened_at"))
+
+
+
+
+ overlapping_functions = cast(list[str], d.pop("overlapping_functions"))
+
+
+ overlapping_files = cast(list[str], d.pop("overlapping_files"))
+
+
+ lavaflow_lineage_evidence = cls(
+ confidence=confidence,
+ parent=parent,
+ deployment=deployment,
+ previous_commit_sha=previous_commit_sha,
+ fix_live_at=fix_live_at,
+ opened_at=opened_at,
+ overlapping_functions=overlapping_functions,
+ overlapping_files=overlapping_files,
+ )
+
+
+ lavaflow_lineage_evidence.additional_properties = d
+ return lavaflow_lineage_evidence
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_lineage_evidence_confidence.py b/src/volcano_sdk/_generated/models/lavaflow_lineage_evidence_confidence.py
new file mode 100644
index 00000000..c3e98c37
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_lineage_evidence_confidence.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowLineageEvidenceConfidence = Literal['display', 'strong', 'weak']
+
+LAVAFLOW_LINEAGE_EVIDENCE_CONFIDENCE_VALUES: set[LavaflowLineageEvidenceConfidence] = { 'display', 'strong', 'weak', }
+
+def check_lavaflow_lineage_evidence_confidence(value: str) -> LavaflowLineageEvidenceConfidence:
+ if value in LAVAFLOW_LINEAGE_EVIDENCE_CONFIDENCE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_LINEAGE_EVIDENCE_CONFIDENCE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_lineage_evidence_deployment.py b/src/volcano_sdk/_generated/models/lavaflow_lineage_evidence_deployment.py
new file mode 100644
index 00000000..99237cb9
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_lineage_evidence_deployment.py
@@ -0,0 +1,85 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowLineageEvidenceDeployment")
+
+
+
+@_attrs_define
+class LavaflowLineageEvidenceDeployment:
+ """
+ Attributes:
+ commit_sha (str): The commit of the deployment that served the occurrence attribution judged (`opened_at`).
+ commit_origin (str): `push` for a commit Volcano built from a push, `client_reported` for one the deploy client
+ reported. New values may appear.
+ """
+
+ commit_sha: str
+ commit_origin: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ commit_sha = self.commit_sha
+
+ commit_origin = self.commit_origin
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "commit_sha": commit_sha,
+ "commit_origin": commit_origin,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ commit_sha = d.pop("commit_sha")
+
+ commit_origin = d.pop("commit_origin")
+
+ lavaflow_lineage_evidence_deployment = cls(
+ commit_sha=commit_sha,
+ commit_origin=commit_origin,
+ )
+
+
+ lavaflow_lineage_evidence_deployment.additional_properties = d
+ return lavaflow_lineage_evidence_deployment
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_lineage_relation.py b/src/volcano_sdk/_generated/models/lavaflow_lineage_relation.py
new file mode 100644
index 00000000..c7ec9cd9
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_lineage_relation.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowLineageRelation = Literal['recurrence', 'regression']
+
+LAVAFLOW_LINEAGE_RELATION_VALUES: set[LavaflowLineageRelation] = { 'recurrence', 'regression', }
+
+def check_lavaflow_lineage_relation(value: str) -> LavaflowLineageRelation:
+ if value in LAVAFLOW_LINEAGE_RELATION_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_LINEAGE_RELATION_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_lineage_remedy.py b/src/volcano_sdk/_generated/models/lavaflow_lineage_remedy.py
new file mode 100644
index 00000000..0b8c9e28
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_lineage_remedy.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowLineageRemedy = Literal['fix', 'none', 'revert']
+
+LAVAFLOW_LINEAGE_REMEDY_VALUES: set[LavaflowLineageRemedy] = { 'fix', 'none', 'revert', }
+
+def check_lavaflow_lineage_remedy(value: str) -> LavaflowLineageRemedy:
+ if value in LAVAFLOW_LINEAGE_REMEDY_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_LINEAGE_REMEDY_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_lineage_state.py b/src/volcano_sdk/_generated/models/lavaflow_lineage_state.py
new file mode 100644
index 00000000..3acd4309
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_lineage_state.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowLineageState = Literal['active', 'held', 'settled']
+
+LAVAFLOW_LINEAGE_STATE_VALUES: set[LavaflowLineageState] = { 'active', 'held', 'settled', }
+
+def check_lavaflow_lineage_state(value: str) -> LavaflowLineageState:
+ if value in LAVAFLOW_LINEAGE_STATE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_LINEAGE_STATE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_log_line.py b/src/volcano_sdk/_generated/models/lavaflow_log_line.py
new file mode 100644
index 00000000..0fce3aa2
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_log_line.py
@@ -0,0 +1,114 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+import datetime
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowLogLine")
+
+
+
+@_attrs_define
+class LavaflowLogLine:
+ """
+ Attributes:
+ timestamp (datetime.datetime | None):
+ level (str):
+ message (str):
+ """
+
+ timestamp: datetime.datetime | None
+ level: str
+ message: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ timestamp: None | str
+ if isinstance(self.timestamp, datetime.datetime):
+ timestamp = self.timestamp.isoformat()
+ else:
+ timestamp = self.timestamp
+
+ level = self.level
+
+ message = self.message
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "timestamp": timestamp,
+ "level": level,
+ "message": message,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ def _parse_timestamp(data: object) -> datetime.datetime | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ timestamp_type_0 = datetime.datetime.fromisoformat(data)
+
+
+
+ return timestamp_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(datetime.datetime | None, data)
+
+ timestamp = _parse_timestamp(d.pop("timestamp"))
+
+
+ level = d.pop("level")
+
+ message = d.pop("message")
+
+ lavaflow_log_line = cls(
+ timestamp=timestamp,
+ level=level,
+ message=message,
+ )
+
+
+ lavaflow_log_line.additional_properties = d
+ return lavaflow_log_line
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_merge.py b/src/volcano_sdk/_generated/models/lavaflow_merge.py
new file mode 100644
index 00000000..ba2d8f0d
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_merge.py
@@ -0,0 +1,144 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_merge_status import check_lavaflow_merge_status
+from ..models.lavaflow_merge_status import LavaflowMergeStatus
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_hold_reason import LavaflowHoldReason
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowMerge")
+
+
+
+@_attrs_define
+class LavaflowMerge:
+ """ Where the run's merge stands. Present for a run that may merge its fix, once its pull request opens.
+
+ Attributes:
+ status (LavaflowMergeStatus): `waiting_for_checks`: LavaFlow waits for the checks on the fix's commit. `queued`:
+ the fix is in the repository's merge queue. `merged`: the pull request merged. `held`: something in
+ `hold_reasons` needs a person. LavaFlow commented on the pull request once and never merges, pushes to, rebases
+ or dequeues it again; review it and merge it yourself if you want it. `stopped`: LavaFlow left the pull request
+ open for you, for `reason`.
+ reason (None | str):
+ hold_reasons (list[LavaflowHoldReason]): Why LavaFlow holds the fix. Empty unless `status` is `held`.
+ merged_by_lavaflow (bool | None): Whether LavaFlow made the merge: `true` when it merged the fix's commit itself
+ or through the merge queue, `false` when someone else merged the pull request while LavaFlow waited. `null`
+ unless `status` is `merged`.
+ """
+
+ status: LavaflowMergeStatus
+ reason: None | str
+ hold_reasons: list[LavaflowHoldReason]
+ merged_by_lavaflow: bool | None
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_hold_reason import LavaflowHoldReason # noqa: PLC0415
+ status: str = self.status
+
+ reason: None | str
+ reason = self.reason
+
+ hold_reasons = []
+ for hold_reasons_item_data in self.hold_reasons:
+ hold_reasons_item = hold_reasons_item_data.to_dict()
+ hold_reasons.append(hold_reasons_item)
+
+
+
+ merged_by_lavaflow: bool | None
+ merged_by_lavaflow = self.merged_by_lavaflow
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "status": status,
+ "reason": reason,
+ "hold_reasons": hold_reasons,
+ "merged_by_lavaflow": merged_by_lavaflow,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_hold_reason import LavaflowHoldReason # noqa: PLC0415
+ d = dict(src_dict)
+ status = check_lavaflow_merge_status(d.pop("status"))
+
+
+
+
+ def _parse_reason(data: object) -> None | str:
+ if data is None:
+ return data
+ return cast(None | str, data)
+
+ reason = _parse_reason(d.pop("reason"))
+
+
+ hold_reasons = []
+ _hold_reasons = d.pop("hold_reasons")
+ for hold_reasons_item_data in (_hold_reasons):
+ hold_reasons_item = LavaflowHoldReason.from_dict(hold_reasons_item_data)
+
+
+
+ hold_reasons.append(hold_reasons_item)
+
+
+ def _parse_merged_by_lavaflow(data: object) -> bool | None:
+ if data is None:
+ return data
+ return cast(bool | None, data)
+
+ merged_by_lavaflow = _parse_merged_by_lavaflow(d.pop("merged_by_lavaflow"))
+
+
+ lavaflow_merge = cls(
+ status=status,
+ reason=reason,
+ hold_reasons=hold_reasons,
+ merged_by_lavaflow=merged_by_lavaflow,
+ )
+
+
+ lavaflow_merge.additional_properties = d
+ return lavaflow_merge
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_merge_policy.py b/src/volcano_sdk/_generated/models/lavaflow_merge_policy.py
new file mode 100644
index 00000000..4c38e493
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_merge_policy.py
@@ -0,0 +1,87 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowMergePolicy")
+
+
+
+@_attrs_define
+class LavaflowMergePolicy:
+ """ Your rules for fixes LavaFlow must never merge. They apply with `autonomy: merge`; at another autonomy they are
+ saved and do nothing.
+
+ Attributes:
+ human_review_paths (list[str]): Globs of paths whose change LavaFlow never merges: a fix that changes one is
+ held and handed to you. Paths are relative to the repository root, such as `db/migrations/**`. `*` and `?` match
+ within one directory, `**/` spans any number of directories, and a final `**` matches the rest. A pattern that
+ starts with `/`, `./` or `../`, ends with `/`, holds an empty, `.` or `..` segment, or holds a NUL character
+ answers `400`. Volcano's own held paths, such as deploy configuration and authentication code, are always held
+ too. Defaults to none.
+ """
+
+ human_review_paths: list[str]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ human_review_paths = self.human_review_paths
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "human_review_paths": human_review_paths,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ human_review_paths = cast(list[str], d.pop("human_review_paths"))
+
+
+ lavaflow_merge_policy = cls(
+ human_review_paths=human_review_paths,
+ )
+
+
+ lavaflow_merge_policy.additional_properties = d
+ return lavaflow_merge_policy
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_merge_policy_update.py b/src/volcano_sdk/_generated/models/lavaflow_merge_policy_update.py
new file mode 100644
index 00000000..7ed04919
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_merge_policy_update.py
@@ -0,0 +1,68 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowMergePolicyUpdate")
+
+
+
+@_attrs_define
+class LavaflowMergePolicyUpdate:
+ """ The merge policy fields to change. An omitted field keeps its saved value. Send `human_review_paths: []` to clear
+ the paths.
+
+ Attributes:
+ human_review_paths (list[str] | Unset):
+ """
+
+ human_review_paths: list[str] | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ human_review_paths: list[str] | Unset = UNSET
+ if not isinstance(self.human_review_paths, Unset):
+ human_review_paths = self.human_review_paths
+
+
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ })
+ if human_review_paths is not UNSET:
+ field_dict["human_review_paths"] = human_review_paths
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ human_review_paths = cast(list[str], d.pop("human_review_paths", UNSET))
+
+
+ lavaflow_merge_policy_update = cls(
+ human_review_paths=human_review_paths,
+ )
+
+ return lavaflow_merge_policy_update
+
diff --git a/src/volcano_sdk/_generated/models/lavaflow_merge_status.py b/src/volcano_sdk/_generated/models/lavaflow_merge_status.py
new file mode 100644
index 00000000..a2700caf
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_merge_status.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowMergeStatus = Literal['held', 'merged', 'queued', 'stopped', 'waiting_for_checks']
+
+LAVAFLOW_MERGE_STATUS_VALUES: set[LavaflowMergeStatus] = { 'held', 'merged', 'queued', 'stopped', 'waiting_for_checks', }
+
+def check_lavaflow_merge_status(value: str) -> LavaflowMergeStatus:
+ if value in LAVAFLOW_MERGE_STATUS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_MERGE_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_pull_request.py b/src/volcano_sdk/_generated/models/lavaflow_pull_request.py
new file mode 100644
index 00000000..503b6b1c
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_pull_request.py
@@ -0,0 +1,246 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_draft_reason import check_lavaflow_draft_reason
+from ..models.lavaflow_draft_reason import LavaflowDraftReason
+from ..models.lavaflow_pull_request_state import check_lavaflow_pull_request_state
+from ..models.lavaflow_pull_request_state import LavaflowPullRequestState
+from ..types import UNSET, Unset
+from typing import cast
+import datetime
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowPullRequest")
+
+
+
+@_attrs_define
+class LavaflowPullRequest:
+ """
+ Attributes:
+ number (int):
+ url (str):
+ state (LavaflowPullRequestState):
+ opened_at (datetime.datetime | None): When the run opened the pull request, null for one opened before LavaFlow
+ recorded the time.
+ merged_at (datetime.datetime | None): When the pull request merged; null unless `state` is `merged`.
+ deployed_at (datetime.datetime | None): When the merged fix went live: the first live deployment of the issue's
+ resource that includes it finished. When more than 20 deployments went live between the merge and the one
+ LavaFlow found the fix in, LavaFlow can't tell which first included it, and this is the merge time. Null until
+ LavaFlow finds the fix live, and for a pull request that didn't merge. LavaFlow watches the resource's
+ deployments for a week after the merge.
+ draft (bool | None): Whether the pull request is a draft, as GitHub last reported it to LavaFlow. Null for one
+ opened before LavaFlow recorded it.
+ draft_reason (LavaflowDraftReason | None): Why the pull request is a draft, null unless `draft` is true.
+ branch (str | Unset): The recorded pull request branch. Omitted when it was not recorded, the run's fix is
+ withheld because it may add a credential, or the full branch name cannot be served under the project's text
+ privacy checks. It is never shortened.
+ """
+
+ number: int
+ url: str
+ state: LavaflowPullRequestState
+ opened_at: datetime.datetime | None
+ merged_at: datetime.datetime | None
+ deployed_at: datetime.datetime | None
+ draft: bool | None
+ draft_reason: LavaflowDraftReason | None
+ branch: str | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ number = self.number
+
+ url = self.url
+
+ state: str = self.state
+
+ opened_at: None | str
+ if isinstance(self.opened_at, datetime.datetime):
+ opened_at = self.opened_at.isoformat()
+ else:
+ opened_at = self.opened_at
+
+ merged_at: None | str
+ if isinstance(self.merged_at, datetime.datetime):
+ merged_at = self.merged_at.isoformat()
+ else:
+ merged_at = self.merged_at
+
+ deployed_at: None | str
+ if isinstance(self.deployed_at, datetime.datetime):
+ deployed_at = self.deployed_at.isoformat()
+ else:
+ deployed_at = self.deployed_at
+
+ draft: bool | None
+ draft = self.draft
+
+ draft_reason: None | str
+ if isinstance(self.draft_reason, str):
+ draft_reason = self.draft_reason
+ else:
+ draft_reason = self.draft_reason
+
+ branch = self.branch
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "number": number,
+ "url": url,
+ "state": state,
+ "opened_at": opened_at,
+ "merged_at": merged_at,
+ "deployed_at": deployed_at,
+ "draft": draft,
+ "draft_reason": draft_reason,
+ })
+ if branch is not UNSET:
+ field_dict["branch"] = branch
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ number = d.pop("number")
+
+ url = d.pop("url")
+
+ state = check_lavaflow_pull_request_state(d.pop("state"))
+
+
+
+
+ def _parse_opened_at(data: object) -> datetime.datetime | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ opened_at_type_0 = datetime.datetime.fromisoformat(data)
+
+
+
+ return opened_at_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(datetime.datetime | None, data)
+
+ opened_at = _parse_opened_at(d.pop("opened_at"))
+
+
+ def _parse_merged_at(data: object) -> datetime.datetime | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ merged_at_type_0 = datetime.datetime.fromisoformat(data)
+
+
+
+ return merged_at_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(datetime.datetime | None, data)
+
+ merged_at = _parse_merged_at(d.pop("merged_at"))
+
+
+ def _parse_deployed_at(data: object) -> datetime.datetime | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ deployed_at_type_0 = datetime.datetime.fromisoformat(data)
+
+
+
+ return deployed_at_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(datetime.datetime | None, data)
+
+ deployed_at = _parse_deployed_at(d.pop("deployed_at"))
+
+
+ def _parse_draft(data: object) -> bool | None:
+ if data is None:
+ return data
+ return cast(bool | None, data)
+
+ draft = _parse_draft(d.pop("draft"))
+
+
+ def _parse_draft_reason(data: object) -> LavaflowDraftReason | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ draft_reason_type_1 = check_lavaflow_draft_reason(data)
+
+
+
+ return draft_reason_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowDraftReason | None, data)
+
+ draft_reason = _parse_draft_reason(d.pop("draft_reason"))
+
+
+ branch = d.pop("branch", UNSET)
+
+ lavaflow_pull_request = cls(
+ number=number,
+ url=url,
+ state=state,
+ opened_at=opened_at,
+ merged_at=merged_at,
+ deployed_at=deployed_at,
+ draft=draft,
+ draft_reason=draft_reason,
+ branch=branch,
+ )
+
+
+ lavaflow_pull_request.additional_properties = d
+ return lavaflow_pull_request
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_pull_request_state.py b/src/volcano_sdk/_generated/models/lavaflow_pull_request_state.py
new file mode 100644
index 00000000..fb42c5cf
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_pull_request_state.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowPullRequestState = Literal['closed', 'merged', 'open']
+
+LAVAFLOW_PULL_REQUEST_STATE_VALUES: set[LavaflowPullRequestState] = { 'closed', 'merged', 'open', }
+
+def check_lavaflow_pull_request_state(value: str) -> LavaflowPullRequestState:
+ if value in LAVAFLOW_PULL_REQUEST_STATE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_PULL_REQUEST_STATE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_pull_request_state_counts.py b/src/volcano_sdk/_generated/models/lavaflow_pull_request_state_counts.py
new file mode 100644
index 00000000..64119ab9
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_pull_request_state_counts.py
@@ -0,0 +1,101 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowPullRequestStateCounts")
+
+
+
+@_attrs_define
+class LavaflowPullRequestStateCounts:
+ """ Matching runs by the state of their pull request, zeros included. `none` counts runs without one.
+
+ Attributes:
+ open_ (int):
+ merged (int):
+ closed (int):
+ none (int):
+ """
+
+ open_: int
+ merged: int
+ closed: int
+ none: int
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ open_ = self.open_
+
+ merged = self.merged
+
+ closed = self.closed
+
+ none = self.none
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "open": open_,
+ "merged": merged,
+ "closed": closed,
+ "none": none,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ open_ = d.pop("open")
+
+ merged = d.pop("merged")
+
+ closed = d.pop("closed")
+
+ none = d.pop("none")
+
+ lavaflow_pull_request_state_counts = cls(
+ open_=open_,
+ merged=merged,
+ closed=closed,
+ none=none,
+ )
+
+
+ lavaflow_pull_request_state_counts.additional_properties = d
+ return lavaflow_pull_request_state_counts
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_repository_check_command.py b/src/volcano_sdk/_generated/models/lavaflow_repository_check_command.py
new file mode 100644
index 00000000..04afbe65
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_repository_check_command.py
@@ -0,0 +1,118 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowRepositoryCheckCommand")
+
+
+
+@_attrs_define
+class LavaflowRepositoryCheckCommand:
+ """ One command the repository's checks ran. `command` and `output` are the repository's own text, served as LavaFlow
+ recorded it. `command` reads `LavaFlow left this command out because it may contain a credential`, and `output`
+ reads `LavaFlow left this output out because it may contain a credential`, when that text may contain a credential,
+ holds one of the project's secret values, or is over 4,000 characters, and when the run is held with
+ `possible_credential`.
+
+ Attributes:
+ command (str): The command as LavaFlow ran it.
+ status (str): `passed`: the command succeeded. `failed`: it exited with an error. `timed_out`: it ran past its
+ time limit, and LavaFlow stopped it. Treat a status you don't know as `failed`.
+ exit_code (int | None): The code the command exited with, null when it gave none, as a command that timed out
+ may not.
+ output (str | Unset): The end of what the command printed, present only when `status` is `failed` or `timed_out`
+ and LavaFlow kept it; `""` when it printed nothing.
+ """
+
+ command: str
+ status: str
+ exit_code: int | None
+ output: str | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ command = self.command
+
+ status = self.status
+
+ exit_code: int | None
+ exit_code = self.exit_code
+
+ output = self.output
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "command": command,
+ "status": status,
+ "exit_code": exit_code,
+ })
+ if output is not UNSET:
+ field_dict["output"] = output
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ command = d.pop("command")
+
+ status = d.pop("status")
+
+ def _parse_exit_code(data: object) -> int | None:
+ if data is None:
+ return data
+ return cast(int | None, data)
+
+ exit_code = _parse_exit_code(d.pop("exit_code"))
+
+
+ output = d.pop("output", UNSET)
+
+ lavaflow_repository_check_command = cls(
+ command=command,
+ status=status,
+ exit_code=exit_code,
+ output=output,
+ )
+
+
+ lavaflow_repository_check_command.additional_properties = d
+ return lavaflow_repository_check_command
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_repository_checks.py b/src/volcano_sdk/_generated/models/lavaflow_repository_checks.py
new file mode 100644
index 00000000..2dede443
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_repository_checks.py
@@ -0,0 +1,155 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_repository_check_command import LavaflowRepositoryCheckCommand
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowRepositoryChecks")
+
+
+
+@_attrs_define
+class LavaflowRepositoryChecks:
+ """ Whether LavaFlow ran the repository's own checks, such as its tests, on a fix itself, before it opened a pull
+ request or held the fix, and what they found. When LavaFlow ran them more than once, this is the last time the run's
+ last attempt ran them; `not_run` when that attempt didn't, or while the run is queued or running. CI that runs on
+ the pull request afterwards is the repository's own.
+
+ Attributes:
+ status (str): `passed`: every command the checks ran passed. `failed`: a command failed or timed out; `commands`
+ shows which. `no_checks_found`: LavaFlow found no checks in the repository to run. `not_run`: LavaFlow did not
+ run the repository's checks on the fix, for the reason `reason` names. Treat a status you don't know as
+ `not_run`.
+ message (str): Text to show for the status and reason. It names the pull request when one opened. For `not_run`
+ on a fix whose pull request opened, a second sentence says what became of the repository's CI there, as the run
+ stands when read: whether LavaFlow started it, tried to, may still, or won't.
+ reason (str | Unset): Stable code for why the checks did not run, present only when `status` is `not_run`.
+ `dependencies_changed`: the fix changes the repository's dependencies. `dependencies_not_installed`: LavaFlow
+ couldn't install the repository's dependencies. `run_deadline`: the run reached its time limit.
+ `sandbox_capacity`: no sandbox slot was free in time to run them. `sandbox_budget`: LavaFlow's sandbox allowance
+ for checks was used up. `sandbox_not_isolated`: LavaFlow couldn't confirm the sandbox was isolated.
+ `sandbox_plan_limit`: LavaFlow couldn't start a sandbox large enough to run them. `sandbox_unavailable`:
+ LavaFlow couldn't run them itself. `source_too_large`: the repository is too large to copy into a sandbox.
+ `source_unavailable`: LavaFlow couldn't fetch the fix's source to check it, as when the repository was
+ disconnected or changed during the run. `tool_unavailable`: a tool the checks need isn't available. New reasons
+ may appear; treat one you don't know like any other `not_run`.
+ revised (bool | Unset): Present and `true` only when `status` is `failed` and LavaFlow then revised the fix once
+ without running the checks again. `status` and `commands` describe that earlier version, not the fix as saved,
+ which the checks never ran on.
+ commands (list[LavaflowRepositoryCheckCommand] | Unset): The commands the checks ran, in order. Absent when
+ LavaFlow recorded none, as for `no_checks_found` and `not_run`.
+ """
+
+ status: str
+ message: str
+ reason: str | Unset = UNSET
+ revised: bool | Unset = UNSET
+ commands: list[LavaflowRepositoryCheckCommand] | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_repository_check_command import LavaflowRepositoryCheckCommand # noqa: PLC0415
+ status = self.status
+
+ message = self.message
+
+ reason = self.reason
+
+ revised = self.revised
+
+ commands: list[dict[str, Any]] | Unset = UNSET
+ if not isinstance(self.commands, Unset):
+ commands = []
+ for commands_item_data in self.commands:
+ commands_item = commands_item_data.to_dict()
+ commands.append(commands_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "status": status,
+ "message": message,
+ })
+ if reason is not UNSET:
+ field_dict["reason"] = reason
+ if revised is not UNSET:
+ field_dict["revised"] = revised
+ if commands is not UNSET:
+ field_dict["commands"] = commands
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_repository_check_command import LavaflowRepositoryCheckCommand # noqa: PLC0415
+ d = dict(src_dict)
+ status = d.pop("status")
+
+ message = d.pop("message")
+
+ reason = d.pop("reason", UNSET)
+
+ revised = d.pop("revised", UNSET)
+
+ _commands = d.pop("commands", UNSET)
+ commands: list[LavaflowRepositoryCheckCommand] | Unset = UNSET
+ if _commands is not UNSET:
+ commands = []
+ for commands_item_data in _commands:
+ commands_item = LavaflowRepositoryCheckCommand.from_dict(commands_item_data)
+
+
+
+ commands.append(commands_item)
+
+
+ lavaflow_repository_checks = cls(
+ status=status,
+ message=message,
+ reason=reason,
+ revised=revised,
+ commands=commands,
+ )
+
+
+ lavaflow_repository_checks.additional_properties = d
+ return lavaflow_repository_checks
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_resource.py b/src/volcano_sdk/_generated/models/lavaflow_resource.py
new file mode 100644
index 00000000..e2f91d29
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_resource.py
@@ -0,0 +1,156 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+from uuid import UUID
+import datetime
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_anomaly import LavaflowAnomaly
+ from ..models.lavaflow_resource_reference import LavaflowResourceReference
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowResource")
+
+
+
+@_attrs_define
+class LavaflowResource:
+ """
+ Attributes:
+ project_id (UUID): The project the resource belongs to.
+ resource (LavaflowResourceReference): A function, durable function or frontend in the project, or the project of
+ a user-reported problem.
+ last_analyzed_at (datetime.datetime | None): When a LavaFlow run last started on the resource, null if never.
+ issues_opened (int): Issues LavaFlow took on in the window.
+ pull_requests_opened (int): Pull requests with a fix LavaFlow opened in the window.
+ anomaly (LavaflowAnomaly):
+ """
+
+ project_id: UUID
+ resource: LavaflowResourceReference
+ last_analyzed_at: datetime.datetime | None
+ issues_opened: int
+ pull_requests_opened: int
+ anomaly: LavaflowAnomaly
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_anomaly import LavaflowAnomaly # noqa: PLC0415
+ from ..models.lavaflow_resource_reference import LavaflowResourceReference # noqa: PLC0415
+ project_id = str(self.project_id)
+
+ resource = self.resource.to_dict()
+
+ last_analyzed_at: None | str
+ if isinstance(self.last_analyzed_at, datetime.datetime):
+ last_analyzed_at = self.last_analyzed_at.isoformat()
+ else:
+ last_analyzed_at = self.last_analyzed_at
+
+ issues_opened = self.issues_opened
+
+ pull_requests_opened = self.pull_requests_opened
+
+ anomaly = self.anomaly.to_dict()
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "project_id": project_id,
+ "resource": resource,
+ "last_analyzed_at": last_analyzed_at,
+ "issues_opened": issues_opened,
+ "pull_requests_opened": pull_requests_opened,
+ "anomaly": anomaly,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_anomaly import LavaflowAnomaly # noqa: PLC0415
+ from ..models.lavaflow_resource_reference import LavaflowResourceReference # noqa: PLC0415
+ d = dict(src_dict)
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ resource = LavaflowResourceReference.from_dict(d.pop("resource"))
+
+
+
+
+ def _parse_last_analyzed_at(data: object) -> datetime.datetime | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ last_analyzed_at_type_0 = datetime.datetime.fromisoformat(data)
+
+
+
+ return last_analyzed_at_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(datetime.datetime | None, data)
+
+ last_analyzed_at = _parse_last_analyzed_at(d.pop("last_analyzed_at"))
+
+
+ issues_opened = d.pop("issues_opened")
+
+ pull_requests_opened = d.pop("pull_requests_opened")
+
+ anomaly = LavaflowAnomaly.from_dict(d.pop("anomaly"))
+
+
+
+
+ lavaflow_resource = cls(
+ project_id=project_id,
+ resource=resource,
+ last_analyzed_at=last_analyzed_at,
+ issues_opened=issues_opened,
+ pull_requests_opened=pull_requests_opened,
+ anomaly=anomaly,
+ )
+
+
+ lavaflow_resource.additional_properties = d
+ return lavaflow_resource
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_resource_list.py b/src/volcano_sdk/_generated/models/lavaflow_resource_list.py
new file mode 100644
index 00000000..6ae7e9c9
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_resource_list.py
@@ -0,0 +1,94 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_resource import LavaflowResource
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowResourceList")
+
+
+
+@_attrs_define
+class LavaflowResourceList:
+ """
+ Attributes:
+ data (list[LavaflowResource]):
+ """
+
+ data: list[LavaflowResource]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_resource import LavaflowResource # noqa: PLC0415
+ data = []
+ for data_item_data in self.data:
+ data_item = data_item_data.to_dict()
+ data.append(data_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "data": data,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_resource import LavaflowResource # noqa: PLC0415
+ d = dict(src_dict)
+ data = []
+ _data = d.pop("data")
+ for data_item_data in (_data):
+ data_item = LavaflowResource.from_dict(data_item_data)
+
+
+
+ data.append(data_item)
+
+
+ lavaflow_resource_list = cls(
+ data=data,
+ )
+
+
+ lavaflow_resource_list.additional_properties = d
+ return lavaflow_resource_list
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_resource_reference.py b/src/volcano_sdk/_generated/models/lavaflow_resource_reference.py
new file mode 100644
index 00000000..b2ded67c
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_resource_reference.py
@@ -0,0 +1,103 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_resource_reference_type import check_lavaflow_resource_reference_type
+from ..models.lavaflow_resource_reference_type import LavaflowResourceReferenceType
+from typing import cast
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowResourceReference")
+
+
+
+@_attrs_define
+class LavaflowResourceReference:
+ """ A function, durable function or frontend in the project, or the project of a user-reported problem.
+
+ Attributes:
+ type_ (LavaflowResourceReferenceType):
+ id (UUID):
+ name (str):
+ """
+
+ type_: LavaflowResourceReferenceType
+ id: UUID
+ name: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ type_: str = self.type_
+
+ id = str(self.id)
+
+ name = self.name
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "type": type_,
+ "id": id,
+ "name": name,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ type_ = check_lavaflow_resource_reference_type(d.pop("type"))
+
+
+
+
+ id = UUID(d.pop("id"))
+
+
+
+
+ name = d.pop("name")
+
+ lavaflow_resource_reference = cls(
+ type_=type_,
+ id=id,
+ name=name,
+ )
+
+
+ lavaflow_resource_reference.additional_properties = d
+ return lavaflow_resource_reference
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_resource_reference_type.py b/src/volcano_sdk/_generated/models/lavaflow_resource_reference_type.py
new file mode 100644
index 00000000..2155be4e
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_resource_reference_type.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowResourceReferenceType = Literal['durable_function', 'frontend', 'function', 'project']
+
+LAVAFLOW_RESOURCE_REFERENCE_TYPE_VALUES: set[LavaflowResourceReferenceType] = { 'durable_function', 'frontend', 'function', 'project', }
+
+def check_lavaflow_resource_reference_type(value: str) -> LavaflowResourceReferenceType:
+ if value in LAVAFLOW_RESOURCE_REFERENCE_TYPE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_RESOURCE_REFERENCE_TYPE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_review.py b/src/volcano_sdk/_generated/models/lavaflow_review.py
new file mode 100644
index 00000000..7b99e44b
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_review.py
@@ -0,0 +1,185 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_review_stop import check_lavaflow_review_stop
+from ..models.lavaflow_review_stop import LavaflowReviewStop
+from ..models.lavaflow_review_verdict import check_lavaflow_review_verdict
+from ..models.lavaflow_review_verdict import LavaflowReviewVerdict
+from ..types import UNSET, Unset
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_review_finding import LavaflowReviewFinding
+ from ..models.lavaflow_review_person_reason import LavaflowReviewPersonReason
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowReview")
+
+
+
+@_attrs_define
+class LavaflowReview:
+ """
+ Attributes:
+ verdict (LavaflowReviewVerdict): The last review round's verdict. `blocked` means a critical or major finding
+ stops the fix; `changes_requested` means only minor findings do; `error` means a reviewer failed without a
+ blocking finding, or no reviewer could run.
+ rounds (int): The review rounds that ran, 0 when no reviewer could run.
+ stopped (LavaflowReviewStop | None): Why the review ended without passing the fix, null when it passed the fix
+ or when the run saved no fix.
+ open_findings (list[LavaflowReviewFinding] | Unset): The findings the review saved with the fix left open.
+ Absent when the review passed the fix, left none open, or the run saved no fix.
+ person_reasons (list[LavaflowReviewPersonReason] | Unset): What the review saved with the fix asks a person to
+ decide before the fix merges. Absent when it asks nothing or the run saved no fix.
+ """
+
+ verdict: LavaflowReviewVerdict
+ rounds: int
+ stopped: LavaflowReviewStop | None
+ open_findings: list[LavaflowReviewFinding] | Unset = UNSET
+ person_reasons: list[LavaflowReviewPersonReason] | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_review_finding import LavaflowReviewFinding # noqa: PLC0415
+ from ..models.lavaflow_review_person_reason import LavaflowReviewPersonReason # noqa: PLC0415
+ verdict: str = self.verdict
+
+ rounds = self.rounds
+
+ stopped: None | str
+ if isinstance(self.stopped, str):
+ stopped = self.stopped
+ else:
+ stopped = self.stopped
+
+ open_findings: list[dict[str, Any]] | Unset = UNSET
+ if not isinstance(self.open_findings, Unset):
+ open_findings = []
+ for open_findings_item_data in self.open_findings:
+ open_findings_item = open_findings_item_data.to_dict()
+ open_findings.append(open_findings_item)
+
+
+
+ person_reasons: list[dict[str, Any]] | Unset = UNSET
+ if not isinstance(self.person_reasons, Unset):
+ person_reasons = []
+ for person_reasons_item_data in self.person_reasons:
+ person_reasons_item = person_reasons_item_data.to_dict()
+ person_reasons.append(person_reasons_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "verdict": verdict,
+ "rounds": rounds,
+ "stopped": stopped,
+ })
+ if open_findings is not UNSET:
+ field_dict["open_findings"] = open_findings
+ if person_reasons is not UNSET:
+ field_dict["person_reasons"] = person_reasons
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_review_finding import LavaflowReviewFinding # noqa: PLC0415
+ from ..models.lavaflow_review_person_reason import LavaflowReviewPersonReason # noqa: PLC0415
+ d = dict(src_dict)
+ verdict = check_lavaflow_review_verdict(d.pop("verdict"))
+
+
+
+
+ rounds = d.pop("rounds")
+
+ def _parse_stopped(data: object) -> LavaflowReviewStop | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ stopped_type_1 = check_lavaflow_review_stop(data)
+
+
+
+ return stopped_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowReviewStop | None, data)
+
+ stopped = _parse_stopped(d.pop("stopped"))
+
+
+ _open_findings = d.pop("open_findings", UNSET)
+ open_findings: list[LavaflowReviewFinding] | Unset = UNSET
+ if _open_findings is not UNSET:
+ open_findings = []
+ for open_findings_item_data in _open_findings:
+ open_findings_item = LavaflowReviewFinding.from_dict(open_findings_item_data)
+
+
+
+ open_findings.append(open_findings_item)
+
+
+ _person_reasons = d.pop("person_reasons", UNSET)
+ person_reasons: list[LavaflowReviewPersonReason] | Unset = UNSET
+ if _person_reasons is not UNSET:
+ person_reasons = []
+ for person_reasons_item_data in _person_reasons:
+ person_reasons_item = LavaflowReviewPersonReason.from_dict(person_reasons_item_data)
+
+
+
+ person_reasons.append(person_reasons_item)
+
+
+ lavaflow_review = cls(
+ verdict=verdict,
+ rounds=rounds,
+ stopped=stopped,
+ open_findings=open_findings,
+ person_reasons=person_reasons,
+ )
+
+
+ lavaflow_review.additional_properties = d
+ return lavaflow_review
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_review_finding.py b/src/volcano_sdk/_generated/models/lavaflow_review_finding.py
new file mode 100644
index 00000000..ba7f5bf7
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_review_finding.py
@@ -0,0 +1,129 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_review_finding_severity import check_lavaflow_review_finding_severity
+from ..models.lavaflow_review_finding_severity import LavaflowReviewFindingSeverity
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowReviewFinding")
+
+
+
+@_attrs_define
+class LavaflowReviewFinding:
+ """ A finding the review left open, in the reviewer's words. When LavaFlow withholds `explanation`, a sentence that says
+ why stands in: `LavaFlow left this explanation out because it may contain a credential` when it may contain a
+ credential or holds one of the project's secret values; `… because it's too long to check for a credential` when it
+ is over 4,000 characters; `… because the fix may add a credential` when the run is held with `possible_credential`;
+ `… because it withheld the changes to this file` when `diff` withholds the changes to its `file`, even past a
+ truncated diff's cut; `… because it withheld this file's path` when `file` is `""`; and `… because it can't tell
+ whether it withheld the changes to this file` when the finding has a `file` and `diff` withholds a file it doesn't
+ name, can't tell its files apart, or the run saved no `diff`.
+
+ Attributes:
+ severity (LavaflowReviewFindingSeverity):
+ file (None | str): The file the finding is about, null when it is about no file. `""` when the path itself may
+ contain a credential, holds a project secret value, or is over 4,000 characters.
+ line (int | None): The line of `file` the finding is about, null when it is about no one line.
+ explanation (str):
+ """
+
+ severity: LavaflowReviewFindingSeverity
+ file: None | str
+ line: int | None
+ explanation: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ severity: str = self.severity
+
+ file: None | str
+ file = self.file
+
+ line: int | None
+ line = self.line
+
+ explanation = self.explanation
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "severity": severity,
+ "file": file,
+ "line": line,
+ "explanation": explanation,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ severity = check_lavaflow_review_finding_severity(d.pop("severity"))
+
+
+
+
+ def _parse_file(data: object) -> None | str:
+ if data is None:
+ return data
+ return cast(None | str, data)
+
+ file = _parse_file(d.pop("file"))
+
+
+ def _parse_line(data: object) -> int | None:
+ if data is None:
+ return data
+ return cast(int | None, data)
+
+ line = _parse_line(d.pop("line"))
+
+
+ explanation = d.pop("explanation")
+
+ lavaflow_review_finding = cls(
+ severity=severity,
+ file=file,
+ line=line,
+ explanation=explanation,
+ )
+
+
+ lavaflow_review_finding.additional_properties = d
+ return lavaflow_review_finding
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_review_finding_severity.py b/src/volcano_sdk/_generated/models/lavaflow_review_finding_severity.py
new file mode 100644
index 00000000..fd9f71d1
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_review_finding_severity.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowReviewFindingSeverity = Literal['critical', 'major', 'minor', 'nit']
+
+LAVAFLOW_REVIEW_FINDING_SEVERITY_VALUES: set[LavaflowReviewFindingSeverity] = { 'critical', 'major', 'minor', 'nit', }
+
+def check_lavaflow_review_finding_severity(value: str) -> LavaflowReviewFindingSeverity:
+ if value in LAVAFLOW_REVIEW_FINDING_SEVERITY_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_REVIEW_FINDING_SEVERITY_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_review_person_reason.py b/src/volcano_sdk/_generated/models/lavaflow_review_person_reason.py
new file mode 100644
index 00000000..871b95e5
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_review_person_reason.py
@@ -0,0 +1,92 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowReviewPersonReason")
+
+
+
+@_attrs_define
+class LavaflowReviewPersonReason:
+ """ One decision the review leaves to a person. When LavaFlow withholds `question`, a sentence that says why stands in:
+ `LavaFlow left this question out because it may contain a credential` when it may contain a credential or holds one
+ of the project's secret values; `… because it's too long to check for a credential` when it is over 4,000
+ characters; and `… because the fix may add a credential` when the run is held with `possible_credential`.
+
+ Attributes:
+ kind (str): `irreversible`: the fix deletes or migrates data, or does what a revert can't undo.
+ `trust_boundary`: it changes authentication, authorization, secrets, or who can reach what. `breaks_contract`:
+ it changes an interface other code or users depend on. `billing`: it touches payments, pricing, metering, or
+ charges. `unexplained`: it changes behavior its context doesn't explain. `not_reviewable`: it couldn't be
+ reviewed closely. New kinds may appear.
+ question (str): What the person decides, written to show as given.
+ """
+
+ kind: str
+ question: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ kind = self.kind
+
+ question = self.question
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "kind": kind,
+ "question": question,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ kind = d.pop("kind")
+
+ question = d.pop("question")
+
+ lavaflow_review_person_reason = cls(
+ kind=kind,
+ question=question,
+ )
+
+
+ lavaflow_review_person_reason.additional_properties = d
+ return lavaflow_review_person_reason
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_review_stop.py b/src/volcano_sdk/_generated/models/lavaflow_review_stop.py
new file mode 100644
index 00000000..8b9bed47
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_review_stop.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowReviewStop = Literal['budget_exhausted', 'context_limit', 'no_revision', 'reviewers_failed', 'rounds', 'timed_out', 'too_few_reviewers', 'unreadable']
+
+LAVAFLOW_REVIEW_STOP_VALUES: set[LavaflowReviewStop] = { 'budget_exhausted', 'context_limit', 'no_revision', 'reviewers_failed', 'rounds', 'timed_out', 'too_few_reviewers', 'unreadable', }
+
+def check_lavaflow_review_stop(value: str) -> LavaflowReviewStop:
+ if value in LAVAFLOW_REVIEW_STOP_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_REVIEW_STOP_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_review_verdict.py b/src/volcano_sdk/_generated/models/lavaflow_review_verdict.py
new file mode 100644
index 00000000..2ac837c9
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_review_verdict.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowReviewVerdict = Literal['blocked', 'changes_requested', 'error', 'passed']
+
+LAVAFLOW_REVIEW_VERDICT_VALUES: set[LavaflowReviewVerdict] = { 'blocked', 'changes_requested', 'error', 'passed', }
+
+def check_lavaflow_review_verdict(value: str) -> LavaflowReviewVerdict:
+ if value in LAVAFLOW_REVIEW_VERDICT_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_REVIEW_VERDICT_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_run.py b/src/volcano_sdk/_generated/models/lavaflow_run.py
new file mode 100644
index 00000000..c893407d
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_run.py
@@ -0,0 +1,872 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_run_category import check_lavaflow_run_category
+from ..models.lavaflow_run_category import LavaflowRunCategory
+from ..models.lavaflow_run_mode import check_lavaflow_run_mode
+from ..models.lavaflow_run_mode import LavaflowRunMode
+from ..models.lavaflow_run_status import check_lavaflow_run_status
+from ..models.lavaflow_run_status import LavaflowRunStatus
+from ..models.lavaflow_skip_reason import check_lavaflow_skip_reason
+from ..models.lavaflow_skip_reason import LavaflowSkipReason
+from ..types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+import datetime
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_allowed_workflow import LavaflowAllowedWorkflow
+ from ..models.lavaflow_diagnosis import LavaflowDiagnosis
+ from ..models.lavaflow_failure import LavaflowFailure
+ from ..models.lavaflow_fix_outcome import LavaflowFixOutcome
+ from ..models.lavaflow_held_workflows import LavaflowHeldWorkflows
+ from ..models.lavaflow_involved_resource import LavaflowInvolvedResource
+ from ..models.lavaflow_issue_summary import LavaflowIssueSummary
+ from ..models.lavaflow_lineage import LavaflowLineage
+ from ..models.lavaflow_lineage_evidence import LavaflowLineageEvidence
+ from ..models.lavaflow_merge import LavaflowMerge
+ from ..models.lavaflow_pull_request import LavaflowPullRequest
+ from ..models.lavaflow_repository_checks import LavaflowRepositoryChecks
+ from ..models.lavaflow_resource_reference import LavaflowResourceReference
+ from ..models.lavaflow_review import LavaflowReview
+ from ..models.lavaflow_run_progress import LavaflowRunProgress
+ from ..models.lavaflow_source_commit import LavaflowSourceCommit
+ from ..models.lavaflow_source_unavailable import LavaflowSourceUnavailable
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowRun")
+
+
+
+@_attrs_define
+class LavaflowRun:
+ """
+ Attributes:
+ id (UUID):
+ project_id (UUID): The project the run belongs to.
+ status (LavaflowRunStatus): Where a run is. `diagnosing`, `fixing` and `reviewing` are the stages of a running
+ run. `pr_open` means its pull request is open; `completed` means it finished, with no pull request or one that
+ was merged or closed.
+ resource (LavaflowResourceReference): A function, durable function or frontend in the project, or the project of
+ a user-reported problem.
+ issue_id (UUID):
+ title (None | str): Names the problem the run worked on, in at most 80 characters: its diagnosis' title, else
+ the title of the fix it proposed, else the first line or sentence of its diagnosis' summary. A sentence too long
+ for a title ends at its last clause that fits, or, with none, is cut at a word and ends with `…`. Null while
+ none is known, and when it or the text it comes from may contain a credential or hold one of the project's
+ secret values.
+ created_at (datetime.datetime):
+ finished_at (datetime.datetime | None):
+ pull_request (LavaflowPullRequest | None):
+ merge (LavaflowMerge | None):
+ mode (LavaflowRunMode): What the run works on: `live` for an issue seen in the project's logs, `code_quality`
+ for a Code Quality finding.
+ category (LavaflowRunCategory | None): A Code Quality run carries its finding's from the start. Any other run's
+ is null until LavaFlow records a diagnosis. Runs from before categories get one when their diagnosis names one
+ or their saved fix's paths imply one, and stay null only when neither does.
+ resources (list[LavaflowInvolvedResource]): Every resource the run involves: the issue's first, then by name. A
+ run without a recorded diagnosis lists only the issue's. For a run whose report came from what it saved rather
+ than its source, such as one from before involved resources were recorded, the list may leave out frontends and
+ the functions involved through shared code or the build root's dependency files.
+ issue (LavaflowIssueSummary | None): Null only for a run that works on no issue.
+ progress (LavaflowRunProgress | None): Where a run LavaFlow is still working on stands; null once it has nothing
+ left to do.
+ pull_request_skipped (LavaflowSkipReason | None): Why a finished run opened no pull request. A `completed` run
+ without `pull_request` always has one; it is `diagnose_only` when the project's `autonomy` stopped the run at
+ its diagnosis. Null when the run opened a pull request, while it is queued or runs, and when it failed or was
+ cancelled.
+ lineage (LavaflowLineage | None): The fix lineage the run belongs to. Null for a run in no lineage.
+ fix_outcome (LavaflowFixOutcome | None): How the run's merged fix fared once it went live. Null until a merged
+ fix goes live with the `lavaflow.lineage` capability on.
+ source_commit (LavaflowSourceCommit | None): The commit the run read the code at. Null when it read none, as for
+ a run that diagnosed from the logs alone.
+ diagnosis (LavaflowDiagnosis | None):
+ diff (None | str): The fix LavaFlow saved, as the unified diff its reviewers read, cut short past 256 KiB as
+ they read it, with a last line that starts with `[diff truncated`. When a file's content, before or after the
+ fix, or any change to it may hold a credential, or the file is too long for LavaFlow to read whole (over 64 KiB,
+ or past 256 KiB across the fix's files), every change to that file is left out, with one line in their place
+ that starts with `# LavaFlow withheld` and names the file. A run held with `possible_credential` leaves out
+ every file. Null for a run with no saved fix, or one saved before LavaFlow kept its diff.
+ diff_sha256 (None | str): The SHA-256, in hex, of `diff` exactly as served, its UTF-8 bytes. Null whenever
+ `diff` is. Example: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08.
+ diff_truncated (bool): `diff` was cut short, so it does not show the whole fix. False when `diff` is null.
+ diff_withheld (list[str]): The files whose changes `diff` leaves out, by path, as its `# LavaFlow withheld`
+ lines name them; an empty string for a file whose path may itself hold a credential. Empty when `diff` shows
+ every file, or is null.
+ review (LavaflowReview | None): The review of the run's fix. When no reviewer could run, it still says why in
+ `stopped`. Null when no review ran.
+ repository_checks (LavaflowRepositoryChecks | None): Whether LavaFlow ran the repository's own checks on the fix
+ itself. Null for a run with no fix.
+ failure (LavaflowFailure | None): Why the run stopped or waits, null when nothing went wrong.
+ changed_files (list[str]): Repository paths the fix changes, sorted; empty without a fix. A path that may itself
+ hold a credential is listed as "", as `diff_withheld` lists it, and so is every path when `diff` can't tell the
+ fix's files apart. A file past a truncated `diff`'s cut is listed.
+ ungated_workflows (list[LavaflowAllowedWorkflow] | None): The workflow jobs the run's pull request opened past
+ because the project's owner allowed ungated workflows, the first one on each branch or commit checked. Empty
+ when none or when the run opened no pull request. Null when there is no record of the workflows its pull request
+ opened past, as for pull requests opened before LavaFlow recorded them. Under the merge stage, LavaFlow holds
+ such a fix as unchecked, with `ungated_workflows`.
+ lineage_evidence (LavaflowLineageEvidence | None): What tied the run's issue to a recent LavaFlow fix's deploy.
+ Null when nothing did, and for a recurrence, whose issue came back after the fix.
+ held_workflows (LavaflowHeldWorkflows | None): For a run whose `pull_request_skipped` is `ungated_workflows`,
+ every workflow job that held its fix. Null for any other run, and for a held run whose workflows LavaFlow
+ couldn't read to the end, such as one with a workflow it couldn't parse, or more than 256 such jobs.
+ source_unavailable (LavaflowSourceUnavailable | None): For a run whose `pull_request_skipped` is
+ `source_unavailable`, why LavaFlow couldn't read, or open a fix on, the code that served the error. Null for any
+ other run, for a run recorded before LavaFlow kept the reason, and when LavaFlow couldn't tell why.
+ fix_summary (str | Unset): The saved proposed fix's title, on one line of at most 80 characters. This describes
+ a proposal, not a verified fix, successful review, merge or deployment. It never falls back to the diagnosis.
+ Omitted when no saved patch title is known, the fix is withheld because it may add a credential, or the full
+ title cannot pass the project's text privacy checks. The full title is checked before normalization and
+ shortening, and the resulting text is checked again. A shortened value ends with `…`.
+ """
+
+ id: UUID
+ project_id: UUID
+ status: LavaflowRunStatus
+ resource: LavaflowResourceReference
+ issue_id: UUID
+ title: None | str
+ created_at: datetime.datetime
+ finished_at: datetime.datetime | None
+ pull_request: LavaflowPullRequest | None
+ merge: LavaflowMerge | None
+ mode: LavaflowRunMode
+ category: LavaflowRunCategory | None
+ resources: list[LavaflowInvolvedResource]
+ issue: LavaflowIssueSummary | None
+ progress: LavaflowRunProgress | None
+ pull_request_skipped: LavaflowSkipReason | None
+ lineage: LavaflowLineage | None
+ fix_outcome: LavaflowFixOutcome | None
+ source_commit: LavaflowSourceCommit | None
+ diagnosis: LavaflowDiagnosis | None
+ diff: None | str
+ diff_sha256: None | str
+ diff_truncated: bool
+ diff_withheld: list[str]
+ review: LavaflowReview | None
+ repository_checks: LavaflowRepositoryChecks | None
+ failure: LavaflowFailure | None
+ changed_files: list[str]
+ ungated_workflows: list[LavaflowAllowedWorkflow] | None
+ lineage_evidence: LavaflowLineageEvidence | None
+ held_workflows: LavaflowHeldWorkflows | None
+ source_unavailable: LavaflowSourceUnavailable | None
+ fix_summary: str | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_allowed_workflow import LavaflowAllowedWorkflow # noqa: PLC0415
+ from ..models.lavaflow_diagnosis import LavaflowDiagnosis # noqa: PLC0415
+ from ..models.lavaflow_failure import LavaflowFailure # noqa: PLC0415
+ from ..models.lavaflow_fix_outcome import LavaflowFixOutcome # noqa: PLC0415
+ from ..models.lavaflow_held_workflows import LavaflowHeldWorkflows # noqa: PLC0415
+ from ..models.lavaflow_involved_resource import LavaflowInvolvedResource # noqa: PLC0415
+ from ..models.lavaflow_issue_summary import LavaflowIssueSummary # noqa: PLC0415
+ from ..models.lavaflow_lineage import LavaflowLineage # noqa: PLC0415
+ from ..models.lavaflow_lineage_evidence import LavaflowLineageEvidence # noqa: PLC0415
+ from ..models.lavaflow_merge import LavaflowMerge # noqa: PLC0415
+ from ..models.lavaflow_pull_request import LavaflowPullRequest # noqa: PLC0415
+ from ..models.lavaflow_repository_checks import LavaflowRepositoryChecks # noqa: PLC0415
+ from ..models.lavaflow_resource_reference import LavaflowResourceReference # noqa: PLC0415
+ from ..models.lavaflow_review import LavaflowReview # noqa: PLC0415
+ from ..models.lavaflow_run_progress import LavaflowRunProgress # noqa: PLC0415
+ from ..models.lavaflow_source_commit import LavaflowSourceCommit # noqa: PLC0415
+ from ..models.lavaflow_source_unavailable import LavaflowSourceUnavailable # noqa: PLC0415
+ id = str(self.id)
+
+ project_id = str(self.project_id)
+
+ status: str = self.status
+
+ resource = self.resource.to_dict()
+
+ issue_id = str(self.issue_id)
+
+ title: None | str
+ title = self.title
+
+ created_at = self.created_at.isoformat()
+
+ finished_at: None | str
+ if isinstance(self.finished_at, datetime.datetime):
+ finished_at = self.finished_at.isoformat()
+ else:
+ finished_at = self.finished_at
+
+ pull_request: dict[str, Any] | None
+ if isinstance(self.pull_request, LavaflowPullRequest):
+ pull_request = self.pull_request.to_dict()
+ else:
+ pull_request = self.pull_request
+
+ merge: dict[str, Any] | None
+ if isinstance(self.merge, LavaflowMerge):
+ merge = self.merge.to_dict()
+ else:
+ merge = self.merge
+
+ mode: str = self.mode
+
+ category: None | str
+ if isinstance(self.category, str):
+ category = self.category
+ else:
+ category = self.category
+
+ resources = []
+ for resources_item_data in self.resources:
+ resources_item = resources_item_data.to_dict()
+ resources.append(resources_item)
+
+
+
+ issue: dict[str, Any] | None
+ if isinstance(self.issue, LavaflowIssueSummary):
+ issue = self.issue.to_dict()
+ else:
+ issue = self.issue
+
+ progress: dict[str, Any] | None
+ if isinstance(self.progress, LavaflowRunProgress):
+ progress = self.progress.to_dict()
+ else:
+ progress = self.progress
+
+ pull_request_skipped: None | str
+ if isinstance(self.pull_request_skipped, str):
+ pull_request_skipped = self.pull_request_skipped
+ else:
+ pull_request_skipped = self.pull_request_skipped
+
+ lineage: dict[str, Any] | None
+ if isinstance(self.lineage, LavaflowLineage):
+ lineage = self.lineage.to_dict()
+ else:
+ lineage = self.lineage
+
+ fix_outcome: dict[str, Any] | None
+ if isinstance(self.fix_outcome, LavaflowFixOutcome):
+ fix_outcome = self.fix_outcome.to_dict()
+ else:
+ fix_outcome = self.fix_outcome
+
+ source_commit: dict[str, Any] | None
+ if isinstance(self.source_commit, LavaflowSourceCommit):
+ source_commit = self.source_commit.to_dict()
+ else:
+ source_commit = self.source_commit
+
+ diagnosis: dict[str, Any] | None
+ if isinstance(self.diagnosis, LavaflowDiagnosis):
+ diagnosis = self.diagnosis.to_dict()
+ else:
+ diagnosis = self.diagnosis
+
+ diff: None | str
+ diff = self.diff
+
+ diff_sha256: None | str
+ diff_sha256 = self.diff_sha256
+
+ diff_truncated = self.diff_truncated
+
+ diff_withheld = self.diff_withheld
+
+
+
+ review: dict[str, Any] | None
+ if isinstance(self.review, LavaflowReview):
+ review = self.review.to_dict()
+ else:
+ review = self.review
+
+ repository_checks: dict[str, Any] | None
+ if isinstance(self.repository_checks, LavaflowRepositoryChecks):
+ repository_checks = self.repository_checks.to_dict()
+ else:
+ repository_checks = self.repository_checks
+
+ failure: dict[str, Any] | None
+ if isinstance(self.failure, LavaflowFailure):
+ failure = self.failure.to_dict()
+ else:
+ failure = self.failure
+
+ changed_files = self.changed_files
+
+
+
+ ungated_workflows: list[dict[str, Any]] | None
+ if isinstance(self.ungated_workflows, list):
+ ungated_workflows = []
+ for ungated_workflows_type_0_item_data in self.ungated_workflows:
+ ungated_workflows_type_0_item = ungated_workflows_type_0_item_data.to_dict()
+ ungated_workflows.append(ungated_workflows_type_0_item)
+
+
+ else:
+ ungated_workflows = self.ungated_workflows
+
+ lineage_evidence: dict[str, Any] | None
+ if isinstance(self.lineage_evidence, LavaflowLineageEvidence):
+ lineage_evidence = self.lineage_evidence.to_dict()
+ else:
+ lineage_evidence = self.lineage_evidence
+
+ held_workflows: dict[str, Any] | None
+ if isinstance(self.held_workflows, LavaflowHeldWorkflows):
+ held_workflows = self.held_workflows.to_dict()
+ else:
+ held_workflows = self.held_workflows
+
+ source_unavailable: dict[str, Any] | None
+ if isinstance(self.source_unavailable, LavaflowSourceUnavailable):
+ source_unavailable = self.source_unavailable.to_dict()
+ else:
+ source_unavailable = self.source_unavailable
+
+ fix_summary = self.fix_summary
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "project_id": project_id,
+ "status": status,
+ "resource": resource,
+ "issue_id": issue_id,
+ "title": title,
+ "created_at": created_at,
+ "finished_at": finished_at,
+ "pull_request": pull_request,
+ "merge": merge,
+ "mode": mode,
+ "category": category,
+ "resources": resources,
+ "issue": issue,
+ "progress": progress,
+ "pull_request_skipped": pull_request_skipped,
+ "lineage": lineage,
+ "fix_outcome": fix_outcome,
+ "source_commit": source_commit,
+ "diagnosis": diagnosis,
+ "diff": diff,
+ "diff_sha256": diff_sha256,
+ "diff_truncated": diff_truncated,
+ "diff_withheld": diff_withheld,
+ "review": review,
+ "repository_checks": repository_checks,
+ "failure": failure,
+ "changed_files": changed_files,
+ "ungated_workflows": ungated_workflows,
+ "lineage_evidence": lineage_evidence,
+ "held_workflows": held_workflows,
+ "source_unavailable": source_unavailable,
+ })
+ if fix_summary is not UNSET:
+ field_dict["fix_summary"] = fix_summary
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_allowed_workflow import LavaflowAllowedWorkflow # noqa: PLC0415
+ from ..models.lavaflow_diagnosis import LavaflowDiagnosis # noqa: PLC0415
+ from ..models.lavaflow_failure import LavaflowFailure # noqa: PLC0415
+ from ..models.lavaflow_fix_outcome import LavaflowFixOutcome # noqa: PLC0415
+ from ..models.lavaflow_held_workflows import LavaflowHeldWorkflows # noqa: PLC0415
+ from ..models.lavaflow_involved_resource import LavaflowInvolvedResource # noqa: PLC0415
+ from ..models.lavaflow_issue_summary import LavaflowIssueSummary # noqa: PLC0415
+ from ..models.lavaflow_lineage import LavaflowLineage # noqa: PLC0415
+ from ..models.lavaflow_lineage_evidence import LavaflowLineageEvidence # noqa: PLC0415
+ from ..models.lavaflow_merge import LavaflowMerge # noqa: PLC0415
+ from ..models.lavaflow_pull_request import LavaflowPullRequest # noqa: PLC0415
+ from ..models.lavaflow_repository_checks import LavaflowRepositoryChecks # noqa: PLC0415
+ from ..models.lavaflow_resource_reference import LavaflowResourceReference # noqa: PLC0415
+ from ..models.lavaflow_review import LavaflowReview # noqa: PLC0415
+ from ..models.lavaflow_run_progress import LavaflowRunProgress # noqa: PLC0415
+ from ..models.lavaflow_source_commit import LavaflowSourceCommit # noqa: PLC0415
+ from ..models.lavaflow_source_unavailable import LavaflowSourceUnavailable # noqa: PLC0415
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ status = check_lavaflow_run_status(d.pop("status"))
+
+
+
+
+ resource = LavaflowResourceReference.from_dict(d.pop("resource"))
+
+
+
+
+ issue_id = UUID(d.pop("issue_id"))
+
+
+
+
+ def _parse_title(data: object) -> None | str:
+ if data is None:
+ return data
+ return cast(None | str, data)
+
+ title = _parse_title(d.pop("title"))
+
+
+ created_at = datetime.datetime.fromisoformat(d.pop("created_at"))
+
+
+
+
+ def _parse_finished_at(data: object) -> datetime.datetime | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ finished_at_type_0 = datetime.datetime.fromisoformat(data)
+
+
+
+ return finished_at_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(datetime.datetime | None, data)
+
+ finished_at = _parse_finished_at(d.pop("finished_at"))
+
+
+ def _parse_pull_request(data: object) -> LavaflowPullRequest | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ pull_request_type_1 = LavaflowPullRequest.from_dict(data)
+
+
+
+ return pull_request_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowPullRequest | None, data)
+
+ pull_request = _parse_pull_request(d.pop("pull_request"))
+
+
+ def _parse_merge(data: object) -> LavaflowMerge | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ merge_type_1 = LavaflowMerge.from_dict(data)
+
+
+
+ return merge_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowMerge | None, data)
+
+ merge = _parse_merge(d.pop("merge"))
+
+
+ mode = check_lavaflow_run_mode(d.pop("mode"))
+
+
+
+
+ def _parse_category(data: object) -> LavaflowRunCategory | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ category_type_1 = check_lavaflow_run_category(data)
+
+
+
+ return category_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowRunCategory | None, data)
+
+ category = _parse_category(d.pop("category"))
+
+
+ resources = []
+ _resources = d.pop("resources")
+ for resources_item_data in (_resources):
+ resources_item = LavaflowInvolvedResource.from_dict(resources_item_data)
+
+
+
+ resources.append(resources_item)
+
+
+ def _parse_issue(data: object) -> LavaflowIssueSummary | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ issue_type_1 = LavaflowIssueSummary.from_dict(data)
+
+
+
+ return issue_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowIssueSummary | None, data)
+
+ issue = _parse_issue(d.pop("issue"))
+
+
+ def _parse_progress(data: object) -> LavaflowRunProgress | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ progress_type_1 = LavaflowRunProgress.from_dict(data)
+
+
+
+ return progress_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowRunProgress | None, data)
+
+ progress = _parse_progress(d.pop("progress"))
+
+
+ def _parse_pull_request_skipped(data: object) -> LavaflowSkipReason | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ pull_request_skipped_type_1 = check_lavaflow_skip_reason(data)
+
+
+
+ return pull_request_skipped_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowSkipReason | None, data)
+
+ pull_request_skipped = _parse_pull_request_skipped(d.pop("pull_request_skipped"))
+
+
+ def _parse_lineage(data: object) -> LavaflowLineage | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ lineage_type_1 = LavaflowLineage.from_dict(data)
+
+
+
+ return lineage_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowLineage | None, data)
+
+ lineage = _parse_lineage(d.pop("lineage"))
+
+
+ def _parse_fix_outcome(data: object) -> LavaflowFixOutcome | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ fix_outcome_type_1 = LavaflowFixOutcome.from_dict(data)
+
+
+
+ return fix_outcome_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowFixOutcome | None, data)
+
+ fix_outcome = _parse_fix_outcome(d.pop("fix_outcome"))
+
+
+ def _parse_source_commit(data: object) -> LavaflowSourceCommit | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ source_commit_type_1 = LavaflowSourceCommit.from_dict(data)
+
+
+
+ return source_commit_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowSourceCommit | None, data)
+
+ source_commit = _parse_source_commit(d.pop("source_commit"))
+
+
+ def _parse_diagnosis(data: object) -> LavaflowDiagnosis | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ diagnosis_type_1 = LavaflowDiagnosis.from_dict(data)
+
+
+
+ return diagnosis_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowDiagnosis | None, data)
+
+ diagnosis = _parse_diagnosis(d.pop("diagnosis"))
+
+
+ def _parse_diff(data: object) -> None | str:
+ if data is None:
+ return data
+ return cast(None | str, data)
+
+ diff = _parse_diff(d.pop("diff"))
+
+
+ def _parse_diff_sha256(data: object) -> None | str:
+ if data is None:
+ return data
+ return cast(None | str, data)
+
+ diff_sha256 = _parse_diff_sha256(d.pop("diff_sha256"))
+
+
+ diff_truncated = d.pop("diff_truncated")
+
+ diff_withheld = cast(list[str], d.pop("diff_withheld"))
+
+
+ def _parse_review(data: object) -> LavaflowReview | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ review_type_1 = LavaflowReview.from_dict(data)
+
+
+
+ return review_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowReview | None, data)
+
+ review = _parse_review(d.pop("review"))
+
+
+ def _parse_repository_checks(data: object) -> LavaflowRepositoryChecks | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ repository_checks_type_1 = LavaflowRepositoryChecks.from_dict(data)
+
+
+
+ return repository_checks_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowRepositoryChecks | None, data)
+
+ repository_checks = _parse_repository_checks(d.pop("repository_checks"))
+
+
+ def _parse_failure(data: object) -> LavaflowFailure | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ failure_type_1 = LavaflowFailure.from_dict(data)
+
+
+
+ return failure_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowFailure | None, data)
+
+ failure = _parse_failure(d.pop("failure"))
+
+
+ changed_files = cast(list[str], d.pop("changed_files"))
+
+
+ def _parse_ungated_workflows(data: object) -> list[LavaflowAllowedWorkflow] | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, list):
+ raise TypeError()
+ ungated_workflows_type_0 = []
+ _ungated_workflows_type_0 = data
+ for ungated_workflows_type_0_item_data in (_ungated_workflows_type_0):
+ ungated_workflows_type_0_item = LavaflowAllowedWorkflow.from_dict(ungated_workflows_type_0_item_data)
+
+
+
+ ungated_workflows_type_0.append(ungated_workflows_type_0_item)
+
+ return ungated_workflows_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(list[LavaflowAllowedWorkflow] | None, data)
+
+ ungated_workflows = _parse_ungated_workflows(d.pop("ungated_workflows"))
+
+
+ def _parse_lineage_evidence(data: object) -> LavaflowLineageEvidence | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ lineage_evidence_type_1 = LavaflowLineageEvidence.from_dict(data)
+
+
+
+ return lineage_evidence_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowLineageEvidence | None, data)
+
+ lineage_evidence = _parse_lineage_evidence(d.pop("lineage_evidence"))
+
+
+ def _parse_held_workflows(data: object) -> LavaflowHeldWorkflows | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ held_workflows_type_1 = LavaflowHeldWorkflows.from_dict(data)
+
+
+
+ return held_workflows_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowHeldWorkflows | None, data)
+
+ held_workflows = _parse_held_workflows(d.pop("held_workflows"))
+
+
+ def _parse_source_unavailable(data: object) -> LavaflowSourceUnavailable | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ source_unavailable_type_1 = LavaflowSourceUnavailable.from_dict(data)
+
+
+
+ return source_unavailable_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowSourceUnavailable | None, data)
+
+ source_unavailable = _parse_source_unavailable(d.pop("source_unavailable"))
+
+
+ fix_summary = d.pop("fix_summary", UNSET)
+
+ lavaflow_run = cls(
+ id=id,
+ project_id=project_id,
+ status=status,
+ resource=resource,
+ issue_id=issue_id,
+ title=title,
+ created_at=created_at,
+ finished_at=finished_at,
+ pull_request=pull_request,
+ merge=merge,
+ mode=mode,
+ category=category,
+ resources=resources,
+ issue=issue,
+ progress=progress,
+ pull_request_skipped=pull_request_skipped,
+ lineage=lineage,
+ fix_outcome=fix_outcome,
+ source_commit=source_commit,
+ diagnosis=diagnosis,
+ diff=diff,
+ diff_sha256=diff_sha256,
+ diff_truncated=diff_truncated,
+ diff_withheld=diff_withheld,
+ review=review,
+ repository_checks=repository_checks,
+ failure=failure,
+ changed_files=changed_files,
+ ungated_workflows=ungated_workflows,
+ lineage_evidence=lineage_evidence,
+ held_workflows=held_workflows,
+ source_unavailable=source_unavailable,
+ fix_summary=fix_summary,
+ )
+
+
+ lavaflow_run.additional_properties = d
+ return lavaflow_run
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_run_category.py b/src/volcano_sdk/_generated/models/lavaflow_run_category.py
new file mode 100644
index 00000000..c3e9f773
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_run_category.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowRunCategory = Literal['bug', 'configuration', 'dependency', 'external', 'improvement', 'performance', 'security']
+
+LAVAFLOW_RUN_CATEGORY_VALUES: set[LavaflowRunCategory] = { 'bug', 'configuration', 'dependency', 'external', 'improvement', 'performance', 'security', }
+
+def check_lavaflow_run_category(value: str) -> LavaflowRunCategory:
+ if value in LAVAFLOW_RUN_CATEGORY_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_RUN_CATEGORY_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_run_counts.py b/src/volcano_sdk/_generated/models/lavaflow_run_counts.py
new file mode 100644
index 00000000..099789fe
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_run_counts.py
@@ -0,0 +1,152 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_category_counts import LavaflowCategoryCounts
+ from ..models.lavaflow_involved_resource_count import LavaflowInvolvedResourceCount
+ from ..models.lavaflow_pull_request_state_counts import LavaflowPullRequestStateCounts
+ from ..models.lavaflow_run_status_counts import LavaflowRunStatusCounts
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowRunCounts")
+
+
+
+@_attrs_define
+class LavaflowRunCounts:
+ """ Runs that match the request. `total` applies every filter. Each breakdown applies every filter but its own, so it
+ shows what picking another value would return.
+
+ Attributes:
+ total (int):
+ status (LavaflowRunStatusCounts): Matching runs in each status, zeros included.
+ category (LavaflowCategoryCounts): Matching runs in each category, zeros included. `uncategorized` counts runs
+ whose `category` is null.
+ pull_request_state (LavaflowPullRequestStateCounts): Matching runs by the state of their pull request, zeros
+ included. `none` counts runs without one.
+ involved_resources (list[LavaflowInvolvedResourceCount]): Resources involved in at least one matching run, most
+ runs first, then by name; at most 50. A run counts once per resource it involves. A run whose report came from
+ what it saved rather than its source, such as one from before involved resources were recorded, may leave out
+ frontends and the functions involved through shared code or the build root's dependency files, so these counts
+ can undercount them.
+ """
+
+ total: int
+ status: LavaflowRunStatusCounts
+ category: LavaflowCategoryCounts
+ pull_request_state: LavaflowPullRequestStateCounts
+ involved_resources: list[LavaflowInvolvedResourceCount]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_category_counts import LavaflowCategoryCounts # noqa: PLC0415
+ from ..models.lavaflow_involved_resource_count import LavaflowInvolvedResourceCount # noqa: PLC0415
+ from ..models.lavaflow_pull_request_state_counts import LavaflowPullRequestStateCounts # noqa: PLC0415
+ from ..models.lavaflow_run_status_counts import LavaflowRunStatusCounts # noqa: PLC0415
+ total = self.total
+
+ status = self.status.to_dict()
+
+ category = self.category.to_dict()
+
+ pull_request_state = self.pull_request_state.to_dict()
+
+ involved_resources = []
+ for involved_resources_item_data in self.involved_resources:
+ involved_resources_item = involved_resources_item_data.to_dict()
+ involved_resources.append(involved_resources_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "total": total,
+ "status": status,
+ "category": category,
+ "pull_request_state": pull_request_state,
+ "involved_resources": involved_resources,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_category_counts import LavaflowCategoryCounts # noqa: PLC0415
+ from ..models.lavaflow_involved_resource_count import LavaflowInvolvedResourceCount # noqa: PLC0415
+ from ..models.lavaflow_pull_request_state_counts import LavaflowPullRequestStateCounts # noqa: PLC0415
+ from ..models.lavaflow_run_status_counts import LavaflowRunStatusCounts # noqa: PLC0415
+ d = dict(src_dict)
+ total = d.pop("total")
+
+ status = LavaflowRunStatusCounts.from_dict(d.pop("status"))
+
+
+
+
+ category = LavaflowCategoryCounts.from_dict(d.pop("category"))
+
+
+
+
+ pull_request_state = LavaflowPullRequestStateCounts.from_dict(d.pop("pull_request_state"))
+
+
+
+
+ involved_resources = []
+ _involved_resources = d.pop("involved_resources")
+ for involved_resources_item_data in (_involved_resources):
+ involved_resources_item = LavaflowInvolvedResourceCount.from_dict(involved_resources_item_data)
+
+
+
+ involved_resources.append(involved_resources_item)
+
+
+ lavaflow_run_counts = cls(
+ total=total,
+ status=status,
+ category=category,
+ pull_request_state=pull_request_state,
+ involved_resources=involved_resources,
+ )
+
+
+ lavaflow_run_counts.additional_properties = d
+ return lavaflow_run_counts
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_run_create.py b/src/volcano_sdk/_generated/models/lavaflow_run_create.py
new file mode 100644
index 00000000..e4fb0013
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_run_create.py
@@ -0,0 +1,74 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowRunCreate")
+
+
+
+@_attrs_define
+class LavaflowRunCreate:
+ """ The project, and the issue to start a run on.
+
+ Attributes:
+ project_id (UUID): The project the issue belongs to.
+ issue_id (UUID): The issue to start a run on.
+ """
+
+ project_id: UUID
+ issue_id: UUID
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ project_id = str(self.project_id)
+
+ issue_id = str(self.issue_id)
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "project_id": project_id,
+ "issue_id": issue_id,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ issue_id = UUID(d.pop("issue_id"))
+
+
+
+
+ lavaflow_run_create = cls(
+ project_id=project_id,
+ issue_id=issue_id,
+ )
+
+ return lavaflow_run_create
+
diff --git a/src/volcano_sdk/_generated/models/lavaflow_run_mode.py b/src/volcano_sdk/_generated/models/lavaflow_run_mode.py
new file mode 100644
index 00000000..c4a55cf1
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_run_mode.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowRunMode = Literal['code_quality', 'live']
+
+LAVAFLOW_RUN_MODE_VALUES: set[LavaflowRunMode] = { 'code_quality', 'live', }
+
+def check_lavaflow_run_mode(value: str) -> LavaflowRunMode:
+ if value in LAVAFLOW_RUN_MODE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_RUN_MODE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_run_progress.py b/src/volcano_sdk/_generated/models/lavaflow_run_progress.py
new file mode 100644
index 00000000..ffac78e9
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_run_progress.py
@@ -0,0 +1,101 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_run_progress_stage import check_lavaflow_run_progress_stage
+from ..models.lavaflow_run_progress_stage import LavaflowRunProgressStage
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowRunProgress")
+
+
+
+@_attrs_define
+class LavaflowRunProgress:
+ """ How far an active run has come. The steps are `queued`, `diagnosing`, `fixing`, `reviewing`, `waiting_for_checks`
+ and `merge_queued`, in that order, and a run takes as many as its autonomy when it was queued allows: 2 for
+ `diagnose_only`, 4 for `open_pr` (opening the pull request ends it), 6 for `merge` (the merge ends it).
+
+ Attributes:
+ stage (LavaflowRunProgressStage): New stages may appear.
+ step (int): The stage's place among the run's steps, from 1.
+ steps (int): How many steps the run takes.
+ """
+
+ stage: LavaflowRunProgressStage
+ step: int
+ steps: int
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ stage: str = self.stage
+
+ step = self.step
+
+ steps = self.steps
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "stage": stage,
+ "step": step,
+ "steps": steps,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ stage = check_lavaflow_run_progress_stage(d.pop("stage"))
+
+
+
+
+ step = d.pop("step")
+
+ steps = d.pop("steps")
+
+ lavaflow_run_progress = cls(
+ stage=stage,
+ step=step,
+ steps=steps,
+ )
+
+
+ lavaflow_run_progress.additional_properties = d
+ return lavaflow_run_progress
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_run_progress_stage.py b/src/volcano_sdk/_generated/models/lavaflow_run_progress_stage.py
new file mode 100644
index 00000000..5f50ea74
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_run_progress_stage.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowRunProgressStage = Literal['diagnosing', 'fixing', 'merge_queued', 'queued', 'reviewing', 'waiting_for_checks']
+
+LAVAFLOW_RUN_PROGRESS_STAGE_VALUES: set[LavaflowRunProgressStage] = { 'diagnosing', 'fixing', 'merge_queued', 'queued', 'reviewing', 'waiting_for_checks', }
+
+def check_lavaflow_run_progress_stage(value: str) -> LavaflowRunProgressStage:
+ if value in LAVAFLOW_RUN_PROGRESS_STAGE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_RUN_PROGRESS_STAGE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_run_reference.py b/src/volcano_sdk/_generated/models/lavaflow_run_reference.py
new file mode 100644
index 00000000..7110bcf5
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_run_reference.py
@@ -0,0 +1,97 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowRunReference")
+
+
+
+@_attrs_define
+class LavaflowRunReference:
+ """ Another LavaFlow run of the same project.
+
+ Attributes:
+ id (UUID):
+ title (None | str): The run's title, as `LavaflowRunSummary.title` gives it.
+ """
+
+ id: UUID
+ title: None | str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ id = str(self.id)
+
+ title: None | str
+ title = self.title
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "title": title,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ def _parse_title(data: object) -> None | str:
+ if data is None:
+ return data
+ return cast(None | str, data)
+
+ title = _parse_title(d.pop("title"))
+
+
+ lavaflow_run_reference = cls(
+ id=id,
+ title=title,
+ )
+
+
+ lavaflow_run_reference.additional_properties = d
+ return lavaflow_run_reference
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_run_status.py b/src/volcano_sdk/_generated/models/lavaflow_run_status.py
new file mode 100644
index 00000000..2e5d3028
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_run_status.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowRunStatus = Literal['cancelled', 'completed', 'diagnosing', 'failed', 'fixing', 'pr_open', 'queued', 'reviewing']
+
+LAVAFLOW_RUN_STATUS_VALUES: set[LavaflowRunStatus] = { 'cancelled', 'completed', 'diagnosing', 'failed', 'fixing', 'pr_open', 'queued', 'reviewing', }
+
+def check_lavaflow_run_status(value: str) -> LavaflowRunStatus:
+ if value in LAVAFLOW_RUN_STATUS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_RUN_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_run_status_counts.py b/src/volcano_sdk/_generated/models/lavaflow_run_status_counts.py
new file mode 100644
index 00000000..94cd25b7
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_run_status_counts.py
@@ -0,0 +1,133 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowRunStatusCounts")
+
+
+
+@_attrs_define
+class LavaflowRunStatusCounts:
+ """ Matching runs in each status, zeros included.
+
+ Attributes:
+ queued (int):
+ diagnosing (int):
+ fixing (int):
+ reviewing (int):
+ pr_open (int):
+ completed (int):
+ failed (int):
+ cancelled (int):
+ """
+
+ queued: int
+ diagnosing: int
+ fixing: int
+ reviewing: int
+ pr_open: int
+ completed: int
+ failed: int
+ cancelled: int
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ queued = self.queued
+
+ diagnosing = self.diagnosing
+
+ fixing = self.fixing
+
+ reviewing = self.reviewing
+
+ pr_open = self.pr_open
+
+ completed = self.completed
+
+ failed = self.failed
+
+ cancelled = self.cancelled
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "queued": queued,
+ "diagnosing": diagnosing,
+ "fixing": fixing,
+ "reviewing": reviewing,
+ "pr_open": pr_open,
+ "completed": completed,
+ "failed": failed,
+ "cancelled": cancelled,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ queued = d.pop("queued")
+
+ diagnosing = d.pop("diagnosing")
+
+ fixing = d.pop("fixing")
+
+ reviewing = d.pop("reviewing")
+
+ pr_open = d.pop("pr_open")
+
+ completed = d.pop("completed")
+
+ failed = d.pop("failed")
+
+ cancelled = d.pop("cancelled")
+
+ lavaflow_run_status_counts = cls(
+ queued=queued,
+ diagnosing=diagnosing,
+ fixing=fixing,
+ reviewing=reviewing,
+ pr_open=pr_open,
+ completed=completed,
+ failed=failed,
+ cancelled=cancelled,
+ )
+
+
+ lavaflow_run_status_counts.additional_properties = d
+ return lavaflow_run_status_counts
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_run_summary.py b/src/volcano_sdk/_generated/models/lavaflow_run_summary.py
new file mode 100644
index 00000000..c86a545b
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_run_summary.py
@@ -0,0 +1,501 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_run_category import check_lavaflow_run_category
+from ..models.lavaflow_run_category import LavaflowRunCategory
+from ..models.lavaflow_run_mode import check_lavaflow_run_mode
+from ..models.lavaflow_run_mode import LavaflowRunMode
+from ..models.lavaflow_run_status import check_lavaflow_run_status
+from ..models.lavaflow_run_status import LavaflowRunStatus
+from ..models.lavaflow_skip_reason import check_lavaflow_skip_reason
+from ..models.lavaflow_skip_reason import LavaflowSkipReason
+from ..types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+import datetime
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_fix_outcome import LavaflowFixOutcome
+ from ..models.lavaflow_involved_resource import LavaflowInvolvedResource
+ from ..models.lavaflow_issue_summary import LavaflowIssueSummary
+ from ..models.lavaflow_lineage import LavaflowLineage
+ from ..models.lavaflow_merge import LavaflowMerge
+ from ..models.lavaflow_pull_request import LavaflowPullRequest
+ from ..models.lavaflow_resource_reference import LavaflowResourceReference
+ from ..models.lavaflow_run_progress import LavaflowRunProgress
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowRunSummary")
+
+
+
+@_attrs_define
+class LavaflowRunSummary:
+ """
+ Attributes:
+ id (UUID):
+ project_id (UUID): The project the run belongs to.
+ status (LavaflowRunStatus): Where a run is. `diagnosing`, `fixing` and `reviewing` are the stages of a running
+ run. `pr_open` means its pull request is open; `completed` means it finished, with no pull request or one that
+ was merged or closed.
+ resource (LavaflowResourceReference): A function, durable function or frontend in the project, or the project of
+ a user-reported problem.
+ issue_id (UUID):
+ title (None | str): Names the problem the run worked on, in at most 80 characters: its diagnosis' title, else
+ the title of the fix it proposed, else the first line or sentence of its diagnosis' summary. A sentence too long
+ for a title ends at its last clause that fits, or, with none, is cut at a word and ends with `…`. Null while
+ none is known, and when it or the text it comes from may contain a credential or hold one of the project's
+ secret values.
+ created_at (datetime.datetime):
+ finished_at (datetime.datetime | None):
+ pull_request (LavaflowPullRequest | None):
+ merge (LavaflowMerge | None):
+ mode (LavaflowRunMode): What the run works on: `live` for an issue seen in the project's logs, `code_quality`
+ for a Code Quality finding.
+ category (LavaflowRunCategory | None): A Code Quality run carries its finding's from the start. Any other run's
+ is null until LavaFlow records a diagnosis. Runs from before categories get one when their diagnosis names one
+ or their saved fix's paths imply one, and stay null only when neither does.
+ resources (list[LavaflowInvolvedResource]): Every resource the run involves: the issue's first, then by name. A
+ run without a recorded diagnosis lists only the issue's. For a run whose report came from what it saved rather
+ than its source, such as one from before involved resources were recorded, the list may leave out frontends and
+ the functions involved through shared code or the build root's dependency files.
+ issue (LavaflowIssueSummary | None): Null only for a run that works on no issue.
+ progress (LavaflowRunProgress | None): Where a run LavaFlow is still working on stands; null once it has nothing
+ left to do.
+ pull_request_skipped (LavaflowSkipReason | None): Why a finished run opened no pull request. A `completed` run
+ without `pull_request` always has one; it is `diagnose_only` when the project's `autonomy` stopped the run at
+ its diagnosis. Null when the run opened a pull request, while it is queued or runs, and when it failed or was
+ cancelled.
+ lineage (LavaflowLineage | None): The fix lineage the run belongs to. Null for a run in no lineage.
+ fix_outcome (LavaflowFixOutcome | None): How the run's merged fix fared once it went live. Null until a merged
+ fix goes live with the `lavaflow.lineage` capability on.
+ fix_summary (str | Unset): The saved proposed fix's title, on one line of at most 80 characters. This describes
+ a proposal, not a verified fix, successful review, merge or deployment. It never falls back to the diagnosis.
+ Omitted when no saved patch title is known, the fix is withheld because it may add a credential, or the full
+ title cannot pass the project's text privacy checks. The full title is checked before normalization and
+ shortening, and the resulting text is checked again. A shortened value ends with `…`.
+ """
+
+ id: UUID
+ project_id: UUID
+ status: LavaflowRunStatus
+ resource: LavaflowResourceReference
+ issue_id: UUID
+ title: None | str
+ created_at: datetime.datetime
+ finished_at: datetime.datetime | None
+ pull_request: LavaflowPullRequest | None
+ merge: LavaflowMerge | None
+ mode: LavaflowRunMode
+ category: LavaflowRunCategory | None
+ resources: list[LavaflowInvolvedResource]
+ issue: LavaflowIssueSummary | None
+ progress: LavaflowRunProgress | None
+ pull_request_skipped: LavaflowSkipReason | None
+ lineage: LavaflowLineage | None
+ fix_outcome: LavaflowFixOutcome | None
+ fix_summary: str | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_fix_outcome import LavaflowFixOutcome # noqa: PLC0415
+ from ..models.lavaflow_involved_resource import LavaflowInvolvedResource # noqa: PLC0415
+ from ..models.lavaflow_issue_summary import LavaflowIssueSummary # noqa: PLC0415
+ from ..models.lavaflow_lineage import LavaflowLineage # noqa: PLC0415
+ from ..models.lavaflow_merge import LavaflowMerge # noqa: PLC0415
+ from ..models.lavaflow_pull_request import LavaflowPullRequest # noqa: PLC0415
+ from ..models.lavaflow_resource_reference import LavaflowResourceReference # noqa: PLC0415
+ from ..models.lavaflow_run_progress import LavaflowRunProgress # noqa: PLC0415
+ id = str(self.id)
+
+ project_id = str(self.project_id)
+
+ status: str = self.status
+
+ resource = self.resource.to_dict()
+
+ issue_id = str(self.issue_id)
+
+ title: None | str
+ title = self.title
+
+ created_at = self.created_at.isoformat()
+
+ finished_at: None | str
+ if isinstance(self.finished_at, datetime.datetime):
+ finished_at = self.finished_at.isoformat()
+ else:
+ finished_at = self.finished_at
+
+ pull_request: dict[str, Any] | None
+ if isinstance(self.pull_request, LavaflowPullRequest):
+ pull_request = self.pull_request.to_dict()
+ else:
+ pull_request = self.pull_request
+
+ merge: dict[str, Any] | None
+ if isinstance(self.merge, LavaflowMerge):
+ merge = self.merge.to_dict()
+ else:
+ merge = self.merge
+
+ mode: str = self.mode
+
+ category: None | str
+ if isinstance(self.category, str):
+ category = self.category
+ else:
+ category = self.category
+
+ resources = []
+ for resources_item_data in self.resources:
+ resources_item = resources_item_data.to_dict()
+ resources.append(resources_item)
+
+
+
+ issue: dict[str, Any] | None
+ if isinstance(self.issue, LavaflowIssueSummary):
+ issue = self.issue.to_dict()
+ else:
+ issue = self.issue
+
+ progress: dict[str, Any] | None
+ if isinstance(self.progress, LavaflowRunProgress):
+ progress = self.progress.to_dict()
+ else:
+ progress = self.progress
+
+ pull_request_skipped: None | str
+ if isinstance(self.pull_request_skipped, str):
+ pull_request_skipped = self.pull_request_skipped
+ else:
+ pull_request_skipped = self.pull_request_skipped
+
+ lineage: dict[str, Any] | None
+ if isinstance(self.lineage, LavaflowLineage):
+ lineage = self.lineage.to_dict()
+ else:
+ lineage = self.lineage
+
+ fix_outcome: dict[str, Any] | None
+ if isinstance(self.fix_outcome, LavaflowFixOutcome):
+ fix_outcome = self.fix_outcome.to_dict()
+ else:
+ fix_outcome = self.fix_outcome
+
+ fix_summary = self.fix_summary
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "project_id": project_id,
+ "status": status,
+ "resource": resource,
+ "issue_id": issue_id,
+ "title": title,
+ "created_at": created_at,
+ "finished_at": finished_at,
+ "pull_request": pull_request,
+ "merge": merge,
+ "mode": mode,
+ "category": category,
+ "resources": resources,
+ "issue": issue,
+ "progress": progress,
+ "pull_request_skipped": pull_request_skipped,
+ "lineage": lineage,
+ "fix_outcome": fix_outcome,
+ })
+ if fix_summary is not UNSET:
+ field_dict["fix_summary"] = fix_summary
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_fix_outcome import LavaflowFixOutcome # noqa: PLC0415
+ from ..models.lavaflow_involved_resource import LavaflowInvolvedResource # noqa: PLC0415
+ from ..models.lavaflow_issue_summary import LavaflowIssueSummary # noqa: PLC0415
+ from ..models.lavaflow_lineage import LavaflowLineage # noqa: PLC0415
+ from ..models.lavaflow_merge import LavaflowMerge # noqa: PLC0415
+ from ..models.lavaflow_pull_request import LavaflowPullRequest # noqa: PLC0415
+ from ..models.lavaflow_resource_reference import LavaflowResourceReference # noqa: PLC0415
+ from ..models.lavaflow_run_progress import LavaflowRunProgress # noqa: PLC0415
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ status = check_lavaflow_run_status(d.pop("status"))
+
+
+
+
+ resource = LavaflowResourceReference.from_dict(d.pop("resource"))
+
+
+
+
+ issue_id = UUID(d.pop("issue_id"))
+
+
+
+
+ def _parse_title(data: object) -> None | str:
+ if data is None:
+ return data
+ return cast(None | str, data)
+
+ title = _parse_title(d.pop("title"))
+
+
+ created_at = datetime.datetime.fromisoformat(d.pop("created_at"))
+
+
+
+
+ def _parse_finished_at(data: object) -> datetime.datetime | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ finished_at_type_0 = datetime.datetime.fromisoformat(data)
+
+
+
+ return finished_at_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(datetime.datetime | None, data)
+
+ finished_at = _parse_finished_at(d.pop("finished_at"))
+
+
+ def _parse_pull_request(data: object) -> LavaflowPullRequest | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ pull_request_type_1 = LavaflowPullRequest.from_dict(data)
+
+
+
+ return pull_request_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowPullRequest | None, data)
+
+ pull_request = _parse_pull_request(d.pop("pull_request"))
+
+
+ def _parse_merge(data: object) -> LavaflowMerge | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ merge_type_1 = LavaflowMerge.from_dict(data)
+
+
+
+ return merge_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowMerge | None, data)
+
+ merge = _parse_merge(d.pop("merge"))
+
+
+ mode = check_lavaflow_run_mode(d.pop("mode"))
+
+
+
+
+ def _parse_category(data: object) -> LavaflowRunCategory | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ category_type_1 = check_lavaflow_run_category(data)
+
+
+
+ return category_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowRunCategory | None, data)
+
+ category = _parse_category(d.pop("category"))
+
+
+ resources = []
+ _resources = d.pop("resources")
+ for resources_item_data in (_resources):
+ resources_item = LavaflowInvolvedResource.from_dict(resources_item_data)
+
+
+
+ resources.append(resources_item)
+
+
+ def _parse_issue(data: object) -> LavaflowIssueSummary | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ issue_type_1 = LavaflowIssueSummary.from_dict(data)
+
+
+
+ return issue_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowIssueSummary | None, data)
+
+ issue = _parse_issue(d.pop("issue"))
+
+
+ def _parse_progress(data: object) -> LavaflowRunProgress | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ progress_type_1 = LavaflowRunProgress.from_dict(data)
+
+
+
+ return progress_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowRunProgress | None, data)
+
+ progress = _parse_progress(d.pop("progress"))
+
+
+ def _parse_pull_request_skipped(data: object) -> LavaflowSkipReason | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ pull_request_skipped_type_1 = check_lavaflow_skip_reason(data)
+
+
+
+ return pull_request_skipped_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowSkipReason | None, data)
+
+ pull_request_skipped = _parse_pull_request_skipped(d.pop("pull_request_skipped"))
+
+
+ def _parse_lineage(data: object) -> LavaflowLineage | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ lineage_type_1 = LavaflowLineage.from_dict(data)
+
+
+
+ return lineage_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowLineage | None, data)
+
+ lineage = _parse_lineage(d.pop("lineage"))
+
+
+ def _parse_fix_outcome(data: object) -> LavaflowFixOutcome | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ fix_outcome_type_1 = LavaflowFixOutcome.from_dict(data)
+
+
+
+ return fix_outcome_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowFixOutcome | None, data)
+
+ fix_outcome = _parse_fix_outcome(d.pop("fix_outcome"))
+
+
+ fix_summary = d.pop("fix_summary", UNSET)
+
+ lavaflow_run_summary = cls(
+ id=id,
+ project_id=project_id,
+ status=status,
+ resource=resource,
+ issue_id=issue_id,
+ title=title,
+ created_at=created_at,
+ finished_at=finished_at,
+ pull_request=pull_request,
+ merge=merge,
+ mode=mode,
+ category=category,
+ resources=resources,
+ issue=issue,
+ progress=progress,
+ pull_request_skipped=pull_request_skipped,
+ lineage=lineage,
+ fix_outcome=fix_outcome,
+ fix_summary=fix_summary,
+ )
+
+
+ lavaflow_run_summary.additional_properties = d
+ return lavaflow_run_summary
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_scan.py b/src/volcano_sdk/_generated/models/lavaflow_scan.py
new file mode 100644
index 00000000..bde2863b
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_scan.py
@@ -0,0 +1,344 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_scan_source import check_lavaflow_scan_source
+from ..models.lavaflow_scan_source import LavaflowScanSource
+from ..models.lavaflow_scan_status import check_lavaflow_scan_status
+from ..models.lavaflow_scan_status import LavaflowScanStatus
+from typing import cast
+from uuid import UUID
+import datetime
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_scan_billed_finding import LavaflowScanBilledFinding
+ from ..models.lavaflow_scan_counts import LavaflowScanCounts
+ from ..models.lavaflow_scan_resource import LavaflowScanResource
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowScan")
+
+
+
+@_attrs_define
+class LavaflowScan:
+ """ One Code Quality scan of the code a project's deploys changed.
+
+ Attributes:
+ id (None | UUID): The scan's ID, null while it is waiting.
+ project_id (UUID):
+ source (LavaflowScanSource): What asked for the scan.
+ status (LavaflowScanStatus): Where the scan stands. `waiting` is the project's next scan: deploys that went live
+ since the last one, waiting out a short settle window or a bound named by `waiting_reason`.
+ outcome (None | str): How a finished scan ended: `scanned`; `no_changes` when the deploy changed nothing since
+ the last scan, as after a redeploy or a rollback; `no_base` when there was no earlier commit to compare against,
+ so the head became the starting point; `unreachable` when the head commit is on neither the project's production
+ branch nor the repository's default branch; `repository_changed`; `failed`; or `cancelled`. Null until it ends.
+ waiting_reason (None | str): The bound a waiting scan waits at: `findings_limit`, `pull_request_limit`,
+ `spend_limit`, `scan_limit` or `feature_unavailable`. Null while it only waits out its settle window, and for a
+ scan that started. A waiting scan skips no deploy: it covers every commit since the last scan when it starts.
+ repository_id (int): The GitHub repository the scan reads.
+ base_sha (None | str): The commit the scan compares against, null while waiting or when there was none.
+ head_sha (str): The newest deployed commit the scan covers.
+ resources (list[LavaflowScanResource]):
+ truncated (bool): Whether the scan reviewed only part of the change. A change too large to review whole keeps
+ the files with the most changed lines, a review that stops early keeps what it found, and a repository too large
+ to read whole skips the files past what it read. No later scan covers the rest.
+ counts (LavaflowScanCounts): What the scan did with the problems it found.
+ billed (list[LavaflowScanBilledFinding]): The scan's findings whose runs were billed.
+ requested_at (datetime.datetime): When the first deploy the scan covers asked for it.
+ started_at (datetime.datetime | None):
+ completed_at (datetime.datetime | None):
+ """
+
+ id: None | UUID
+ project_id: UUID
+ source: LavaflowScanSource
+ status: LavaflowScanStatus
+ outcome: None | str
+ waiting_reason: None | str
+ repository_id: int
+ base_sha: None | str
+ head_sha: str
+ resources: list[LavaflowScanResource]
+ truncated: bool
+ counts: LavaflowScanCounts
+ billed: list[LavaflowScanBilledFinding]
+ requested_at: datetime.datetime
+ started_at: datetime.datetime | None
+ completed_at: datetime.datetime | None
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_scan_billed_finding import LavaflowScanBilledFinding # noqa: PLC0415
+ from ..models.lavaflow_scan_counts import LavaflowScanCounts # noqa: PLC0415
+ from ..models.lavaflow_scan_resource import LavaflowScanResource # noqa: PLC0415
+ id: None | str
+ if isinstance(self.id, UUID):
+ id = str(self.id)
+ else:
+ id = self.id
+
+ project_id = str(self.project_id)
+
+ source: str = self.source
+
+ status: str = self.status
+
+ outcome: None | str
+ outcome = self.outcome
+
+ waiting_reason: None | str
+ waiting_reason = self.waiting_reason
+
+ repository_id = self.repository_id
+
+ base_sha: None | str
+ base_sha = self.base_sha
+
+ head_sha = self.head_sha
+
+ resources = []
+ for resources_item_data in self.resources:
+ resources_item = resources_item_data.to_dict()
+ resources.append(resources_item)
+
+
+
+ truncated = self.truncated
+
+ counts = self.counts.to_dict()
+
+ billed = []
+ for billed_item_data in self.billed:
+ billed_item = billed_item_data.to_dict()
+ billed.append(billed_item)
+
+
+
+ requested_at = self.requested_at.isoformat()
+
+ started_at: None | str
+ if isinstance(self.started_at, datetime.datetime):
+ started_at = self.started_at.isoformat()
+ else:
+ started_at = self.started_at
+
+ completed_at: None | str
+ if isinstance(self.completed_at, datetime.datetime):
+ completed_at = self.completed_at.isoformat()
+ else:
+ completed_at = self.completed_at
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "project_id": project_id,
+ "source": source,
+ "status": status,
+ "outcome": outcome,
+ "waiting_reason": waiting_reason,
+ "repository_id": repository_id,
+ "base_sha": base_sha,
+ "head_sha": head_sha,
+ "resources": resources,
+ "truncated": truncated,
+ "counts": counts,
+ "billed": billed,
+ "requested_at": requested_at,
+ "started_at": started_at,
+ "completed_at": completed_at,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_scan_billed_finding import LavaflowScanBilledFinding # noqa: PLC0415
+ from ..models.lavaflow_scan_counts import LavaflowScanCounts # noqa: PLC0415
+ from ..models.lavaflow_scan_resource import LavaflowScanResource # noqa: PLC0415
+ d = dict(src_dict)
+ def _parse_id(data: object) -> None | UUID:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ id_type_0 = UUID(data)
+
+
+
+ return id_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(None | UUID, data)
+
+ id = _parse_id(d.pop("id"))
+
+
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ source = check_lavaflow_scan_source(d.pop("source"))
+
+
+
+
+ status = check_lavaflow_scan_status(d.pop("status"))
+
+
+
+
+ def _parse_outcome(data: object) -> None | str:
+ if data is None:
+ return data
+ return cast(None | str, data)
+
+ outcome = _parse_outcome(d.pop("outcome"))
+
+
+ def _parse_waiting_reason(data: object) -> None | str:
+ if data is None:
+ return data
+ return cast(None | str, data)
+
+ waiting_reason = _parse_waiting_reason(d.pop("waiting_reason"))
+
+
+ repository_id = d.pop("repository_id")
+
+ def _parse_base_sha(data: object) -> None | str:
+ if data is None:
+ return data
+ return cast(None | str, data)
+
+ base_sha = _parse_base_sha(d.pop("base_sha"))
+
+
+ head_sha = d.pop("head_sha")
+
+ resources = []
+ _resources = d.pop("resources")
+ for resources_item_data in (_resources):
+ resources_item = LavaflowScanResource.from_dict(resources_item_data)
+
+
+
+ resources.append(resources_item)
+
+
+ truncated = d.pop("truncated")
+
+ counts = LavaflowScanCounts.from_dict(d.pop("counts"))
+
+
+
+
+ billed = []
+ _billed = d.pop("billed")
+ for billed_item_data in (_billed):
+ billed_item = LavaflowScanBilledFinding.from_dict(billed_item_data)
+
+
+
+ billed.append(billed_item)
+
+
+ requested_at = datetime.datetime.fromisoformat(d.pop("requested_at"))
+
+
+
+
+ def _parse_started_at(data: object) -> datetime.datetime | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ started_at_type_0 = datetime.datetime.fromisoformat(data)
+
+
+
+ return started_at_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(datetime.datetime | None, data)
+
+ started_at = _parse_started_at(d.pop("started_at"))
+
+
+ def _parse_completed_at(data: object) -> datetime.datetime | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ completed_at_type_0 = datetime.datetime.fromisoformat(data)
+
+
+
+ return completed_at_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(datetime.datetime | None, data)
+
+ completed_at = _parse_completed_at(d.pop("completed_at"))
+
+
+ lavaflow_scan = cls(
+ id=id,
+ project_id=project_id,
+ source=source,
+ status=status,
+ outcome=outcome,
+ waiting_reason=waiting_reason,
+ repository_id=repository_id,
+ base_sha=base_sha,
+ head_sha=head_sha,
+ resources=resources,
+ truncated=truncated,
+ counts=counts,
+ billed=billed,
+ requested_at=requested_at,
+ started_at=started_at,
+ completed_at=completed_at,
+ )
+
+
+ lavaflow_scan.additional_properties = d
+ return lavaflow_scan
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_scan_billed_finding.py b/src/volcano_sdk/_generated/models/lavaflow_scan_billed_finding.py
new file mode 100644
index 00000000..8077d4b2
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_scan_billed_finding.py
@@ -0,0 +1,114 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+from uuid import UUID
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_scan_billed_finding_billable_events import LavaflowScanBilledFindingBillableEvents
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowScanBilledFinding")
+
+
+
+@_attrs_define
+class LavaflowScanBilledFinding:
+ """ A finding of the scan whose Code Quality runs were billed.
+
+ Attributes:
+ issue_id (UUID): The finding's issue. Its `finding` says where the problem is and why.
+ rule (str): The rule the finding is about.
+ title (str):
+ billable_events (LavaflowScanBilledFindingBillableEvents): How many billable events of each kind the finding's
+ runs recorded, keyed by kind, such as `issue_diagnosed` and `pull_request_opened`.
+ """
+
+ issue_id: UUID
+ rule: str
+ title: str
+ billable_events: LavaflowScanBilledFindingBillableEvents
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_scan_billed_finding_billable_events import LavaflowScanBilledFindingBillableEvents # noqa: PLC0415
+ issue_id = str(self.issue_id)
+
+ rule = self.rule
+
+ title = self.title
+
+ billable_events = self.billable_events.to_dict()
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "issue_id": issue_id,
+ "rule": rule,
+ "title": title,
+ "billable_events": billable_events,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_scan_billed_finding_billable_events import LavaflowScanBilledFindingBillableEvents # noqa: PLC0415
+ d = dict(src_dict)
+ issue_id = UUID(d.pop("issue_id"))
+
+
+
+
+ rule = d.pop("rule")
+
+ title = d.pop("title")
+
+ billable_events = LavaflowScanBilledFindingBillableEvents.from_dict(d.pop("billable_events"))
+
+
+
+
+ lavaflow_scan_billed_finding = cls(
+ issue_id=issue_id,
+ rule=rule,
+ title=title,
+ billable_events=billable_events,
+ )
+
+
+ lavaflow_scan_billed_finding.additional_properties = d
+ return lavaflow_scan_billed_finding
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_scan_billed_finding_billable_events.py b/src/volcano_sdk/_generated/models/lavaflow_scan_billed_finding_billable_events.py
new file mode 100644
index 00000000..179324d4
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_scan_billed_finding_billable_events.py
@@ -0,0 +1,67 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowScanBilledFindingBillableEvents")
+
+
+
+@_attrs_define
+class LavaflowScanBilledFindingBillableEvents:
+ """ How many billable events of each kind the finding's runs recorded, keyed by kind, such as `issue_diagnosed` and
+ `pull_request_opened`.
+
+ """
+
+ additional_properties: dict[str, int] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ lavaflow_scan_billed_finding_billable_events = cls(
+ )
+
+
+ lavaflow_scan_billed_finding_billable_events.additional_properties = d
+ return lavaflow_scan_billed_finding_billable_events
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> int:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: int) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_scan_counts.py b/src/volcano_sdk/_generated/models/lavaflow_scan_counts.py
new file mode 100644
index 00000000..677435e0
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_scan_counts.py
@@ -0,0 +1,118 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowScanCounts")
+
+
+
+@_attrs_define
+class LavaflowScanCounts:
+ """ What the scan did with the problems it found.
+
+ Attributes:
+ found (int): Candidates the scan found in the changed lines.
+ created (int): New issues the scan opened.
+ duplicate (int): Candidates that matched an issue the project already has, or a finding the scan already kept.
+ suppressed (int): Candidates a person had already turned down, by closing their pull request or ignoring their
+ issue.
+ capped (int): Confirmed findings past the plan's findings per scan, which no later scan reports again.
+ rejected (int): Candidates LavaFlow's second check didn't confirm, or that it couldn't report.
+ """
+
+ found: int
+ created: int
+ duplicate: int
+ suppressed: int
+ capped: int
+ rejected: int
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ found = self.found
+
+ created = self.created
+
+ duplicate = self.duplicate
+
+ suppressed = self.suppressed
+
+ capped = self.capped
+
+ rejected = self.rejected
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "found": found,
+ "created": created,
+ "duplicate": duplicate,
+ "suppressed": suppressed,
+ "capped": capped,
+ "rejected": rejected,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ found = d.pop("found")
+
+ created = d.pop("created")
+
+ duplicate = d.pop("duplicate")
+
+ suppressed = d.pop("suppressed")
+
+ capped = d.pop("capped")
+
+ rejected = d.pop("rejected")
+
+ lavaflow_scan_counts = cls(
+ found=found,
+ created=created,
+ duplicate=duplicate,
+ suppressed=suppressed,
+ capped=capped,
+ rejected=rejected,
+ )
+
+
+ lavaflow_scan_counts.additional_properties = d
+ return lavaflow_scan_counts
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_scan_resource.py b/src/volcano_sdk/_generated/models/lavaflow_scan_resource.py
new file mode 100644
index 00000000..0d950aa4
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_scan_resource.py
@@ -0,0 +1,106 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_scan_resource_resource_type import check_lavaflow_scan_resource_resource_type
+from ..models.lavaflow_scan_resource_resource_type import LavaflowScanResourceResourceType
+from typing import cast
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowScanResource")
+
+
+
+@_attrs_define
+class LavaflowScanResource:
+ """ A resource whose production deploy the scan covers. Only frontend deploys ask for a scan for now.
+
+ Attributes:
+ resource_type (LavaflowScanResourceResourceType):
+ resource_id (UUID):
+ deployment_id (UUID):
+ """
+
+ resource_type: LavaflowScanResourceResourceType
+ resource_id: UUID
+ deployment_id: UUID
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ resource_type: str = self.resource_type
+
+ resource_id = str(self.resource_id)
+
+ deployment_id = str(self.deployment_id)
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "resource_type": resource_type,
+ "resource_id": resource_id,
+ "deployment_id": deployment_id,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ resource_type = check_lavaflow_scan_resource_resource_type(d.pop("resource_type"))
+
+
+
+
+ resource_id = UUID(d.pop("resource_id"))
+
+
+
+
+ deployment_id = UUID(d.pop("deployment_id"))
+
+
+
+
+ lavaflow_scan_resource = cls(
+ resource_type=resource_type,
+ resource_id=resource_id,
+ deployment_id=deployment_id,
+ )
+
+
+ lavaflow_scan_resource.additional_properties = d
+ return lavaflow_scan_resource
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_scan_resource_resource_type.py b/src/volcano_sdk/_generated/models/lavaflow_scan_resource_resource_type.py
new file mode 100644
index 00000000..fb71bc16
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_scan_resource_resource_type.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowScanResourceResourceType = Literal['frontend', 'function']
+
+LAVAFLOW_SCAN_RESOURCE_RESOURCE_TYPE_VALUES: set[LavaflowScanResourceResourceType] = { 'frontend', 'function', }
+
+def check_lavaflow_scan_resource_resource_type(value: str) -> LavaflowScanResourceResourceType:
+ if value in LAVAFLOW_SCAN_RESOURCE_RESOURCE_TYPE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_SCAN_RESOURCE_RESOURCE_TYPE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_scan_source.py b/src/volcano_sdk/_generated/models/lavaflow_scan_source.py
new file mode 100644
index 00000000..7fd78a87
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_scan_source.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowScanSource = Literal['deployment']
+
+LAVAFLOW_SCAN_SOURCE_VALUES: set[LavaflowScanSource] = { 'deployment', }
+
+def check_lavaflow_scan_source(value: str) -> LavaflowScanSource:
+ if value in LAVAFLOW_SCAN_SOURCE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_SCAN_SOURCE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_scan_status.py b/src/volcano_sdk/_generated/models/lavaflow_scan_status.py
new file mode 100644
index 00000000..924ad7be
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_scan_status.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowScanStatus = Literal['cancelled', 'completed', 'failed', 'running', 'waiting']
+
+LAVAFLOW_SCAN_STATUS_VALUES: set[LavaflowScanStatus] = { 'cancelled', 'completed', 'failed', 'running', 'waiting', }
+
+def check_lavaflow_scan_status(value: str) -> LavaflowScanStatus:
+ if value in LAVAFLOW_SCAN_STATUS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_SCAN_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_settings.py b/src/volcano_sdk/_generated/models/lavaflow_settings.py
new file mode 100644
index 00000000..0103a3b8
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_settings.py
@@ -0,0 +1,324 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_autonomy import check_lavaflow_autonomy
+from ..models.lavaflow_autonomy import LavaflowAutonomy
+from ..models.lavaflow_skill_learning import check_lavaflow_skill_learning
+from ..models.lavaflow_skill_learning import LavaflowSkillLearning
+from typing import cast
+from uuid import UUID
+import datetime
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_code_quality_settings import LavaflowCodeQualitySettings
+ from ..models.lavaflow_failure import LavaflowFailure
+ from ..models.lavaflow_merge_policy import LavaflowMergePolicy
+ from ..models.project_git_connection_summary import ProjectGitConnectionSummary
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowSettings")
+
+
+
+@_attrs_define
+class LavaflowSettings:
+ """ A project's LavaFlow settings. LavaFlow sends this project's logs and source code to an AI service that Volcano
+ operates.
+
+ Attributes:
+ project_id (UUID): The project the settings belong to.
+ enabled (bool): Whether LavaFlow works on the project's issues. Off by default.
+ autonomy (LavaflowAutonomy): How far LavaFlow goes on its own. `diagnose_only` stops at a diagnosis. `open_pr`
+ also opens a pull request with a fix, and never merges it. `merge` also merges the fix once LavaFlow's reviewers
+ pass it, its required checks pass, and nothing holds it; a held fix is handed to you for good. LavaFlow merges
+ only into a base branch that requires at least one status check, through branch protection or a ruleset; on any
+ other branch it holds every fix with `no_required_checks`. Turning on merge lets LavaFlow's fixes, including
+ those from runs it starts on its own, run your CI with the secrets your pull request workflows get. Choosing
+ `merge` needs the project's `lavaflow.merge` capability.
+ merge_policy (LavaflowMergePolicy): Your rules for fixes LavaFlow must never merge. They apply with `autonomy:
+ merge`; at another autonomy they are saved and do nothing.
+ skill_learning (LavaflowSkillLearning): What LavaFlow will do with a skill it learns from a writer's correction
+ of one of its fixes, once learning ships in a later release. `auto`, the default, activates it at once. `review`
+ keeps it `proposed` until the owner activates it. `off` learns none and loads no project skill; the project's
+ skills stay readable and deletable. A writer of the repository can steer LavaFlow through what it learns,
+ outside the repository's history and branch protection, so a repository that protects its guidance, or relays CI
+ output through a bot account with write access, should use `review`. Turning learning up needs the project's
+ `lavaflow.skills` capability.
+ custom_context (str): Context about the project for LavaFlow's runs. Empty when unset. Saved, but runs do not
+ use it yet.
+ system_prompt (str): Instructions for LavaFlow's runs, to follow after LavaFlow's own, which take precedence.
+ Empty when unset. Saved, but runs do not use it yet.
+ code_quality (LavaflowCodeQualitySettings): LavaFlow Code Quality: whether LavaFlow reviews the code each
+ production deploy changes and opens pull requests that fix what it confirms.
+ allow_ungated_workflows (bool): Whether LavaFlow opens a fix's pull request even where a workflow could run it,
+ or put its text into a command, with the repository's secrets before a person approves it. Off by default; while
+ off, such a fix stays on its run and no pull request opens. Only the project's owner turns it on, signed in as a
+ person: with the platform token `volcano login` stores, or another platform token that expires. It applies to
+ the repository their GitHub account can push to. Connecting the project to another repository, or disconnecting
+ it, turns it off, and connecting the first one again doesn't turn it back on. Workflows in the repository may
+ then run LavaFlow's pull requests, or put their text into commands, with the repository's secrets before a
+ person reviews them. LavaFlow writes those changes from the project's error logs, which its users can influence.
+ Turn it on only if those workflows keep secrets away from untrusted code; gating them on a label a person adds
+ is safer.
+ updated_at (datetime.datetime | None): When the settings were last saved, or last changed by connecting a
+ repository. Null until they first are.
+ updated_by (None | str): The user ID of the person who made the last save; null when no person made it, such as
+ a project access token.
+ can_update (bool): Whether the caller can save the settings: true only for the project's owner with a platform
+ token while the owner's account is active; false for any project access token and for a read-only account.
+ repository (None | ProjectGitConnectionSummary): The GitHub repository the project is linked to, as `GET
+ /projects/{id}/git-connection` reports it. LavaFlow opens fix pull requests there, against `production_branch`.
+ Null when the project has none.
+ fix_blocker (LavaflowFailure | None): What in the project's repository setup stops LavaFlow from fixing issues
+ although it is on. Null when the repository setup doesn't, and while the project's `lavaflow` capability isn't
+ available; null doesn't mean nothing else stops LavaFlow. `message` is text to show as given.
+ `repository_required`: the project has no linked repository. With `autonomy` `open_pr` or `merge`, LavaFlow
+ diagnoses issues but fixes none; turned on for a repository the project no longer links, it starts no runs. Link
+ a repository with `PUT /projects/{id}/git-connection` or `volcano git connect `. Turned on with none,
+ LavaFlow fixes issues in the first one linked, unless `message` asks to turn it on again after the link; linking
+ the one it was turned on for resumes it. `repository_changed`: the project is linked to a repository LavaFlow
+ wasn't turned on for. LavaFlow starts no runs until the owner turns it on again, with `{"enabled": true}` or
+ `volcano cloud lavaflow enable`, which makes the linked repository the one it fixes. New codes may appear; show
+ the `message` of one you don't know.
+ """
+
+ project_id: UUID
+ enabled: bool
+ autonomy: LavaflowAutonomy
+ merge_policy: LavaflowMergePolicy
+ skill_learning: LavaflowSkillLearning
+ custom_context: str
+ system_prompt: str
+ code_quality: LavaflowCodeQualitySettings
+ allow_ungated_workflows: bool
+ updated_at: datetime.datetime | None
+ updated_by: None | str
+ can_update: bool
+ repository: None | ProjectGitConnectionSummary
+ fix_blocker: LavaflowFailure | None
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_code_quality_settings import LavaflowCodeQualitySettings # noqa: PLC0415
+ from ..models.lavaflow_failure import LavaflowFailure # noqa: PLC0415
+ from ..models.lavaflow_merge_policy import LavaflowMergePolicy # noqa: PLC0415
+ from ..models.project_git_connection_summary import ProjectGitConnectionSummary # noqa: PLC0415
+ project_id = str(self.project_id)
+
+ enabled = self.enabled
+
+ autonomy: str = self.autonomy
+
+ merge_policy = self.merge_policy.to_dict()
+
+ skill_learning: str = self.skill_learning
+
+ custom_context = self.custom_context
+
+ system_prompt = self.system_prompt
+
+ code_quality = self.code_quality.to_dict()
+
+ allow_ungated_workflows = self.allow_ungated_workflows
+
+ updated_at: None | str
+ if isinstance(self.updated_at, datetime.datetime):
+ updated_at = self.updated_at.isoformat()
+ else:
+ updated_at = self.updated_at
+
+ updated_by: None | str
+ updated_by = self.updated_by
+
+ can_update = self.can_update
+
+ repository: dict[str, Any] | None
+ if isinstance(self.repository, ProjectGitConnectionSummary):
+ repository = self.repository.to_dict()
+ else:
+ repository = self.repository
+
+ fix_blocker: dict[str, Any] | None
+ if isinstance(self.fix_blocker, LavaflowFailure):
+ fix_blocker = self.fix_blocker.to_dict()
+ else:
+ fix_blocker = self.fix_blocker
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "project_id": project_id,
+ "enabled": enabled,
+ "autonomy": autonomy,
+ "merge_policy": merge_policy,
+ "skill_learning": skill_learning,
+ "custom_context": custom_context,
+ "system_prompt": system_prompt,
+ "code_quality": code_quality,
+ "allow_ungated_workflows": allow_ungated_workflows,
+ "updated_at": updated_at,
+ "updated_by": updated_by,
+ "can_update": can_update,
+ "repository": repository,
+ "fix_blocker": fix_blocker,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_code_quality_settings import LavaflowCodeQualitySettings # noqa: PLC0415
+ from ..models.lavaflow_failure import LavaflowFailure # noqa: PLC0415
+ from ..models.lavaflow_merge_policy import LavaflowMergePolicy # noqa: PLC0415
+ from ..models.project_git_connection_summary import ProjectGitConnectionSummary # noqa: PLC0415
+ d = dict(src_dict)
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ enabled = d.pop("enabled")
+
+ autonomy = check_lavaflow_autonomy(d.pop("autonomy"))
+
+
+
+
+ merge_policy = LavaflowMergePolicy.from_dict(d.pop("merge_policy"))
+
+
+
+
+ skill_learning = check_lavaflow_skill_learning(d.pop("skill_learning"))
+
+
+
+
+ custom_context = d.pop("custom_context")
+
+ system_prompt = d.pop("system_prompt")
+
+ code_quality = LavaflowCodeQualitySettings.from_dict(d.pop("code_quality"))
+
+
+
+
+ allow_ungated_workflows = d.pop("allow_ungated_workflows")
+
+ def _parse_updated_at(data: object) -> datetime.datetime | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ updated_at_type_0 = datetime.datetime.fromisoformat(data)
+
+
+
+ return updated_at_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(datetime.datetime | None, data)
+
+ updated_at = _parse_updated_at(d.pop("updated_at"))
+
+
+ def _parse_updated_by(data: object) -> None | str:
+ if data is None:
+ return data
+ return cast(None | str, data)
+
+ updated_by = _parse_updated_by(d.pop("updated_by"))
+
+
+ can_update = d.pop("can_update")
+
+ def _parse_repository(data: object) -> None | ProjectGitConnectionSummary:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ repository_type_1 = ProjectGitConnectionSummary.from_dict(data)
+
+
+
+ return repository_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(None | ProjectGitConnectionSummary, data)
+
+ repository = _parse_repository(d.pop("repository"))
+
+
+ def _parse_fix_blocker(data: object) -> LavaflowFailure | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ fix_blocker_type_1 = LavaflowFailure.from_dict(data)
+
+
+
+ return fix_blocker_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowFailure | None, data)
+
+ fix_blocker = _parse_fix_blocker(d.pop("fix_blocker"))
+
+
+ lavaflow_settings = cls(
+ project_id=project_id,
+ enabled=enabled,
+ autonomy=autonomy,
+ merge_policy=merge_policy,
+ skill_learning=skill_learning,
+ custom_context=custom_context,
+ system_prompt=system_prompt,
+ code_quality=code_quality,
+ allow_ungated_workflows=allow_ungated_workflows,
+ updated_at=updated_at,
+ updated_by=updated_by,
+ can_update=can_update,
+ repository=repository,
+ fix_blocker=fix_blocker,
+ )
+
+
+ lavaflow_settings.additional_properties = d
+ return lavaflow_settings
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_settings_update.py b/src/volcano_sdk/_generated/models/lavaflow_settings_update.py
new file mode 100644
index 00000000..10cde11d
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_settings_update.py
@@ -0,0 +1,213 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_autonomy import check_lavaflow_autonomy
+from ..models.lavaflow_autonomy import LavaflowAutonomy
+from ..models.lavaflow_skill_learning import check_lavaflow_skill_learning
+from ..models.lavaflow_skill_learning import LavaflowSkillLearning
+from ..types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_code_quality_update import LavaflowCodeQualityUpdate
+ from ..models.lavaflow_merge_policy_update import LavaflowMergePolicyUpdate
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowSettingsUpdate")
+
+
+
+@_attrs_define
+class LavaflowSettingsUpdate:
+ """ The project, and at least one field to change. An omitted field keeps its saved value.
+
+ Attributes:
+ project_id (UUID): The project whose settings to change.
+ enabled (bool | Unset):
+ autonomy (LavaflowAutonomy | Unset): How far LavaFlow goes on its own. `diagnose_only` stops at a diagnosis.
+ `open_pr` also opens a pull request with a fix, and never merges it. `merge` also merges the fix once LavaFlow's
+ reviewers pass it, its required checks pass, and nothing holds it; a held fix is handed to you for good.
+ LavaFlow merges only into a base branch that requires at least one status check, through branch protection or a
+ ruleset; on any other branch it holds every fix with `no_required_checks`. Turning on merge lets LavaFlow's
+ fixes, including those from runs it starts on its own, run your CI with the secrets your pull request workflows
+ get. Choosing `merge` needs the project's `lavaflow.merge` capability.
+ merge_policy (LavaflowMergePolicyUpdate | Unset): The merge policy fields to change. An omitted field keeps its
+ saved value. Send `human_review_paths: []` to clear the paths.
+ skill_learning (LavaflowSkillLearning | Unset): What LavaFlow will do with a skill it learns from a writer's
+ correction of one of its fixes, once learning ships in a later release. `auto`, the default, activates it at
+ once. `review` keeps it `proposed` until the owner activates it. `off` learns none and loads no project skill;
+ the project's skills stay readable and deletable. A writer of the repository can steer LavaFlow through what it
+ learns, outside the repository's history and branch protection, so a repository that protects its guidance, or
+ relays CI output through a bot account with write access, should use `review`. Turning learning up needs the
+ project's `lavaflow.skills` capability.
+ custom_context (str | Unset):
+ system_prompt (str | Unset):
+ code_quality (LavaflowCodeQualityUpdate | Unset): Turns Code Quality on or off. Only the project's owner, signed
+ in, can turn it on; any credential that can save the settings can turn it off.
+ allow_ungated_workflows (bool | Unset): Turns on opening fixes past ungated workflows, for the repository the
+ project is connected to now; it applies only to that repository. Only the project's owner turns it on, signed in
+ as a person: with the platform token `volcano login` stores, or another platform token that expires. Their
+ GitHub account must be able to push to that repository. A project access token, a platform token that never
+ expires, or anyone else gets `403` with `person_required`. Any of the owner's credentials turns it off.
+ Workflows in the repository may then run LavaFlow's pull requests, or put their text into commands, with the
+ repository's secrets before a person reviews them. LavaFlow writes those changes from the project's error logs,
+ which its users can influence. Turn it on only if those workflows keep secrets away from untrusted code; gating
+ them on a label a person adds is safer. While LavaFlow is not available, only `false` is saved, and only with
+ `enabled: false`, `skill_learning: off` or both.
+ """
+
+ project_id: UUID
+ enabled: bool | Unset = UNSET
+ autonomy: LavaflowAutonomy | Unset = UNSET
+ merge_policy: LavaflowMergePolicyUpdate | Unset = UNSET
+ skill_learning: LavaflowSkillLearning | Unset = UNSET
+ custom_context: str | Unset = UNSET
+ system_prompt: str | Unset = UNSET
+ code_quality: LavaflowCodeQualityUpdate | Unset = UNSET
+ allow_ungated_workflows: bool | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_code_quality_update import LavaflowCodeQualityUpdate # noqa: PLC0415
+ from ..models.lavaflow_merge_policy_update import LavaflowMergePolicyUpdate # noqa: PLC0415
+ project_id = str(self.project_id)
+
+ enabled = self.enabled
+
+ autonomy: str | Unset = UNSET
+ if not isinstance(self.autonomy, Unset):
+ autonomy = self.autonomy
+
+
+ merge_policy: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.merge_policy, Unset):
+ merge_policy = self.merge_policy.to_dict()
+
+ skill_learning: str | Unset = UNSET
+ if not isinstance(self.skill_learning, Unset):
+ skill_learning = self.skill_learning
+
+
+ custom_context = self.custom_context
+
+ system_prompt = self.system_prompt
+
+ code_quality: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.code_quality, Unset):
+ code_quality = self.code_quality.to_dict()
+
+ allow_ungated_workflows = self.allow_ungated_workflows
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "project_id": project_id,
+ })
+ if enabled is not UNSET:
+ field_dict["enabled"] = enabled
+ if autonomy is not UNSET:
+ field_dict["autonomy"] = autonomy
+ if merge_policy is not UNSET:
+ field_dict["merge_policy"] = merge_policy
+ if skill_learning is not UNSET:
+ field_dict["skill_learning"] = skill_learning
+ if custom_context is not UNSET:
+ field_dict["custom_context"] = custom_context
+ if system_prompt is not UNSET:
+ field_dict["system_prompt"] = system_prompt
+ if code_quality is not UNSET:
+ field_dict["code_quality"] = code_quality
+ if allow_ungated_workflows is not UNSET:
+ field_dict["allow_ungated_workflows"] = allow_ungated_workflows
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_code_quality_update import LavaflowCodeQualityUpdate # noqa: PLC0415
+ from ..models.lavaflow_merge_policy_update import LavaflowMergePolicyUpdate # noqa: PLC0415
+ d = dict(src_dict)
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ enabled = d.pop("enabled", UNSET)
+
+ _autonomy = d.pop("autonomy", UNSET)
+ autonomy: LavaflowAutonomy | Unset
+ if isinstance(_autonomy, Unset):
+ autonomy = UNSET
+ else:
+ autonomy = check_lavaflow_autonomy(_autonomy)
+
+
+
+
+ _merge_policy = d.pop("merge_policy", UNSET)
+ merge_policy: LavaflowMergePolicyUpdate | Unset
+ if isinstance(_merge_policy, Unset):
+ merge_policy = UNSET
+ else:
+ merge_policy = LavaflowMergePolicyUpdate.from_dict(_merge_policy)
+
+
+
+
+ _skill_learning = d.pop("skill_learning", UNSET)
+ skill_learning: LavaflowSkillLearning | Unset
+ if isinstance(_skill_learning, Unset):
+ skill_learning = UNSET
+ else:
+ skill_learning = check_lavaflow_skill_learning(_skill_learning)
+
+
+
+
+ custom_context = d.pop("custom_context", UNSET)
+
+ system_prompt = d.pop("system_prompt", UNSET)
+
+ _code_quality = d.pop("code_quality", UNSET)
+ code_quality: LavaflowCodeQualityUpdate | Unset
+ if isinstance(_code_quality, Unset):
+ code_quality = UNSET
+ else:
+ code_quality = LavaflowCodeQualityUpdate.from_dict(_code_quality)
+
+
+
+
+ allow_ungated_workflows = d.pop("allow_ungated_workflows", UNSET)
+
+ lavaflow_settings_update = cls(
+ project_id=project_id,
+ enabled=enabled,
+ autonomy=autonomy,
+ merge_policy=merge_policy,
+ skill_learning=skill_learning,
+ custom_context=custom_context,
+ system_prompt=system_prompt,
+ code_quality=code_quality,
+ allow_ungated_workflows=allow_ungated_workflows,
+ )
+
+ return lavaflow_settings_update
+
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skill.py b/src/volcano_sdk/_generated/models/lavaflow_skill.py
new file mode 100644
index 00000000..ff7c83e6
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skill.py
@@ -0,0 +1,350 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_skill_retired_reason import check_lavaflow_skill_retired_reason
+from ..models.lavaflow_skill_retired_reason import LavaflowSkillRetiredReason
+from ..models.lavaflow_skill_scope import check_lavaflow_skill_scope
+from ..models.lavaflow_skill_scope import LavaflowSkillScope
+from ..models.lavaflow_skill_status import check_lavaflow_skill_status
+from ..models.lavaflow_skill_status import LavaflowSkillStatus
+from typing import cast
+from uuid import UUID
+import datetime
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_skill_applies_to import LavaflowSkillAppliesTo
+ from ..models.lavaflow_skill_citation import LavaflowSkillCitation
+ from ..models.lavaflow_skill_counts import LavaflowSkillCounts
+ from ..models.lavaflow_skill_source import LavaflowSkillSource
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowSkill")
+
+
+
+@_attrs_define
+class LavaflowSkill:
+ """ A project skill with its active version.
+
+ Attributes:
+ id (UUID):
+ project_id (UUID):
+ scope (LavaflowSkillScope): `project` skills belong to this project and never leave it. `volcano` skills are
+ written by Volcano for every project.
+ name (str): Unique in the project.
+ status (LavaflowSkillStatus): `proposed` waits for the owner to activate it. `active` is in force. `retired` is
+ set aside and can be restored.
+ retired_reason (LavaflowSkillRetiredReason | None): Why it retired, null unless `status` is `retired`.
+ version (int): The active version.
+ description (str): When the skill applies.
+ body (str): Markdown, at most 2 KiB.
+ applies_to (LavaflowSkillAppliesTo): Where a skill applies. Empty lists apply it to the whole project.
+ citations (list[LavaflowSkillCitation]):
+ content_sha256 (str): The hash of the active version's text, as a run records it.
+ source (LavaflowSkillSource): Where a version came from: a writer's act on a fix's pull request, or the owner's
+ edit.
+ counts (LavaflowSkillCounts):
+ last_used_at (datetime.datetime | None):
+ last_renewed_at (datetime.datetime): When the skill was created, or last renewed by the owner's edit, activation
+ or restore.
+ retired_at (datetime.datetime | None):
+ created_at (datetime.datetime):
+ updated_at (datetime.datetime):
+ """
+
+ id: UUID
+ project_id: UUID
+ scope: LavaflowSkillScope
+ name: str
+ status: LavaflowSkillStatus
+ retired_reason: LavaflowSkillRetiredReason | None
+ version: int
+ description: str
+ body: str
+ applies_to: LavaflowSkillAppliesTo
+ citations: list[LavaflowSkillCitation]
+ content_sha256: str
+ source: LavaflowSkillSource
+ counts: LavaflowSkillCounts
+ last_used_at: datetime.datetime | None
+ last_renewed_at: datetime.datetime
+ retired_at: datetime.datetime | None
+ created_at: datetime.datetime
+ updated_at: datetime.datetime
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_skill_applies_to import LavaflowSkillAppliesTo # noqa: PLC0415
+ from ..models.lavaflow_skill_citation import LavaflowSkillCitation # noqa: PLC0415
+ from ..models.lavaflow_skill_counts import LavaflowSkillCounts # noqa: PLC0415
+ from ..models.lavaflow_skill_source import LavaflowSkillSource # noqa: PLC0415
+ id = str(self.id)
+
+ project_id = str(self.project_id)
+
+ scope: str = self.scope
+
+ name = self.name
+
+ status: str = self.status
+
+ retired_reason: None | str
+ if isinstance(self.retired_reason, str):
+ retired_reason = self.retired_reason
+ else:
+ retired_reason = self.retired_reason
+
+ version = self.version
+
+ description = self.description
+
+ body = self.body
+
+ applies_to = self.applies_to.to_dict()
+
+ citations = []
+ for citations_item_data in self.citations:
+ citations_item = citations_item_data.to_dict()
+ citations.append(citations_item)
+
+
+
+ content_sha256 = self.content_sha256
+
+ source = self.source.to_dict()
+
+ counts = self.counts.to_dict()
+
+ last_used_at: None | str
+ if isinstance(self.last_used_at, datetime.datetime):
+ last_used_at = self.last_used_at.isoformat()
+ else:
+ last_used_at = self.last_used_at
+
+ last_renewed_at = self.last_renewed_at.isoformat()
+
+ retired_at: None | str
+ if isinstance(self.retired_at, datetime.datetime):
+ retired_at = self.retired_at.isoformat()
+ else:
+ retired_at = self.retired_at
+
+ created_at = self.created_at.isoformat()
+
+ updated_at = self.updated_at.isoformat()
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "project_id": project_id,
+ "scope": scope,
+ "name": name,
+ "status": status,
+ "retired_reason": retired_reason,
+ "version": version,
+ "description": description,
+ "body": body,
+ "applies_to": applies_to,
+ "citations": citations,
+ "content_sha256": content_sha256,
+ "source": source,
+ "counts": counts,
+ "last_used_at": last_used_at,
+ "last_renewed_at": last_renewed_at,
+ "retired_at": retired_at,
+ "created_at": created_at,
+ "updated_at": updated_at,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_skill_applies_to import LavaflowSkillAppliesTo # noqa: PLC0415
+ from ..models.lavaflow_skill_citation import LavaflowSkillCitation # noqa: PLC0415
+ from ..models.lavaflow_skill_counts import LavaflowSkillCounts # noqa: PLC0415
+ from ..models.lavaflow_skill_source import LavaflowSkillSource # noqa: PLC0415
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ scope = check_lavaflow_skill_scope(d.pop("scope"))
+
+
+
+
+ name = d.pop("name")
+
+ status = check_lavaflow_skill_status(d.pop("status"))
+
+
+
+
+ def _parse_retired_reason(data: object) -> LavaflowSkillRetiredReason | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ retired_reason_type_1 = check_lavaflow_skill_retired_reason(data)
+
+
+
+ return retired_reason_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowSkillRetiredReason | None, data)
+
+ retired_reason = _parse_retired_reason(d.pop("retired_reason"))
+
+
+ version = d.pop("version")
+
+ description = d.pop("description")
+
+ body = d.pop("body")
+
+ applies_to = LavaflowSkillAppliesTo.from_dict(d.pop("applies_to"))
+
+
+
+
+ citations = []
+ _citations = d.pop("citations")
+ for citations_item_data in (_citations):
+ citations_item = LavaflowSkillCitation.from_dict(citations_item_data)
+
+
+
+ citations.append(citations_item)
+
+
+ content_sha256 = d.pop("content_sha256")
+
+ source = LavaflowSkillSource.from_dict(d.pop("source"))
+
+
+
+
+ counts = LavaflowSkillCounts.from_dict(d.pop("counts"))
+
+
+
+
+ def _parse_last_used_at(data: object) -> datetime.datetime | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ last_used_at_type_0 = datetime.datetime.fromisoformat(data)
+
+
+
+ return last_used_at_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(datetime.datetime | None, data)
+
+ last_used_at = _parse_last_used_at(d.pop("last_used_at"))
+
+
+ last_renewed_at = datetime.datetime.fromisoformat(d.pop("last_renewed_at"))
+
+
+
+
+ def _parse_retired_at(data: object) -> datetime.datetime | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ retired_at_type_0 = datetime.datetime.fromisoformat(data)
+
+
+
+ return retired_at_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(datetime.datetime | None, data)
+
+ retired_at = _parse_retired_at(d.pop("retired_at"))
+
+
+ created_at = datetime.datetime.fromisoformat(d.pop("created_at"))
+
+
+
+
+ updated_at = datetime.datetime.fromisoformat(d.pop("updated_at"))
+
+
+
+
+ lavaflow_skill = cls(
+ id=id,
+ project_id=project_id,
+ scope=scope,
+ name=name,
+ status=status,
+ retired_reason=retired_reason,
+ version=version,
+ description=description,
+ body=body,
+ applies_to=applies_to,
+ citations=citations,
+ content_sha256=content_sha256,
+ source=source,
+ counts=counts,
+ last_used_at=last_used_at,
+ last_renewed_at=last_renewed_at,
+ retired_at=retired_at,
+ created_at=created_at,
+ updated_at=updated_at,
+ )
+
+
+ lavaflow_skill.additional_properties = d
+ return lavaflow_skill
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skill_applies_to.py b/src/volcano_sdk/_generated/models/lavaflow_skill_applies_to.py
new file mode 100644
index 00000000..1c8a226b
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skill_applies_to.py
@@ -0,0 +1,103 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowSkillAppliesTo")
+
+
+
+@_attrs_define
+class LavaflowSkillAppliesTo:
+ """ Where a skill applies. Empty lists apply it to the whole project.
+
+ Attributes:
+ resource_ids (list[UUID]): Functions, durable functions and frontends it applies to.
+ paths (list[str]): Repository path globs it applies to, relative to the repository root.
+ """
+
+ resource_ids: list[UUID]
+ paths: list[str]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ resource_ids = []
+ for resource_ids_item_data in self.resource_ids:
+ resource_ids_item = str(resource_ids_item_data)
+ resource_ids.append(resource_ids_item)
+
+
+
+ paths = self.paths
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "resource_ids": resource_ids,
+ "paths": paths,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ resource_ids = []
+ _resource_ids = d.pop("resource_ids")
+ for resource_ids_item_data in (_resource_ids):
+ resource_ids_item = UUID(resource_ids_item_data)
+
+
+
+ resource_ids.append(resource_ids_item)
+
+
+ paths = cast(list[str], d.pop("paths"))
+
+
+ lavaflow_skill_applies_to = cls(
+ resource_ids=resource_ids,
+ paths=paths,
+ )
+
+
+ lavaflow_skill_applies_to.additional_properties = d
+ return lavaflow_skill_applies_to
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skill_applies_to_update.py b/src/volcano_sdk/_generated/models/lavaflow_skill_applies_to_update.py
new file mode 100644
index 00000000..ab94c49b
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skill_applies_to_update.py
@@ -0,0 +1,95 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowSkillAppliesToUpdate")
+
+
+
+@_attrs_define
+class LavaflowSkillAppliesToUpdate:
+ """ The members of `applies_to` to change. An omitted member keeps its value, and a list you send replaces it, so `[]`
+ clears it.
+
+ Attributes:
+ resource_ids (list[UUID] | Unset): Functions, durable functions and frontends it applies to.
+ paths (list[str] | Unset): Repository path globs it applies to, relative to the repository root.
+ """
+
+ resource_ids: list[UUID] | Unset = UNSET
+ paths: list[str] | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ resource_ids: list[str] | Unset = UNSET
+ if not isinstance(self.resource_ids, Unset):
+ resource_ids = []
+ for resource_ids_item_data in self.resource_ids:
+ resource_ids_item = str(resource_ids_item_data)
+ resource_ids.append(resource_ids_item)
+
+
+
+ paths: list[str] | Unset = UNSET
+ if not isinstance(self.paths, Unset):
+ paths = self.paths
+
+
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ })
+ if resource_ids is not UNSET:
+ field_dict["resource_ids"] = resource_ids
+ if paths is not UNSET:
+ field_dict["paths"] = paths
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ _resource_ids = d.pop("resource_ids", UNSET)
+ resource_ids: list[UUID] | Unset = UNSET
+ if _resource_ids is not UNSET:
+ resource_ids = []
+ for resource_ids_item_data in _resource_ids:
+ resource_ids_item = UUID(resource_ids_item_data)
+
+
+
+ resource_ids.append(resource_ids_item)
+
+
+ paths = cast(list[str], d.pop("paths", UNSET))
+
+
+ lavaflow_skill_applies_to_update = cls(
+ resource_ids=resource_ids,
+ paths=paths,
+ )
+
+ return lavaflow_skill_applies_to_update
+
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skill_citation.py b/src/volcano_sdk/_generated/models/lavaflow_skill_citation.py
new file mode 100644
index 00000000..ad46252c
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skill_citation.py
@@ -0,0 +1,85 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowSkillCitation")
+
+
+
+@_attrs_define
+class LavaflowSkillCitation:
+ """ Repository code a skill rests on: a path and a string the file holds.
+
+ Attributes:
+ path (str):
+ anchor (str):
+ """
+
+ path: str
+ anchor: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ path = self.path
+
+ anchor = self.anchor
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "path": path,
+ "anchor": anchor,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ path = d.pop("path")
+
+ anchor = d.pop("anchor")
+
+ lavaflow_skill_citation = cls(
+ path=path,
+ anchor=anchor,
+ )
+
+
+ lavaflow_skill_citation.additional_properties = d
+ return lavaflow_skill_citation
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skill_counts.py b/src/volcano_sdk/_generated/models/lavaflow_skill_counts.py
new file mode 100644
index 00000000..73c72037
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skill_counts.py
@@ -0,0 +1,92 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowSkillCounts")
+
+
+
+@_attrs_define
+class LavaflowSkillCounts:
+ """
+ Attributes:
+ helpful (int): Fixes that used the skill and merged as LavaFlow left them.
+ harmful (int): Fixes that used the skill and a writer corrected or closed, or whose issue came back.
+ used (int): Runs that loaded the skill's body.
+ """
+
+ helpful: int
+ harmful: int
+ used: int
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ helpful = self.helpful
+
+ harmful = self.harmful
+
+ used = self.used
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "helpful": helpful,
+ "harmful": harmful,
+ "used": used,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ helpful = d.pop("helpful")
+
+ harmful = d.pop("harmful")
+
+ used = d.pop("used")
+
+ lavaflow_skill_counts = cls(
+ helpful=helpful,
+ harmful=harmful,
+ used=used,
+ )
+
+
+ lavaflow_skill_counts.additional_properties = d
+ return lavaflow_skill_counts
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skill_error.py b/src/volcano_sdk/_generated/models/lavaflow_skill_error.py
new file mode 100644
index 00000000..45047991
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skill_error.py
@@ -0,0 +1,118 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_skill_error_rules_item import check_lavaflow_skill_error_rules_item
+from ..models.lavaflow_skill_error_rules_item import LavaflowSkillErrorRulesItem
+from ..types import UNSET, Unset
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowSkillError")
+
+
+
+@_attrs_define
+class LavaflowSkillError:
+ """ An error, with the rules a refused skill failed.
+
+ Attributes:
+ error (str):
+ code (str | Unset): `skill_refused` means the skill check refused the text. `feature_unavailable` means the
+ change needs the project's `lavaflow.skills` capability.
+ rules (list[LavaflowSkillErrorRulesItem] | Unset): With `skill_refused`, the rules the text failed. The answer
+ never repeats the text.
+ """
+
+ error: str
+ code: str | Unset = UNSET
+ rules: list[LavaflowSkillErrorRulesItem] | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ error = self.error
+
+ code = self.code
+
+ rules: list[str] | Unset = UNSET
+ if not isinstance(self.rules, Unset):
+ rules = []
+ for rules_item_data in self.rules:
+ rules_item: str = rules_item_data
+ rules.append(rules_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "error": error,
+ })
+ if code is not UNSET:
+ field_dict["code"] = code
+ if rules is not UNSET:
+ field_dict["rules"] = rules
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ error = d.pop("error")
+
+ code = d.pop("code", UNSET)
+
+ _rules = d.pop("rules", UNSET)
+ rules: list[LavaflowSkillErrorRulesItem] | Unset = UNSET
+ if _rules is not UNSET:
+ rules = []
+ for rules_item_data in _rules:
+ rules_item = check_lavaflow_skill_error_rules_item(rules_item_data)
+
+
+
+ rules.append(rules_item)
+
+
+ lavaflow_skill_error = cls(
+ error=error,
+ code=code,
+ rules=rules,
+ )
+
+
+ lavaflow_skill_error.additional_properties = d
+ return lavaflow_skill_error
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skill_error_rules_item.py b/src/volcano_sdk/_generated/models/lavaflow_skill_error_rules_item.py
new file mode 100644
index 00000000..22ed6150
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skill_error_rules_item.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowSkillErrorRulesItem = Literal['characters', 'credential', 'credential_scan', 'directive', 'email', 'link', 'policy', 'read_value', 'sanitizer', 'secret', 'shape']
+
+LAVAFLOW_SKILL_ERROR_RULES_ITEM_VALUES: set[LavaflowSkillErrorRulesItem] = { 'characters', 'credential', 'credential_scan', 'directive', 'email', 'link', 'policy', 'read_value', 'sanitizer', 'secret', 'shape', }
+
+def check_lavaflow_skill_error_rules_item(value: str) -> LavaflowSkillErrorRulesItem:
+ if value in LAVAFLOW_SKILL_ERROR_RULES_ITEM_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_SKILL_ERROR_RULES_ITEM_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skill_learning.py b/src/volcano_sdk/_generated/models/lavaflow_skill_learning.py
new file mode 100644
index 00000000..bb09a78d
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skill_learning.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowSkillLearning = Literal['auto', 'off', 'review']
+
+LAVAFLOW_SKILL_LEARNING_VALUES: set[LavaflowSkillLearning] = { 'auto', 'off', 'review', }
+
+def check_lavaflow_skill_learning(value: str) -> LavaflowSkillLearning:
+ if value in LAVAFLOW_SKILL_LEARNING_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_SKILL_LEARNING_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skill_list.py b/src/volcano_sdk/_generated/models/lavaflow_skill_list.py
new file mode 100644
index 00000000..9b782e3a
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skill_list.py
@@ -0,0 +1,94 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_skill import LavaflowSkill
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowSkillList")
+
+
+
+@_attrs_define
+class LavaflowSkillList:
+ """
+ Attributes:
+ data (list[LavaflowSkill]):
+ """
+
+ data: list[LavaflowSkill]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_skill import LavaflowSkill # noqa: PLC0415
+ data = []
+ for data_item_data in self.data:
+ data_item = data_item_data.to_dict()
+ data.append(data_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "data": data,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_skill import LavaflowSkill # noqa: PLC0415
+ d = dict(src_dict)
+ data = []
+ _data = d.pop("data")
+ for data_item_data in (_data):
+ data_item = LavaflowSkill.from_dict(data_item_data)
+
+
+
+ data.append(data_item)
+
+
+ lavaflow_skill_list = cls(
+ data=data,
+ )
+
+
+ lavaflow_skill_list.additional_properties = d
+ return lavaflow_skill_list
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skill_retired_reason.py b/src/volcano_sdk/_generated/models/lavaflow_skill_retired_reason.py
new file mode 100644
index 00000000..169dea80
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skill_retired_reason.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowSkillRetiredReason = Literal['gate', 'harmful', 'owner', 'repository_changed', 'stale', 'unused']
+
+LAVAFLOW_SKILL_RETIRED_REASON_VALUES: set[LavaflowSkillRetiredReason] = { 'gate', 'harmful', 'owner', 'repository_changed', 'stale', 'unused', }
+
+def check_lavaflow_skill_retired_reason(value: str) -> LavaflowSkillRetiredReason:
+ if value in LAVAFLOW_SKILL_RETIRED_REASON_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_SKILL_RETIRED_REASON_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skill_scope.py b/src/volcano_sdk/_generated/models/lavaflow_skill_scope.py
new file mode 100644
index 00000000..27d88d0f
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skill_scope.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowSkillScope = Literal['project', 'volcano']
+
+LAVAFLOW_SKILL_SCOPE_VALUES: set[LavaflowSkillScope] = { 'project', 'volcano', }
+
+def check_lavaflow_skill_scope(value: str) -> LavaflowSkillScope:
+ if value in LAVAFLOW_SKILL_SCOPE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_SKILL_SCOPE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skill_source.py b/src/volcano_sdk/_generated/models/lavaflow_skill_source.py
new file mode 100644
index 00000000..289e9997
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skill_source.py
@@ -0,0 +1,155 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_skill_source_act import check_lavaflow_skill_source_act
+from ..models.lavaflow_skill_source_act import LavaflowSkillSourceAct
+from ..models.lavaflow_skill_source_kind import check_lavaflow_skill_source_kind
+from ..models.lavaflow_skill_source_kind import LavaflowSkillSourceKind
+from typing import cast
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowSkillSource")
+
+
+
+@_attrs_define
+class LavaflowSkillSource:
+ """ Where a version came from: a writer's act on a fix's pull request, or the owner's edit.
+
+ Attributes:
+ kind (LavaflowSkillSourceKind):
+ run_id (None | UUID): The run whose pull request taught it, for `run`.
+ pull_request (int | None): That run's pull request number.
+ act (LavaflowSkillSourceAct): The writer's act it came from, for `run`.
+ user_id (None | str): The person who edited it, for `person`.
+ """
+
+ kind: LavaflowSkillSourceKind
+ run_id: None | UUID
+ pull_request: int | None
+ act: LavaflowSkillSourceAct
+ user_id: None | str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ kind: str = self.kind
+
+ run_id: None | str
+ if isinstance(self.run_id, UUID):
+ run_id = str(self.run_id)
+ else:
+ run_id = self.run_id
+
+ pull_request: int | None
+ pull_request = self.pull_request
+
+ act: str = self.act
+
+ user_id: None | str
+ user_id = self.user_id
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "kind": kind,
+ "run_id": run_id,
+ "pull_request": pull_request,
+ "act": act,
+ "user_id": user_id,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ kind = check_lavaflow_skill_source_kind(d.pop("kind"))
+
+
+
+
+ def _parse_run_id(data: object) -> None | UUID:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ run_id_type_0 = UUID(data)
+
+
+
+ return run_id_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(None | UUID, data)
+
+ run_id = _parse_run_id(d.pop("run_id"))
+
+
+ def _parse_pull_request(data: object) -> int | None:
+ if data is None:
+ return data
+ return cast(int | None, data)
+
+ pull_request = _parse_pull_request(d.pop("pull_request"))
+
+
+ act = check_lavaflow_skill_source_act(d.pop("act"))
+
+
+
+
+ def _parse_user_id(data: object) -> None | str:
+ if data is None:
+ return data
+ return cast(None | str, data)
+
+ user_id = _parse_user_id(d.pop("user_id"))
+
+
+ lavaflow_skill_source = cls(
+ kind=kind,
+ run_id=run_id,
+ pull_request=pull_request,
+ act=act,
+ user_id=user_id,
+ )
+
+
+ lavaflow_skill_source.additional_properties = d
+ return lavaflow_skill_source
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skill_source_act.py b/src/volcano_sdk/_generated/models/lavaflow_skill_source_act.py
new file mode 100644
index 00000000..3247f9db
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skill_source_act.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowSkillSourceAct = Literal['comment', 'commit', 'review']
+
+LAVAFLOW_SKILL_SOURCE_ACT_VALUES: set[LavaflowSkillSourceAct] = { 'comment', 'commit', 'review', }
+
+def check_lavaflow_skill_source_act(value: str) -> LavaflowSkillSourceAct:
+ if value in LAVAFLOW_SKILL_SOURCE_ACT_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_SKILL_SOURCE_ACT_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skill_source_kind.py b/src/volcano_sdk/_generated/models/lavaflow_skill_source_kind.py
new file mode 100644
index 00000000..ee7766ec
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skill_source_kind.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowSkillSourceKind = Literal['person', 'run']
+
+LAVAFLOW_SKILL_SOURCE_KIND_VALUES: set[LavaflowSkillSourceKind] = { 'person', 'run', }
+
+def check_lavaflow_skill_source_kind(value: str) -> LavaflowSkillSourceKind:
+ if value in LAVAFLOW_SKILL_SOURCE_KIND_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_SKILL_SOURCE_KIND_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skill_status.py b/src/volcano_sdk/_generated/models/lavaflow_skill_status.py
new file mode 100644
index 00000000..3c307347
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skill_status.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowSkillStatus = Literal['active', 'proposed', 'retired']
+
+LAVAFLOW_SKILL_STATUS_VALUES: set[LavaflowSkillStatus] = { 'active', 'proposed', 'retired', }
+
+def check_lavaflow_skill_status(value: str) -> LavaflowSkillStatus:
+ if value in LAVAFLOW_SKILL_STATUS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_SKILL_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skill_update.py b/src/volcano_sdk/_generated/models/lavaflow_skill_update.py
new file mode 100644
index 00000000..51dd0576
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skill_update.py
@@ -0,0 +1,118 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_skill_update_status import check_lavaflow_skill_update_status
+from ..models.lavaflow_skill_update_status import LavaflowSkillUpdateStatus
+from ..types import UNSET, Unset
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_skill_applies_to_update import LavaflowSkillAppliesToUpdate
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowSkillUpdate")
+
+
+
+@_attrs_define
+class LavaflowSkillUpdate:
+ """ The fields to change. An omitted field keeps its value.
+
+ Attributes:
+ description (str | Unset):
+ body (str | Unset):
+ applies_to (LavaflowSkillAppliesToUpdate | Unset): The members of `applies_to` to change. An omitted member
+ keeps its value, and a list you send replaces it, so `[]` clears it.
+ status (LavaflowSkillUpdateStatus | Unset): `active` activates a proposed skill or restores a retired one.
+ `retired` retires it.
+ """
+
+ description: str | Unset = UNSET
+ body: str | Unset = UNSET
+ applies_to: LavaflowSkillAppliesToUpdate | Unset = UNSET
+ status: LavaflowSkillUpdateStatus | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_skill_applies_to_update import LavaflowSkillAppliesToUpdate # noqa: PLC0415
+ description = self.description
+
+ body = self.body
+
+ applies_to: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.applies_to, Unset):
+ applies_to = self.applies_to.to_dict()
+
+ status: str | Unset = UNSET
+ if not isinstance(self.status, Unset):
+ status = self.status
+
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ })
+ if description is not UNSET:
+ field_dict["description"] = description
+ if body is not UNSET:
+ field_dict["body"] = body
+ if applies_to is not UNSET:
+ field_dict["applies_to"] = applies_to
+ if status is not UNSET:
+ field_dict["status"] = status
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_skill_applies_to_update import LavaflowSkillAppliesToUpdate # noqa: PLC0415
+ d = dict(src_dict)
+ description = d.pop("description", UNSET)
+
+ body = d.pop("body", UNSET)
+
+ _applies_to = d.pop("applies_to", UNSET)
+ applies_to: LavaflowSkillAppliesToUpdate | Unset
+ if isinstance(_applies_to, Unset):
+ applies_to = UNSET
+ else:
+ applies_to = LavaflowSkillAppliesToUpdate.from_dict(_applies_to)
+
+
+
+
+ _status = d.pop("status", UNSET)
+ status: LavaflowSkillUpdateStatus | Unset
+ if isinstance(_status, Unset):
+ status = UNSET
+ else:
+ status = check_lavaflow_skill_update_status(_status)
+
+
+
+
+ lavaflow_skill_update = cls(
+ description=description,
+ body=body,
+ applies_to=applies_to,
+ status=status,
+ )
+
+ return lavaflow_skill_update
+
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skill_update_status.py b/src/volcano_sdk/_generated/models/lavaflow_skill_update_status.py
new file mode 100644
index 00000000..eb0632fd
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skill_update_status.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowSkillUpdateStatus = Literal['active', 'retired']
+
+LAVAFLOW_SKILL_UPDATE_STATUS_VALUES: set[LavaflowSkillUpdateStatus] = { 'active', 'retired', }
+
+def check_lavaflow_skill_update_status(value: str) -> LavaflowSkillUpdateStatus:
+ if value in LAVAFLOW_SKILL_UPDATE_STATUS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_SKILL_UPDATE_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skill_version.py b/src/volcano_sdk/_generated/models/lavaflow_skill_version.py
new file mode 100644
index 00000000..a940aeda
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skill_version.py
@@ -0,0 +1,190 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+from uuid import UUID
+import datetime
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_skill_applies_to import LavaflowSkillAppliesTo
+ from ..models.lavaflow_skill_citation import LavaflowSkillCitation
+ from ..models.lavaflow_skill_source import LavaflowSkillSource
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowSkillVersion")
+
+
+
+@_attrs_define
+class LavaflowSkillVersion:
+ """
+ Attributes:
+ skill_id (UUID):
+ project_id (UUID):
+ version (int):
+ description (str):
+ body (str):
+ applies_to (LavaflowSkillAppliesTo): Where a skill applies. Empty lists apply it to the whole project.
+ citations (list[LavaflowSkillCitation]):
+ content_sha256 (str):
+ source (LavaflowSkillSource): Where a version came from: a writer's act on a fix's pull request, or the owner's
+ edit.
+ created_at (datetime.datetime):
+ """
+
+ skill_id: UUID
+ project_id: UUID
+ version: int
+ description: str
+ body: str
+ applies_to: LavaflowSkillAppliesTo
+ citations: list[LavaflowSkillCitation]
+ content_sha256: str
+ source: LavaflowSkillSource
+ created_at: datetime.datetime
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_skill_applies_to import LavaflowSkillAppliesTo # noqa: PLC0415
+ from ..models.lavaflow_skill_citation import LavaflowSkillCitation # noqa: PLC0415
+ from ..models.lavaflow_skill_source import LavaflowSkillSource # noqa: PLC0415
+ skill_id = str(self.skill_id)
+
+ project_id = str(self.project_id)
+
+ version = self.version
+
+ description = self.description
+
+ body = self.body
+
+ applies_to = self.applies_to.to_dict()
+
+ citations = []
+ for citations_item_data in self.citations:
+ citations_item = citations_item_data.to_dict()
+ citations.append(citations_item)
+
+
+
+ content_sha256 = self.content_sha256
+
+ source = self.source.to_dict()
+
+ created_at = self.created_at.isoformat()
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "skill_id": skill_id,
+ "project_id": project_id,
+ "version": version,
+ "description": description,
+ "body": body,
+ "applies_to": applies_to,
+ "citations": citations,
+ "content_sha256": content_sha256,
+ "source": source,
+ "created_at": created_at,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_skill_applies_to import LavaflowSkillAppliesTo # noqa: PLC0415
+ from ..models.lavaflow_skill_citation import LavaflowSkillCitation # noqa: PLC0415
+ from ..models.lavaflow_skill_source import LavaflowSkillSource # noqa: PLC0415
+ d = dict(src_dict)
+ skill_id = UUID(d.pop("skill_id"))
+
+
+
+
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ version = d.pop("version")
+
+ description = d.pop("description")
+
+ body = d.pop("body")
+
+ applies_to = LavaflowSkillAppliesTo.from_dict(d.pop("applies_to"))
+
+
+
+
+ citations = []
+ _citations = d.pop("citations")
+ for citations_item_data in (_citations):
+ citations_item = LavaflowSkillCitation.from_dict(citations_item_data)
+
+
+
+ citations.append(citations_item)
+
+
+ content_sha256 = d.pop("content_sha256")
+
+ source = LavaflowSkillSource.from_dict(d.pop("source"))
+
+
+
+
+ created_at = datetime.datetime.fromisoformat(d.pop("created_at"))
+
+
+
+
+ lavaflow_skill_version = cls(
+ skill_id=skill_id,
+ project_id=project_id,
+ version=version,
+ description=description,
+ body=body,
+ applies_to=applies_to,
+ citations=citations,
+ content_sha256=content_sha256,
+ source=source,
+ created_at=created_at,
+ )
+
+
+ lavaflow_skill_version.additional_properties = d
+ return lavaflow_skill_version
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skill_version_list.py b/src/volcano_sdk/_generated/models/lavaflow_skill_version_list.py
new file mode 100644
index 00000000..abfa1b6d
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skill_version_list.py
@@ -0,0 +1,94 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_skill_version import LavaflowSkillVersion
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowSkillVersionList")
+
+
+
+@_attrs_define
+class LavaflowSkillVersionList:
+ """
+ Attributes:
+ data (list[LavaflowSkillVersion]):
+ """
+
+ data: list[LavaflowSkillVersion]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_skill_version import LavaflowSkillVersion # noqa: PLC0415
+ data = []
+ for data_item_data in self.data:
+ data_item = data_item_data.to_dict()
+ data.append(data_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "data": data,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_skill_version import LavaflowSkillVersion # noqa: PLC0415
+ d = dict(src_dict)
+ data = []
+ _data = d.pop("data")
+ for data_item_data in (_data):
+ data_item = LavaflowSkillVersion.from_dict(data_item_data)
+
+
+
+ data.append(data_item)
+
+
+ lavaflow_skill_version_list = cls(
+ data=data,
+ )
+
+
+ lavaflow_skill_version_list.additional_properties = d
+ return lavaflow_skill_version_list
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_skip_reason.py b/src/volcano_sdk/_generated/models/lavaflow_skip_reason.py
new file mode 100644
index 00000000..02d31731
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_skip_reason.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowSkipReason = Literal['convention_unsatisfiable', 'diagnose_only', 'duplicate_in_repository', 'lineage_cap', 'lineage_held', 'low_confidence', 'no_patch', 'not_fixable', 'permission_missing', 'possible_credential', 'possible_personal_data', 'publish_failed', 'pull_request_open', 'repository_changed', 'review_unresolved', 'security_finding', 'source_unavailable', 'ungated_workflows']
+
+LAVAFLOW_SKIP_REASON_VALUES: set[LavaflowSkipReason] = { 'convention_unsatisfiable', 'diagnose_only', 'duplicate_in_repository', 'lineage_cap', 'lineage_held', 'low_confidence', 'no_patch', 'not_fixable', 'permission_missing', 'possible_credential', 'possible_personal_data', 'publish_failed', 'pull_request_open', 'repository_changed', 'review_unresolved', 'security_finding', 'source_unavailable', 'ungated_workflows', }
+
+def check_lavaflow_skip_reason(value: str) -> LavaflowSkipReason:
+ if value in LAVAFLOW_SKIP_REASON_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_SKIP_REASON_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_slack_binding.py b/src/volcano_sdk/_generated/models/lavaflow_slack_binding.py
new file mode 100644
index 00000000..8f036118
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_slack_binding.py
@@ -0,0 +1,93 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowSlackBinding")
+
+
+
+@_attrs_define
+class LavaflowSlackBinding:
+ """ The Slack channel a binding reports from. Present when `connector_type` is `slack`.
+
+ Attributes:
+ team_id (str): A Slack workspace ID, such as `T0123ABCD`.
+ team_name (str): The workspace's name, or empty while the Volcano app is not installed in it.
+ channel_id (str): A Slack channel ID, such as `C0123ABCD`.
+ """
+
+ team_id: str
+ team_name: str
+ channel_id: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ team_id = self.team_id
+
+ team_name = self.team_name
+
+ channel_id = self.channel_id
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "team_id": team_id,
+ "team_name": team_name,
+ "channel_id": channel_id,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ team_id = d.pop("team_id")
+
+ team_name = d.pop("team_name")
+
+ channel_id = d.pop("channel_id")
+
+ lavaflow_slack_binding = cls(
+ team_id=team_id,
+ team_name=team_name,
+ channel_id=channel_id,
+ )
+
+
+ lavaflow_slack_binding.additional_properties = d
+ return lavaflow_slack_binding
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_slack_binding_target.py b/src/volcano_sdk/_generated/models/lavaflow_slack_binding_target.py
new file mode 100644
index 00000000..a405a85f
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_slack_binding_target.py
@@ -0,0 +1,59 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowSlackBindingTarget")
+
+
+
+@_attrs_define
+class LavaflowSlackBindingTarget:
+ """ The channel to bind, for a `slack` connector.
+
+ Attributes:
+ channel_id (str): A Slack channel ID, such as `C0123ABCD`.
+ """
+
+ channel_id: str
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ channel_id = self.channel_id
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "channel_id": channel_id,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ channel_id = d.pop("channel_id")
+
+ lavaflow_slack_binding_target = cls(
+ channel_id=channel_id,
+ )
+
+ return lavaflow_slack_binding_target
+
diff --git a/src/volcano_sdk/_generated/models/lavaflow_source_commit.py b/src/volcano_sdk/_generated/models/lavaflow_source_commit.py
new file mode 100644
index 00000000..6d8a98f1
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_source_commit.py
@@ -0,0 +1,109 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_commit_origin import check_lavaflow_commit_origin
+from ..models.lavaflow_commit_origin import LavaflowCommitOrigin
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowSourceCommit")
+
+
+
+@_attrs_define
+class LavaflowSourceCommit:
+ """ The commit a run read its source at.
+
+ Attributes:
+ sha (str): The commit's full SHA.
+ origin (LavaflowCommitOrigin | None): Where the commit came from. Null for a run recorded before Volcano kept
+ it.
+ """
+
+ sha: str
+ origin: LavaflowCommitOrigin | None
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ sha = self.sha
+
+ origin: None | str
+ if isinstance(self.origin, str):
+ origin = self.origin
+ else:
+ origin = self.origin
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "sha": sha,
+ "origin": origin,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ sha = d.pop("sha")
+
+ def _parse_origin(data: object) -> LavaflowCommitOrigin | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ origin_type_1 = check_lavaflow_commit_origin(data)
+
+
+
+ return origin_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(LavaflowCommitOrigin | None, data)
+
+ origin = _parse_origin(d.pop("origin"))
+
+
+ lavaflow_source_commit = cls(
+ sha=sha,
+ origin=origin,
+ )
+
+
+ lavaflow_source_commit.additional_properties = d
+ return lavaflow_source_commit
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_source_unavailable.py b/src/volcano_sdk/_generated/models/lavaflow_source_unavailable.py
new file mode 100644
index 00000000..889e30af
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_source_unavailable.py
@@ -0,0 +1,135 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.lavaflow_source_unavailable_reason import check_lavaflow_source_unavailable_reason
+from ..models.lavaflow_source_unavailable_reason import LavaflowSourceUnavailableReason
+from typing import cast
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowSourceUnavailable")
+
+
+
+@_attrs_define
+class LavaflowSourceUnavailable:
+ """ Why LavaFlow couldn't read, or open a fix on, the code that served a run's error, so the run opened no pull request.
+
+ Attributes:
+ reason (LavaflowSourceUnavailableReason): Why LavaFlow couldn't read, or open a fix on, the code that served the
+ error, with what you can do. LavaFlow reads the deployment that served the error, so once you deploy code it can
+ read, it starts a new run when the error happens again. `no_repository`: LavaFlow is on for no repository; link
+ one. `no_commit`: the deployment recorded no commit, nor did the build a redeploy serves, or no deployment was
+ serving; deploy by pushing to the linked repository's production branch, or with the CLI from a clean checkout
+ of a commit on that branch. `uncommitted_changes`: the deployment's files differ from its commit (`dirty:
+ true`), as when the checkout had uncommitted changes; commit and push them, then deploy from the clean checkout.
+ `unverified_commit`: Volcano couldn't verify the deployment's commit against the linked repository
+ (`verification: none`), for example because the commit isn't on the production branch, or the deployment is a
+ function redeploy, which doesn't carry its upload's `verification: repository` commit; push the commit to the
+ production branch and deploy it again. `other_repository`: the commit LavaFlow would read is from a repository
+ other than the one LavaFlow is on for, Volcano checked it under an earlier repository link, or the project no
+ longer links that repository. For a deployment, deploy again from the linked repository; for a reported problem
+ or a Code Quality finding, start a new run while the project links the repository LavaFlow is on for.
+ `repository_unreadable`: LavaFlow couldn't read the repository at the commit, for example because the Volcano
+ GitHub App lost access to it; check the project's repository link and the App's access.
+ `commit_not_on_production_branch`: the production branch no longer holds the commit the fix is on, so LavaFlow
+ opened no pull request; deploy from the production branch. `deployment_unattributed`: a newer deployment was
+ going live when the error happened, so LavaFlow couldn't tell which one threw it; if the error happens again,
+ LavaFlow starts a new run once; if that run also ends `deployment_unattributed`, the next waits for a new
+ deploy. A `deployment_unattributed` run right after another one, even one a deploy started, gets no such run.
+ New reasons may appear.
+ deployment_id (None | UUID): The deployment of the run's `resource` that served the error, for `no_commit`,
+ `uncommitted_changes`, `unverified_commit` and `other_repository`. Null for any other reason, including
+ `deployment_unattributed`, and when no deployment was serving. Example: 7c2e5a1f-3b8d-4e6a-9f0c-1d2e3f4a5b6c.
+ """
+
+ reason: LavaflowSourceUnavailableReason
+ deployment_id: None | UUID
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ reason: str = self.reason
+
+ deployment_id: None | str
+ if isinstance(self.deployment_id, UUID):
+ deployment_id = str(self.deployment_id)
+ else:
+ deployment_id = self.deployment_id
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "reason": reason,
+ "deployment_id": deployment_id,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ reason = check_lavaflow_source_unavailable_reason(d.pop("reason"))
+
+
+
+
+ def _parse_deployment_id(data: object) -> None | UUID:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ deployment_id_type_0 = UUID(data)
+
+
+
+ return deployment_id_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(None | UUID, data)
+
+ deployment_id = _parse_deployment_id(d.pop("deployment_id"))
+
+
+ lavaflow_source_unavailable = cls(
+ reason=reason,
+ deployment_id=deployment_id,
+ )
+
+
+ lavaflow_source_unavailable.additional_properties = d
+ return lavaflow_source_unavailable
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_source_unavailable_reason.py b/src/volcano_sdk/_generated/models/lavaflow_source_unavailable_reason.py
new file mode 100644
index 00000000..b9a94a9b
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_source_unavailable_reason.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+LavaflowSourceUnavailableReason = Literal['commit_not_on_production_branch', 'deployment_unattributed', 'no_commit', 'no_repository', 'other_repository', 'repository_unreadable', 'uncommitted_changes', 'unverified_commit']
+
+LAVAFLOW_SOURCE_UNAVAILABLE_REASON_VALUES: set[LavaflowSourceUnavailableReason] = { 'commit_not_on_production_branch', 'deployment_unattributed', 'no_commit', 'no_repository', 'other_repository', 'repository_unreadable', 'uncommitted_changes', 'unverified_commit', }
+
+def check_lavaflow_source_unavailable_reason(value: str) -> LavaflowSourceUnavailableReason:
+ if value in LAVAFLOW_SOURCE_UNAVAILABLE_REASON_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LAVAFLOW_SOURCE_UNAVAILABLE_REASON_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/lavaflow_stats.py b/src/volcano_sdk/_generated/models/lavaflow_stats.py
new file mode 100644
index 00000000..3e4b6e4a
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_stats.py
@@ -0,0 +1,143 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+from uuid import UUID
+import datetime
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_day_counts import LavaflowDayCounts
+ from ..models.lavaflow_stats_totals import LavaflowStatsTotals
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowStats")
+
+
+
+@_attrs_define
+class LavaflowStats:
+ """
+ Attributes:
+ project_id (UUID): The project the counts are for.
+ window_start (datetime.date): The first UTC day in the window.
+ window_end (datetime.date): The last UTC day in the window, today.
+ days (list[LavaflowDayCounts]): One entry per UTC day, oldest first, zeros included.
+ totals (LavaflowStatsTotals):
+ """
+
+ project_id: UUID
+ window_start: datetime.date
+ window_end: datetime.date
+ days: list[LavaflowDayCounts]
+ totals: LavaflowStatsTotals
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_day_counts import LavaflowDayCounts # noqa: PLC0415
+ from ..models.lavaflow_stats_totals import LavaflowStatsTotals # noqa: PLC0415
+ project_id = str(self.project_id)
+
+ window_start = self.window_start.isoformat()
+
+ window_end = self.window_end.isoformat()
+
+ days = []
+ for days_item_data in self.days:
+ days_item = days_item_data.to_dict()
+ days.append(days_item)
+
+
+
+ totals = self.totals.to_dict()
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "project_id": project_id,
+ "window_start": window_start,
+ "window_end": window_end,
+ "days": days,
+ "totals": totals,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_day_counts import LavaflowDayCounts # noqa: PLC0415
+ from ..models.lavaflow_stats_totals import LavaflowStatsTotals # noqa: PLC0415
+ d = dict(src_dict)
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ window_start = datetime.date.fromisoformat(d.pop("window_start"))
+
+
+
+
+ window_end = datetime.date.fromisoformat(d.pop("window_end"))
+
+
+
+
+ days = []
+ _days = d.pop("days")
+ for days_item_data in (_days):
+ days_item = LavaflowDayCounts.from_dict(days_item_data)
+
+
+
+ days.append(days_item)
+
+
+ totals = LavaflowStatsTotals.from_dict(d.pop("totals"))
+
+
+
+
+ lavaflow_stats = cls(
+ project_id=project_id,
+ window_start=window_start,
+ window_end=window_end,
+ days=days,
+ totals=totals,
+ )
+
+
+ lavaflow_stats.additional_properties = d
+ return lavaflow_stats
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_stats_totals.py b/src/volcano_sdk/_generated/models/lavaflow_stats_totals.py
new file mode 100644
index 00000000..ad0c8262
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_stats_totals.py
@@ -0,0 +1,84 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowStatsTotals")
+
+
+
+@_attrs_define
+class LavaflowStatsTotals:
+ """
+ Attributes:
+ issues_opened (int):
+ pull_requests_opened (int):
+ """
+
+ issues_opened: int
+ pull_requests_opened: int
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ issues_opened = self.issues_opened
+
+ pull_requests_opened = self.pull_requests_opened
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "issues_opened": issues_opened,
+ "pull_requests_opened": pull_requests_opened,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ issues_opened = d.pop("issues_opened")
+
+ pull_requests_opened = d.pop("pull_requests_opened")
+
+ lavaflow_stats_totals = cls(
+ issues_opened=issues_opened,
+ pull_requests_opened=pull_requests_opened,
+ )
+
+
+ lavaflow_stats_totals.additional_properties = d
+ return lavaflow_stats_totals
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/lavaflow_workflow_source.py b/src/volcano_sdk/_generated/models/lavaflow_workflow_source.py
new file mode 100644
index 00000000..ba44f2c5
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/lavaflow_workflow_source.py
@@ -0,0 +1,85 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="LavaflowWorkflowSource")
+
+
+
+@_attrs_define
+class LavaflowWorkflowSource:
+ """ A branch or commit whose workflows LavaFlow read, and the commit it read them at.
+
+ Attributes:
+ source (str): The branch, or the commit SHA for a commit. Example: main.
+ commit_sha (str): The commit LavaFlow read the workflows at. Example: 3f786850e387550fdab836ed7e6dc881de23001b.
+ """
+
+ source: str
+ commit_sha: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ source = self.source
+
+ commit_sha = self.commit_sha
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "source": source,
+ "commit_sha": commit_sha,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ source = d.pop("source")
+
+ commit_sha = d.pop("commit_sha")
+
+ lavaflow_workflow_source = cls(
+ source=source,
+ commit_sha=commit_sha,
+ )
+
+
+ lavaflow_workflow_source.additional_properties = d
+ return lavaflow_workflow_source
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/list_account_sessions_sort.py b/src/volcano_sdk/_generated/models/list_account_sessions_sort.py
new file mode 100644
index 00000000..9489ad46
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/list_account_sessions_sort.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+ListAccountSessionsSort = Literal['created_at', 'last_activity']
+
+LIST_ACCOUNT_SESSIONS_SORT_VALUES: set[ListAccountSessionsSort] = { 'created_at', 'last_activity', }
+
+def check_list_account_sessions_sort(value: str) -> ListAccountSessionsSort:
+ if value in LIST_ACCOUNT_SESSIONS_SORT_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LIST_ACCOUNT_SESSIONS_SORT_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/list_account_sessions_status.py b/src/volcano_sdk/_generated/models/list_account_sessions_status.py
new file mode 100644
index 00000000..e35b562c
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/list_account_sessions_status.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+ListAccountSessionsStatus = Literal['active', 'expired']
+
+LIST_ACCOUNT_SESSIONS_STATUS_VALUES: set[ListAccountSessionsStatus] = { 'active', 'expired', }
+
+def check_list_account_sessions_status(value: str) -> ListAccountSessionsStatus:
+ if value in LIST_ACCOUNT_SESSIONS_STATUS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LIST_ACCOUNT_SESSIONS_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/list_lavaflow_resources_category.py b/src/volcano_sdk/_generated/models/list_lavaflow_resources_category.py
new file mode 100644
index 00000000..f13bfe42
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/list_lavaflow_resources_category.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+ListLavaflowResourcesCategory = Literal['bug', 'configuration', 'dependency', 'external', 'improvement', 'performance', 'security', 'uncategorized']
+
+LIST_LAVAFLOW_RESOURCES_CATEGORY_VALUES: set[ListLavaflowResourcesCategory] = { 'bug', 'configuration', 'dependency', 'external', 'improvement', 'performance', 'security', 'uncategorized', }
+
+def check_list_lavaflow_resources_category(value: str) -> ListLavaflowResourcesCategory:
+ if value in LIST_LAVAFLOW_RESOURCES_CATEGORY_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LIST_LAVAFLOW_RESOURCES_CATEGORY_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/list_lavaflow_runs_category.py b/src/volcano_sdk/_generated/models/list_lavaflow_runs_category.py
new file mode 100644
index 00000000..6dedaa80
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/list_lavaflow_runs_category.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+ListLavaflowRunsCategory = Literal['bug', 'configuration', 'dependency', 'external', 'improvement', 'performance', 'security', 'uncategorized']
+
+LIST_LAVAFLOW_RUNS_CATEGORY_VALUES: set[ListLavaflowRunsCategory] = { 'bug', 'configuration', 'dependency', 'external', 'improvement', 'performance', 'security', 'uncategorized', }
+
+def check_list_lavaflow_runs_category(value: str) -> ListLavaflowRunsCategory:
+ if value in LIST_LAVAFLOW_RUNS_CATEGORY_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LIST_LAVAFLOW_RUNS_CATEGORY_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/list_lavaflow_runs_include_item.py b/src/volcano_sdk/_generated/models/list_lavaflow_runs_include_item.py
new file mode 100644
index 00000000..1782e384
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/list_lavaflow_runs_include_item.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+ListLavaflowRunsIncludeItem = Literal['counts']
+
+LIST_LAVAFLOW_RUNS_INCLUDE_ITEM_VALUES: set[ListLavaflowRunsIncludeItem] = { 'counts', }
+
+def check_list_lavaflow_runs_include_item(value: str) -> ListLavaflowRunsIncludeItem:
+ if value in LIST_LAVAFLOW_RUNS_INCLUDE_ITEM_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LIST_LAVAFLOW_RUNS_INCLUDE_ITEM_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/list_lavaflow_runs_order.py b/src/volcano_sdk/_generated/models/list_lavaflow_runs_order.py
new file mode 100644
index 00000000..a9bfd36d
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/list_lavaflow_runs_order.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+ListLavaflowRunsOrder = Literal['created_at.asc', 'created_at.desc', 'issue_events.desc']
+
+LIST_LAVAFLOW_RUNS_ORDER_VALUES: set[ListLavaflowRunsOrder] = { 'created_at.asc', 'created_at.desc', 'issue_events.desc', }
+
+def check_list_lavaflow_runs_order(value: str) -> ListLavaflowRunsOrder:
+ if value in LIST_LAVAFLOW_RUNS_ORDER_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LIST_LAVAFLOW_RUNS_ORDER_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/list_lavaflow_runs_pull_request_state.py b/src/volcano_sdk/_generated/models/list_lavaflow_runs_pull_request_state.py
new file mode 100644
index 00000000..047cbb4e
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/list_lavaflow_runs_pull_request_state.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+ListLavaflowRunsPullRequestState = Literal['closed', 'merged', 'none', 'open']
+
+LIST_LAVAFLOW_RUNS_PULL_REQUEST_STATE_VALUES: set[ListLavaflowRunsPullRequestState] = { 'closed', 'merged', 'none', 'open', }
+
+def check_list_lavaflow_runs_pull_request_state(value: str) -> ListLavaflowRunsPullRequestState:
+ if value in LIST_LAVAFLOW_RUNS_PULL_REQUEST_STATE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {LIST_LAVAFLOW_RUNS_PULL_REQUEST_STATE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/notification_email_settings.py b/src/volcano_sdk/_generated/models/notification_email_settings.py
new file mode 100644
index 00000000..c5dbcf5d
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/notification_email_settings.py
@@ -0,0 +1,87 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.notification_email_status import check_notification_email_status
+from ..models.notification_email_status import NotificationEmailStatus
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="NotificationEmailSettings")
+
+
+
+@_attrs_define
+class NotificationEmailSettings:
+ """
+ Attributes:
+ enabled (bool): Whether alerts are emailed.
+ recipients (list[str]): Empty. Alerts are emailed to the project owner's verified account email address, the
+ only recipient supported.
+ status (NotificationEmailStatus): Whether alerts are being emailed. `owner_email_unverified` means email is
+ enabled but the project owner has no active account with a verified email address, so no alert is emailed, and
+ email does not count as a channel when deciding whether to announce a failing scheduler, until the owner
+ verifies it. Changing the account email address needs a new verification.
+ """
+
+ enabled: bool
+ recipients: list[str]
+ status: NotificationEmailStatus
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ enabled = self.enabled
+
+ recipients = self.recipients
+
+
+
+ status: str = self.status
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "enabled": enabled,
+ "recipients": recipients,
+ "status": status,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ enabled = d.pop("enabled")
+
+ recipients = cast(list[str], d.pop("recipients"))
+
+
+ status = check_notification_email_status(d.pop("status"))
+
+
+
+
+ notification_email_settings = cls(
+ enabled=enabled,
+ recipients=recipients,
+ status=status,
+ )
+
+ return notification_email_settings
+
diff --git a/src/volcano_sdk/_generated/models/notification_email_status.py b/src/volcano_sdk/_generated/models/notification_email_status.py
new file mode 100644
index 00000000..6fbace3d
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/notification_email_status.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+NotificationEmailStatus = Literal['delivering', 'disabled', 'owner_email_unverified']
+
+NOTIFICATION_EMAIL_STATUS_VALUES: set[NotificationEmailStatus] = { 'delivering', 'disabled', 'owner_email_unverified', }
+
+def check_notification_email_status(value: str) -> NotificationEmailStatus:
+ if value in NOTIFICATION_EMAIL_STATUS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {NOTIFICATION_EMAIL_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/notification_settings.py b/src/volcano_sdk/_generated/models/notification_settings.py
new file mode 100644
index 00000000..12769c5f
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/notification_settings.py
@@ -0,0 +1,127 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+import datetime
+
+if TYPE_CHECKING:
+ from ..models.notification_email_settings import NotificationEmailSettings
+ from ..models.notification_webhook_settings import NotificationWebhookSettings
+ from ..models.scheduler_failure_alert_policy import SchedulerFailureAlertPolicy
+
+
+
+
+
+T = TypeVar("T", bound="NotificationSettings")
+
+
+
+@_attrs_define
+class NotificationSettings:
+ """
+ Attributes:
+ project_id (UUID):
+ email (NotificationEmailSettings):
+ webhook (NotificationWebhookSettings):
+ scheduler_failures (SchedulerFailureAlertPolicy):
+ updated_at (datetime.datetime | Unset): When the settings were last saved. Absent until the first save.
+ """
+
+ project_id: UUID
+ email: NotificationEmailSettings
+ webhook: NotificationWebhookSettings
+ scheduler_failures: SchedulerFailureAlertPolicy
+ updated_at: datetime.datetime | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.notification_email_settings import NotificationEmailSettings # noqa: PLC0415
+ from ..models.notification_webhook_settings import NotificationWebhookSettings # noqa: PLC0415
+ from ..models.scheduler_failure_alert_policy import SchedulerFailureAlertPolicy # noqa: PLC0415
+ project_id = str(self.project_id)
+
+ email = self.email.to_dict()
+
+ webhook = self.webhook.to_dict()
+
+ scheduler_failures = self.scheduler_failures.to_dict()
+
+ updated_at: str | Unset = UNSET
+ if not isinstance(self.updated_at, Unset):
+ updated_at = self.updated_at.isoformat()
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "project_id": project_id,
+ "email": email,
+ "webhook": webhook,
+ "scheduler_failures": scheduler_failures,
+ })
+ if updated_at is not UNSET:
+ field_dict["updated_at"] = updated_at
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.notification_email_settings import NotificationEmailSettings # noqa: PLC0415
+ from ..models.notification_webhook_settings import NotificationWebhookSettings # noqa: PLC0415
+ from ..models.scheduler_failure_alert_policy import SchedulerFailureAlertPolicy # noqa: PLC0415
+ d = dict(src_dict)
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ email = NotificationEmailSettings.from_dict(d.pop("email"))
+
+
+
+
+ webhook = NotificationWebhookSettings.from_dict(d.pop("webhook"))
+
+
+
+
+ scheduler_failures = SchedulerFailureAlertPolicy.from_dict(d.pop("scheduler_failures"))
+
+
+
+
+ _updated_at = d.pop("updated_at", UNSET)
+ updated_at: datetime.datetime | Unset
+ if isinstance(_updated_at, Unset):
+ updated_at = UNSET
+ else:
+ updated_at = datetime.datetime.fromisoformat(_updated_at)
+
+
+
+
+ notification_settings = cls(
+ project_id=project_id,
+ email=email,
+ webhook=webhook,
+ scheduler_failures=scheduler_failures,
+ updated_at=updated_at,
+ )
+
+ return notification_settings
+
diff --git a/src/volcano_sdk/_generated/models/notification_test_delivery.py b/src/volcano_sdk/_generated/models/notification_test_delivery.py
new file mode 100644
index 00000000..b8c98b34
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/notification_test_delivery.py
@@ -0,0 +1,91 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.notification_test_delivery_channel import check_notification_test_delivery_channel
+from ..models.notification_test_delivery_channel import NotificationTestDeliveryChannel
+from ..types import UNSET, Unset
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="NotificationTestDelivery")
+
+
+
+@_attrs_define
+class NotificationTestDelivery:
+ """
+ Attributes:
+ channel (NotificationTestDeliveryChannel):
+ delivered (bool):
+ status_code (int | Unset): The webhook's response status. Absent for email, and when no response arrived.
+ error (str | Unset): Why the delivery failed. Absent when it arrived.
+ """
+
+ channel: NotificationTestDeliveryChannel
+ delivered: bool
+ status_code: int | Unset = UNSET
+ error: str | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ channel: str = self.channel
+
+ delivered = self.delivered
+
+ status_code = self.status_code
+
+ error = self.error
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "channel": channel,
+ "delivered": delivered,
+ })
+ if status_code is not UNSET:
+ field_dict["status_code"] = status_code
+ if error is not UNSET:
+ field_dict["error"] = error
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ channel = check_notification_test_delivery_channel(d.pop("channel"))
+
+
+
+
+ delivered = d.pop("delivered")
+
+ status_code = d.pop("status_code", UNSET)
+
+ error = d.pop("error", UNSET)
+
+ notification_test_delivery = cls(
+ channel=channel,
+ delivered=delivered,
+ status_code=status_code,
+ error=error,
+ )
+
+ return notification_test_delivery
+
diff --git a/src/volcano_sdk/_generated/models/notification_test_delivery_channel.py b/src/volcano_sdk/_generated/models/notification_test_delivery_channel.py
new file mode 100644
index 00000000..c4077729
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/notification_test_delivery_channel.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+NotificationTestDeliveryChannel = Literal['email', 'webhook']
+
+NOTIFICATION_TEST_DELIVERY_CHANNEL_VALUES: set[NotificationTestDeliveryChannel] = { 'email', 'webhook', }
+
+def check_notification_test_delivery_channel(value: str) -> NotificationTestDeliveryChannel:
+ if value in NOTIFICATION_TEST_DELIVERY_CHANNEL_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {NOTIFICATION_TEST_DELIVERY_CHANNEL_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/notification_test_result.py b/src/volcano_sdk/_generated/models/notification_test_result.py
new file mode 100644
index 00000000..333c652f
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/notification_test_result.py
@@ -0,0 +1,76 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.notification_test_delivery import NotificationTestDelivery
+
+
+
+
+
+T = TypeVar("T", bound="NotificationTestResult")
+
+
+
+@_attrs_define
+class NotificationTestResult:
+ """
+ Attributes:
+ deliveries (list[NotificationTestDelivery]):
+ """
+
+ deliveries: list[NotificationTestDelivery]
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.notification_test_delivery import NotificationTestDelivery # noqa: PLC0415
+ deliveries = []
+ for deliveries_item_data in self.deliveries:
+ deliveries_item = deliveries_item_data.to_dict()
+ deliveries.append(deliveries_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "deliveries": deliveries,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.notification_test_delivery import NotificationTestDelivery # noqa: PLC0415
+ d = dict(src_dict)
+ deliveries = []
+ _deliveries = d.pop("deliveries")
+ for deliveries_item_data in (_deliveries):
+ deliveries_item = NotificationTestDelivery.from_dict(deliveries_item_data)
+
+
+
+ deliveries.append(deliveries_item)
+
+
+ notification_test_result = cls(
+ deliveries=deliveries,
+ )
+
+ return notification_test_result
+
diff --git a/src/volcano_sdk/_generated/models/notification_webhook_settings.py b/src/volcano_sdk/_generated/models/notification_webhook_settings.py
new file mode 100644
index 00000000..3b7cde32
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/notification_webhook_settings.py
@@ -0,0 +1,78 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+T = TypeVar("T", bound="NotificationWebhookSettings")
+
+
+
+@_attrs_define
+class NotificationWebhookSettings:
+ """
+ Attributes:
+ secret_configured (bool): Whether a signing secret is set. The secret itself is returned only once.
+ url (str | Unset): Where alerts are posted. Absent when no webhook is configured.
+ secret (str | Unset): The signing secret, starting with `whsec_`. Present only in the response that generated
+ it: the update that first set `url`, or a rotation. Store it then; it cannot be read again.
+ """
+
+ secret_configured: bool
+ url: str | Unset = UNSET
+ secret: str | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ secret_configured = self.secret_configured
+
+ url = self.url
+
+ secret = self.secret
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "secret_configured": secret_configured,
+ })
+ if url is not UNSET:
+ field_dict["url"] = url
+ if secret is not UNSET:
+ field_dict["secret"] = secret
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ secret_configured = d.pop("secret_configured")
+
+ url = d.pop("url", UNSET)
+
+ secret = d.pop("secret", UNSET)
+
+ notification_webhook_settings = cls(
+ secret_configured=secret_configured,
+ url=url,
+ secret=secret,
+ )
+
+ return notification_webhook_settings
+
diff --git a/src/volcano_sdk/_generated/models/paginated_autofix_runs.py b/src/volcano_sdk/_generated/models/paginated_git_deployment_runs.py
similarity index 79%
rename from src/volcano_sdk/_generated/models/paginated_autofix_runs.py
rename to src/volcano_sdk/_generated/models/paginated_git_deployment_runs.py
index a61325e1..6006de72 100644
--- a/src/volcano_sdk/_generated/models/paginated_autofix_runs.py
+++ b/src/volcano_sdk/_generated/models/paginated_git_deployment_runs.py
@@ -12,27 +12,27 @@
from typing import cast
if TYPE_CHECKING:
- from ..models.autofix_run import AutofixRun
+ from ..models.git_deployment_run import GitDeploymentRun
-T = TypeVar("T", bound="PaginatedAutofixRuns")
+T = TypeVar("T", bound="PaginatedGitDeploymentRuns")
@_attrs_define
-class PaginatedAutofixRuns:
+class PaginatedGitDeploymentRuns:
"""
Attributes:
- data (list[AutofixRun]):
+ data (list[GitDeploymentRun]):
limit (int): Number of items per page
has_more (bool): Whether a next page exists
next_cursor (str | Unset): Opaque cursor for the next page (present if has_more is true)
"""
- data: list[AutofixRun]
+ data: list[GitDeploymentRun]
limit: int
has_more: bool
next_cursor: str | Unset = UNSET
@@ -43,7 +43,7 @@ class PaginatedAutofixRuns:
def to_dict(self) -> dict[str, Any]:
- from ..models.autofix_run import AutofixRun # noqa: PLC0415
+ from ..models.git_deployment_run import GitDeploymentRun # noqa: PLC0415
data = []
for data_item_data in self.data:
data_item = data_item_data.to_dict()
@@ -74,12 +74,12 @@ def to_dict(self) -> dict[str, Any]:
@classmethod
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
- from ..models.autofix_run import AutofixRun # noqa: PLC0415
+ from ..models.git_deployment_run import GitDeploymentRun # noqa: PLC0415
d = dict(src_dict)
data = []
_data = d.pop("data")
for data_item_data in (_data):
- data_item = AutofixRun.from_dict(data_item_data)
+ data_item = GitDeploymentRun.from_dict(data_item_data)
@@ -92,7 +92,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
next_cursor = d.pop("next_cursor", UNSET)
- paginated_autofix_runs = cls(
+ paginated_git_deployment_runs = cls(
data=data,
limit=limit,
has_more=has_more,
@@ -100,8 +100,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
)
- paginated_autofix_runs.additional_properties = d
- return paginated_autofix_runs
+ paginated_git_deployment_runs.additional_properties = d
+ return paginated_git_deployment_runs
@property
def additional_keys(self) -> list[str]:
diff --git a/src/volcano_sdk/_generated/models/paginated_lavaflow_runs.py b/src/volcano_sdk/_generated/models/paginated_lavaflow_runs.py
new file mode 100644
index 00000000..da646062
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/paginated_lavaflow_runs.py
@@ -0,0 +1,144 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_run_counts import LavaflowRunCounts
+ from ..models.lavaflow_run_summary import LavaflowRunSummary
+
+
+
+
+
+T = TypeVar("T", bound="PaginatedLavaflowRuns")
+
+
+
+@_attrs_define
+class PaginatedLavaflowRuns:
+ """
+ Attributes:
+ data (list[LavaflowRunSummary]):
+ limit (int): Number of items per page
+ has_more (bool): Whether a next page exists
+ next_cursor (str | Unset): Opaque cursor for the next page, present if has_more is true. It works only for the
+ same project_id, caller and order.
+ counts (LavaflowRunCounts | Unset): Runs that match the request. `total` applies every filter. Each breakdown
+ applies every filter but its own, so it shows what picking another value would return.
+ """
+
+ data: list[LavaflowRunSummary]
+ limit: int
+ has_more: bool
+ next_cursor: str | Unset = UNSET
+ counts: LavaflowRunCounts | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_run_counts import LavaflowRunCounts # noqa: PLC0415
+ from ..models.lavaflow_run_summary import LavaflowRunSummary # noqa: PLC0415
+ data = []
+ for data_item_data in self.data:
+ data_item = data_item_data.to_dict()
+ data.append(data_item)
+
+
+
+ limit = self.limit
+
+ has_more = self.has_more
+
+ next_cursor = self.next_cursor
+
+ counts: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.counts, Unset):
+ counts = self.counts.to_dict()
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "data": data,
+ "limit": limit,
+ "has_more": has_more,
+ })
+ if next_cursor is not UNSET:
+ field_dict["next_cursor"] = next_cursor
+ if counts is not UNSET:
+ field_dict["counts"] = counts
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_run_counts import LavaflowRunCounts # noqa: PLC0415
+ from ..models.lavaflow_run_summary import LavaflowRunSummary # noqa: PLC0415
+ d = dict(src_dict)
+ data = []
+ _data = d.pop("data")
+ for data_item_data in (_data):
+ data_item = LavaflowRunSummary.from_dict(data_item_data)
+
+
+
+ data.append(data_item)
+
+
+ limit = d.pop("limit")
+
+ has_more = d.pop("has_more")
+
+ next_cursor = d.pop("next_cursor", UNSET)
+
+ _counts = d.pop("counts", UNSET)
+ counts: LavaflowRunCounts | Unset
+ if isinstance(_counts, Unset):
+ counts = UNSET
+ else:
+ counts = LavaflowRunCounts.from_dict(_counts)
+
+
+
+
+ paginated_lavaflow_runs = cls(
+ data=data,
+ limit=limit,
+ has_more=has_more,
+ next_cursor=next_cursor,
+ counts=counts,
+ )
+
+
+ paginated_lavaflow_runs.additional_properties = d
+ return paginated_lavaflow_runs
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/paginated_lavaflow_scans.py b/src/volcano_sdk/_generated/models/paginated_lavaflow_scans.py
new file mode 100644
index 00000000..25814ced
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/paginated_lavaflow_scans.py
@@ -0,0 +1,121 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.lavaflow_scan import LavaflowScan
+
+
+
+
+
+T = TypeVar("T", bound="PaginatedLavaflowScans")
+
+
+
+@_attrs_define
+class PaginatedLavaflowScans:
+ """
+ Attributes:
+ data (list[LavaflowScan]):
+ limit (int): Number of items per page
+ has_more (bool): Whether a next page exists
+ next_cursor (str | Unset): Opaque cursor for the next page, present if has_more is true. It works only for the
+ same project_id and caller.
+ """
+
+ data: list[LavaflowScan]
+ limit: int
+ has_more: bool
+ next_cursor: str | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.lavaflow_scan import LavaflowScan # noqa: PLC0415
+ data = []
+ for data_item_data in self.data:
+ data_item = data_item_data.to_dict()
+ data.append(data_item)
+
+
+
+ limit = self.limit
+
+ has_more = self.has_more
+
+ next_cursor = self.next_cursor
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "data": data,
+ "limit": limit,
+ "has_more": has_more,
+ })
+ if next_cursor is not UNSET:
+ field_dict["next_cursor"] = next_cursor
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.lavaflow_scan import LavaflowScan # noqa: PLC0415
+ d = dict(src_dict)
+ data = []
+ _data = d.pop("data")
+ for data_item_data in (_data):
+ data_item = LavaflowScan.from_dict(data_item_data)
+
+
+
+ data.append(data_item)
+
+
+ limit = d.pop("limit")
+
+ has_more = d.pop("has_more")
+
+ next_cursor = d.pop("next_cursor", UNSET)
+
+ paginated_lavaflow_scans = cls(
+ data=data,
+ limit=limit,
+ has_more=has_more,
+ next_cursor=next_cursor,
+ )
+
+
+ paginated_lavaflow_scans.additional_properties = d
+ return paginated_lavaflow_scans
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/paginated_share_releases.py b/src/volcano_sdk/_generated/models/paginated_share_releases.py
new file mode 100644
index 00000000..8d19b329
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/paginated_share_releases.py
@@ -0,0 +1,121 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.share_release import ShareRelease
+
+
+
+
+
+T = TypeVar("T", bound="PaginatedShareReleases")
+
+
+
+@_attrs_define
+class PaginatedShareReleases:
+ """
+ Attributes:
+ data (list[ShareRelease]):
+ limit (int): Number of items per page
+ has_more (bool): Whether a next page exists
+ next_cursor (str | Unset): Opaque cursor for the next page, present if has_more is true. It works only for the
+ same share_id and limit.
+ """
+
+ data: list[ShareRelease]
+ limit: int
+ has_more: bool
+ next_cursor: str | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.share_release import ShareRelease # noqa: PLC0415
+ data = []
+ for data_item_data in self.data:
+ data_item = data_item_data.to_dict()
+ data.append(data_item)
+
+
+
+ limit = self.limit
+
+ has_more = self.has_more
+
+ next_cursor = self.next_cursor
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "data": data,
+ "limit": limit,
+ "has_more": has_more,
+ })
+ if next_cursor is not UNSET:
+ field_dict["next_cursor"] = next_cursor
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.share_release import ShareRelease # noqa: PLC0415
+ d = dict(src_dict)
+ data = []
+ _data = d.pop("data")
+ for data_item_data in (_data):
+ data_item = ShareRelease.from_dict(data_item_data)
+
+
+
+ data.append(data_item)
+
+
+ limit = d.pop("limit")
+
+ has_more = d.pop("has_more")
+
+ next_cursor = d.pop("next_cursor", UNSET)
+
+ paginated_share_releases = cls(
+ data=data,
+ limit=limit,
+ has_more=has_more,
+ next_cursor=next_cursor,
+ )
+
+
+ paginated_share_releases.additional_properties = d
+ return paginated_share_releases
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/project_config.py b/src/volcano_sdk/_generated/models/project_config.py
index ead8f893..86fceb02 100644
--- a/src/volcano_sdk/_generated/models/project_config.py
+++ b/src/volcano_sdk/_generated/models/project_config.py
@@ -15,11 +15,12 @@
if TYPE_CHECKING:
from ..models.project_config_auth import ProjectConfigAuth
- from ..models.project_config_autofix import ProjectConfigAutofix
from ..models.project_config_bucket import ProjectConfigBucket
from ..models.project_config_database import ProjectConfigDatabase
from ..models.project_config_frontend import ProjectConfigFrontend
from ..models.project_config_function import ProjectConfigFunction
+ from ..models.project_config_lava_flow import ProjectConfigLavaFlow
+ from ..models.project_config_notifications import ProjectConfigNotifications
from ..models.project_config_project import ProjectConfigProject
from ..models.project_config_realtime import ProjectConfigRealtime
from ..models.project_config_sandbox import ProjectConfigSandbox
@@ -59,9 +60,13 @@ class ProjectConfig:
are deleted.
buckets (list[ProjectConfigBucket] | Unset):
realtime (ProjectConfigRealtime | Unset):
- autofix (ProjectConfigAutofix | Unset): AI diagnosis and fix settings. Omitted fields keep their current value.
- Your API key is never part of the manifest, and an apply never sets or deletes it: set it with `PUT
- /projects/{id}/autofix` before turning on a provider that runs on your own key.
+ lavaflow (ProjectConfigLavaFlow | Unset): Ignored. The manifest doesn't configure LavaFlow. A manifest that
+ still declares this section applies as before, without it, and the result reports it as `unchanged` with a
+ notice. Export never includes it.
+ notifications (ProjectConfigNotifications | Unset): Where the project's alerts go and when a failing scheduler
+ is announced. Omitted fields keep their current value. The webhook signing secret is never part of the manifest:
+ setting `webhook.url` on a project without a webhook generates one that is never shown. Rotate it with `POST
+ /projects/{id}/notifications/webhook-secret` to get a secret you can use.
auth (ProjectConfigAuth | Unset): Authentication settings, grouped like the dashboard auth-settings tabs.
functions (list[ProjectConfigFunction] | Unset):
frontends (list[ProjectConfigFrontend] | Unset):
@@ -77,7 +82,8 @@ class ProjectConfig:
variables: list[ProjectConfigVariable] | Unset = UNSET
buckets: list[ProjectConfigBucket] | Unset = UNSET
realtime: ProjectConfigRealtime | Unset = UNSET
- autofix: ProjectConfigAutofix | Unset = UNSET
+ lavaflow: ProjectConfigLavaFlow | Unset = UNSET
+ notifications: ProjectConfigNotifications | Unset = UNSET
auth: ProjectConfigAuth | Unset = UNSET
functions: list[ProjectConfigFunction] | Unset = UNSET
frontends: list[ProjectConfigFrontend] | Unset = UNSET
@@ -89,11 +95,12 @@ class ProjectConfig:
def to_dict(self) -> dict[str, Any]:
from ..models.project_config_auth import ProjectConfigAuth # noqa: PLC0415
- from ..models.project_config_autofix import ProjectConfigAutofix # noqa: PLC0415
from ..models.project_config_bucket import ProjectConfigBucket # noqa: PLC0415
from ..models.project_config_database import ProjectConfigDatabase # noqa: PLC0415
from ..models.project_config_frontend import ProjectConfigFrontend # noqa: PLC0415
from ..models.project_config_function import ProjectConfigFunction # noqa: PLC0415
+ from ..models.project_config_lava_flow import ProjectConfigLavaFlow # noqa: PLC0415
+ from ..models.project_config_notifications import ProjectConfigNotifications # noqa: PLC0415
from ..models.project_config_project import ProjectConfigProject # noqa: PLC0415
from ..models.project_config_realtime import ProjectConfigRealtime # noqa: PLC0415
from ..models.project_config_sandbox import ProjectConfigSandbox # noqa: PLC0415
@@ -147,9 +154,13 @@ def to_dict(self) -> dict[str, Any]:
if not isinstance(self.realtime, Unset):
realtime = self.realtime.to_dict()
- autofix: dict[str, Any] | Unset = UNSET
- if not isinstance(self.autofix, Unset):
- autofix = self.autofix.to_dict()
+ lavaflow: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.lavaflow, Unset):
+ lavaflow = self.lavaflow.to_dict()
+
+ notifications: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.notifications, Unset):
+ notifications = self.notifications.to_dict()
auth: dict[str, Any] | Unset = UNSET
if not isinstance(self.auth, Unset):
@@ -202,8 +213,10 @@ def to_dict(self) -> dict[str, Any]:
field_dict["buckets"] = buckets
if realtime is not UNSET:
field_dict["realtime"] = realtime
- if autofix is not UNSET:
- field_dict["autofix"] = autofix
+ if lavaflow is not UNSET:
+ field_dict["lavaflow"] = lavaflow
+ if notifications is not UNSET:
+ field_dict["notifications"] = notifications
if auth is not UNSET:
field_dict["auth"] = auth
if functions is not UNSET:
@@ -220,11 +233,12 @@ def to_dict(self) -> dict[str, Any]:
@classmethod
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
from ..models.project_config_auth import ProjectConfigAuth # noqa: PLC0415
- from ..models.project_config_autofix import ProjectConfigAutofix # noqa: PLC0415
from ..models.project_config_bucket import ProjectConfigBucket # noqa: PLC0415
from ..models.project_config_database import ProjectConfigDatabase # noqa: PLC0415
from ..models.project_config_frontend import ProjectConfigFrontend # noqa: PLC0415
from ..models.project_config_function import ProjectConfigFunction # noqa: PLC0415
+ from ..models.project_config_lava_flow import ProjectConfigLavaFlow # noqa: PLC0415
+ from ..models.project_config_notifications import ProjectConfigNotifications # noqa: PLC0415
from ..models.project_config_project import ProjectConfigProject # noqa: PLC0415
from ..models.project_config_realtime import ProjectConfigRealtime # noqa: PLC0415
from ..models.project_config_sandbox import ProjectConfigSandbox # noqa: PLC0415
@@ -297,12 +311,22 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
- _autofix = d.pop("autofix", UNSET)
- autofix: ProjectConfigAutofix | Unset
- if isinstance(_autofix, Unset):
- autofix = UNSET
+ _lavaflow = d.pop("lavaflow", UNSET)
+ lavaflow: ProjectConfigLavaFlow | Unset
+ if isinstance(_lavaflow, Unset):
+ lavaflow = UNSET
+ else:
+ lavaflow = ProjectConfigLavaFlow.from_dict(_lavaflow)
+
+
+
+
+ _notifications = d.pop("notifications", UNSET)
+ notifications: ProjectConfigNotifications | Unset
+ if isinstance(_notifications, Unset):
+ notifications = UNSET
else:
- autofix = ProjectConfigAutofix.from_dict(_autofix)
+ notifications = ProjectConfigNotifications.from_dict(_notifications)
@@ -362,7 +386,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
variables=variables,
buckets=buckets,
realtime=realtime,
- autofix=autofix,
+ lavaflow=lavaflow,
+ notifications=notifications,
auth=auth,
functions=functions,
frontends=frontends,
diff --git a/src/volcano_sdk/_generated/models/project_config_auth_cors.py b/src/volcano_sdk/_generated/models/project_config_auth_cors.py
index 7b0ca723..40604b35 100644
--- a/src/volcano_sdk/_generated/models/project_config_auth_cors.py
+++ b/src/volcano_sdk/_generated/models/project_config_auth_cors.py
@@ -28,12 +28,14 @@ class ProjectConfigAuthCORS:
allowed_origins (list[str] | Unset):
allow_credentials (bool | Unset):
max_age (int | Unset):
+ allow_frontend_previews (bool | Unset): Allow the origins of the project's own live frontend previews.
"""
enabled: bool | Unset = UNSET
allowed_origins: list[str] | Unset = UNSET
allow_credentials: bool | Unset = UNSET
max_age: int | Unset = UNSET
+ allow_frontend_previews: bool | Unset = UNSET
@@ -52,6 +54,8 @@ def to_dict(self) -> dict[str, Any]:
max_age = self.max_age
+ allow_frontend_previews = self.allow_frontend_previews
+
field_dict: dict[str, Any] = {}
@@ -65,6 +69,8 @@ def to_dict(self) -> dict[str, Any]:
field_dict["allow_credentials"] = allow_credentials
if max_age is not UNSET:
field_dict["max_age"] = max_age
+ if allow_frontend_previews is not UNSET:
+ field_dict["allow_frontend_previews"] = allow_frontend_previews
return field_dict
@@ -82,11 +88,14 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
max_age = d.pop("max_age", UNSET)
+ allow_frontend_previews = d.pop("allow_frontend_previews", UNSET)
+
project_config_auth_cors = cls(
enabled=enabled,
allowed_origins=allowed_origins,
allow_credentials=allow_credentials,
max_age=max_age,
+ allow_frontend_previews=allow_frontend_previews,
)
return project_config_auth_cors
diff --git a/src/volcano_sdk/_generated/models/project_config_auth_email_from.py b/src/volcano_sdk/_generated/models/project_config_auth_email_from.py
index a841d893..ea408e15 100644
--- a/src/volcano_sdk/_generated/models/project_config_auth_email_from.py
+++ b/src/volcano_sdk/_generated/models/project_config_auth_email_from.py
@@ -23,8 +23,10 @@
class ProjectConfigAuthEmailFrom:
"""
Attributes:
- address (str | Unset):
- name (str | Unset):
+ address (str | Unset): Sender email address. New or changed values containing carriage returns or newlines
+ return 422. Unchanged exported values are preserved.
+ name (str | Unset): Sender display name; supports punctuation and Unicode. New or changed values containing
+ carriage returns or newlines return 422. Unchanged exported values are preserved.
"""
address: str | Unset = UNSET
diff --git a/src/volcano_sdk/_generated/models/project_config_autofix.py b/src/volcano_sdk/_generated/models/project_config_autofix.py
deleted file mode 100644
index 9e5c4161..00000000
--- a/src/volcano_sdk/_generated/models/project_config_autofix.py
+++ /dev/null
@@ -1,141 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Mapping
-from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
-
-from attrs import define as _attrs_define
-from attrs import field as _attrs_field
-
-from ..types import UNSET, Unset
-
-from ..models.autofix_model import AutofixModel
-from ..models.autofix_model import check_autofix_model
-from ..models.autofix_provider import AutofixProvider
-from ..models.autofix_provider import check_autofix_provider
-from ..models.autofix_stage import AutofixStage
-from ..models.autofix_stage import check_autofix_stage
-from ..types import UNSET, Unset
-from typing import cast
-
-
-
-
-
-
-T = TypeVar("T", bound="ProjectConfigAutofix")
-
-
-
-@_attrs_define
-class ProjectConfigAutofix:
- """ AI diagnosis and fix settings. Omitted fields keep their current value. Your API key is never part of the manifest,
- and an apply never sets or deletes it: set it with `PUT /projects/{id}/autofix` before turning on a provider that
- runs on your own key.
-
- Attributes:
- enabled (bool | Unset):
- max_stage (AutofixStage | Unset): How far a run may go. `diagnose` stops at a root-cause diagnosis.
- `pull_request` may also open a draft pull request with a fix in the project's connected repository.
- auto_trigger (bool | Unset):
- provider (AutofixProvider | Unset): Who serves the model. `volcano` runs on Volcano's models. `anthropic` runs
- on your own Anthropic API key.
- model (AutofixModel | Unset): The Claude model a run uses. `claude-opus-5-5` is the default.
- """
-
- enabled: bool | Unset = UNSET
- max_stage: AutofixStage | Unset = UNSET
- auto_trigger: bool | Unset = UNSET
- provider: AutofixProvider | Unset = UNSET
- model: AutofixModel | Unset = UNSET
-
-
-
-
-
- def to_dict(self) -> dict[str, Any]:
- enabled = self.enabled
-
- max_stage: str | Unset = UNSET
- if not isinstance(self.max_stage, Unset):
- max_stage = self.max_stage
-
-
- auto_trigger = self.auto_trigger
-
- provider: str | Unset = UNSET
- if not isinstance(self.provider, Unset):
- provider = self.provider
-
-
- model: str | Unset = UNSET
- if not isinstance(self.model, Unset):
- model = self.model
-
-
-
- field_dict: dict[str, Any] = {}
-
- field_dict.update({
- })
- if enabled is not UNSET:
- field_dict["enabled"] = enabled
- if max_stage is not UNSET:
- field_dict["max_stage"] = max_stage
- if auto_trigger is not UNSET:
- field_dict["auto_trigger"] = auto_trigger
- if provider is not UNSET:
- field_dict["provider"] = provider
- if model is not UNSET:
- field_dict["model"] = model
-
- return field_dict
-
-
-
- @classmethod
- def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
- d = dict(src_dict)
- enabled = d.pop("enabled", UNSET)
-
- _max_stage = d.pop("max_stage", UNSET)
- max_stage: AutofixStage | Unset
- if isinstance(_max_stage, Unset):
- max_stage = UNSET
- else:
- max_stage = check_autofix_stage(_max_stage)
-
-
-
-
- auto_trigger = d.pop("auto_trigger", UNSET)
-
- _provider = d.pop("provider", UNSET)
- provider: AutofixProvider | Unset
- if isinstance(_provider, Unset):
- provider = UNSET
- else:
- provider = check_autofix_provider(_provider)
-
-
-
-
- _model = d.pop("model", UNSET)
- model: AutofixModel | Unset
- if isinstance(_model, Unset):
- model = UNSET
- else:
- model = check_autofix_model(_model)
-
-
-
-
- project_config_autofix = cls(
- enabled=enabled,
- max_stage=max_stage,
- auto_trigger=auto_trigger,
- provider=provider,
- model=model,
- )
-
- return project_config_autofix
-
diff --git a/src/volcano_sdk/_generated/models/project_config_custom_domain_redirect.py b/src/volcano_sdk/_generated/models/project_config_custom_domain_redirect.py
new file mode 100644
index 00000000..4f3b64b9
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/project_config_custom_domain_redirect.py
@@ -0,0 +1,82 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.project_config_custom_domain_redirect_status import check_project_config_custom_domain_redirect_status
+from ..models.project_config_custom_domain_redirect_status import ProjectConfigCustomDomainRedirectStatus
+from ..types import UNSET, Unset
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="ProjectConfigCustomDomainRedirect")
+
+
+
+@_attrs_define
+class ProjectConfigCustomDomainRedirect:
+ """
+ Attributes:
+ to (str): Another domain in the same `custom_domains` list, without `redirect`.
+ status (ProjectConfigCustomDomainRedirectStatus | Unset): Default: 308.
+ """
+
+ to: str
+ status: ProjectConfigCustomDomainRedirectStatus | Unset = 308
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ to = self.to
+
+ status: int | Unset = UNSET
+ if not isinstance(self.status, Unset):
+ status = self.status
+
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "to": to,
+ })
+ if status is not UNSET:
+ field_dict["status"] = status
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ to = d.pop("to")
+
+ _status = d.pop("status", UNSET)
+ status: ProjectConfigCustomDomainRedirectStatus | Unset
+ if isinstance(_status, Unset):
+ status = UNSET
+ else:
+ status = check_project_config_custom_domain_redirect_status(_status)
+
+
+
+
+ project_config_custom_domain_redirect = cls(
+ to=to,
+ status=status,
+ )
+
+ return project_config_custom_domain_redirect
+
diff --git a/src/volcano_sdk/_generated/models/project_config_custom_domain_redirect_status.py b/src/volcano_sdk/_generated/models/project_config_custom_domain_redirect_status.py
new file mode 100644
index 00000000..9e37c4ee
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/project_config_custom_domain_redirect_status.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+ProjectConfigCustomDomainRedirectStatus = Literal[301, 302, 307, 308]
+
+PROJECT_CONFIG_CUSTOM_DOMAIN_REDIRECT_STATUS_VALUES: set[ProjectConfigCustomDomainRedirectStatus] = { 301, 302, 307, 308, }
+
+def check_project_config_custom_domain_redirect_status(value: int) -> ProjectConfigCustomDomainRedirectStatus:
+ if value in PROJECT_CONFIG_CUSTOM_DOMAIN_REDIRECT_STATUS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {PROJECT_CONFIG_CUSTOM_DOMAIN_REDIRECT_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/project_config_email_template.py b/src/volcano_sdk/_generated/models/project_config_email_template.py
index 654f2b76..6f9a245f 100644
--- a/src/volcano_sdk/_generated/models/project_config_email_template.py
+++ b/src/volcano_sdk/_generated/models/project_config_email_template.py
@@ -23,7 +23,9 @@
class ProjectConfigEmailTemplate:
"""
Attributes:
- subject (str | Unset):
+ subject (str | Unset): Subject template. For new or changed values, literal interior carriage returns or
+ newlines after Go template whitespace trimming return 422. Outer whitespace and trailing block-scalar newlines
+ are allowed. Unchanged stored subjects are preserved.
html_body (str | Unset): HTML body. Max 256 KiB. SUPERAGENT plan required for custom bodies.
text_body (str | Unset): Plain-text body. Max 256 KiB. SUPERAGENT plan required for custom bodies.
"""
diff --git a/src/volcano_sdk/_generated/models/project_config_frontend.py b/src/volcano_sdk/_generated/models/project_config_frontend.py
index 8664d9cf..cf057235 100644
--- a/src/volcano_sdk/_generated/models/project_config_frontend.py
+++ b/src/volcano_sdk/_generated/models/project_config_frontend.py
@@ -15,7 +15,9 @@
if TYPE_CHECKING:
from ..models.project_config_custom_domain import ProjectConfigCustomDomain
+ from ..models.project_config_frontend_custom_domain import ProjectConfigFrontendCustomDomain
from ..models.project_config_frontend_function_route import ProjectConfigFrontendFunctionRoute
+ from ..models.project_config_frontend_route import ProjectConfigFrontendRoute
@@ -28,8 +30,7 @@
@_attrs_define
class ProjectConfigFrontend:
""" Configuration for an existing (deployed) frontend. Frontends are never
- created or deleted through the manifest. A declared frontend entry
- without `custom_domain` deletes an existing custom domain.
+ created or deleted through the manifest.
Attributes:
name (str):
@@ -38,24 +39,31 @@ class ProjectConfigFrontend:
in builds and runtime. Omission preserves the stored selection.
variables (list[str] | Unset): Names selected when variable_scope is scoped. Missing declared values reject
deployment. Omission preserves the stored list; an empty list clears it.
- custom_domain (ProjectConfigCustomDomain | Unset): Custom domain with managed or BYOC TLS. `tls` is required
- when the domain is first created and optional afterwards. For an existing
- domain, omitting `tls` or sending only `tls.mode` keeps the stored
- certificate; new BYOC material for the same domain rotates the
- certificate in place (zero downtime). Changing `tls.mode` for the same
- hostname switches an active domain in place (zero downtime); a domain
- that is not yet active, or a managed domain changing hostname, must be
- deleted first. BYOC TLS material is write-only; exports render only
- `tls.mode`.
+ custom_domain (None | ProjectConfigCustomDomain | Unset): The frontend's custom domain. Omission leaves an
+ existing domain
+ untouched; null deletes it. For a frontend with more than one
+ domain, or a redirect, use `custom_domains`; an entry may not set
+ both.
+ custom_domains (list[ProjectConfigFrontendCustomDomain] | Unset): Complete set of the frontend's custom domains
+ when declared.
+ Domains not listed are deleted; an empty list deletes all of them.
+ Omission leaves existing domains untouched. More than one domain
+ needs a plan that allows it.
function_routes (list[ProjectConfigFrontendFunctionRoute] | Unset): Complete set of same-origin Function path
mappings when declared. Omission preserves existing mappings; an empty list deletes all mappings.
+ frontend_routes (list[ProjectConfigFrontendRoute] | Unset): Complete set of paths this frontend serves from
+ another frontend in the project when
+ declared. Omission preserves existing routes; an empty list deletes all of them.
+ Function and Frontend routes share one path namespace and the 64-route limit.
"""
name: str
variable_scope: ProjectConfigFrontendVariableScope | Unset = UNSET
variables: list[str] | Unset = UNSET
- custom_domain: ProjectConfigCustomDomain | Unset = UNSET
+ custom_domain: None | ProjectConfigCustomDomain | Unset = UNSET
+ custom_domains: list[ProjectConfigFrontendCustomDomain] | Unset = UNSET
function_routes: list[ProjectConfigFrontendFunctionRoute] | Unset = UNSET
+ frontend_routes: list[ProjectConfigFrontendRoute] | Unset = UNSET
@@ -63,7 +71,9 @@ class ProjectConfigFrontend:
def to_dict(self) -> dict[str, Any]:
from ..models.project_config_custom_domain import ProjectConfigCustomDomain # noqa: PLC0415
+ from ..models.project_config_frontend_custom_domain import ProjectConfigFrontendCustomDomain # noqa: PLC0415
from ..models.project_config_frontend_function_route import ProjectConfigFrontendFunctionRoute # noqa: PLC0415
+ from ..models.project_config_frontend_route import ProjectConfigFrontendRoute # noqa: PLC0415
name = self.name
variable_scope: str | Unset = UNSET
@@ -77,9 +87,22 @@ def to_dict(self) -> dict[str, Any]:
- custom_domain: dict[str, Any] | Unset = UNSET
- if not isinstance(self.custom_domain, Unset):
+ custom_domain: dict[str, Any] | None | Unset
+ if isinstance(self.custom_domain, Unset):
+ custom_domain = UNSET
+ elif isinstance(self.custom_domain, ProjectConfigCustomDomain):
custom_domain = self.custom_domain.to_dict()
+ else:
+ custom_domain = self.custom_domain
+
+ custom_domains: list[dict[str, Any]] | Unset = UNSET
+ if not isinstance(self.custom_domains, Unset):
+ custom_domains = []
+ for custom_domains_item_data in self.custom_domains:
+ custom_domains_item = custom_domains_item_data.to_dict()
+ custom_domains.append(custom_domains_item)
+
+
function_routes: list[dict[str, Any]] | Unset = UNSET
if not isinstance(self.function_routes, Unset):
@@ -90,6 +113,15 @@ def to_dict(self) -> dict[str, Any]:
+ frontend_routes: list[dict[str, Any]] | Unset = UNSET
+ if not isinstance(self.frontend_routes, Unset):
+ frontend_routes = []
+ for frontend_routes_item_data in self.frontend_routes:
+ frontend_routes_item = frontend_routes_item_data.to_dict()
+ frontend_routes.append(frontend_routes_item)
+
+
+
field_dict: dict[str, Any] = {}
@@ -102,8 +134,12 @@ def to_dict(self) -> dict[str, Any]:
field_dict["variables"] = variables
if custom_domain is not UNSET:
field_dict["custom_domain"] = custom_domain
+ if custom_domains is not UNSET:
+ field_dict["custom_domains"] = custom_domains
if function_routes is not UNSET:
field_dict["function_routes"] = function_routes
+ if frontend_routes is not UNSET:
+ field_dict["frontend_routes"] = frontend_routes
return field_dict
@@ -112,7 +148,9 @@ def to_dict(self) -> dict[str, Any]:
@classmethod
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
from ..models.project_config_custom_domain import ProjectConfigCustomDomain # noqa: PLC0415
+ from ..models.project_config_frontend_custom_domain import ProjectConfigFrontendCustomDomain # noqa: PLC0415
from ..models.project_config_frontend_function_route import ProjectConfigFrontendFunctionRoute # noqa: PLC0415
+ from ..models.project_config_frontend_route import ProjectConfigFrontendRoute # noqa: PLC0415
d = dict(src_dict)
name = d.pop("name")
@@ -129,14 +167,36 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
variables = cast(list[str], d.pop("variables", UNSET))
- _custom_domain = d.pop("custom_domain", UNSET)
- custom_domain: ProjectConfigCustomDomain | Unset
- if isinstance(_custom_domain, Unset):
- custom_domain = UNSET
- else:
- custom_domain = ProjectConfigCustomDomain.from_dict(_custom_domain)
+ def _parse_custom_domain(data: object) -> None | ProjectConfigCustomDomain | Unset:
+ if data is None:
+ return data
+ if isinstance(data, Unset):
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ custom_domain_type_1 = ProjectConfigCustomDomain.from_dict(data)
+
+ return custom_domain_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(None | ProjectConfigCustomDomain | Unset, data)
+
+ custom_domain = _parse_custom_domain(d.pop("custom_domain", UNSET))
+
+
+ _custom_domains = d.pop("custom_domains", UNSET)
+ custom_domains: list[ProjectConfigFrontendCustomDomain] | Unset = UNSET
+ if _custom_domains is not UNSET:
+ custom_domains = []
+ for custom_domains_item_data in _custom_domains:
+ custom_domains_item = ProjectConfigFrontendCustomDomain.from_dict(custom_domains_item_data)
+
+
+
+ custom_domains.append(custom_domains_item)
_function_routes = d.pop("function_routes", UNSET)
@@ -151,12 +211,26 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
function_routes.append(function_routes_item)
+ _frontend_routes = d.pop("frontend_routes", UNSET)
+ frontend_routes: list[ProjectConfigFrontendRoute] | Unset = UNSET
+ if _frontend_routes is not UNSET:
+ frontend_routes = []
+ for frontend_routes_item_data in _frontend_routes:
+ frontend_routes_item = ProjectConfigFrontendRoute.from_dict(frontend_routes_item_data)
+
+
+
+ frontend_routes.append(frontend_routes_item)
+
+
project_config_frontend = cls(
name=name,
variable_scope=variable_scope,
variables=variables,
custom_domain=custom_domain,
+ custom_domains=custom_domains,
function_routes=function_routes,
+ frontend_routes=frontend_routes,
)
return project_config_frontend
diff --git a/src/volcano_sdk/_generated/models/project_config_frontend_custom_domain.py b/src/volcano_sdk/_generated/models/project_config_frontend_custom_domain.py
new file mode 100644
index 00000000..010eee55
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/project_config_frontend_custom_domain.py
@@ -0,0 +1,132 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.byoc_project_config_frontend_custom_domain_tls_config import BYOCProjectConfigFrontendCustomDomainTLSConfig
+ from ..models.managed_project_config_frontend_custom_domain_tls_config import ManagedProjectConfigFrontendCustomDomainTLSConfig
+ from ..models.project_config_custom_domain_redirect import ProjectConfigCustomDomainRedirect
+
+
+
+
+
+T = TypeVar("T", bound="ProjectConfigFrontendCustomDomain")
+
+
+
+@_attrs_define
+class ProjectConfigFrontendCustomDomain:
+ """ One of the frontend's custom domains. `domain` and `tls` behave as in
+ `custom_domain`. With `redirect`, the domain redirects every request to
+ another listed domain that serves the frontend.
+
+ Attributes:
+ domain (str): Fully-qualified domain name (hostname only, no scheme/path). Managed TLS (`tls.mode: managed`)
+ accepts at most 219 characters; BYOC accepts 253.
+ tls (BYOCProjectConfigFrontendCustomDomainTLSConfig | ManagedProjectConfigFrontendCustomDomainTLSConfig |
+ Unset): TLS for the custom domain. `mode` defaults to `byoc` when omitted.
+ redirect (ProjectConfigCustomDomainRedirect | Unset):
+ """
+
+ domain: str
+ tls: BYOCProjectConfigFrontendCustomDomainTLSConfig | ManagedProjectConfigFrontendCustomDomainTLSConfig | Unset = UNSET
+ redirect: ProjectConfigCustomDomainRedirect | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.byoc_project_config_frontend_custom_domain_tls_config import BYOCProjectConfigFrontendCustomDomainTLSConfig # noqa: PLC0415
+ from ..models.managed_project_config_frontend_custom_domain_tls_config import ManagedProjectConfigFrontendCustomDomainTLSConfig # noqa: PLC0415
+ from ..models.project_config_custom_domain_redirect import ProjectConfigCustomDomainRedirect # noqa: PLC0415
+ domain = self.domain
+
+ tls: dict[str, Any] | Unset
+ if isinstance(self.tls, Unset):
+ tls = UNSET
+ elif isinstance(self.tls, ManagedProjectConfigFrontendCustomDomainTLSConfig):
+ tls = self.tls.to_dict()
+ else:
+ tls = self.tls.to_dict()
+
+
+ redirect: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.redirect, Unset):
+ redirect = self.redirect.to_dict()
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "domain": domain,
+ })
+ if tls is not UNSET:
+ field_dict["tls"] = tls
+ if redirect is not UNSET:
+ field_dict["redirect"] = redirect
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.byoc_project_config_frontend_custom_domain_tls_config import BYOCProjectConfigFrontendCustomDomainTLSConfig # noqa: PLC0415
+ from ..models.managed_project_config_frontend_custom_domain_tls_config import ManagedProjectConfigFrontendCustomDomainTLSConfig # noqa: PLC0415
+ from ..models.project_config_custom_domain_redirect import ProjectConfigCustomDomainRedirect # noqa: PLC0415
+ d = dict(src_dict)
+ domain = d.pop("domain")
+
+ def _parse_tls(data: object) -> BYOCProjectConfigFrontendCustomDomainTLSConfig | ManagedProjectConfigFrontendCustomDomainTLSConfig | Unset:
+ if isinstance(data, Unset):
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ componentsschemas_project_config_frontend_custom_domain_tls_config_type_0 = ManagedProjectConfigFrontendCustomDomainTLSConfig.from_dict(data)
+
+
+
+ return componentsschemas_project_config_frontend_custom_domain_tls_config_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ if not isinstance(data, dict):
+ raise TypeError()
+ componentsschemas_project_config_frontend_custom_domain_tls_config_type_1 = BYOCProjectConfigFrontendCustomDomainTLSConfig.from_dict(data)
+
+
+
+ return componentsschemas_project_config_frontend_custom_domain_tls_config_type_1
+
+ tls = _parse_tls(d.pop("tls", UNSET))
+
+
+ _redirect = d.pop("redirect", UNSET)
+ redirect: ProjectConfigCustomDomainRedirect | Unset
+ if isinstance(_redirect, Unset):
+ redirect = UNSET
+ else:
+ redirect = ProjectConfigCustomDomainRedirect.from_dict(_redirect)
+
+
+
+
+ project_config_frontend_custom_domain = cls(
+ domain=domain,
+ tls=tls,
+ redirect=redirect,
+ )
+
+ return project_config_frontend_custom_domain
+
diff --git a/src/volcano_sdk/_generated/models/project_config_frontend_route.py b/src/volcano_sdk/_generated/models/project_config_frontend_route.py
new file mode 100644
index 00000000..eff87beb
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/project_config_frontend_route.py
@@ -0,0 +1,66 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="ProjectConfigFrontendRoute")
+
+
+
+@_attrs_define
+class ProjectConfigFrontendRoute:
+ """
+ Attributes:
+ frontend (str): Name of another existing frontend in the project to mount. Paths are forwarded unchanged.
+ path_prefix (str):
+ """
+
+ frontend: str
+ path_prefix: str
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ frontend = self.frontend
+
+ path_prefix = self.path_prefix
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "frontend": frontend,
+ "path_prefix": path_prefix,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ frontend = d.pop("frontend")
+
+ path_prefix = d.pop("path_prefix")
+
+ project_config_frontend_route = cls(
+ frontend=frontend,
+ path_prefix=path_prefix,
+ )
+
+ return project_config_frontend_route
+
diff --git a/src/volcano_sdk/_generated/models/project_config_lava_flow.py b/src/volcano_sdk/_generated/models/project_config_lava_flow.py
new file mode 100644
index 00000000..e25eed3a
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/project_config_lava_flow.py
@@ -0,0 +1,67 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="ProjectConfigLavaFlow")
+
+
+
+@_attrs_define
+class ProjectConfigLavaFlow:
+ """ Ignored. The manifest doesn't configure LavaFlow. A manifest that still declares this section applies as before,
+ without it, and the result reports it as `unchanged` with a notice. Export never includes it.
+
+ """
+
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ project_config_lava_flow = cls(
+ )
+
+
+ project_config_lava_flow.additional_properties = d
+ return project_config_lava_flow
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/project_config_notifications.py b/src/volcano_sdk/_generated/models/project_config_notifications.py
new file mode 100644
index 00000000..0f9d710c
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/project_config_notifications.py
@@ -0,0 +1,123 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.update_notification_email import UpdateNotificationEmail
+ from ..models.update_notification_webhook import UpdateNotificationWebhook
+ from ..models.update_scheduler_failure_alert_policy import UpdateSchedulerFailureAlertPolicy
+
+
+
+
+
+T = TypeVar("T", bound="ProjectConfigNotifications")
+
+
+
+@_attrs_define
+class ProjectConfigNotifications:
+ """ Where the project's alerts go and when a failing scheduler is announced. Omitted fields keep their current value.
+ The webhook signing secret is never part of the manifest: setting `webhook.url` on a project without a webhook
+ generates one that is never shown. Rotate it with `POST /projects/{id}/notifications/webhook-secret` to get a secret
+ you can use.
+
+ Attributes:
+ email (UpdateNotificationEmail | Unset):
+ webhook (UpdateNotificationWebhook | Unset):
+ scheduler_failures (UpdateSchedulerFailureAlertPolicy | Unset):
+ """
+
+ email: UpdateNotificationEmail | Unset = UNSET
+ webhook: UpdateNotificationWebhook | Unset = UNSET
+ scheduler_failures: UpdateSchedulerFailureAlertPolicy | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.update_notification_email import UpdateNotificationEmail # noqa: PLC0415
+ from ..models.update_notification_webhook import UpdateNotificationWebhook # noqa: PLC0415
+ from ..models.update_scheduler_failure_alert_policy import UpdateSchedulerFailureAlertPolicy # noqa: PLC0415
+ email: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.email, Unset):
+ email = self.email.to_dict()
+
+ webhook: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.webhook, Unset):
+ webhook = self.webhook.to_dict()
+
+ scheduler_failures: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.scheduler_failures, Unset):
+ scheduler_failures = self.scheduler_failures.to_dict()
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ })
+ if email is not UNSET:
+ field_dict["email"] = email
+ if webhook is not UNSET:
+ field_dict["webhook"] = webhook
+ if scheduler_failures is not UNSET:
+ field_dict["scheduler_failures"] = scheduler_failures
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.update_notification_email import UpdateNotificationEmail # noqa: PLC0415
+ from ..models.update_notification_webhook import UpdateNotificationWebhook # noqa: PLC0415
+ from ..models.update_scheduler_failure_alert_policy import UpdateSchedulerFailureAlertPolicy # noqa: PLC0415
+ d = dict(src_dict)
+ _email = d.pop("email", UNSET)
+ email: UpdateNotificationEmail | Unset
+ if isinstance(_email, Unset):
+ email = UNSET
+ else:
+ email = UpdateNotificationEmail.from_dict(_email)
+
+
+
+
+ _webhook = d.pop("webhook", UNSET)
+ webhook: UpdateNotificationWebhook | Unset
+ if isinstance(_webhook, Unset):
+ webhook = UNSET
+ else:
+ webhook = UpdateNotificationWebhook.from_dict(_webhook)
+
+
+
+
+ _scheduler_failures = d.pop("scheduler_failures", UNSET)
+ scheduler_failures: UpdateSchedulerFailureAlertPolicy | Unset
+ if isinstance(_scheduler_failures, Unset):
+ scheduler_failures = UNSET
+ else:
+ scheduler_failures = UpdateSchedulerFailureAlertPolicy.from_dict(_scheduler_failures)
+
+
+
+
+ project_config_notifications = cls(
+ email=email,
+ webhook=webhook,
+ scheduler_failures=scheduler_failures,
+ )
+
+ return project_config_notifications
+
diff --git a/src/volcano_sdk/_generated/models/project_deployment.py b/src/volcano_sdk/_generated/models/project_deployment.py
index 4529c3b1..51c11f0d 100644
--- a/src/volcano_sdk/_generated/models/project_deployment.py
+++ b/src/volcano_sdk/_generated/models/project_deployment.py
@@ -20,6 +20,7 @@
import datetime
if TYPE_CHECKING:
+ from ..models.deployment_commit import DeploymentCommit
from ..models.deployment_progress import DeploymentProgress
from ..models.project_deployment_resource import ProjectDeploymentResource
@@ -48,6 +49,9 @@ class ProjectDeployment:
completed_at (datetime.datetime | Unset):
progress (DeploymentProgress | Unset): Normalized live progress derived from the deployment workflow and build
phases.
+ commit (DeploymentCommit | Unset): The commit a deploy client reported for the deployment's source. Absent when
+ the client reported none. A frontend deployment that publishes another deployment's build carries that
+ deployment's commit.
"""
id: UUID
@@ -61,6 +65,7 @@ class ProjectDeployment:
error_message: str | Unset = UNSET
completed_at: datetime.datetime | Unset = UNSET
progress: DeploymentProgress | Unset = UNSET
+ commit: DeploymentCommit | Unset = UNSET
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
@@ -68,6 +73,7 @@ class ProjectDeployment:
def to_dict(self) -> dict[str, Any]:
+ from ..models.deployment_commit import DeploymentCommit # noqa: PLC0415
from ..models.deployment_progress import DeploymentProgress # noqa: PLC0415
from ..models.project_deployment_resource import ProjectDeploymentResource # noqa: PLC0415
id = str(self.id)
@@ -96,6 +102,10 @@ def to_dict(self) -> dict[str, Any]:
if not isinstance(self.progress, Unset):
progress = self.progress.to_dict()
+ commit: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.commit, Unset):
+ commit = self.commit.to_dict()
+
field_dict: dict[str, Any] = {}
field_dict.update(self.additional_properties)
@@ -115,6 +125,8 @@ def to_dict(self) -> dict[str, Any]:
field_dict["completed_at"] = completed_at
if progress is not UNSET:
field_dict["progress"] = progress
+ if commit is not UNSET:
+ field_dict["commit"] = commit
return field_dict
@@ -122,6 +134,7 @@ def to_dict(self) -> dict[str, Any]:
@classmethod
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.deployment_commit import DeploymentCommit # noqa: PLC0415
from ..models.deployment_progress import DeploymentProgress # noqa: PLC0415
from ..models.project_deployment_resource import ProjectDeploymentResource # noqa: PLC0415
d = dict(src_dict)
@@ -187,6 +200,16 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ _commit = d.pop("commit", UNSET)
+ commit: DeploymentCommit | Unset
+ if isinstance(_commit, Unset):
+ commit = UNSET
+ else:
+ commit = DeploymentCommit.from_dict(_commit)
+
+
+
+
project_deployment = cls(
id=id,
project_id=project_id,
@@ -199,6 +222,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
error_message=error_message,
completed_at=completed_at,
progress=progress,
+ commit=commit,
)
diff --git a/src/volcano_sdk/_generated/models/project_frontend_custom_domain.py b/src/volcano_sdk/_generated/models/project_frontend_custom_domain.py
index eeee1384..76fb3b68 100644
--- a/src/volcano_sdk/_generated/models/project_frontend_custom_domain.py
+++ b/src/volcano_sdk/_generated/models/project_frontend_custom_domain.py
@@ -21,6 +21,7 @@
import datetime
if TYPE_CHECKING:
+ from ..models.frontend_custom_domain_redirect import FrontendCustomDomainRedirect
from ..models.frontend_domain_routing_record import FrontendDomainRoutingRecord
from ..models.frontend_domain_verification_record import FrontendDomainVerificationRecord
from ..models.project_frontend_custom_domain_frontend import ProjectFrontendCustomDomainFrontend
@@ -45,6 +46,8 @@ class ProjectFrontendCustomDomain:
withdrawn, or Volcano is retrying after a failure. `failed`: a failure left the domain unserved, alongside
`domain_status: failed`; managed domains report the cause in `failure_reason`.
effective_urls (list[str]):
+ redirect (FrontendCustomDomainRedirect | None): Where the domain redirects every request, or null when it serves
+ the frontend.
created_at (datetime.datetime):
updated_at (datetime.datetime):
frontend (ProjectFrontendCustomDomainFrontend): The frontend this custom domain is attached to. Inlined to
@@ -72,6 +75,7 @@ class ProjectFrontendCustomDomain:
domain_status: FrontendCustomDomainResponseDomainStatus
verification_status: FrontendCustomDomainResponseVerificationStatus
effective_urls: list[str]
+ redirect: FrontendCustomDomainRedirect | None
created_at: datetime.datetime
updated_at: datetime.datetime
frontend: ProjectFrontendCustomDomainFrontend
@@ -87,6 +91,7 @@ class ProjectFrontendCustomDomain:
def to_dict(self) -> dict[str, Any]:
+ from ..models.frontend_custom_domain_redirect import FrontendCustomDomainRedirect # noqa: PLC0415
from ..models.frontend_domain_routing_record import FrontendDomainRoutingRecord # noqa: PLC0415
from ..models.frontend_domain_verification_record import FrontendDomainVerificationRecord # noqa: PLC0415
from ..models.project_frontend_custom_domain_frontend import ProjectFrontendCustomDomainFrontend # noqa: PLC0415
@@ -102,6 +107,12 @@ def to_dict(self) -> dict[str, Any]:
+ redirect: dict[str, Any] | None
+ if isinstance(self.redirect, FrontendCustomDomainRedirect):
+ redirect = self.redirect.to_dict()
+ else:
+ redirect = self.redirect
+
created_at = self.created_at.isoformat()
updated_at = self.updated_at.isoformat()
@@ -139,6 +150,7 @@ def to_dict(self) -> dict[str, Any]:
"domain_status": domain_status,
"verification_status": verification_status,
"effective_urls": effective_urls,
+ "redirect": redirect,
"created_at": created_at,
"updated_at": updated_at,
"frontend": frontend,
@@ -160,6 +172,7 @@ def to_dict(self) -> dict[str, Any]:
@classmethod
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.frontend_custom_domain_redirect import FrontendCustomDomainRedirect # noqa: PLC0415
from ..models.frontend_domain_routing_record import FrontendDomainRoutingRecord # noqa: PLC0415
from ..models.frontend_domain_verification_record import FrontendDomainVerificationRecord # noqa: PLC0415
from ..models.project_frontend_custom_domain_frontend import ProjectFrontendCustomDomainFrontend # noqa: PLC0415
@@ -184,6 +197,24 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
effective_urls = cast(list[str], d.pop("effective_urls"))
+ def _parse_redirect(data: object) -> FrontendCustomDomainRedirect | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ redirect_type_1 = FrontendCustomDomainRedirect.from_dict(data)
+
+
+
+ return redirect_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(FrontendCustomDomainRedirect | None, data)
+
+ redirect = _parse_redirect(d.pop("redirect"))
+
+
created_at = datetime.datetime.fromisoformat(d.pop("created_at"))
@@ -241,6 +272,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
domain_status=domain_status,
verification_status=verification_status,
effective_urls=effective_urls,
+ redirect=redirect,
created_at=created_at,
updated_at=updated_at,
frontend=frontend,
diff --git a/src/volcano_sdk/_generated/models/project_git_connection.py b/src/volcano_sdk/_generated/models/project_git_connection.py
index 679d5046..3a8e766d 100644
--- a/src/volcano_sdk/_generated/models/project_git_connection.py
+++ b/src/volcano_sdk/_generated/models/project_git_connection.py
@@ -30,7 +30,13 @@ class ProjectGitConnection:
root_directory (str):
production_branch (str): The branch a push must land on to deploy. Follows the repository's GitHub default
branch unless the project set its own, which a default-branch rename on GitHub then leaves alone.
- updated_at (datetime.datetime):
+ production_branch_follows_default (bool): True when `production_branch` follows the repository's default branch
+ and moves with a default-branch rename on GitHub. False when the project pinned a branch, even one that matches
+ the current default. Pin a branch with `PUT /projects/{id}/git-connection/production-branch`; send an empty
+ `production_branch` there to follow the default again.
+ updated_at (datetime.datetime): When the connection last changed: its repository, root directory or production
+ branch. Naming the branch it already uses, and other changes to the project, leave it alone. A connection that
+ has not changed since Volcano began tracking this reports the project's last change before then.
"""
repo_installation_id: int
@@ -38,6 +44,7 @@ class ProjectGitConnection:
repo_full_name: str
root_directory: str
production_branch: str
+ production_branch_follows_default: bool
updated_at: datetime.datetime
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
@@ -56,6 +63,8 @@ def to_dict(self) -> dict[str, Any]:
production_branch = self.production_branch
+ production_branch_follows_default = self.production_branch_follows_default
+
updated_at = self.updated_at.isoformat()
@@ -67,6 +76,7 @@ def to_dict(self) -> dict[str, Any]:
"repo_full_name": repo_full_name,
"root_directory": root_directory,
"production_branch": production_branch,
+ "production_branch_follows_default": production_branch_follows_default,
"updated_at": updated_at,
})
@@ -87,6 +97,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
production_branch = d.pop("production_branch")
+ production_branch_follows_default = d.pop("production_branch_follows_default")
+
updated_at = datetime.datetime.fromisoformat(d.pop("updated_at"))
@@ -98,6 +110,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
repo_full_name=repo_full_name,
root_directory=root_directory,
production_branch=production_branch,
+ production_branch_follows_default=production_branch_follows_default,
updated_at=updated_at,
)
diff --git a/src/volcano_sdk/_generated/models/project_git_connection_summary.py b/src/volcano_sdk/_generated/models/project_git_connection_summary.py
index 746925ee..0959eee0 100644
--- a/src/volcano_sdk/_generated/models/project_git_connection_summary.py
+++ b/src/volcano_sdk/_generated/models/project_git_connection_summary.py
@@ -29,7 +29,9 @@ class ProjectGitConnectionSummary:
repo_full_name (str):
root_directory (str):
production_branch (str):
- updated_at (datetime.datetime):
+ updated_at (datetime.datetime): When the connection last changed: its repository, root directory or production
+ branch. Naming the branch it already uses, and other changes to the project, leave it alone. A connection that
+ has not changed since Volcano began tracking this reports the project's last change before then.
"""
repo_installation_id: int
diff --git a/src/volcano_sdk/_generated/models/project_git_deploy_settings.py b/src/volcano_sdk/_generated/models/project_git_deploy_settings.py
index 33b56aff..3a2e2698 100644
--- a/src/volcano_sdk/_generated/models/project_git_deploy_settings.py
+++ b/src/volcano_sdk/_generated/models/project_git_deploy_settings.py
@@ -29,7 +29,19 @@ class ProjectGitDeploySettings:
Attributes:
auto_deploy_enabled (bool): Whether a production-branch push triggers a deployment.
deploy_functions (bool): Whether the repo's functions are deployed on push.
- updated_at (datetime.datetime):
+ apply_migrations (bool): Whether a push applies the commit's pending migrations, the SQL files under
+ volcano/migrations, before it deploys anything. Each database gets a migration run with source `git_deploy`;
+ when one fails, nothing from the push deploys and the live version keeps serving. A push starts a migration run
+ only while the project owner's account is `active`; otherwise it starts none, deploys nothing, and fails with
+ code `owner_not_active`. A run an earlier attempt of the push started before the account changed keeps its
+ outcome, but the push still deploys none of its code and fails with `owner_not_active`; its message says the
+ schema changes stay. Nothing retries that push; push again once the account is `active`, and that push skips the
+ migrations already applied. Reads back as saved even where the `databases.migrations` capability is unavailable;
+ there, a push whose commit has migrations deploys nothing.
+ updated_at (datetime.datetime): When the settings were last saved, or last changed by connecting a repository.
+ Other changes to the project leave it alone. Settings a connection turned on before Volcano began tracking this
+ report the project's last change before then; settings never saved or changed report when the project was
+ created.
frontend_name (str | Unset): Name of the frontend to build and deploy on push. Omitted when no frontend is
deployed. Resolved at deploy time; need not exist yet.
frontend_app_root (str | Unset): App root (subdirectory) the frontend builds from. Omitted for the repo root.
@@ -37,6 +49,7 @@ class ProjectGitDeploySettings:
auto_deploy_enabled: bool
deploy_functions: bool
+ apply_migrations: bool
updated_at: datetime.datetime
frontend_name: str | Unset = UNSET
frontend_app_root: str | Unset = UNSET
@@ -51,6 +64,8 @@ def to_dict(self) -> dict[str, Any]:
deploy_functions = self.deploy_functions
+ apply_migrations = self.apply_migrations
+
updated_at = self.updated_at.isoformat()
frontend_name = self.frontend_name
@@ -63,6 +78,7 @@ def to_dict(self) -> dict[str, Any]:
field_dict.update({
"auto_deploy_enabled": auto_deploy_enabled,
"deploy_functions": deploy_functions,
+ "apply_migrations": apply_migrations,
"updated_at": updated_at,
})
if frontend_name is not UNSET:
@@ -81,6 +97,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
deploy_functions = d.pop("deploy_functions")
+ apply_migrations = d.pop("apply_migrations")
+
updated_at = datetime.datetime.fromisoformat(d.pop("updated_at"))
@@ -93,6 +111,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
project_git_deploy_settings = cls(
auto_deploy_enabled=auto_deploy_enabled,
deploy_functions=deploy_functions,
+ apply_migrations=apply_migrations,
updated_at=updated_at,
frontend_name=frontend_name,
frontend_app_root=frontend_app_root,
diff --git a/src/volcano_sdk/_generated/models/project_git_owner_push.py b/src/volcano_sdk/_generated/models/project_git_owner_push.py
new file mode 100644
index 00000000..b33927b6
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/project_git_owner_push.py
@@ -0,0 +1,114 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.project_git_owner_push_reason import check_project_git_owner_push_reason
+from ..models.project_git_owner_push_reason import ProjectGitOwnerPushReason
+from ..types import UNSET, Unset
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="ProjectGitOwnerPush")
+
+
+
+@_attrs_define
+class ProjectGitOwnerPush:
+ """ Whether the project owner can push to the project's connected repository.
+
+ Attributes:
+ repository_id (int): Stable GitHub repository id of the connected repository, the `repo_id` of the project's git
+ connection.
+ can_push (bool): True when the project owner's GitHub account can push to the repository.
+ reason (ProjectGitOwnerPushReason | Unset): Why `can_push` is false; absent when it is true.
+ `owner_not_connected`: the owner has not connected a GitHub account. `owner_reconnect_required`: the owner's
+ GitHub connection expired or was revoked; the owner reconnects GitHub. `repository_access_lost`: the owner's
+ GitHub account can no longer see the repository. `no_push_permission`: the owner's GitHub account can read the
+ repository but not push to it.
+ """
+
+ repository_id: int
+ can_push: bool
+ reason: ProjectGitOwnerPushReason | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ repository_id = self.repository_id
+
+ can_push = self.can_push
+
+ reason: str | Unset = UNSET
+ if not isinstance(self.reason, Unset):
+ reason = self.reason
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "repository_id": repository_id,
+ "can_push": can_push,
+ })
+ if reason is not UNSET:
+ field_dict["reason"] = reason
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ repository_id = d.pop("repository_id")
+
+ can_push = d.pop("can_push")
+
+ _reason = d.pop("reason", UNSET)
+ reason: ProjectGitOwnerPushReason | Unset
+ if isinstance(_reason, Unset):
+ reason = UNSET
+ else:
+ reason = check_project_git_owner_push_reason(_reason)
+
+
+
+
+ project_git_owner_push = cls(
+ repository_id=repository_id,
+ can_push=can_push,
+ reason=reason,
+ )
+
+
+ project_git_owner_push.additional_properties = d
+ return project_git_owner_push
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/project_git_owner_push_reason.py b/src/volcano_sdk/_generated/models/project_git_owner_push_reason.py
new file mode 100644
index 00000000..ad7502bd
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/project_git_owner_push_reason.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+ProjectGitOwnerPushReason = Literal['no_push_permission', 'owner_not_connected', 'owner_reconnect_required', 'repository_access_lost']
+
+PROJECT_GIT_OWNER_PUSH_REASON_VALUES: set[ProjectGitOwnerPushReason] = { 'no_push_permission', 'owner_not_connected', 'owner_reconnect_required', 'repository_access_lost', }
+
+def check_project_git_owner_push_reason(value: str) -> ProjectGitOwnerPushReason:
+ if value in PROJECT_GIT_OWNER_PUSH_REASON_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {PROJECT_GIT_OWNER_PUSH_REASON_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/project_import_run.py b/src/volcano_sdk/_generated/models/project_import_run.py
index e37697ff..e5c7d3fa 100644
--- a/src/volcano_sdk/_generated/models/project_import_run.py
+++ b/src/volcano_sdk/_generated/models/project_import_run.py
@@ -41,7 +41,10 @@ class ProjectImportRun:
status (ProjectImportRunStatus):
created_at (datetime.datetime):
updated_at (datetime.datetime):
- error_code (str | Unset):
+ error_code (str | Unset): Set when `status` is `failed`: `import.deployment_skipped` when the import's
+ deployment was skipped, otherwise the error code of the Git deployment run the import started (see
+ `GitDeploymentRunError.code`), such as `source_invalid`, `deploy_refused`, `child_deploy_failed`,
+ `child_deploy_not_started`, or `deploy_failed`. Treat a code you do not know as a failure.
error_message (str | Unset):
"""
diff --git a/src/volcano_sdk/_generated/models/project_template_installation.py b/src/volcano_sdk/_generated/models/project_template_installation.py
index 211f658e..97dd13ca 100644
--- a/src/volcano_sdk/_generated/models/project_template_installation.py
+++ b/src/volcano_sdk/_generated/models/project_template_installation.py
@@ -12,8 +12,11 @@
from ..models.project_template_installation_phase import ProjectTemplateInstallationPhase
from ..models.project_template_installation_status import check_project_template_installation_status
from ..models.project_template_installation_status import ProjectTemplateInstallationStatus
+from ..types import UNSET, Unset
from typing import cast
+if TYPE_CHECKING:
+ from ..models.project_template_installation_source import ProjectTemplateInstallationSource
@@ -33,10 +36,34 @@ class ProjectTemplateInstallation:
Attributes:
status (ProjectTemplateInstallationStatus):
phase (ProjectTemplateInstallationPhase):
+ source (ProjectTemplateInstallationSource | Unset): The share release a fork was installed from.
+ failure_code (str | Unset): Why the installation failed. Present only when `status` is `failed`, and
+ absent for installations that failed before Volcano recorded a reason.
+ New codes can be added, so treat an unknown one as a generic failure.
+ `source_withdrawn`: the deploy link was switched off or deleted, or its
+ project is being deleted. `source_invalid`: the source failed Volcano's checks,
+ such as a release archive whose digest, size or contents are wrong.
+ `source_access_lost`: Volcano can no longer read the source repository.
+ `invalid_source_configuration`: the source's `volcano-config.yaml` is
+ invalid, or it declares a variable the new project does not have.
+ `nothing_to_deploy`: the source has no function or frontend.
+ `database_not_supported`: the source ships database SQL.
+ `function_deploy_refused`: a function in the source cannot be deployed
+ as defined. `function_quota_exceeded`,
+ `durable_function_quota_exceeded`, `frontend_quota_exceeded`,
+ `frontend_deploy_limit` and `build_minutes_exceeded`: the project
+ reached a plan limit. `build_failed`: a function or frontend from the
+ source failed to build or deploy; its deployment's build logs say why.
+ `retry_budget_exhausted`: the installation kept failing and Volcano
+ stopped retrying. `internal_error`: Volcano failed for a reason of its
+ own.
+ Example: source_withdrawn.
"""
status: ProjectTemplateInstallationStatus
phase: ProjectTemplateInstallationPhase
+ source: ProjectTemplateInstallationSource | Unset = UNSET
+ failure_code: str | Unset = UNSET
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
@@ -44,10 +71,17 @@ class ProjectTemplateInstallation:
def to_dict(self) -> dict[str, Any]:
+ from ..models.project_template_installation_source import ProjectTemplateInstallationSource # noqa: PLC0415
status: str = self.status
phase: str = self.phase
+ source: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.source, Unset):
+ source = self.source.to_dict()
+
+ failure_code = self.failure_code
+
field_dict: dict[str, Any] = {}
field_dict.update(self.additional_properties)
@@ -55,6 +89,10 @@ def to_dict(self) -> dict[str, Any]:
"status": status,
"phase": phase,
})
+ if source is not UNSET:
+ field_dict["source"] = source
+ if failure_code is not UNSET:
+ field_dict["failure_code"] = failure_code
return field_dict
@@ -62,6 +100,7 @@ def to_dict(self) -> dict[str, Any]:
@classmethod
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.project_template_installation_source import ProjectTemplateInstallationSource # noqa: PLC0415
d = dict(src_dict)
status = check_project_template_installation_status(d.pop("status"))
@@ -73,9 +112,23 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ _source = d.pop("source", UNSET)
+ source: ProjectTemplateInstallationSource | Unset
+ if isinstance(_source, Unset):
+ source = UNSET
+ else:
+ source = ProjectTemplateInstallationSource.from_dict(_source)
+
+
+
+
+ failure_code = d.pop("failure_code", UNSET)
+
project_template_installation = cls(
status=status,
phase=phase,
+ source=source,
+ failure_code=failure_code,
)
diff --git a/src/volcano_sdk/_generated/models/project_template_installation_source.py b/src/volcano_sdk/_generated/models/project_template_installation_source.py
new file mode 100644
index 00000000..c4fb8e2e
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/project_template_installation_source.py
@@ -0,0 +1,103 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.project_template_installation_source_kind import check_project_template_installation_source_kind
+from ..models.project_template_installation_source_kind import ProjectTemplateInstallationSourceKind
+from typing import cast
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="ProjectTemplateInstallationSource")
+
+
+
+@_attrs_define
+class ProjectTemplateInstallationSource:
+ """ The share release a fork was installed from.
+
+ Attributes:
+ kind (ProjectTemplateInstallationSourceKind):
+ share_id (str): The share the release belongs to.
+ release_id (UUID): The release the project was installed from.
+ """
+
+ kind: ProjectTemplateInstallationSourceKind
+ share_id: str
+ release_id: UUID
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ kind: str = self.kind
+
+ share_id = self.share_id
+
+ release_id = str(self.release_id)
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "kind": kind,
+ "share_id": share_id,
+ "release_id": release_id,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ kind = check_project_template_installation_source_kind(d.pop("kind"))
+
+
+
+
+ share_id = d.pop("share_id")
+
+ release_id = UUID(d.pop("release_id"))
+
+
+
+
+ project_template_installation_source = cls(
+ kind=kind,
+ share_id=share_id,
+ release_id=release_id,
+ )
+
+
+ project_template_installation_source.additional_properties = d
+ return project_template_installation_source
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/project_template_installation_source_kind.py b/src/volcano_sdk/_generated/models/project_template_installation_source_kind.py
new file mode 100644
index 00000000..ee1ce2e7
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/project_template_installation_source_kind.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+ProjectTemplateInstallationSourceKind = Literal['share_release']
+
+PROJECT_TEMPLATE_INSTALLATION_SOURCE_KIND_VALUES: set[ProjectTemplateInstallationSourceKind] = { 'share_release', }
+
+def check_project_template_installation_source_kind(value: str) -> ProjectTemplateInstallationSourceKind:
+ if value in PROJECT_TEMPLATE_INSTALLATION_SOURCE_KIND_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {PROJECT_TEMPLATE_INSTALLATION_SOURCE_KIND_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/promote_frontend_candidate_body.py b/src/volcano_sdk/_generated/models/promote_frontend_candidate_body.py
new file mode 100644
index 00000000..327d4d30
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/promote_frontend_candidate_body.py
@@ -0,0 +1,58 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="PromoteFrontendCandidateBody")
+
+
+
+@_attrs_define
+class PromoteFrontendCandidateBody:
+ """
+ Attributes:
+ expected_revision (int):
+ """
+
+ expected_revision: int
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ expected_revision = self.expected_revision
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "expected_revision": expected_revision,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ expected_revision = d.pop("expected_revision")
+
+ promote_frontend_candidate_body = cls(
+ expected_revision=expected_revision,
+ )
+
+ return promote_frontend_candidate_body
+
diff --git a/src/volcano_sdk/_generated/models/redeploy_frontend_candidate_body.py b/src/volcano_sdk/_generated/models/redeploy_frontend_candidate_body.py
new file mode 100644
index 00000000..45b615a7
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/redeploy_frontend_candidate_body.py
@@ -0,0 +1,101 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+import json
+from .. import types
+
+from ..types import UNSET, Unset
+
+from ..types import File, FileTypes
+from io import BytesIO
+
+
+
+
+
+
+T = TypeVar("T", bound="RedeployFrontendCandidateBody")
+
+
+
+@_attrs_define
+class RedeployFrontendCandidateBody:
+ """
+ Attributes:
+ archive (File): ZIP or tar.gz archive of the frontend project, as for creating a frontend.
+ """
+
+ archive: File
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ archive = self.archive.to_tuple()
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "archive": archive,
+ })
+
+ return field_dict
+
+
+ def to_multipart(self) -> types.RequestFiles:
+ files: types.RequestFiles = []
+
+ files.append(("archive", self.archive.to_tuple()))
+
+
+
+
+ for prop_name, prop in self.additional_properties.items():
+ files.append((prop_name, (None, str(prop).encode(), "text/plain")))
+
+
+
+ return files
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ archive = File(
+ payload = BytesIO(d.pop("archive"))
+ )
+
+
+
+
+ redeploy_frontend_candidate_body = cls(
+ archive=archive,
+ )
+
+
+ redeploy_frontend_candidate_body.additional_properties = d
+ return redeploy_frontend_candidate_body
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/resolve_function_response.py b/src/volcano_sdk/_generated/models/resolve_function_response.py
index e8596032..dbf47b51 100644
--- a/src/volcano_sdk/_generated/models/resolve_function_response.py
+++ b/src/volcano_sdk/_generated/models/resolve_function_response.py
@@ -28,9 +28,9 @@ class ResolveFunctionResponse:
function_id (UUID): Canonical function ID used for invocation routing
cache_ttl_seconds (int): Suggested SDK cache TTL for this name-to-ID mapping
invoke_url (str | Unset): Canonical HTTPS endpoint for invoking this function. Use it as-is: it does not share a
- domain with the API, so a host derived from the API URL will not reach the function. Omitted when the deployment
- serves no public invocation domain, as in local development; invoke through POST /functions/{functionId}/invoke
- instead.
+ domain with the API, so a host derived from the API URL will not reach the function. Omitted in local
+ development and when the deployment serves no public invocation domain; invoke through POST
+ /functions/{functionId}/invoke instead.
"""
name: str
diff --git a/src/volcano_sdk/_generated/models/rollback_frontend_serving_body.py b/src/volcano_sdk/_generated/models/rollback_frontend_serving_body.py
new file mode 100644
index 00000000..87a123f0
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/rollback_frontend_serving_body.py
@@ -0,0 +1,68 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+T = TypeVar("T", bound="RollbackFrontendServingBody")
+
+
+
+@_attrs_define
+class RollbackFrontendServingBody:
+ """
+ Attributes:
+ expected_revision (int):
+ to_production (bool | Unset): Return to the frontend's own runtime whatever it served before. Default: False.
+ """
+
+ expected_revision: int
+ to_production: bool | Unset = False
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ expected_revision = self.expected_revision
+
+ to_production = self.to_production
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "expected_revision": expected_revision,
+ })
+ if to_production is not UNSET:
+ field_dict["to_production"] = to_production
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ expected_revision = d.pop("expected_revision")
+
+ to_production = d.pop("to_production", UNSET)
+
+ rollback_frontend_serving_body = cls(
+ expected_revision=expected_revision,
+ to_production=to_production,
+ )
+
+ return rollback_frontend_serving_body
+
diff --git a/src/volcano_sdk/_generated/models/sandbox_command_request.py b/src/volcano_sdk/_generated/models/sandbox_command_request.py
index 7c8e31dc..4c4ece6a 100644
--- a/src/volcano_sdk/_generated/models/sandbox_command_request.py
+++ b/src/volcano_sdk/_generated/models/sandbox_command_request.py
@@ -32,11 +32,19 @@ class SandboxCommandRequest:
precedence. Cloud synchronous requests must return within the public connection idle limit (1000 seconds); use a
session with a background process and short polling requests for longer work.
environment (SandboxCommandRequestEnvironment | Unset):
+ keep_output (bool | Unset): Set false to keep no output. stdout and stderr are returned once in this response,
+ and Volcano's control plane never stores them in the execution journal, database, logs or traces. This does not
+ cover the Sandbox's memory or a suspended session's snapshot. A retry with the same Idempotency-Key returns the
+ exit code with `output_kept` false and empty streams, without running the command again. Omit it to use the
+ session's `executions.keep_output`. True in a session that keeps no output is refused with 400 and code
+ `sandbox_session_keeps_no_output`. False is refused with 400 and code `feature_unavailable` while the
+ `sandboxes.output_not_kept` capability is unavailable.
"""
command: str
timeout_seconds: int | Unset = UNSET
environment: SandboxCommandRequestEnvironment | Unset = UNSET
+ keep_output: bool | Unset = UNSET
@@ -52,6 +60,8 @@ def to_dict(self) -> dict[str, Any]:
if not isinstance(self.environment, Unset):
environment = self.environment.to_dict()
+ keep_output = self.keep_output
+
field_dict: dict[str, Any] = {}
@@ -62,6 +72,8 @@ def to_dict(self) -> dict[str, Any]:
field_dict["timeout_seconds"] = timeout_seconds
if environment is not UNSET:
field_dict["environment"] = environment
+ if keep_output is not UNSET:
+ field_dict["keep_output"] = keep_output
return field_dict
@@ -85,10 +97,13 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ keep_output = d.pop("keep_output", UNSET)
+
sandbox_command_request = cls(
command=command,
timeout_seconds=timeout_seconds,
environment=environment,
+ keep_output=keep_output,
)
return sandbox_command_request
diff --git a/src/volcano_sdk/_generated/models/sandbox_command_result.py b/src/volcano_sdk/_generated/models/sandbox_command_result.py
index 60d05f3e..18c28226 100644
--- a/src/volcano_sdk/_generated/models/sandbox_command_result.py
+++ b/src/volcano_sdk/_generated/models/sandbox_command_result.py
@@ -22,12 +22,20 @@
class SandboxCommandResult:
"""
Attributes:
- stdout (str):
- stderr (str):
+ stdout (str): The first 1 MiB (1,048,576 bytes) the command wrote to stdout. Empty in a replay of a command that
+ kept no output.
+ stderr (str): The first 1 MiB (1,048,576 bytes) the command wrote to stderr. Empty in a replay of a command that
+ kept no output.
exit_code (int):
- stdout_truncated (bool):
- stderr_truncated (bool):
+ stdout_truncated (bool): True when the command wrote more than 1 MiB to stdout. False in a replay of a command
+ that kept no output.
+ stderr_truncated (bool): True when the command wrote more than 1 MiB to stderr. False in a replay of a command
+ that kept no output.
timed_out (bool):
+ output_kept (bool): False when the command kept no output. Its streams appear only in the response to the
+ request that ran it, and Volcano's control plane never stores them in the execution journal, database, logs or
+ traces. This does not cover the Sandbox's memory or a suspended session's snapshot. A retry with the same
+ Idempotency-Key returns them empty.
"""
stdout: str
@@ -36,6 +44,7 @@ class SandboxCommandResult:
stdout_truncated: bool
stderr_truncated: bool
timed_out: bool
+ output_kept: bool
@@ -54,6 +63,8 @@ def to_dict(self) -> dict[str, Any]:
timed_out = self.timed_out
+ output_kept = self.output_kept
+
field_dict: dict[str, Any] = {}
@@ -64,6 +75,7 @@ def to_dict(self) -> dict[str, Any]:
"stdout_truncated": stdout_truncated,
"stderr_truncated": stderr_truncated,
"timed_out": timed_out,
+ "output_kept": output_kept,
})
return field_dict
@@ -85,6 +97,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
timed_out = d.pop("timed_out")
+ output_kept = d.pop("output_kept")
+
sandbox_command_result = cls(
stdout=stdout,
stderr=stderr,
@@ -92,6 +106,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
stdout_truncated=stdout_truncated,
stderr_truncated=stderr_truncated,
timed_out=timed_out,
+ output_kept=output_kept,
)
return sandbox_command_result
diff --git a/src/volcano_sdk/_generated/models/sandbox_execution_result.py b/src/volcano_sdk/_generated/models/sandbox_execution_result.py
index ce8174c2..4b234340 100644
--- a/src/volcano_sdk/_generated/models/sandbox_execution_result.py
+++ b/src/volcano_sdk/_generated/models/sandbox_execution_result.py
@@ -23,12 +23,20 @@
class SandboxExecutionResult:
"""
Attributes:
- stdout (str):
- stderr (str):
+ stdout (str): The first 1 MiB (1,048,576 bytes) the command wrote to stdout. Empty in a replay of a command that
+ kept no output.
+ stderr (str): The first 1 MiB (1,048,576 bytes) the command wrote to stderr. Empty in a replay of a command that
+ kept no output.
exit_code (int):
- stdout_truncated (bool):
- stderr_truncated (bool):
+ stdout_truncated (bool): True when the command wrote more than 1 MiB to stdout. False in a replay of a command
+ that kept no output.
+ stderr_truncated (bool): True when the command wrote more than 1 MiB to stderr. False in a replay of a command
+ that kept no output.
timed_out (bool):
+ output_kept (bool): False when the command kept no output. Its streams appear only in the response to the
+ request that ran it, and Volcano's control plane never stores them in the execution journal, database, logs or
+ traces. This does not cover the Sandbox's memory or a suspended session's snapshot. A retry with the same
+ Idempotency-Key returns them empty.
session_id (UUID):
region (str):
duration_ms (int):
@@ -40,6 +48,7 @@ class SandboxExecutionResult:
stdout_truncated: bool
stderr_truncated: bool
timed_out: bool
+ output_kept: bool
session_id: UUID
region: str
duration_ms: int
@@ -61,6 +70,8 @@ def to_dict(self) -> dict[str, Any]:
timed_out = self.timed_out
+ output_kept = self.output_kept
+
session_id = str(self.session_id)
region = self.region
@@ -77,6 +88,7 @@ def to_dict(self) -> dict[str, Any]:
"stdout_truncated": stdout_truncated,
"stderr_truncated": stderr_truncated,
"timed_out": timed_out,
+ "output_kept": output_kept,
"session_id": session_id,
"region": region,
"duration_ms": duration_ms,
@@ -101,6 +113,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
timed_out = d.pop("timed_out")
+ output_kept = d.pop("output_kept")
+
session_id = UUID(d.pop("session_id"))
@@ -117,6 +131,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
stdout_truncated=stdout_truncated,
stderr_truncated=stderr_truncated,
timed_out=timed_out,
+ output_kept=output_kept,
session_id=session_id,
region=region,
duration_ms=duration_ms,
diff --git a/src/volcano_sdk/_generated/models/sandbox_file_archive.py b/src/volcano_sdk/_generated/models/sandbox_file_archive.py
new file mode 100644
index 00000000..a505fb47
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/sandbox_file_archive.py
@@ -0,0 +1,96 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="SandboxFileArchive")
+
+
+
+@_attrs_define
+class SandboxFileArchive:
+ """
+ Attributes:
+ project_id (UUID):
+ session_id (UUID):
+ path (str):
+ files (int): Regular files written.
+ bytes_ (int): Bytes of file content written.
+ """
+
+ project_id: UUID
+ session_id: UUID
+ path: str
+ files: int
+ bytes_: int
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ project_id = str(self.project_id)
+
+ session_id = str(self.session_id)
+
+ path = self.path
+
+ files = self.files
+
+ bytes_ = self.bytes_
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "project_id": project_id,
+ "session_id": session_id,
+ "path": path,
+ "files": files,
+ "bytes": bytes_,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ session_id = UUID(d.pop("session_id"))
+
+
+
+
+ path = d.pop("path")
+
+ files = d.pop("files")
+
+ bytes_ = d.pop("bytes")
+
+ sandbox_file_archive = cls(
+ project_id=project_id,
+ session_id=session_id,
+ path=path,
+ files=files,
+ bytes_=bytes_,
+ )
+
+ return sandbox_file_archive
diff --git a/src/volcano_sdk/_generated/models/sandbox_file_archive_form.py b/src/volcano_sdk/_generated/models/sandbox_file_archive_form.py
new file mode 100644
index 00000000..318b10cc
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/sandbox_file_archive_form.py
@@ -0,0 +1,147 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+import json
+from .. import types
+
+from ..types import UNSET, Unset
+
+from ..types import File, FileTypes
+from io import BytesIO
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="SandboxFileArchiveForm")
+
+
+
+@_attrs_define
+class SandboxFileArchiveForm:
+ """ Send `project_id`, `session_id` and `path`, in any order, then the `archive` part.
+
+ Attributes:
+ project_id (UUID):
+ session_id (UUID):
+ path (str): Workspace directory to extract into, relative to `/workspace`. It must name a directory below the
+ workspace root; a path that resolves to the root or to `/`, such as `.`, `./`, `/`, `/workspace` or
+ `/workspace/.`, is refused.
+ archive (File): A tar archive, optionally gzip-compressed.
+ """
+
+ project_id: UUID
+ session_id: UUID
+ path: str
+ archive: File
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ project_id = str(self.project_id)
+
+ session_id = str(self.session_id)
+
+ path = self.path
+
+ archive = self.archive.to_tuple()
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "project_id": project_id,
+ "session_id": session_id,
+ "path": path,
+ "archive": archive,
+ })
+
+ return field_dict
+
+
+ def to_multipart(self) -> types.RequestFiles:
+ files: types.RequestFiles = []
+
+ files.append(("project_id", (None, str(self.project_id), "text/plain")))
+
+
+
+ files.append(("session_id", (None, str(self.session_id), "text/plain")))
+
+
+
+ files.append(("path", (None, str(self.path).encode(), "text/plain")))
+
+
+
+ files.append(("archive", self.archive.to_tuple()))
+
+
+
+
+ for prop_name, prop in self.additional_properties.items():
+ files.append((prop_name, (None, str(prop).encode(), "text/plain")))
+
+
+
+ return files
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ session_id = UUID(d.pop("session_id"))
+
+
+
+
+ path = d.pop("path")
+
+ archive = File(
+ payload = BytesIO(d.pop("archive"))
+ )
+
+
+
+
+ sandbox_file_archive_form = cls(
+ project_id=project_id,
+ session_id=session_id,
+ path=path,
+ archive=archive,
+ )
+
+
+ sandbox_file_archive_form.additional_properties = d
+ return sandbox_file_archive_form
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/sandbox_file_entry.py b/src/volcano_sdk/_generated/models/sandbox_file_entry.py
new file mode 100644
index 00000000..e333ebc7
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/sandbox_file_entry.py
@@ -0,0 +1,146 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.sandbox_file_entry_sha_256_skipped import check_sandbox_file_entry_sha_256_skipped
+from ..models.sandbox_file_entry_sha_256_skipped import SandboxFileEntrySha256Skipped
+from ..models.sandbox_file_entry_type import check_sandbox_file_entry_type
+from ..models.sandbox_file_entry_type import SandboxFileEntryType
+from ..types import UNSET, Unset
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="SandboxFileEntry")
+
+
+
+@_attrs_define
+class SandboxFileEntry:
+ """
+ Attributes:
+ path (str): Path relative to the workspace root, usable with the read and write file routes.
+ type_ (SandboxFileEntryType): Entry type from the entry itself. A symlink is reported, never followed.
+ size (int): Size in bytes of a regular file; 0 for every other type.
+ mode (int): Permission bits, including setuid, setgid and sticky (`st_mode & 07777`). For example, 420 is `0644`
+ and 493 is `0755`.
+ sha256 (str | Unset): Lowercase hex SHA-256 of a regular file's content, present only when `include_sha256` is
+ true and the file could be hashed.
+ sha256_skipped (SandboxFileEntrySha256Skipped | Unset): Why a regular file has no `sha256` when `include_sha256`
+ is true. `budget` is a file over 256 MiB. `changing` is a file that changed while it was hashed or kept
+ changing; list it again later. `unreadable` is a file the session user doesn't own, whose owner-read bit
+ (`0400`) is clear, or that has more than one hard link. Treat such a file as unverified.
+ unreadable (bool | Unset): True on a directory the session user can't list; the listing doesn't enter it. The
+ user's permission bits on the directory lack read or execute: the owner bits when the user owns it, the group
+ bits when it belongs to the user's group, and the other bits otherwise. Absent on every other entry.
+ unsupported_names (int | Unset): In a recursive listing, how many names directly inside this directory no entry
+ can carry: names that are not UTF-8, or whose path would pass 4096 bytes. The listing skips them and everything
+ below them. Absent when there are none.
+ """
+
+ path: str
+ type_: SandboxFileEntryType
+ size: int
+ mode: int
+ sha256: str | Unset = UNSET
+ sha256_skipped: SandboxFileEntrySha256Skipped | Unset = UNSET
+ unreadable: bool | Unset = UNSET
+ unsupported_names: int | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ path = self.path
+
+ type_: str = self.type_
+
+ size = self.size
+
+ mode = self.mode
+
+ sha256 = self.sha256
+
+ sha256_skipped: str | Unset = UNSET
+ if not isinstance(self.sha256_skipped, Unset):
+ sha256_skipped = self.sha256_skipped
+
+
+ unreadable = self.unreadable
+
+ unsupported_names = self.unsupported_names
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "path": path,
+ "type": type_,
+ "size": size,
+ "mode": mode,
+ })
+ if sha256 is not UNSET:
+ field_dict["sha256"] = sha256
+ if sha256_skipped is not UNSET:
+ field_dict["sha256_skipped"] = sha256_skipped
+ if unreadable is not UNSET:
+ field_dict["unreadable"] = unreadable
+ if unsupported_names is not UNSET:
+ field_dict["unsupported_names"] = unsupported_names
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ path = d.pop("path")
+
+ type_ = check_sandbox_file_entry_type(d.pop("type"))
+
+
+
+
+ size = d.pop("size")
+
+ mode = d.pop("mode")
+
+ sha256 = d.pop("sha256", UNSET)
+
+ _sha256_skipped = d.pop("sha256_skipped", UNSET)
+ sha256_skipped: SandboxFileEntrySha256Skipped | Unset
+ if isinstance(_sha256_skipped, Unset):
+ sha256_skipped = UNSET
+ else:
+ sha256_skipped = check_sandbox_file_entry_sha_256_skipped(_sha256_skipped)
+
+
+
+
+ unreadable = d.pop("unreadable", UNSET)
+
+ unsupported_names = d.pop("unsupported_names", UNSET)
+
+ sandbox_file_entry = cls(
+ path=path,
+ type_=type_,
+ size=size,
+ mode=mode,
+ sha256=sha256,
+ sha256_skipped=sha256_skipped,
+ unreadable=unreadable,
+ unsupported_names=unsupported_names,
+ )
+
+ return sandbox_file_entry
diff --git a/src/volcano_sdk/_generated/models/sandbox_file_entry_sha_256_skipped.py b/src/volcano_sdk/_generated/models/sandbox_file_entry_sha_256_skipped.py
new file mode 100644
index 00000000..38b0fe78
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/sandbox_file_entry_sha_256_skipped.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+SandboxFileEntrySha256Skipped = Literal['budget', 'changing', 'unreadable']
+
+SANDBOX_FILE_ENTRY_SHA_256_SKIPPED_VALUES: set[SandboxFileEntrySha256Skipped] = { 'budget', 'changing', 'unreadable', }
+
+def check_sandbox_file_entry_sha_256_skipped(value: str) -> SandboxFileEntrySha256Skipped:
+ if value in SANDBOX_FILE_ENTRY_SHA_256_SKIPPED_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {SANDBOX_FILE_ENTRY_SHA_256_SKIPPED_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/sandbox_file_entry_type.py b/src/volcano_sdk/_generated/models/sandbox_file_entry_type.py
new file mode 100644
index 00000000..5cff4d9b
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/sandbox_file_entry_type.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+SandboxFileEntryType = Literal['directory', 'file', 'other', 'symlink']
+
+SANDBOX_FILE_ENTRY_TYPE_VALUES: set[SandboxFileEntryType] = { 'directory', 'file', 'other', 'symlink', }
+
+def check_sandbox_file_entry_type(value: str) -> SandboxFileEntryType:
+ if value in SANDBOX_FILE_ENTRY_TYPE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {SANDBOX_FILE_ENTRY_TYPE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/sandbox_file_list_result.py b/src/volcano_sdk/_generated/models/sandbox_file_list_result.py
new file mode 100644
index 00000000..57519a58
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/sandbox_file_list_result.py
@@ -0,0 +1,120 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+if TYPE_CHECKING:
+ from ..models.sandbox_file_entry import SandboxFileEntry
+
+
+
+
+
+T = TypeVar("T", bound="SandboxFileListResult")
+
+
+
+@_attrs_define
+class SandboxFileListResult:
+ """
+ Attributes:
+ project_id (UUID): The project the session belongs to.
+ session_id (UUID): The session listed.
+ entries (list[SandboxFileEntry]): Entries sorted by path, compared one path element at a time by bytes, so a
+ directory comes right before its contents.
+ unsupported_names (int | Unset): How many names directly inside the listed directory no entry can carry: names
+ that are not UTF-8, or whose path would pass 4096 bytes. The listing skips them and everything below them. Every
+ page reports it. Absent when there are none.
+ next_cursor (str | Unset): Present when more entries remain. Pass it as `cursor` to get the next page.
+ """
+
+ project_id: UUID
+ session_id: UUID
+ entries: list[SandboxFileEntry]
+ unsupported_names: int | Unset = UNSET
+ next_cursor: str | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.sandbox_file_entry import SandboxFileEntry # noqa: PLC0415
+ project_id = str(self.project_id)
+
+ session_id = str(self.session_id)
+
+ entries = []
+ for entries_item_data in self.entries:
+ entries_item = entries_item_data.to_dict()
+ entries.append(entries_item)
+
+
+
+ unsupported_names = self.unsupported_names
+
+ next_cursor = self.next_cursor
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "project_id": project_id,
+ "session_id": session_id,
+ "entries": entries,
+ })
+ if unsupported_names is not UNSET:
+ field_dict["unsupported_names"] = unsupported_names
+ if next_cursor is not UNSET:
+ field_dict["next_cursor"] = next_cursor
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.sandbox_file_entry import SandboxFileEntry # noqa: PLC0415
+ d = dict(src_dict)
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ session_id = UUID(d.pop("session_id"))
+
+
+
+
+ entries = []
+ _entries = d.pop("entries")
+ for entries_item_data in (_entries):
+ entries_item = SandboxFileEntry.from_dict(entries_item_data)
+
+
+
+ entries.append(entries_item)
+
+
+ unsupported_names = d.pop("unsupported_names", UNSET)
+
+ next_cursor = d.pop("next_cursor", UNSET)
+
+ sandbox_file_list_result = cls(
+ project_id=project_id,
+ session_id=session_id,
+ entries=entries,
+ unsupported_names=unsupported_names,
+ next_cursor=next_cursor,
+ )
+
+ return sandbox_file_list_result
diff --git a/src/volcano_sdk/_generated/models/sandbox_file_part.py b/src/volcano_sdk/_generated/models/sandbox_file_part.py
new file mode 100644
index 00000000..f30b4afe
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/sandbox_file_part.py
@@ -0,0 +1,112 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="SandboxFilePart")
+
+
+
+@_attrs_define
+class SandboxFilePart:
+ """
+ Attributes:
+ project_id (UUID):
+ session_id (UUID):
+ path (str):
+ offset (int):
+ size (int):
+ received (int): Bytes of the file received through the end of this part.
+ complete (bool): True when this part finished the file and it is now at `path`.
+ """
+
+ project_id: UUID
+ session_id: UUID
+ path: str
+ offset: int
+ size: int
+ received: int
+ complete: bool
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ project_id = str(self.project_id)
+
+ session_id = str(self.session_id)
+
+ path = self.path
+
+ offset = self.offset
+
+ size = self.size
+
+ received = self.received
+
+ complete = self.complete
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "project_id": project_id,
+ "session_id": session_id,
+ "path": path,
+ "offset": offset,
+ "size": size,
+ "received": received,
+ "complete": complete,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ session_id = UUID(d.pop("session_id"))
+
+
+
+
+ path = d.pop("path")
+
+ offset = d.pop("offset")
+
+ size = d.pop("size")
+
+ received = d.pop("received")
+
+ complete = d.pop("complete")
+
+ sandbox_file_part = cls(
+ project_id=project_id,
+ session_id=session_id,
+ path=path,
+ offset=offset,
+ size=size,
+ received=received,
+ complete=complete,
+ )
+
+ return sandbox_file_part
diff --git a/src/volcano_sdk/_generated/models/sandbox_file_part_request.py b/src/volcano_sdk/_generated/models/sandbox_file_part_request.py
new file mode 100644
index 00000000..150e0222
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/sandbox_file_part_request.py
@@ -0,0 +1,112 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="SandboxFilePartRequest")
+
+
+
+@_attrs_define
+class SandboxFilePartRequest:
+ """
+ Attributes:
+ project_id (UUID):
+ session_id (UUID):
+ path (str): Workspace file to write, relative to `/workspace`.
+ offset (int): Byte offset of this part's data in the file.
+ size (int): Size of the whole file in bytes, at most 1 GiB.
+ sha256 (str): Lowercase hex SHA-256 of the whole file.
+ data (str): This part's bytes, at most 8 MiB.
+ """
+
+ project_id: UUID
+ session_id: UUID
+ path: str
+ offset: int
+ size: int
+ sha256: str
+ data: str
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ project_id = str(self.project_id)
+
+ session_id = str(self.session_id)
+
+ path = self.path
+
+ offset = self.offset
+
+ size = self.size
+
+ sha256 = self.sha256
+
+ data = self.data
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "project_id": project_id,
+ "session_id": session_id,
+ "path": path,
+ "offset": offset,
+ "size": size,
+ "sha256": sha256,
+ "data": data,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ session_id = UUID(d.pop("session_id"))
+
+
+
+
+ path = d.pop("path")
+
+ offset = d.pop("offset")
+
+ size = d.pop("size")
+
+ sha256 = d.pop("sha256")
+
+ data = d.pop("data")
+
+ sandbox_file_part_request = cls(
+ project_id=project_id,
+ session_id=session_id,
+ path=path,
+ offset=offset,
+ size=size,
+ sha256=sha256,
+ data=data,
+ )
+
+ return sandbox_file_part_request
diff --git a/src/volcano_sdk/_generated/models/sandbox_limits_applied.py b/src/volcano_sdk/_generated/models/sandbox_limits_applied.py
new file mode 100644
index 00000000..173d0d0f
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/sandbox_limits_applied.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+SandboxLimitsApplied = Literal['enforced', 'not_enforced', 'unknown']
+
+SANDBOX_LIMITS_APPLIED_VALUES: set[SandboxLimitsApplied] = { 'enforced', 'not_enforced', 'unknown', }
+
+def check_sandbox_limits_applied(value: str) -> SandboxLimitsApplied:
+ if value in SANDBOX_LIMITS_APPLIED_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {SANDBOX_LIMITS_APPLIED_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/sandbox_session.py b/src/volcano_sdk/_generated/models/sandbox_session.py
index 9cc9b99e..9f4e95b4 100644
--- a/src/volcano_sdk/_generated/models/sandbox_session.py
+++ b/src/volcano_sdk/_generated/models/sandbox_session.py
@@ -17,6 +17,10 @@
from uuid import UUID
import datetime
+if TYPE_CHECKING:
+ from ..models.sandbox_session_applied_limits import SandboxSessionAppliedLimits
+ from ..models.sandbox_session_executions import SandboxSessionExecutions
+ from ..models.sandbox_session_network import SandboxSessionNetwork
@@ -40,7 +44,19 @@ class SandboxSession:
memory_mb (int):
created_at (datetime.datetime):
expires_at (datetime.datetime | None): Absolute VM expiry. Null means unlimited in local mode.
+ network (SandboxSessionNetwork):
+ executions (SandboxSessionExecutions): How the session's command executions are kept. Fixed when the session is
+ created.
+ last_error_code (str | Unset): Last recorded lifecycle reason, such as sandbox_run_hook_timeout or
+ sandbox_authority_or_expiry. Historical information, not a current error; use state for the current session
+ state. Retained when later observations supply no reason, including after termination or recovery. Omitted when
+ no reason is known. Values may be added; this field does not imply whether a command ran or whether it can be
+ retried.
started_at (datetime.datetime | Unset):
+ limits (SandboxSessionAppliedLimits | Unset): The caps the session enforces, as the session reports them.
+ Present only
+ when the session was created with `limits`. The session stays
+ `starting` until `applied` is known.
"""
id: UUID
@@ -52,13 +68,20 @@ class SandboxSession:
memory_mb: int
created_at: datetime.datetime
expires_at: datetime.datetime | None
+ network: SandboxSessionNetwork
+ executions: SandboxSessionExecutions
+ last_error_code: str | Unset = UNSET
started_at: datetime.datetime | Unset = UNSET
+ limits: SandboxSessionAppliedLimits | Unset = UNSET
def to_dict(self) -> dict[str, Any]:
+ from ..models.sandbox_session_applied_limits import SandboxSessionAppliedLimits # noqa: PLC0415
+ from ..models.sandbox_session_executions import SandboxSessionExecutions # noqa: PLC0415
+ from ..models.sandbox_session_network import SandboxSessionNetwork # noqa: PLC0415
id = str(self.id)
project_id = str(self.project_id)
@@ -85,10 +108,20 @@ def to_dict(self) -> dict[str, Any]:
else:
expires_at = self.expires_at
+ network = self.network.to_dict()
+
+ executions = self.executions.to_dict()
+
+ last_error_code = self.last_error_code
+
started_at: str | Unset = UNSET
if not isinstance(self.started_at, Unset):
started_at = self.started_at.isoformat()
+ limits: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.limits, Unset):
+ limits = self.limits.to_dict()
+
field_dict: dict[str, Any] = {}
@@ -102,9 +135,15 @@ def to_dict(self) -> dict[str, Any]:
"memory_mb": memory_mb,
"created_at": created_at,
"expires_at": expires_at,
+ "network": network,
+ "executions": executions,
})
+ if last_error_code is not UNSET:
+ field_dict["last_error_code"] = last_error_code
if started_at is not UNSET:
field_dict["started_at"] = started_at
+ if limits is not UNSET:
+ field_dict["limits"] = limits
return field_dict
@@ -112,6 +151,9 @@ def to_dict(self) -> dict[str, Any]:
@classmethod
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.sandbox_session_applied_limits import SandboxSessionAppliedLimits # noqa: PLC0415
+ from ..models.sandbox_session_executions import SandboxSessionExecutions # noqa: PLC0415
+ from ..models.sandbox_session_network import SandboxSessionNetwork # noqa: PLC0415
d = dict(src_dict)
id = UUID(d.pop("id"))
@@ -178,6 +220,18 @@ def _parse_expires_at(data: object) -> datetime.datetime | None:
expires_at = _parse_expires_at(d.pop("expires_at"))
+ network = SandboxSessionNetwork.from_dict(d.pop("network"))
+
+
+
+
+ executions = SandboxSessionExecutions.from_dict(d.pop("executions"))
+
+
+
+
+ last_error_code = d.pop("last_error_code", UNSET)
+
_started_at = d.pop("started_at", UNSET)
started_at: datetime.datetime | Unset
if isinstance(_started_at, Unset):
@@ -188,6 +242,16 @@ def _parse_expires_at(data: object) -> datetime.datetime | None:
+ _limits = d.pop("limits", UNSET)
+ limits: SandboxSessionAppliedLimits | Unset
+ if isinstance(_limits, Unset):
+ limits = UNSET
+ else:
+ limits = SandboxSessionAppliedLimits.from_dict(_limits)
+
+
+
+
sandbox_session = cls(
id=id,
project_id=project_id,
@@ -198,7 +262,11 @@ def _parse_expires_at(data: object) -> datetime.datetime | None:
memory_mb=memory_mb,
created_at=created_at,
expires_at=expires_at,
+ network=network,
+ executions=executions,
+ last_error_code=last_error_code,
started_at=started_at,
+ limits=limits,
)
return sandbox_session
diff --git a/src/volcano_sdk/_generated/models/sandbox_session_applied_limits.py b/src/volcano_sdk/_generated/models/sandbox_session_applied_limits.py
new file mode 100644
index 00000000..d2a1cea4
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/sandbox_session_applied_limits.py
@@ -0,0 +1,89 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.sandbox_limits_applied import check_sandbox_limits_applied
+from ..models.sandbox_limits_applied import SandboxLimitsApplied
+from ..types import UNSET, Unset
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="SandboxSessionAppliedLimits")
+
+
+
+@_attrs_define
+class SandboxSessionAppliedLimits:
+ """ The caps the session enforces, as the session reports them. Present only
+ when the session was created with `limits`. The session stays
+ `starting` until `applied` is known.
+
+ Attributes:
+ applied (SandboxLimitsApplied): `enforced` when every requested cap is enforced, `not_enforced` when the
+ session could not enforce them, and `unknown` until the session reports.
+ Terminate a session that reports anything but `enforced` if you rely on
+ the caps.
+ vcpus (int | Unset): Enforced vCPU cap. Never higher than requested; lower when the session has fewer vCPUs.
+ disk_mib (int | Unset): Enforced disk cap in MiB. Never higher than requested; lower when the session's disk has
+ less free space.
+ """
+
+ applied: SandboxLimitsApplied
+ vcpus: int | Unset = UNSET
+ disk_mib: int | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ applied: str = self.applied
+
+ vcpus = self.vcpus
+
+ disk_mib = self.disk_mib
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "applied": applied,
+ })
+ if vcpus is not UNSET:
+ field_dict["vcpus"] = vcpus
+ if disk_mib is not UNSET:
+ field_dict["disk_mib"] = disk_mib
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ applied = check_sandbox_limits_applied(d.pop("applied"))
+
+
+
+
+ vcpus = d.pop("vcpus", UNSET)
+
+ disk_mib = d.pop("disk_mib", UNSET)
+
+ sandbox_session_applied_limits = cls(
+ applied=applied,
+ vcpus=vcpus,
+ disk_mib=disk_mib,
+ )
+
+ return sandbox_session_applied_limits
diff --git a/src/volcano_sdk/_generated/models/sandbox_session_executions.py b/src/volcano_sdk/_generated/models/sandbox_session_executions.py
new file mode 100644
index 00000000..9365a709
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/sandbox_session_executions.py
@@ -0,0 +1,63 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="SandboxSessionExecutions")
+
+
+
+@_attrs_define
+class SandboxSessionExecutions:
+ """ How the session's command executions are kept. Fixed when the session is created.
+
+ Attributes:
+ keep_output (bool): When false, every command in the session keeps no output. stdout and stderr are returned
+ once in the command's response, and Volcano's control plane never stores them in the execution journal,
+ database, logs or traces. This does not cover the Sandbox's memory or a suspended session's snapshot. A retry
+ with the same Idempotency-Key returns the exit code with empty streams. A command in such a session that sets
+ `keep_output` to true is refused with 400 and code `sandbox_session_keeps_no_output`. False is refused with 400
+ and code `feature_unavailable` while the `sandboxes.output_not_kept` capability is unavailable.
+ """
+
+ keep_output: bool
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ keep_output = self.keep_output
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "keep_output": keep_output,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ keep_output = d.pop("keep_output")
+
+ sandbox_session_executions = cls(
+ keep_output=keep_output,
+ )
+
+ return sandbox_session_executions
diff --git a/src/volcano_sdk/_generated/models/sandbox_session_limits.py b/src/volcano_sdk/_generated/models/sandbox_session_limits.py
new file mode 100644
index 00000000..74e77210
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/sandbox_session_limits.py
@@ -0,0 +1,76 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+T = TypeVar("T", bound="SandboxSessionLimits")
+
+
+
+@_attrs_define
+class SandboxSessionLimits:
+ """ Caps the session's code runs under, enforced inside the session. Each
+ cap is an upper bound; the session's own size still bounds both.
+
+ Attributes:
+ vcpus (int | Unset): CPU time the session's commands and template service may use
+ together, in vCPUs. A 1024 MiB session has 2 vCPUs and a 2048 MiB
+ session has 4; asking for more answers 400 with code
+ `sandbox_limits_exceed_session`.
+ disk_mib (int | Unset): Space the session can write beyond its image's contents, in MiB.
+ It covers every path commands and the template service can write,
+ including `/workspace` and `/tmp`. A write past it fails with
+ `ENOSPC`. `/dev/shm` is memory, capped separately at 64 MiB.
+ """
+
+ vcpus: int | Unset = UNSET
+ disk_mib: int | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ vcpus = self.vcpus
+
+ disk_mib = self.disk_mib
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ })
+ if vcpus is not UNSET:
+ field_dict["vcpus"] = vcpus
+ if disk_mib is not UNSET:
+ field_dict["disk_mib"] = disk_mib
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ vcpus = d.pop("vcpus", UNSET)
+
+ disk_mib = d.pop("disk_mib", UNSET)
+
+ sandbox_session_limits = cls(
+ vcpus=vcpus,
+ disk_mib=disk_mib,
+ )
+
+ return sandbox_session_limits
diff --git a/src/volcano_sdk/_generated/models/sandbox_session_network.py b/src/volcano_sdk/_generated/models/sandbox_session_network.py
new file mode 100644
index 00000000..dce4c786
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/sandbox_session_network.py
@@ -0,0 +1,84 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.sandbox_session_network_applied import check_sandbox_session_network_applied
+from ..models.sandbox_session_network_applied import SandboxSessionNetworkApplied
+from ..models.sandbox_session_network_egress import check_sandbox_session_network_egress
+from ..models.sandbox_session_network_egress import SandboxSessionNetworkEgress
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="SandboxSessionNetwork")
+
+
+
+@_attrs_define
+class SandboxSessionNetwork:
+ """
+ Attributes:
+ egress (SandboxSessionNetworkEgress): The outbound network policy the session was created with. It never
+ changes.
+ applied (SandboxSessionNetworkApplied): The outbound network policy Volcano last observed on the session's VM,
+ never the request alone. It is `unknown` until the session is first observed, from a suspend or resume request
+ until it is observed again, briefly while Volcano rolls out an update, and whenever the observation does not
+ match the request. A terminated session keeps what Volcano last observed, so a `deny_all` session ended because
+ Volcano observed outbound access reads `default`. A session first reports `state` `running` only once its
+ network has been observed. To depend on `deny_all`, wait for `running`, then terminate the session unless
+ `applied` is `deny_all`. Act on `applied` only while the session is `running`, and on a later `unknown` only
+ while `desired_state` is `running`.
+ """
+
+ egress: SandboxSessionNetworkEgress
+ applied: SandboxSessionNetworkApplied
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ egress: str = self.egress
+
+ applied: str = self.applied
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "egress": egress,
+ "applied": applied,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ egress = check_sandbox_session_network_egress(d.pop("egress"))
+
+
+
+
+ applied = check_sandbox_session_network_applied(d.pop("applied"))
+
+
+
+
+ sandbox_session_network = cls(
+ egress=egress,
+ applied=applied,
+ )
+
+ return sandbox_session_network
diff --git a/src/volcano_sdk/_generated/models/sandbox_session_network_applied.py b/src/volcano_sdk/_generated/models/sandbox_session_network_applied.py
new file mode 100644
index 00000000..fe69d933
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/sandbox_session_network_applied.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+SandboxSessionNetworkApplied = Literal['default', 'deny_all', 'unknown']
+
+SANDBOX_SESSION_NETWORK_APPLIED_VALUES: set[SandboxSessionNetworkApplied] = { 'default', 'deny_all', 'unknown', }
+
+def check_sandbox_session_network_applied(value: str) -> SandboxSessionNetworkApplied:
+ if value in SANDBOX_SESSION_NETWORK_APPLIED_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {SANDBOX_SESSION_NETWORK_APPLIED_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/sandbox_session_network_egress.py b/src/volcano_sdk/_generated/models/sandbox_session_network_egress.py
new file mode 100644
index 00000000..e50a7f70
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/sandbox_session_network_egress.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+SandboxSessionNetworkEgress = Literal['default', 'deny_all']
+
+SANDBOX_SESSION_NETWORK_EGRESS_VALUES: set[SandboxSessionNetworkEgress] = { 'default', 'deny_all', }
+
+def check_sandbox_session_network_egress(value: str) -> SandboxSessionNetworkEgress:
+ if value in SANDBOX_SESSION_NETWORK_EGRESS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {SANDBOX_SESSION_NETWORK_EGRESS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/sandbox_session_network_request.py b/src/volcano_sdk/_generated/models/sandbox_session_network_request.py
new file mode 100644
index 00000000..c598a348
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/sandbox_session_network_request.py
@@ -0,0 +1,69 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.sandbox_session_network_request_egress import check_sandbox_session_network_request_egress
+from ..models.sandbox_session_network_request_egress import SandboxSessionNetworkRequestEgress
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="SandboxSessionNetworkRequest")
+
+
+
+@_attrs_define
+class SandboxSessionNetworkRequest:
+ """ Outbound network policy for the session. Omitting `network` is the same as `egress` `default`.
+
+ Attributes:
+ egress (SandboxSessionNetworkRequestEgress): `default` gives the session the region's standard outbound internet
+ access. `deny_all` gives it no outbound network for its whole lifetime: DNS lookups, internet and link-local
+ addresses, and connections back out through Volcano all fail, and the session accepts no port access. Commands,
+ files and the rest of the session API work as usual. The policy cannot be changed after creation; suspend and
+ resume keep it. Check `network.applied` before relying on it. Where `GET /capabilities` lists
+ `sandboxes.network_isolation` as unavailable, `deny_all` answers `400` with code `feature_unavailable`.
+ """
+
+ egress: SandboxSessionNetworkRequestEgress
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ egress: str = self.egress
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "egress": egress,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ egress = check_sandbox_session_network_request_egress(d.pop("egress"))
+
+
+
+
+ sandbox_session_network_request = cls(
+ egress=egress,
+ )
+
+ return sandbox_session_network_request
diff --git a/src/volcano_sdk/_generated/models/sandbox_session_network_request_egress.py b/src/volcano_sdk/_generated/models/sandbox_session_network_request_egress.py
new file mode 100644
index 00000000..1405a212
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/sandbox_session_network_request_egress.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+SandboxSessionNetworkRequestEgress = Literal['default', 'deny_all']
+
+SANDBOX_SESSION_NETWORK_REQUEST_EGRESS_VALUES: set[SandboxSessionNetworkRequestEgress] = { 'default', 'deny_all', }
+
+def check_sandbox_session_network_request_egress(value: str) -> SandboxSessionNetworkRequestEgress:
+ if value in SANDBOX_SESSION_NETWORK_REQUEST_EGRESS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {SANDBOX_SESSION_NETWORK_REQUEST_EGRESS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/scheduler_failure_alert_policy.py b/src/volcano_sdk/_generated/models/scheduler_failure_alert_policy.py
new file mode 100644
index 00000000..6d3c0c39
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/scheduler_failure_alert_policy.py
@@ -0,0 +1,84 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.scheduler_failure_notify_on import check_scheduler_failure_notify_on
+from ..models.scheduler_failure_notify_on import SchedulerFailureNotifyOn
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="SchedulerFailureAlertPolicy")
+
+
+
+@_attrs_define
+class SchedulerFailureAlertPolicy:
+ """
+ Attributes:
+ notify_on (SchedulerFailureNotifyOn): When a failing scheduler is announced: on its first failed run, or once
+ `threshold` runs in a row have failed. Either way a streak is announced once, and a scheduler is announced
+ failing at most once an hour.
+ threshold (int): How many runs in a row have to fail before a `consecutive_failures` alert. Ignored for
+ `first_failure`.
+ notify_on_recovery (bool): Whether a successful run after an alerted failure streak sends a
+ `scheduler.recovered` alert.
+ """
+
+ notify_on: SchedulerFailureNotifyOn
+ threshold: int
+ notify_on_recovery: bool
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ notify_on: str = self.notify_on
+
+ threshold = self.threshold
+
+ notify_on_recovery = self.notify_on_recovery
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "notify_on": notify_on,
+ "threshold": threshold,
+ "notify_on_recovery": notify_on_recovery,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ notify_on = check_scheduler_failure_notify_on(d.pop("notify_on"))
+
+
+
+
+ threshold = d.pop("threshold")
+
+ notify_on_recovery = d.pop("notify_on_recovery")
+
+ scheduler_failure_alert_policy = cls(
+ notify_on=notify_on,
+ threshold=threshold,
+ notify_on_recovery=notify_on_recovery,
+ )
+
+ return scheduler_failure_alert_policy
+
diff --git a/src/volcano_sdk/_generated/models/scheduler_failure_notify_on.py b/src/volcano_sdk/_generated/models/scheduler_failure_notify_on.py
new file mode 100644
index 00000000..be7f3e06
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/scheduler_failure_notify_on.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+SchedulerFailureNotifyOn = Literal['consecutive_failures', 'first_failure']
+
+SCHEDULER_FAILURE_NOTIFY_ON_VALUES: set[SchedulerFailureNotifyOn] = { 'consecutive_failures', 'first_failure', }
+
+def check_scheduler_failure_notify_on(value: str) -> SchedulerFailureNotifyOn:
+ if value in SCHEDULER_FAILURE_NOTIFY_ON_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {SCHEDULER_FAILURE_NOTIFY_ON_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/service_key.py b/src/volcano_sdk/_generated/models/service_key.py
index f2f25a9f..d81d07f0 100644
--- a/src/volcano_sdk/_generated/models/service_key.py
+++ b/src/volcano_sdk/_generated/models/service_key.py
@@ -37,7 +37,8 @@ class ServiceKey:
Example: ['*'].
project_id (UUID | Unset):
key_value (str | Unset): Full JWT token for Authorization header.
- Returned on create, get, and list (decrypted from storage).
+ Returned on create, get, and list (decrypted from storage). List
+ responses leave it out for a key that holds `ai.invoke`.
**Store securely - NEVER expose in frontend code!**
created_at (datetime.datetime | Unset):
updated_at (datetime.datetime | Unset):
diff --git a/src/volcano_sdk/_generated/models/set_project_git_production_branch_request.py b/src/volcano_sdk/_generated/models/set_project_git_production_branch_request.py
index c5e9c766..54dea511 100644
--- a/src/volcano_sdk/_generated/models/set_project_git_production_branch_request.py
+++ b/src/volcano_sdk/_generated/models/set_project_git_production_branch_request.py
@@ -23,7 +23,7 @@ class SetProjectGitProductionBranchRequest:
"""
Attributes:
production_branch (str): The branch a push must land on to deploy. Validated as a Git branch name only — it does
- not have to exist yet.
+ not have to exist yet. An empty string follows the repository's default branch, including later renames.
"""
production_branch: str
diff --git a/src/volcano_sdk/_generated/models/set_project_git_root_directory_request.py b/src/volcano_sdk/_generated/models/set_project_git_root_directory_request.py
new file mode 100644
index 00000000..d44aefb8
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/set_project_git_root_directory_request.py
@@ -0,0 +1,77 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="SetProjectGitRootDirectoryRequest")
+
+
+
+@_attrs_define
+class SetProjectGitRootDirectoryRequest:
+ """
+ Attributes:
+ root_directory (str): Monorepo subdirectory the project builds from, relative to the repository root. An empty
+ string means the repository root.
+ """
+
+ root_directory: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ root_directory = self.root_directory
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "root_directory": root_directory,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ root_directory = d.pop("root_directory")
+
+ set_project_git_root_directory_request = cls(
+ root_directory=root_directory,
+ )
+
+
+ set_project_git_root_directory_request.additional_properties = d
+ return set_project_git_root_directory_request
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/share.py b/src/volcano_sdk/_generated/models/share.py
new file mode 100644
index 00000000..98defd50
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share.py
@@ -0,0 +1,232 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.share_status import check_share_status
+from ..models.share_status import ShareStatus
+from ..types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+import datetime
+
+if TYPE_CHECKING:
+ from ..models.share_release_ref import ShareReleaseRef
+
+
+
+
+
+T = TypeVar("T", bound="Share")
+
+
+
+@_attrs_define
+class Share:
+ """
+ Attributes:
+ id (str): The link's public identifier. Its address is `https://volcano.dev/deploy/`.
+ project_id (UUID):
+ suggested_name (str): A project name for clients to offer a visitor as the default. The create request still
+ carries its own `name`; Volcano does not fill one in from the link.
+ description (str): What the project does, in the owner's words, shown to visitors before they deploy. One line
+ of plain text; empty when the owner wrote none.
+ allow_reshare (bool): Whether the projects made from this link, and the projects made from those, may be shared
+ again by their owners. False by default, so a copy of this project cannot create, draft, publish or switch on a
+ deploy link of its own, and its links serve nothing. Read at each request, so switching it off stops copies'
+ links that are already on.
+ status (ShareStatus): Whether the owner, or Volcano, has the link on. An `active` link can still not serve; see
+ `serving`.
+ serving (bool): Whether the link's address serves its current release now: it is
+ `active`, published, and nothing stops it, such as deploy links not being
+ available in this environment, the project being deleted, the owner's
+ account not allowing traffic, or the project being a copy that may no
+ longer be shared. An `active` link that is not serving
+ answers visitors as one switched off, and switching it on again changes
+ nothing until what stops it is resolved.
+ current_release (None | ShareReleaseRef): The release visitors are offered. Null until the first publish; until
+ then the link's preview answers `404`.
+ created_at (datetime.datetime):
+ updated_at (datetime.datetime):
+ disabled_reason (None | str | Unset): Why the link is off. Set only while it is disabled. New reasons can be
+ added, so treat an unknown one as disabled. `owner`: its owner switched
+ it off. `operator`: Volcano took it down; its owner cannot switch it back
+ on or delete it (`PATCH` and `DELETE` answer `403` with code
+ `operator_disabled`), but can still edit it. While it is down, its
+ project cannot be shared any more (no new link, draft or publish, and no
+ link switched on), and no project made from it, or from a copy of it, can
+ be shared either.
+ Example: owner.
+ """
+
+ id: str
+ project_id: UUID
+ suggested_name: str
+ description: str
+ allow_reshare: bool
+ status: ShareStatus
+ serving: bool
+ current_release: None | ShareReleaseRef
+ created_at: datetime.datetime
+ updated_at: datetime.datetime
+ disabled_reason: None | str | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.share_release_ref import ShareReleaseRef # noqa: PLC0415
+ id = self.id
+
+ project_id = str(self.project_id)
+
+ suggested_name = self.suggested_name
+
+ description = self.description
+
+ allow_reshare = self.allow_reshare
+
+ status: str = self.status
+
+ serving = self.serving
+
+ current_release: dict[str, Any] | None
+ if isinstance(self.current_release, ShareReleaseRef):
+ current_release = self.current_release.to_dict()
+ else:
+ current_release = self.current_release
+
+ created_at = self.created_at.isoformat()
+
+ updated_at = self.updated_at.isoformat()
+
+ disabled_reason: None | str | Unset
+ if isinstance(self.disabled_reason, Unset):
+ disabled_reason = UNSET
+ else:
+ disabled_reason = self.disabled_reason
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "project_id": project_id,
+ "suggested_name": suggested_name,
+ "description": description,
+ "allow_reshare": allow_reshare,
+ "status": status,
+ "serving": serving,
+ "current_release": current_release,
+ "created_at": created_at,
+ "updated_at": updated_at,
+ })
+ if disabled_reason is not UNSET:
+ field_dict["disabled_reason"] = disabled_reason
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.share_release_ref import ShareReleaseRef # noqa: PLC0415
+ d = dict(src_dict)
+ id = d.pop("id")
+
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ suggested_name = d.pop("suggested_name")
+
+ description = d.pop("description")
+
+ allow_reshare = d.pop("allow_reshare")
+
+ status = check_share_status(d.pop("status"))
+
+
+
+
+ serving = d.pop("serving")
+
+ def _parse_current_release(data: object) -> None | ShareReleaseRef:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ current_release_type_1 = ShareReleaseRef.from_dict(data)
+
+
+
+ return current_release_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(None | ShareReleaseRef, data)
+
+ current_release = _parse_current_release(d.pop("current_release"))
+
+
+ created_at = datetime.datetime.fromisoformat(d.pop("created_at"))
+
+
+
+
+ updated_at = datetime.datetime.fromisoformat(d.pop("updated_at"))
+
+
+
+
+ def _parse_disabled_reason(data: object) -> None | str | Unset:
+ if data is None:
+ return data
+ if isinstance(data, Unset):
+ return data
+ return cast(None | str | Unset, data)
+
+ disabled_reason = _parse_disabled_reason(d.pop("disabled_reason", UNSET))
+
+
+ share = cls(
+ id=id,
+ project_id=project_id,
+ suggested_name=suggested_name,
+ description=description,
+ allow_reshare=allow_reshare,
+ status=status,
+ serving=serving,
+ current_release=current_release,
+ created_at=created_at,
+ updated_at=updated_at,
+ disabled_reason=disabled_reason,
+ )
+
+
+ share.additional_properties = d
+ return share
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/share_create_request.py b/src/volcano_sdk/_generated/models/share_create_request.py
new file mode 100644
index 00000000..affff1ea
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_create_request.py
@@ -0,0 +1,93 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from uuid import UUID
+
+
+
+
+
+
+T = TypeVar("T", bound="ShareCreateRequest")
+
+
+
+@_attrs_define
+class ShareCreateRequest:
+ """
+ Attributes:
+ project_id (UUID): The project to share. A project the caller can't share answers like one that doesn't exist.
+ suggested_name (str | Unset): A project name for clients to offer visitors as the default; the create request
+ still carries its own `name`. It may contain only letters, numbers, underscores and hyphens.
+ description (str | Unset): What the project does, shown to visitors before they deploy. One line of plain text
+ with no control characters; surrounding spaces are trimmed.
+ allow_reshare (bool | Unset): Lets the projects made from this link be shared again by their owners. Defaults to
+ false.
+ """
+
+ project_id: UUID
+ suggested_name: str | Unset = UNSET
+ description: str | Unset = UNSET
+ allow_reshare: bool | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ project_id = str(self.project_id)
+
+ suggested_name = self.suggested_name
+
+ description = self.description
+
+ allow_reshare = self.allow_reshare
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "project_id": project_id,
+ })
+ if suggested_name is not UNSET:
+ field_dict["suggested_name"] = suggested_name
+ if description is not UNSET:
+ field_dict["description"] = description
+ if allow_reshare is not UNSET:
+ field_dict["allow_reshare"] = allow_reshare
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ suggested_name = d.pop("suggested_name", UNSET)
+
+ description = d.pop("description", UNSET)
+
+ allow_reshare = d.pop("allow_reshare", UNSET)
+
+ share_create_request = cls(
+ project_id=project_id,
+ suggested_name=suggested_name,
+ description=description,
+ allow_reshare=allow_reshare,
+ )
+
+ return share_create_request
+
diff --git a/src/volcano_sdk/_generated/models/share_daily_count.py b/src/volcano_sdk/_generated/models/share_daily_count.py
new file mode 100644
index 00000000..6db21b80
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_daily_count.py
@@ -0,0 +1,102 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.share_daily_count_kind import check_share_daily_count_kind
+from ..models.share_daily_count_kind import ShareDailyCountKind
+from typing import cast
+import datetime
+
+
+
+
+
+
+T = TypeVar("T", bound="ShareDailyCount")
+
+
+
+@_attrs_define
+class ShareDailyCount:
+ """
+ Attributes:
+ day (datetime.date): UTC day.
+ kind (ShareDailyCountKind):
+ events (int):
+ """
+
+ day: datetime.date
+ kind: ShareDailyCountKind
+ events: int
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ day = self.day.isoformat()
+
+ kind: str = self.kind
+
+ events = self.events
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "day": day,
+ "kind": kind,
+ "events": events,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ day = datetime.date.fromisoformat(d.pop("day"))
+
+
+
+
+ kind = check_share_daily_count_kind(d.pop("kind"))
+
+
+
+
+ events = d.pop("events")
+
+ share_daily_count = cls(
+ day=day,
+ kind=kind,
+ events=events,
+ )
+
+
+ share_daily_count.additional_properties = d
+ return share_daily_count
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/share_daily_count_kind.py b/src/volcano_sdk/_generated/models/share_daily_count_kind.py
new file mode 100644
index 00000000..b77cfcd9
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_daily_count_kind.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+ShareDailyCountKind = Literal['accepted', 'click', 'confirm', 'failed', 'preview', 'ready']
+
+SHARE_DAILY_COUNT_KIND_VALUES: set[ShareDailyCountKind] = { 'accepted', 'click', 'confirm', 'failed', 'preview', 'ready', }
+
+def check_share_daily_count_kind(value: str) -> ShareDailyCountKind:
+ if value in SHARE_DAILY_COUNT_KIND_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {SHARE_DAILY_COUNT_KIND_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/share_draft_changed_error.py b/src/volcano_sdk/_generated/models/share_draft_changed_error.py
new file mode 100644
index 00000000..1c640c22
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_draft_changed_error.py
@@ -0,0 +1,105 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.share_draft_changed_error_code import check_share_draft_changed_error_code
+from ..models.share_draft_changed_error_code import ShareDraftChangedErrorCode
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.share_release_draft import ShareReleaseDraft
+
+
+
+
+
+T = TypeVar("T", bound="ShareDraftChangedError")
+
+
+
+@_attrs_define
+class ShareDraftChangedError:
+ """
+ Attributes:
+ error (str):
+ code (ShareDraftChangedErrorCode):
+ draft (ShareReleaseDraft):
+ """
+
+ error: str
+ code: ShareDraftChangedErrorCode
+ draft: ShareReleaseDraft
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.share_release_draft import ShareReleaseDraft # noqa: PLC0415
+ error = self.error
+
+ code: str = self.code
+
+ draft = self.draft.to_dict()
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "error": error,
+ "code": code,
+ "draft": draft,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.share_release_draft import ShareReleaseDraft # noqa: PLC0415
+ d = dict(src_dict)
+ error = d.pop("error")
+
+ code = check_share_draft_changed_error_code(d.pop("code"))
+
+
+
+
+ draft = ShareReleaseDraft.from_dict(d.pop("draft"))
+
+
+
+
+ share_draft_changed_error = cls(
+ error=error,
+ code=code,
+ draft=draft,
+ )
+
+
+ share_draft_changed_error.additional_properties = d
+ return share_draft_changed_error
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/share_draft_changed_error_code.py b/src/volcano_sdk/_generated/models/share_draft_changed_error_code.py
new file mode 100644
index 00000000..91727651
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_draft_changed_error_code.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+ShareDraftChangedErrorCode = Literal['draft_changed']
+
+SHARE_DRAFT_CHANGED_ERROR_CODE_VALUES: set[ShareDraftChangedErrorCode] = { 'draft_changed', }
+
+def check_share_draft_changed_error_code(value: str) -> ShareDraftChangedErrorCode:
+ if value in SHARE_DRAFT_CHANGED_ERROR_CODE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {SHARE_DRAFT_CHANGED_ERROR_CODE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/share_kind_count.py b/src/volcano_sdk/_generated/models/share_kind_count.py
new file mode 100644
index 00000000..74f653aa
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_kind_count.py
@@ -0,0 +1,99 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.share_kind_count_kind import check_share_kind_count_kind
+from ..models.share_kind_count_kind import ShareKindCountKind
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="ShareKindCount")
+
+
+
+@_attrs_define
+class ShareKindCount:
+ """
+ Attributes:
+ kind (ShareKindCountKind):
+ events (int):
+ visitors (int): Unique daily visitors among the events that carried one. A visitor is pseudonymised per day, so
+ one who returns on another day counts again.
+ """
+
+ kind: ShareKindCountKind
+ events: int
+ visitors: int
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ kind: str = self.kind
+
+ events = self.events
+
+ visitors = self.visitors
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "kind": kind,
+ "events": events,
+ "visitors": visitors,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ kind = check_share_kind_count_kind(d.pop("kind"))
+
+
+
+
+ events = d.pop("events")
+
+ visitors = d.pop("visitors")
+
+ share_kind_count = cls(
+ kind=kind,
+ events=events,
+ visitors=visitors,
+ )
+
+
+ share_kind_count.additional_properties = d
+ return share_kind_count
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/share_kind_count_kind.py b/src/volcano_sdk/_generated/models/share_kind_count_kind.py
new file mode 100644
index 00000000..427d4b57
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_kind_count_kind.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+ShareKindCountKind = Literal['accepted', 'click', 'confirm', 'failed', 'preview', 'ready']
+
+SHARE_KIND_COUNT_KIND_VALUES: set[ShareKindCountKind] = { 'accepted', 'click', 'confirm', 'failed', 'preview', 'ready', }
+
+def check_share_kind_count_kind(value: str) -> ShareKindCountKind:
+ if value in SHARE_KIND_COUNT_KIND_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {SHARE_KIND_COUNT_KIND_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/share_preview.py b/src/volcano_sdk/_generated/models/share_preview.py
new file mode 100644
index 00000000..3ab31ffc
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_preview.py
@@ -0,0 +1,109 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.share_preview_release import SharePreviewRelease
+
+
+
+
+
+T = TypeVar("T", bound="SharePreview")
+
+
+
+@_attrs_define
+class SharePreview:
+ """
+ Attributes:
+ id (str):
+ suggested_name (str): A project name the link's owner suggests, for clients to offer as the default. The create
+ request still carries its own `name`; Volcano does not fill one in from the link.
+ description (str): What the project does, in the owner's words. Plain text; empty when the owner wrote none.
+ release (SharePreviewRelease): The release a project created from the link installs.
+ """
+
+ id: str
+ suggested_name: str
+ description: str
+ release: SharePreviewRelease
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.share_preview_release import SharePreviewRelease # noqa: PLC0415
+ id = self.id
+
+ suggested_name = self.suggested_name
+
+ description = self.description
+
+ release = self.release.to_dict()
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "suggested_name": suggested_name,
+ "description": description,
+ "release": release,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.share_preview_release import SharePreviewRelease # noqa: PLC0415
+ d = dict(src_dict)
+ id = d.pop("id")
+
+ suggested_name = d.pop("suggested_name")
+
+ description = d.pop("description")
+
+ release = SharePreviewRelease.from_dict(d.pop("release"))
+
+
+
+
+ share_preview = cls(
+ id=id,
+ suggested_name=suggested_name,
+ description=description,
+ release=release,
+ )
+
+
+ share_preview.additional_properties = d
+ return share_preview
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/share_preview_release.py b/src/volcano_sdk/_generated/models/share_preview_release.py
new file mode 100644
index 00000000..57b2814e
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_preview_release.py
@@ -0,0 +1,191 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+from uuid import UUID
+import datetime
+
+if TYPE_CHECKING:
+ from ..models.share_release_omission import ShareReleaseOmission
+ from ..models.share_variable import ShareVariable
+
+
+
+
+
+T = TypeVar("T", bound="SharePreviewRelease")
+
+
+
+@_attrs_define
+class SharePreviewRelease:
+ """ The release a project created from the link installs.
+
+ Attributes:
+ id (UUID): Send it as `release_id` in `POST /forks` to confirm this release.
+ published_at (datetime.datetime):
+ sha256 (str): The digest of the stored release archive.
+ frontends (list[str]): Names of the frontends installing the release creates.
+ functions (list[str]): Names of the functions installing the release creates.
+ service_key_functions (list[str]): Names of the functions that receive the new project's `VOLCANO_SERVICE_KEY`,
+ which bypasses row-level security. Show them to the visitor before they
+ confirm. Empty when no function receives it.
+ variables (list[ShareVariable]): The project variables the new project gets, sorted by name. A visitor may
+ give a value for any of them as `variables` when creating
+ the fork with `POST /forks`; each one left out is created empty, for the visitor to set
+ later. Volcano's own variables, such as `VOLCANO_API_URL`, are never
+ listed: the install sets them.
+ omissions (list[ShareReleaseOmission]): What the release does not carry. A `database` entry means the new
+ project starts without that database.
+ """
+
+ id: UUID
+ published_at: datetime.datetime
+ sha256: str
+ frontends: list[str]
+ functions: list[str]
+ service_key_functions: list[str]
+ variables: list[ShareVariable]
+ omissions: list[ShareReleaseOmission]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.share_release_omission import ShareReleaseOmission # noqa: PLC0415
+ from ..models.share_variable import ShareVariable # noqa: PLC0415
+ id = str(self.id)
+
+ published_at = self.published_at.isoformat()
+
+ sha256 = self.sha256
+
+ frontends = self.frontends
+
+
+
+ functions = self.functions
+
+
+
+ service_key_functions = self.service_key_functions
+
+
+
+ variables = []
+ for variables_item_data in self.variables:
+ variables_item = variables_item_data.to_dict()
+ variables.append(variables_item)
+
+
+
+ omissions = []
+ for omissions_item_data in self.omissions:
+ omissions_item = omissions_item_data.to_dict()
+ omissions.append(omissions_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "published_at": published_at,
+ "sha256": sha256,
+ "frontends": frontends,
+ "functions": functions,
+ "service_key_functions": service_key_functions,
+ "variables": variables,
+ "omissions": omissions,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.share_release_omission import ShareReleaseOmission # noqa: PLC0415
+ from ..models.share_variable import ShareVariable # noqa: PLC0415
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ published_at = datetime.datetime.fromisoformat(d.pop("published_at"))
+
+
+
+
+ sha256 = d.pop("sha256")
+
+ frontends = cast(list[str], d.pop("frontends"))
+
+
+ functions = cast(list[str], d.pop("functions"))
+
+
+ service_key_functions = cast(list[str], d.pop("service_key_functions"))
+
+
+ variables = []
+ _variables = d.pop("variables")
+ for variables_item_data in (_variables):
+ variables_item = ShareVariable.from_dict(variables_item_data)
+
+
+
+ variables.append(variables_item)
+
+
+ omissions = []
+ _omissions = d.pop("omissions")
+ for omissions_item_data in (_omissions):
+ omissions_item = ShareReleaseOmission.from_dict(omissions_item_data)
+
+
+
+ omissions.append(omissions_item)
+
+
+ share_preview_release = cls(
+ id=id,
+ published_at=published_at,
+ sha256=sha256,
+ frontends=frontends,
+ functions=functions,
+ service_key_functions=service_key_functions,
+ variables=variables,
+ omissions=omissions,
+ )
+
+
+ share_preview_release.additional_properties = d
+ return share_preview_release
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/share_release.py b/src/volcano_sdk/_generated/models/share_release.py
new file mode 100644
index 00000000..f0ff1fe5
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_release.py
@@ -0,0 +1,231 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+from uuid import UUID
+import datetime
+
+if TYPE_CHECKING:
+ from ..models.share_release_function import ShareReleaseFunction
+ from ..models.share_release_omission import ShareReleaseOmission
+ from ..models.share_variable import ShareVariable
+
+
+
+
+
+T = TypeVar("T", bound="ShareRelease")
+
+
+
+@_attrs_define
+class ShareRelease:
+ """
+ Attributes:
+ id (UUID):
+ share_id (str):
+ project_id (UUID):
+ published_at (datetime.datetime):
+ published_by (str): The id of the user who published the release.
+ sha256 (str): The digest of the stored release archive. An install refuses an archive that does not match it.
+ size_bytes (int):
+ functions (list[ShareReleaseFunction]):
+ frontends (list[str]):
+ variables (list[ShareVariable]):
+ service_key_functions (list[str]):
+ omissions (list[ShareReleaseOmission]):
+ """
+
+ id: UUID
+ share_id: str
+ project_id: UUID
+ published_at: datetime.datetime
+ published_by: str
+ sha256: str
+ size_bytes: int
+ functions: list[ShareReleaseFunction]
+ frontends: list[str]
+ variables: list[ShareVariable]
+ service_key_functions: list[str]
+ omissions: list[ShareReleaseOmission]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.share_release_function import ShareReleaseFunction # noqa: PLC0415
+ from ..models.share_release_omission import ShareReleaseOmission # noqa: PLC0415
+ from ..models.share_variable import ShareVariable # noqa: PLC0415
+ id = str(self.id)
+
+ share_id = self.share_id
+
+ project_id = str(self.project_id)
+
+ published_at = self.published_at.isoformat()
+
+ published_by = self.published_by
+
+ sha256 = self.sha256
+
+ size_bytes = self.size_bytes
+
+ functions = []
+ for functions_item_data in self.functions:
+ functions_item = functions_item_data.to_dict()
+ functions.append(functions_item)
+
+
+
+ frontends = self.frontends
+
+
+
+ variables = []
+ for variables_item_data in self.variables:
+ variables_item = variables_item_data.to_dict()
+ variables.append(variables_item)
+
+
+
+ service_key_functions = self.service_key_functions
+
+
+
+ omissions = []
+ for omissions_item_data in self.omissions:
+ omissions_item = omissions_item_data.to_dict()
+ omissions.append(omissions_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "share_id": share_id,
+ "project_id": project_id,
+ "published_at": published_at,
+ "published_by": published_by,
+ "sha256": sha256,
+ "size_bytes": size_bytes,
+ "functions": functions,
+ "frontends": frontends,
+ "variables": variables,
+ "service_key_functions": service_key_functions,
+ "omissions": omissions,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.share_release_function import ShareReleaseFunction # noqa: PLC0415
+ from ..models.share_release_omission import ShareReleaseOmission # noqa: PLC0415
+ from ..models.share_variable import ShareVariable # noqa: PLC0415
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ share_id = d.pop("share_id")
+
+ project_id = UUID(d.pop("project_id"))
+
+
+
+
+ published_at = datetime.datetime.fromisoformat(d.pop("published_at"))
+
+
+
+
+ published_by = d.pop("published_by")
+
+ sha256 = d.pop("sha256")
+
+ size_bytes = d.pop("size_bytes")
+
+ functions = []
+ _functions = d.pop("functions")
+ for functions_item_data in (_functions):
+ functions_item = ShareReleaseFunction.from_dict(functions_item_data)
+
+
+
+ functions.append(functions_item)
+
+
+ frontends = cast(list[str], d.pop("frontends"))
+
+
+ variables = []
+ _variables = d.pop("variables")
+ for variables_item_data in (_variables):
+ variables_item = ShareVariable.from_dict(variables_item_data)
+
+
+
+ variables.append(variables_item)
+
+
+ service_key_functions = cast(list[str], d.pop("service_key_functions"))
+
+
+ omissions = []
+ _omissions = d.pop("omissions")
+ for omissions_item_data in (_omissions):
+ omissions_item = ShareReleaseOmission.from_dict(omissions_item_data)
+
+
+
+ omissions.append(omissions_item)
+
+
+ share_release = cls(
+ id=id,
+ share_id=share_id,
+ project_id=project_id,
+ published_at=published_at,
+ published_by=published_by,
+ sha256=sha256,
+ size_bytes=size_bytes,
+ functions=functions,
+ frontends=frontends,
+ variables=variables,
+ service_key_functions=service_key_functions,
+ omissions=omissions,
+ )
+
+
+ share_release.additional_properties = d
+ return share_release
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/share_release_create_request.py b/src/volcano_sdk/_generated/models/share_release_create_request.py
new file mode 100644
index 00000000..c6cd316b
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_release_create_request.py
@@ -0,0 +1,95 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="ShareReleaseCreateRequest")
+
+
+
+@_attrs_define
+class ShareReleaseCreateRequest:
+ """
+ Attributes:
+ share_id (str): The share to publish to. Its own project authorizes the publish.
+ draft_id (str): The `draft_id` of the draft the owner reviewed. If a fresh build of the
+ project is not that draft, nothing is published and the answer is `409`
+ `draft_changed` with the new draft.
+ variables (list[str]): Every name in the draft's `variables`, which a project created from the
+ release gets. Values are never carried: each is created empty unless the
+ visitor gives one.
+ service_key_functions (list[str]): The functions that receive the new project's `VOLCANO_SERVICE_KEY`, which
+ bypasses row-level security. Must be exactly the draft's
+ `service_key_functions`.
+ """
+
+ share_id: str
+ draft_id: str
+ variables: list[str]
+ service_key_functions: list[str]
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ share_id = self.share_id
+
+ draft_id = self.draft_id
+
+ variables = self.variables
+
+
+
+ service_key_functions = self.service_key_functions
+
+
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "share_id": share_id,
+ "draft_id": draft_id,
+ "variables": variables,
+ "service_key_functions": service_key_functions,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ share_id = d.pop("share_id")
+
+ draft_id = d.pop("draft_id")
+
+ variables = cast(list[str], d.pop("variables"))
+
+
+ service_key_functions = cast(list[str], d.pop("service_key_functions"))
+
+
+ share_release_create_request = cls(
+ share_id=share_id,
+ draft_id=draft_id,
+ variables=variables,
+ service_key_functions=service_key_functions,
+ )
+
+ return share_release_create_request
+
diff --git a/src/volcano_sdk/_generated/models/share_release_draft.py b/src/volcano_sdk/_generated/models/share_release_draft.py
new file mode 100644
index 00000000..2f559410
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_release_draft.py
@@ -0,0 +1,199 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.share_release_draft_frontend_variables import ShareReleaseDraftFrontendVariables
+ from ..models.share_release_function import ShareReleaseFunction
+ from ..models.share_release_omission import ShareReleaseOmission
+ from ..models.share_variable import ShareVariable
+
+
+
+
+
+T = TypeVar("T", bound="ShareReleaseDraft")
+
+
+
+@_attrs_define
+class ShareReleaseDraft:
+ """
+ Attributes:
+ draft_id (str): Opaque. Names exactly what a release built now would carry: each
+ function's and frontend's current deployment, and everything the draft
+ lists, including each function's settings (`http_auth_mode`,
+ `openapi_spec_sha256`, `variable_scope`), the `variables`, the
+ `frontend_variables` and the `omissions`. It stays the same while those
+ do, and changes when a function or frontend is redeployed or anything the
+ draft lists changes. A sandbox is not part of it, since a release does not
+ carry one: rebuilding only a sandbox leaves it unchanged. Send it with the
+ publish.
+ functions (list[ShareReleaseFunction]):
+ frontends (list[str]):
+ variables (list[ShareVariable]): The project's variables a visitor could be asked to supply. Volcano's own, such
+ as `VOLCANO_API_URL`, are never listed.
+ service_key_functions (list[str]): The functions whose code reads `VOLCANO_SERVICE_KEY`. A release gives them
+ the visitor project's service key once the owner confirms them.
+ omissions (list[ShareReleaseOmission]):
+ frontend_variables (ShareReleaseDraftFrontendVariables): The draft's variables each frontend receives, by
+ frontend name, as your
+ project's frontend of that name selects them by its variable scope now.
+ A frontend receives no others.
+ """
+
+ draft_id: str
+ functions: list[ShareReleaseFunction]
+ frontends: list[str]
+ variables: list[ShareVariable]
+ service_key_functions: list[str]
+ omissions: list[ShareReleaseOmission]
+ frontend_variables: ShareReleaseDraftFrontendVariables
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.share_release_draft_frontend_variables import ShareReleaseDraftFrontendVariables # noqa: PLC0415
+ from ..models.share_release_function import ShareReleaseFunction # noqa: PLC0415
+ from ..models.share_release_omission import ShareReleaseOmission # noqa: PLC0415
+ from ..models.share_variable import ShareVariable # noqa: PLC0415
+ draft_id = self.draft_id
+
+ functions = []
+ for functions_item_data in self.functions:
+ functions_item = functions_item_data.to_dict()
+ functions.append(functions_item)
+
+
+
+ frontends = self.frontends
+
+
+
+ variables = []
+ for variables_item_data in self.variables:
+ variables_item = variables_item_data.to_dict()
+ variables.append(variables_item)
+
+
+
+ service_key_functions = self.service_key_functions
+
+
+
+ omissions = []
+ for omissions_item_data in self.omissions:
+ omissions_item = omissions_item_data.to_dict()
+ omissions.append(omissions_item)
+
+
+
+ frontend_variables = self.frontend_variables.to_dict()
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "draft_id": draft_id,
+ "functions": functions,
+ "frontends": frontends,
+ "variables": variables,
+ "service_key_functions": service_key_functions,
+ "omissions": omissions,
+ "frontend_variables": frontend_variables,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.share_release_draft_frontend_variables import ShareReleaseDraftFrontendVariables # noqa: PLC0415
+ from ..models.share_release_function import ShareReleaseFunction # noqa: PLC0415
+ from ..models.share_release_omission import ShareReleaseOmission # noqa: PLC0415
+ from ..models.share_variable import ShareVariable # noqa: PLC0415
+ d = dict(src_dict)
+ draft_id = d.pop("draft_id")
+
+ functions = []
+ _functions = d.pop("functions")
+ for functions_item_data in (_functions):
+ functions_item = ShareReleaseFunction.from_dict(functions_item_data)
+
+
+
+ functions.append(functions_item)
+
+
+ frontends = cast(list[str], d.pop("frontends"))
+
+
+ variables = []
+ _variables = d.pop("variables")
+ for variables_item_data in (_variables):
+ variables_item = ShareVariable.from_dict(variables_item_data)
+
+
+
+ variables.append(variables_item)
+
+
+ service_key_functions = cast(list[str], d.pop("service_key_functions"))
+
+
+ omissions = []
+ _omissions = d.pop("omissions")
+ for omissions_item_data in (_omissions):
+ omissions_item = ShareReleaseOmission.from_dict(omissions_item_data)
+
+
+
+ omissions.append(omissions_item)
+
+
+ frontend_variables = ShareReleaseDraftFrontendVariables.from_dict(d.pop("frontend_variables"))
+
+
+
+
+ share_release_draft = cls(
+ draft_id=draft_id,
+ functions=functions,
+ frontends=frontends,
+ variables=variables,
+ service_key_functions=service_key_functions,
+ omissions=omissions,
+ frontend_variables=frontend_variables,
+ )
+
+
+ share_release_draft.additional_properties = d
+ return share_release_draft
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/share_release_draft_frontend_variables.py b/src/volcano_sdk/_generated/models/share_release_draft_frontend_variables.py
new file mode 100644
index 00000000..bfd27c1a
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_release_draft_frontend_variables.py
@@ -0,0 +1,79 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="ShareReleaseDraftFrontendVariables")
+
+
+
+@_attrs_define
+class ShareReleaseDraftFrontendVariables:
+ """ The draft's variables each frontend receives, by frontend name, as your
+ project's frontend of that name selects them by its variable scope now.
+ A frontend receives no others.
+
+ """
+
+ additional_properties: dict[str, list[str]] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+
+ field_dict: dict[str, Any] = {}
+ for prop_name, prop in self.additional_properties.items():
+ field_dict[prop_name] = prop
+
+
+
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ share_release_draft_frontend_variables = cls(
+ )
+
+
+ additional_properties = {}
+ for prop_name, prop_dict in d.items():
+ additional_property = cast(list[str], prop_dict)
+
+ additional_properties[prop_name] = additional_property
+
+ share_release_draft_frontend_variables.additional_properties = additional_properties
+ return share_release_draft_frontend_variables
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> list[str]:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: list[str]) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/share_release_function.py b/src/volcano_sdk/_generated/models/share_release_function.py
new file mode 100644
index 00000000..b8b75853
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_release_function.py
@@ -0,0 +1,174 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.share_release_function_kind import check_share_release_function_kind
+from ..models.share_release_function_kind import ShareReleaseFunctionKind
+from ..models.share_release_function_variable_scope import check_share_release_function_variable_scope
+from ..models.share_release_function_variable_scope import ShareReleaseFunctionVariableScope
+from ..types import UNSET, Unset
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="ShareReleaseFunction")
+
+
+
+@_attrs_define
+class ShareReleaseFunction:
+ """
+ Attributes:
+ name (str):
+ kind (ShareReleaseFunctionKind):
+ visibility (str | Unset): The function's invocation visibility, as installed.
+ invocation_mode (str | Unset): The function's invocation mode, when it is not the default.
+ http_auth_mode (str | Unset): How the function's HTTP invocations authenticate, when its invocation
+ settings are not the default; omitted means `volcano`. `none` lets
+ anyone call the function without a credential in every project made from
+ the release. Releases published before this was recorded omit it.
+ openapi_spec_sha256 (str | Unset): The SHA-256 of the function's OpenAPI document as the release carries it,
+ when it has one, so a draft shows when the document changed. Releases
+ published before this was recorded omit it.
+ variable_scope (ShareReleaseFunctionVariableScope | Unset): `scoped` when the function receives only the
+ variables it declares, as
+ your project's function does, listed in `variables`. Omitted when it
+ receives every variable shared with functions. The service key is not
+ part of it: `service_key_functions` says which functions receive that.
+ Releases published before this was recorded omit it.
+ variables (list[str] | Unset): For a `scoped` function, the variables it declares that a project made from the
+ release has.
+ """
+
+ name: str
+ kind: ShareReleaseFunctionKind
+ visibility: str | Unset = UNSET
+ invocation_mode: str | Unset = UNSET
+ http_auth_mode: str | Unset = UNSET
+ openapi_spec_sha256: str | Unset = UNSET
+ variable_scope: ShareReleaseFunctionVariableScope | Unset = UNSET
+ variables: list[str] | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ name = self.name
+
+ kind: str = self.kind
+
+ visibility = self.visibility
+
+ invocation_mode = self.invocation_mode
+
+ http_auth_mode = self.http_auth_mode
+
+ openapi_spec_sha256 = self.openapi_spec_sha256
+
+ variable_scope: str | Unset = UNSET
+ if not isinstance(self.variable_scope, Unset):
+ variable_scope = self.variable_scope
+
+
+ variables: list[str] | Unset = UNSET
+ if not isinstance(self.variables, Unset):
+ variables = self.variables
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "name": name,
+ "kind": kind,
+ })
+ if visibility is not UNSET:
+ field_dict["visibility"] = visibility
+ if invocation_mode is not UNSET:
+ field_dict["invocation_mode"] = invocation_mode
+ if http_auth_mode is not UNSET:
+ field_dict["http_auth_mode"] = http_auth_mode
+ if openapi_spec_sha256 is not UNSET:
+ field_dict["openapi_spec_sha256"] = openapi_spec_sha256
+ if variable_scope is not UNSET:
+ field_dict["variable_scope"] = variable_scope
+ if variables is not UNSET:
+ field_dict["variables"] = variables
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ name = d.pop("name")
+
+ kind = check_share_release_function_kind(d.pop("kind"))
+
+
+
+
+ visibility = d.pop("visibility", UNSET)
+
+ invocation_mode = d.pop("invocation_mode", UNSET)
+
+ http_auth_mode = d.pop("http_auth_mode", UNSET)
+
+ openapi_spec_sha256 = d.pop("openapi_spec_sha256", UNSET)
+
+ _variable_scope = d.pop("variable_scope", UNSET)
+ variable_scope: ShareReleaseFunctionVariableScope | Unset
+ if isinstance(_variable_scope, Unset):
+ variable_scope = UNSET
+ else:
+ variable_scope = check_share_release_function_variable_scope(_variable_scope)
+
+
+
+
+ variables = cast(list[str], d.pop("variables", UNSET))
+
+
+ share_release_function = cls(
+ name=name,
+ kind=kind,
+ visibility=visibility,
+ invocation_mode=invocation_mode,
+ http_auth_mode=http_auth_mode,
+ openapi_spec_sha256=openapi_spec_sha256,
+ variable_scope=variable_scope,
+ variables=variables,
+ )
+
+
+ share_release_function.additional_properties = d
+ return share_release_function
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/share_release_function_kind.py b/src/volcano_sdk/_generated/models/share_release_function_kind.py
new file mode 100644
index 00000000..33d1156c
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_release_function_kind.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+ShareReleaseFunctionKind = Literal['durable', 'standard']
+
+SHARE_RELEASE_FUNCTION_KIND_VALUES: set[ShareReleaseFunctionKind] = { 'durable', 'standard', }
+
+def check_share_release_function_kind(value: str) -> ShareReleaseFunctionKind:
+ if value in SHARE_RELEASE_FUNCTION_KIND_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {SHARE_RELEASE_FUNCTION_KIND_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/share_release_function_variable_scope.py b/src/volcano_sdk/_generated/models/share_release_function_variable_scope.py
new file mode 100644
index 00000000..20b152e9
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_release_function_variable_scope.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+ShareReleaseFunctionVariableScope = Literal['scoped']
+
+SHARE_RELEASE_FUNCTION_VARIABLE_SCOPE_VALUES: set[ShareReleaseFunctionVariableScope] = { 'scoped', }
+
+def check_share_release_function_variable_scope(value: str) -> ShareReleaseFunctionVariableScope:
+ if value in SHARE_RELEASE_FUNCTION_VARIABLE_SCOPE_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {SHARE_RELEASE_FUNCTION_VARIABLE_SCOPE_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/share_release_omission.py b/src/volcano_sdk/_generated/models/share_release_omission.py
new file mode 100644
index 00000000..dec422dc
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_release_omission.py
@@ -0,0 +1,109 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.share_release_omission_kind import check_share_release_omission_kind
+from ..models.share_release_omission_kind import ShareReleaseOmissionKind
+from ..types import UNSET, Unset
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="ShareReleaseOmission")
+
+
+
+@_attrs_define
+class ShareReleaseOmission:
+ """ Something a release does not carry.
+
+ Attributes:
+ kind (ShareReleaseOmissionKind): `no_source`: a function or frontend whose current deployment has no stored
+ source to carry. `database`: a database; a visitor's project starts without
+ one. `sandbox`: a sandbox, which releases do not deploy. `secret_file`: a
+ file that may hold credentials, such as a dotenv or `.envrc` file, a tool's
+ token file like `.netrc` or an `.npmrc` holding a registry credential, a
+ private key, a credential JSON or a Terraform variables file. `unsupported_entry`: a file that is not a regular
+ file,
+ such as a symbolic link.
+ resource (str | Unset): The function, frontend, database or sandbox, when there is one.
+ path (str | Unset): The file left out, for a file.
+ """
+
+ kind: ShareReleaseOmissionKind
+ resource: str | Unset = UNSET
+ path: str | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ kind: str = self.kind
+
+ resource = self.resource
+
+ path = self.path
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "kind": kind,
+ })
+ if resource is not UNSET:
+ field_dict["resource"] = resource
+ if path is not UNSET:
+ field_dict["path"] = path
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ kind = check_share_release_omission_kind(d.pop("kind"))
+
+
+
+
+ resource = d.pop("resource", UNSET)
+
+ path = d.pop("path", UNSET)
+
+ share_release_omission = cls(
+ kind=kind,
+ resource=resource,
+ path=path,
+ )
+
+
+ share_release_omission.additional_properties = d
+ return share_release_omission
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/share_release_omission_kind.py b/src/volcano_sdk/_generated/models/share_release_omission_kind.py
new file mode 100644
index 00000000..81c3c3f9
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_release_omission_kind.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+ShareReleaseOmissionKind = Literal['database', 'no_source', 'sandbox', 'secret_file', 'unsupported_entry']
+
+SHARE_RELEASE_OMISSION_KIND_VALUES: set[ShareReleaseOmissionKind] = { 'database', 'no_source', 'sandbox', 'secret_file', 'unsupported_entry', }
+
+def check_share_release_omission_kind(value: str) -> ShareReleaseOmissionKind:
+ if value in SHARE_RELEASE_OMISSION_KIND_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {SHARE_RELEASE_OMISSION_KIND_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/share_release_ref.py b/src/volcano_sdk/_generated/models/share_release_ref.py
new file mode 100644
index 00000000..491ebd78
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_release_ref.py
@@ -0,0 +1,93 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+from uuid import UUID
+import datetime
+
+
+
+
+
+
+T = TypeVar("T", bound="ShareReleaseRef")
+
+
+
+@_attrs_define
+class ShareReleaseRef:
+ """
+ Attributes:
+ id (UUID):
+ published_at (datetime.datetime):
+ """
+
+ id: UUID
+ published_at: datetime.datetime
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ id = str(self.id)
+
+ published_at = self.published_at.isoformat()
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "published_at": published_at,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ published_at = datetime.datetime.fromisoformat(d.pop("published_at"))
+
+
+
+
+ share_release_ref = cls(
+ id=id,
+ published_at=published_at,
+ )
+
+
+ share_release_ref.additional_properties = d
+ return share_release_ref
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/share_stats.py b/src/volcano_sdk/_generated/models/share_stats.py
new file mode 100644
index 00000000..19ea9ad3
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_stats.py
@@ -0,0 +1,130 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+import datetime
+
+if TYPE_CHECKING:
+ from ..models.share_daily_count import ShareDailyCount
+ from ..models.share_kind_count import ShareKindCount
+
+
+
+
+
+T = TypeVar("T", bound="ShareStats")
+
+
+
+@_attrs_define
+class ShareStats:
+ """
+ Attributes:
+ since (datetime.datetime): Start of the counted window.
+ totals (list[ShareKindCount]):
+ daily (list[ShareDailyCount]):
+ """
+
+ since: datetime.datetime
+ totals: list[ShareKindCount]
+ daily: list[ShareDailyCount]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.share_daily_count import ShareDailyCount # noqa: PLC0415
+ from ..models.share_kind_count import ShareKindCount # noqa: PLC0415
+ since = self.since.isoformat()
+
+ totals = []
+ for totals_item_data in self.totals:
+ totals_item = totals_item_data.to_dict()
+ totals.append(totals_item)
+
+
+
+ daily = []
+ for daily_item_data in self.daily:
+ daily_item = daily_item_data.to_dict()
+ daily.append(daily_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "since": since,
+ "totals": totals,
+ "daily": daily,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.share_daily_count import ShareDailyCount # noqa: PLC0415
+ from ..models.share_kind_count import ShareKindCount # noqa: PLC0415
+ d = dict(src_dict)
+ since = datetime.datetime.fromisoformat(d.pop("since"))
+
+
+
+
+ totals = []
+ _totals = d.pop("totals")
+ for totals_item_data in (_totals):
+ totals_item = ShareKindCount.from_dict(totals_item_data)
+
+
+
+ totals.append(totals_item)
+
+
+ daily = []
+ _daily = d.pop("daily")
+ for daily_item_data in (_daily):
+ daily_item = ShareDailyCount.from_dict(daily_item_data)
+
+
+
+ daily.append(daily_item)
+
+
+ share_stats = cls(
+ since=since,
+ totals=totals,
+ daily=daily,
+ )
+
+
+ share_stats.additional_properties = d
+ return share_stats
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/share_status.py b/src/volcano_sdk/_generated/models/share_status.py
new file mode 100644
index 00000000..1a149b0f
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_status.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+ShareStatus = Literal['active', 'disabled']
+
+SHARE_STATUS_VALUES: set[ShareStatus] = { 'active', 'disabled', }
+
+def check_share_status(value: str) -> ShareStatus:
+ if value in SHARE_STATUS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {SHARE_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/share_update_request.py b/src/volcano_sdk/_generated/models/share_update_request.py
new file mode 100644
index 00000000..a387c2ec
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_update_request.py
@@ -0,0 +1,104 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.share_update_request_status import check_share_update_request_status
+from ..models.share_update_request_status import ShareUpdateRequestStatus
+from ..types import UNSET, Unset
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="ShareUpdateRequest")
+
+
+
+@_attrs_define
+class ShareUpdateRequest:
+ """
+ Attributes:
+ suggested_name (str | Unset):
+ description (str | Unset): What the project does, shown to visitors before they deploy. One line of plain text
+ with no control characters; surrounding spaces are trimmed. Send an empty string to remove it.
+ allow_reshare (bool | Unset): Lets the projects made from this link be shared again by their owners. Switching
+ it off stops their copies, and copies of those, from sharing again, read at each request, including links of
+ theirs that are already on.
+ status (ShareUpdateRequestStatus | Unset):
+ """
+
+ suggested_name: str | Unset = UNSET
+ description: str | Unset = UNSET
+ allow_reshare: bool | Unset = UNSET
+ status: ShareUpdateRequestStatus | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ suggested_name = self.suggested_name
+
+ description = self.description
+
+ allow_reshare = self.allow_reshare
+
+ status: str | Unset = UNSET
+ if not isinstance(self.status, Unset):
+ status = self.status
+
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ })
+ if suggested_name is not UNSET:
+ field_dict["suggested_name"] = suggested_name
+ if description is not UNSET:
+ field_dict["description"] = description
+ if allow_reshare is not UNSET:
+ field_dict["allow_reshare"] = allow_reshare
+ if status is not UNSET:
+ field_dict["status"] = status
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ suggested_name = d.pop("suggested_name", UNSET)
+
+ description = d.pop("description", UNSET)
+
+ allow_reshare = d.pop("allow_reshare", UNSET)
+
+ _status = d.pop("status", UNSET)
+ status: ShareUpdateRequestStatus | Unset
+ if isinstance(_status, Unset):
+ status = UNSET
+ else:
+ status = check_share_update_request_status(_status)
+
+
+
+
+ share_update_request = cls(
+ suggested_name=suggested_name,
+ description=description,
+ allow_reshare=allow_reshare,
+ status=status,
+ )
+
+ return share_update_request
+
diff --git a/src/volcano_sdk/_generated/models/share_update_request_status.py b/src/volcano_sdk/_generated/models/share_update_request_status.py
new file mode 100644
index 00000000..bec66fa0
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_update_request_status.py
@@ -0,0 +1,10 @@
+from typing import Literal
+
+ShareUpdateRequestStatus = Literal['active', 'disabled']
+
+SHARE_UPDATE_REQUEST_STATUS_VALUES: set[ShareUpdateRequestStatus] = { 'active', 'disabled', }
+
+def check_share_update_request_status(value: str) -> ShareUpdateRequestStatus:
+ if value in SHARE_UPDATE_REQUEST_STATUS_VALUES:
+ return value
+ raise TypeError(f"Unexpected value {value!r}. Expected one of {SHARE_UPDATE_REQUEST_STATUS_VALUES!r}")
diff --git a/src/volcano_sdk/_generated/models/share_variable.py b/src/volcano_sdk/_generated/models/share_variable.py
new file mode 100644
index 00000000..09d4b6d4
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/share_variable.py
@@ -0,0 +1,108 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+T = TypeVar("T", bound="ShareVariable")
+
+
+
+@_attrs_define
+class ShareVariable:
+ """ A project variable a deploy link's release declares. A project created from the link always gets it.
+
+ Attributes:
+ name (str): The variable's name.
+ required (bool): Always true: a project created from the link always gets this variable,
+ created empty when the visitor gives no value. It never means a value must
+ be given.
+ secret (bool): Whether to treat the value as a secret: take it masked and never show it back. Only a
+ `NEXT_PUBLIC_` name, which a Next.js build copies into the browser, is not secret.
+ unshared (bool | Unset): True when the source project gives the variable only to the scoped
+ functions that declare it, not to every function, and so does a project
+ made from the release. Omitted when false.
+ """
+
+ name: str
+ required: bool
+ secret: bool
+ unshared: bool | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ name = self.name
+
+ required = self.required
+
+ secret = self.secret
+
+ unshared = self.unshared
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "name": name,
+ "required": required,
+ "secret": secret,
+ })
+ if unshared is not UNSET:
+ field_dict["unshared"] = unshared
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ name = d.pop("name")
+
+ required = d.pop("required")
+
+ secret = d.pop("secret")
+
+ unshared = d.pop("unshared", UNSET)
+
+ share_variable = cls(
+ name=name,
+ required=required,
+ secret=secret,
+ unshared=unshared,
+ )
+
+
+ share_variable.additional_properties = d
+ return share_variable
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/shares_response.py b/src/volcano_sdk/_generated/models/shares_response.py
new file mode 100644
index 00000000..8a2a03dc
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/shares_response.py
@@ -0,0 +1,94 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.share import Share
+
+
+
+
+
+T = TypeVar("T", bound="SharesResponse")
+
+
+
+@_attrs_define
+class SharesResponse:
+ """
+ Attributes:
+ shares (list[Share]):
+ """
+
+ shares: list[Share]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.share import Share # noqa: PLC0415
+ shares = []
+ for shares_item_data in self.shares:
+ shares_item = shares_item_data.to_dict()
+ shares.append(shares_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "shares": shares,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.share import Share # noqa: PLC0415
+ d = dict(src_dict)
+ shares = []
+ _shares = d.pop("shares")
+ for shares_item_data in (_shares):
+ shares_item = Share.from_dict(shares_item_data)
+
+
+
+ shares.append(shares_item)
+
+
+ shares_response = cls(
+ shares=shares,
+ )
+
+
+ shares_response.additional_properties = d
+ return shares_response
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/slack_authorization_response.py b/src/volcano_sdk/_generated/models/slack_authorization_response.py
new file mode 100644
index 00000000..98817995
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/slack_authorization_response.py
@@ -0,0 +1,76 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="SlackAuthorizationResponse")
+
+
+
+@_attrs_define
+class SlackAuthorizationResponse:
+ """
+ Attributes:
+ authorization_url (str): The Slack page to send the browser to.
+ """
+
+ authorization_url: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ authorization_url = self.authorization_url
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "authorization_url": authorization_url,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ authorization_url = d.pop("authorization_url")
+
+ slack_authorization_response = cls(
+ authorization_url=authorization_url,
+ )
+
+
+ slack_authorization_response.additional_properties = d
+ return slack_authorization_response
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/slack_channel.py b/src/volcano_sdk/_generated/models/slack_channel.py
new file mode 100644
index 00000000..f7d32462
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/slack_channel.py
@@ -0,0 +1,92 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="SlackChannel")
+
+
+
+@_attrs_define
+class SlackChannel:
+ """
+ Attributes:
+ id (str): A Slack channel ID, such as `C0123ABCD`.
+ name (str):
+ is_private (bool):
+ """
+
+ id: str
+ name: str
+ is_private: bool
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ id = self.id
+
+ name = self.name
+
+ is_private = self.is_private
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "name": name,
+ "is_private": is_private,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ id = d.pop("id")
+
+ name = d.pop("name")
+
+ is_private = d.pop("is_private")
+
+ slack_channel = cls(
+ id=id,
+ name=name,
+ is_private=is_private,
+ )
+
+
+ slack_channel.additional_properties = d
+ return slack_channel
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/slack_channels_response.py b/src/volcano_sdk/_generated/models/slack_channels_response.py
new file mode 100644
index 00000000..fa6ecfd4
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/slack_channels_response.py
@@ -0,0 +1,94 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.slack_channel import SlackChannel
+
+
+
+
+
+T = TypeVar("T", bound="SlackChannelsResponse")
+
+
+
+@_attrs_define
+class SlackChannelsResponse:
+ """
+ Attributes:
+ channels (list[SlackChannel]):
+ """
+
+ channels: list[SlackChannel]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.slack_channel import SlackChannel # noqa: PLC0415
+ channels = []
+ for channels_item_data in self.channels:
+ channels_item = channels_item_data.to_dict()
+ channels.append(channels_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "channels": channels,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.slack_channel import SlackChannel # noqa: PLC0415
+ d = dict(src_dict)
+ channels = []
+ _channels = d.pop("channels")
+ for channels_item_data in (_channels):
+ channels_item = SlackChannel.from_dict(channels_item_data)
+
+
+
+ channels.append(channels_item)
+
+
+ slack_channels_response = cls(
+ channels=channels,
+ )
+
+
+ slack_channels_response.additional_properties = d
+ return slack_channels_response
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/slack_connection.py b/src/volcano_sdk/_generated/models/slack_connection.py
new file mode 100644
index 00000000..4d17d1b4
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/slack_connection.py
@@ -0,0 +1,126 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+from uuid import UUID
+import datetime
+
+
+
+
+
+
+T = TypeVar("T", bound="SlackConnection")
+
+
+
+@_attrs_define
+class SlackConnection:
+ """ A Slack identity connected to the caller's Volcano account.
+
+ Attributes:
+ id (UUID):
+ team_id (str): A Slack workspace ID, such as `T0123ABCD`.
+ team_name (str): The workspace's name, or empty until the Volcano app is installed in it.
+ slack_user_id (str): The Slack user ID Slack verified.
+ installed (bool): Whether the Volcano app is installed in the workspace.
+ created_at (datetime.datetime):
+ """
+
+ id: UUID
+ team_id: str
+ team_name: str
+ slack_user_id: str
+ installed: bool
+ created_at: datetime.datetime
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ id = str(self.id)
+
+ team_id = self.team_id
+
+ team_name = self.team_name
+
+ slack_user_id = self.slack_user_id
+
+ installed = self.installed
+
+ created_at = self.created_at.isoformat()
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "team_id": team_id,
+ "team_name": team_name,
+ "slack_user_id": slack_user_id,
+ "installed": installed,
+ "created_at": created_at,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ team_id = d.pop("team_id")
+
+ team_name = d.pop("team_name")
+
+ slack_user_id = d.pop("slack_user_id")
+
+ installed = d.pop("installed")
+
+ created_at = datetime.datetime.fromisoformat(d.pop("created_at"))
+
+
+
+
+ slack_connection = cls(
+ id=id,
+ team_id=team_id,
+ team_name=team_name,
+ slack_user_id=slack_user_id,
+ installed=installed,
+ created_at=created_at,
+ )
+
+
+ slack_connection.additional_properties = d
+ return slack_connection
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/slack_connections_response.py b/src/volcano_sdk/_generated/models/slack_connections_response.py
new file mode 100644
index 00000000..2f727663
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/slack_connections_response.py
@@ -0,0 +1,94 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.slack_connection import SlackConnection
+
+
+
+
+
+T = TypeVar("T", bound="SlackConnectionsResponse")
+
+
+
+@_attrs_define
+class SlackConnectionsResponse:
+ """
+ Attributes:
+ connections (list[SlackConnection]):
+ """
+
+ connections: list[SlackConnection]
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.slack_connection import SlackConnection # noqa: PLC0415
+ connections = []
+ for connections_item_data in self.connections:
+ connections_item = connections_item_data.to_dict()
+ connections.append(connections_item)
+
+
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "connections": connections,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.slack_connection import SlackConnection # noqa: PLC0415
+ d = dict(src_dict)
+ connections = []
+ _connections = d.pop("connections")
+ for connections_item_data in (_connections):
+ connections_item = SlackConnection.from_dict(connections_item_data)
+
+
+
+ connections.append(connections_item)
+
+
+ slack_connections_response = cls(
+ connections=connections,
+ )
+
+
+ slack_connections_response.additional_properties = d
+ return slack_connections_response
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/slack_connector.py b/src/volcano_sdk/_generated/models/slack_connector.py
new file mode 100644
index 00000000..4a1b3667
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/slack_connector.py
@@ -0,0 +1,77 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+
+T = TypeVar("T", bound="SlackConnector")
+
+
+
+@_attrs_define
+class SlackConnector:
+ """ A `slack` connector's workspace. Present when `type` is `slack`.
+
+ Attributes:
+ team_id (str): A Slack workspace ID, such as `T0123ABCD`.
+ """
+
+ team_id: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ team_id = self.team_id
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "team_id": team_id,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ team_id = d.pop("team_id")
+
+ slack_connector = cls(
+ team_id=team_id,
+ )
+
+
+ slack_connector.additional_properties = d
+ return slack_connector
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/src/volcano_sdk/_generated/models/update_auth_config_request.py b/src/volcano_sdk/_generated/models/update_auth_config_request.py
index 7da93df3..c86f5a6d 100644
--- a/src/volcano_sdk/_generated/models/update_auth_config_request.py
+++ b/src/volcano_sdk/_generated/models/update_auth_config_request.py
@@ -52,6 +52,7 @@ class UpdateAuthConfigRequest:
'http://localhost:3000'].
cors_allow_credentials (bool | Unset):
cors_max_age (int | Unset):
+ cors_allow_frontend_previews (bool | Unset): Allow the origins of the project's own live frontend previews.
enable_anonymous_signins (bool | Unset):
allowed_email_domains (list[str] | Unset): Replaces the email domain allowlist. Empty array removes the
restriction so any domain can sign up. Entries must be bare domains
@@ -79,17 +80,27 @@ class UpdateAuthConfigRequest:
the same email instead of returning a conflict. Requires require_email_confirmation to be true.
email_enabled (bool | Unset): Enable transactional email sending. Cannot be false while
require_email_confirmation is true.
- email_from_address (str | Unset):
- email_from_name (str | Unset):
+ email_from_address (str | Unset): Sender email address. New or changed values containing carriage returns or
+ newlines return 400. Unchanged stored or exported values are preserved. Leading and trailing whitespace in
+ previously saved settings is ignored when sending.
+ email_from_name (str | Unset): Sender display name; supports punctuation and Unicode. New or changed values
+ containing carriage returns or newlines return 400. Unchanged stored or exported values are preserved. Leading
+ and trailing whitespace in previously saved settings is ignored when sending.
smtp_host (str | Unset):
smtp_port (int | Unset):
smtp_username (str | Unset):
smtp_password (str | Unset): Replacement SMTP password. Omit this field to preserve the configured password. The
value is encrypted at rest and never returned.
smtp_use_tls (bool | Unset):
- email_confirmation_subject (str | Unset):
- email_password_reset_subject (str | Unset):
- email_password_changed_subject (str | Unset):
+ email_confirmation_subject (str | Unset): Subject template. For new or changed values, literal interior carriage
+ returns or newlines after Go template whitespace trimming return 400. Outer whitespace and trailing block-scalar
+ newlines are allowed. Unchanged stored subjects are preserved.
+ email_password_reset_subject (str | Unset): Subject template. For new or changed values, literal interior
+ carriage returns or newlines after Go template whitespace trimming return 400. Outer whitespace and trailing
+ block-scalar newlines are allowed. Unchanged stored subjects are preserved.
+ email_password_changed_subject (str | Unset): Subject template. For new or changed values, literal interior
+ carriage returns or newlines after Go template whitespace trimming return 400. Outer whitespace and trailing
+ block-scalar newlines are allowed. Unchanged stored subjects are preserved.
managed_auth_enabled (bool | Unset): Enable or disable managed auth hosted pages for the project.
post_auth_redirect_url (str | Unset): Must be included in allowed_redirect_urls when set.
allowed_redirect_urls (list[str] | Unset): Redirect allowlist. Every entry must be a valid http/https URL.
@@ -121,6 +132,7 @@ class UpdateAuthConfigRequest:
cors_allowed_origins: list[str] | Unset = UNSET
cors_allow_credentials: bool | Unset = UNSET
cors_max_age: int | Unset = UNSET
+ cors_allow_frontend_previews: bool | Unset = UNSET
enable_anonymous_signins: bool | Unset = UNSET
allowed_email_domains: list[str] | Unset = UNSET
allowed_email_domains_mode: UpdateAuthConfigRequestAllowedEmailDomainsMode | Unset = UNSET
@@ -199,6 +211,8 @@ def to_dict(self) -> dict[str, Any]:
cors_max_age = self.cors_max_age
+ cors_allow_frontend_previews = self.cors_allow_frontend_previews
+
enable_anonymous_signins = self.enable_anonymous_signins
allowed_email_domains: list[str] | Unset = UNSET
@@ -307,6 +321,8 @@ def to_dict(self) -> dict[str, Any]:
field_dict["cors_allow_credentials"] = cors_allow_credentials
if cors_max_age is not UNSET:
field_dict["cors_max_age"] = cors_max_age
+ if cors_allow_frontend_previews is not UNSET:
+ field_dict["cors_allow_frontend_previews"] = cors_allow_frontend_previews
if enable_anonymous_signins is not UNSET:
field_dict["enable_anonymous_signins"] = enable_anonymous_signins
if allowed_email_domains is not UNSET:
@@ -408,6 +424,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
cors_max_age = d.pop("cors_max_age", UNSET)
+ cors_allow_frontend_previews = d.pop("cors_allow_frontend_previews", UNSET)
+
enable_anonymous_signins = d.pop("enable_anonymous_signins", UNSET)
allowed_email_domains = cast(list[str], d.pop("allowed_email_domains", UNSET))
@@ -490,6 +508,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
cors_allowed_origins=cors_allowed_origins,
cors_allow_credentials=cors_allow_credentials,
cors_max_age=cors_max_age,
+ cors_allow_frontend_previews=cors_allow_frontend_previews,
enable_anonymous_signins=enable_anonymous_signins,
allowed_email_domains=allowed_email_domains,
allowed_email_domains_mode=allowed_email_domains_mode,
diff --git a/src/volcano_sdk/_generated/models/update_autofix_settings_request.py b/src/volcano_sdk/_generated/models/update_autofix_settings_request.py
deleted file mode 100644
index 272b6b10..00000000
--- a/src/volcano_sdk/_generated/models/update_autofix_settings_request.py
+++ /dev/null
@@ -1,147 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Mapping
-from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
-
-from attrs import define as _attrs_define
-from attrs import field as _attrs_field
-
-from ..types import UNSET, Unset
-
-from ..models.autofix_model import AutofixModel
-from ..models.autofix_model import check_autofix_model
-from ..models.autofix_provider import AutofixProvider
-from ..models.autofix_provider import check_autofix_provider
-from ..models.autofix_stage import AutofixStage
-from ..models.autofix_stage import check_autofix_stage
-from ..types import UNSET, Unset
-from typing import cast
-
-
-
-
-
-
-T = TypeVar("T", bound="UpdateAutofixSettingsRequest")
-
-
-
-@_attrs_define
-class UpdateAutofixSettingsRequest:
- """
- Attributes:
- enabled (bool):
- max_stage (AutofixStage | Unset): How far a run may go. `diagnose` stops at a root-cause diagnosis.
- `pull_request` may also open a draft pull request with a fix in the project's connected repository.
- auto_trigger (bool | Unset): Default: False.
- provider (AutofixProvider | Unset): Who serves the model. `volcano` runs on Volcano's models. `anthropic` runs
- on your own Anthropic API key.
- model (AutofixModel | Unset): The Claude model a run uses. `claude-opus-5-5` is the default.
- api_key (str | Unset): Your own API key for `provider`, such as an Anthropic key for `anthropic`. Omit it to
- keep the stored key. Encrypted at rest and never returned.
- """
-
- enabled: bool
- max_stage: AutofixStage | Unset = UNSET
- auto_trigger: bool | Unset = False
- provider: AutofixProvider | Unset = UNSET
- model: AutofixModel | Unset = UNSET
- api_key: str | Unset = UNSET
-
-
-
-
-
- def to_dict(self) -> dict[str, Any]:
- enabled = self.enabled
-
- max_stage: str | Unset = UNSET
- if not isinstance(self.max_stage, Unset):
- max_stage = self.max_stage
-
-
- auto_trigger = self.auto_trigger
-
- provider: str | Unset = UNSET
- if not isinstance(self.provider, Unset):
- provider = self.provider
-
-
- model: str | Unset = UNSET
- if not isinstance(self.model, Unset):
- model = self.model
-
-
- api_key = self.api_key
-
-
- field_dict: dict[str, Any] = {}
-
- field_dict.update({
- "enabled": enabled,
- })
- if max_stage is not UNSET:
- field_dict["max_stage"] = max_stage
- if auto_trigger is not UNSET:
- field_dict["auto_trigger"] = auto_trigger
- if provider is not UNSET:
- field_dict["provider"] = provider
- if model is not UNSET:
- field_dict["model"] = model
- if api_key is not UNSET:
- field_dict["api_key"] = api_key
-
- return field_dict
-
-
-
- @classmethod
- def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
- d = dict(src_dict)
- enabled = d.pop("enabled")
-
- _max_stage = d.pop("max_stage", UNSET)
- max_stage: AutofixStage | Unset
- if isinstance(_max_stage, Unset):
- max_stage = UNSET
- else:
- max_stage = check_autofix_stage(_max_stage)
-
-
-
-
- auto_trigger = d.pop("auto_trigger", UNSET)
-
- _provider = d.pop("provider", UNSET)
- provider: AutofixProvider | Unset
- if isinstance(_provider, Unset):
- provider = UNSET
- else:
- provider = check_autofix_provider(_provider)
-
-
-
-
- _model = d.pop("model", UNSET)
- model: AutofixModel | Unset
- if isinstance(_model, Unset):
- model = UNSET
- else:
- model = check_autofix_model(_model)
-
-
-
-
- api_key = d.pop("api_key", UNSET)
-
- update_autofix_settings_request = cls(
- enabled=enabled,
- max_stage=max_stage,
- auto_trigger=auto_trigger,
- provider=provider,
- model=model,
- api_key=api_key,
- )
-
- return update_autofix_settings_request
-
diff --git a/src/volcano_sdk/_generated/models/update_email_template_request.py b/src/volcano_sdk/_generated/models/update_email_template_request.py
index dc903645..ceac7294 100644
--- a/src/volcano_sdk/_generated/models/update_email_template_request.py
+++ b/src/volcano_sdk/_generated/models/update_email_template_request.py
@@ -23,7 +23,9 @@
class UpdateEmailTemplateRequest:
"""
Attributes:
- subject (str | Unset):
+ subject (str | Unset): Subject template. For new or changed values, literal interior carriage returns or
+ newlines after Go template whitespace trimming return 400. Outer whitespace and trailing block-scalar newlines
+ are allowed. Unchanged stored subjects are preserved.
html_body (str | Unset):
text_body (str | Unset):
"""
diff --git a/src/volcano_sdk/_generated/models/update_frontend_custom_domain_request.py b/src/volcano_sdk/_generated/models/update_frontend_custom_domain_request.py
new file mode 100644
index 00000000..0cda6df0
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/update_frontend_custom_domain_request.py
@@ -0,0 +1,84 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.frontend_custom_domain_redirect_request import FrontendCustomDomainRedirectRequest
+
+
+
+
+
+T = TypeVar("T", bound="UpdateFrontendCustomDomainRequest")
+
+
+
+@_attrs_define
+class UpdateFrontendCustomDomainRequest:
+ """
+ Attributes:
+ redirect (FrontendCustomDomainRedirectRequest | None): The redirect to set, or null to make the domain serve the
+ frontend.
+ """
+
+ redirect: FrontendCustomDomainRedirectRequest | None
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.frontend_custom_domain_redirect_request import FrontendCustomDomainRedirectRequest # noqa: PLC0415
+ redirect: dict[str, Any] | None
+ if isinstance(self.redirect, FrontendCustomDomainRedirectRequest):
+ redirect = self.redirect.to_dict()
+ else:
+ redirect = self.redirect
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "redirect": redirect,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.frontend_custom_domain_redirect_request import FrontendCustomDomainRedirectRequest # noqa: PLC0415
+ d = dict(src_dict)
+ def _parse_redirect(data: object) -> FrontendCustomDomainRedirectRequest | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ redirect_type_1 = FrontendCustomDomainRedirectRequest.from_dict(data)
+
+
+
+ return redirect_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(FrontendCustomDomainRedirectRequest | None, data)
+
+ redirect = _parse_redirect(d.pop("redirect"))
+
+
+ update_frontend_custom_domain_request = cls(
+ redirect=redirect,
+ )
+
+ return update_frontend_custom_domain_request
+
diff --git a/src/volcano_sdk/_generated/models/update_issue_request.py b/src/volcano_sdk/_generated/models/update_issue_request.py
index 4ac87a7c..5eba1dde 100644
--- a/src/volcano_sdk/_generated/models/update_issue_request.py
+++ b/src/volcano_sdk/_generated/models/update_issue_request.py
@@ -26,7 +26,9 @@ class UpdateIssueRequest:
"""
Attributes:
status (IssueStatus): `open` until someone resolves or ignores the issue. A resolved issue
- seen again reopens.
+ seen again reopens. A reported problem resolves when its LavaFlow fix
+ merges. Volcano ignores one whose report it deleted before any fix
+ merged, so it no longer counts toward the project's open issues.
"""
status: IssueStatus
diff --git a/src/volcano_sdk/_generated/models/update_notification_email.py b/src/volcano_sdk/_generated/models/update_notification_email.py
new file mode 100644
index 00000000..c149c6be
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/update_notification_email.py
@@ -0,0 +1,77 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="UpdateNotificationEmail")
+
+
+
+@_attrs_define
+class UpdateNotificationEmail:
+ """
+ Attributes:
+ enabled (bool | Unset):
+ recipients (list[str] | Unset): Only the project owner's verified account email address is supported. An empty
+ list, or one naming only that address, emails the owner and is saved as an empty list. Any other list is refused
+ as invalid.
+ """
+
+ enabled: bool | Unset = UNSET
+ recipients: list[str] | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ enabled = self.enabled
+
+ recipients: list[str] | Unset = UNSET
+ if not isinstance(self.recipients, Unset):
+ recipients = self.recipients
+
+
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ })
+ if enabled is not UNSET:
+ field_dict["enabled"] = enabled
+ if recipients is not UNSET:
+ field_dict["recipients"] = recipients
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ enabled = d.pop("enabled", UNSET)
+
+ recipients = cast(list[str], d.pop("recipients", UNSET))
+
+
+ update_notification_email = cls(
+ enabled=enabled,
+ recipients=recipients,
+ )
+
+ return update_notification_email
+
diff --git a/src/volcano_sdk/_generated/models/update_notification_settings_request.py b/src/volcano_sdk/_generated/models/update_notification_settings_request.py
new file mode 100644
index 00000000..5abfb2a3
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/update_notification_settings_request.py
@@ -0,0 +1,120 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.update_notification_email import UpdateNotificationEmail
+ from ..models.update_notification_webhook import UpdateNotificationWebhook
+ from ..models.update_scheduler_failure_alert_policy import UpdateSchedulerFailureAlertPolicy
+
+
+
+
+
+T = TypeVar("T", bound="UpdateNotificationSettingsRequest")
+
+
+
+@_attrs_define
+class UpdateNotificationSettingsRequest:
+ """ Omitted fields keep their current values.
+
+ Attributes:
+ email (UpdateNotificationEmail | Unset):
+ webhook (UpdateNotificationWebhook | Unset):
+ scheduler_failures (UpdateSchedulerFailureAlertPolicy | Unset):
+ """
+
+ email: UpdateNotificationEmail | Unset = UNSET
+ webhook: UpdateNotificationWebhook | Unset = UNSET
+ scheduler_failures: UpdateSchedulerFailureAlertPolicy | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.update_notification_email import UpdateNotificationEmail # noqa: PLC0415
+ from ..models.update_notification_webhook import UpdateNotificationWebhook # noqa: PLC0415
+ from ..models.update_scheduler_failure_alert_policy import UpdateSchedulerFailureAlertPolicy # noqa: PLC0415
+ email: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.email, Unset):
+ email = self.email.to_dict()
+
+ webhook: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.webhook, Unset):
+ webhook = self.webhook.to_dict()
+
+ scheduler_failures: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.scheduler_failures, Unset):
+ scheduler_failures = self.scheduler_failures.to_dict()
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ })
+ if email is not UNSET:
+ field_dict["email"] = email
+ if webhook is not UNSET:
+ field_dict["webhook"] = webhook
+ if scheduler_failures is not UNSET:
+ field_dict["scheduler_failures"] = scheduler_failures
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.update_notification_email import UpdateNotificationEmail # noqa: PLC0415
+ from ..models.update_notification_webhook import UpdateNotificationWebhook # noqa: PLC0415
+ from ..models.update_scheduler_failure_alert_policy import UpdateSchedulerFailureAlertPolicy # noqa: PLC0415
+ d = dict(src_dict)
+ _email = d.pop("email", UNSET)
+ email: UpdateNotificationEmail | Unset
+ if isinstance(_email, Unset):
+ email = UNSET
+ else:
+ email = UpdateNotificationEmail.from_dict(_email)
+
+
+
+
+ _webhook = d.pop("webhook", UNSET)
+ webhook: UpdateNotificationWebhook | Unset
+ if isinstance(_webhook, Unset):
+ webhook = UNSET
+ else:
+ webhook = UpdateNotificationWebhook.from_dict(_webhook)
+
+
+
+
+ _scheduler_failures = d.pop("scheduler_failures", UNSET)
+ scheduler_failures: UpdateSchedulerFailureAlertPolicy | Unset
+ if isinstance(_scheduler_failures, Unset):
+ scheduler_failures = UNSET
+ else:
+ scheduler_failures = UpdateSchedulerFailureAlertPolicy.from_dict(_scheduler_failures)
+
+
+
+
+ update_notification_settings_request = cls(
+ email=email,
+ webhook=webhook,
+ scheduler_failures=scheduler_failures,
+ )
+
+ return update_notification_settings_request
+
diff --git a/src/volcano_sdk/_generated/models/update_notification_webhook.py b/src/volcano_sdk/_generated/models/update_notification_webhook.py
new file mode 100644
index 00000000..92e9f7b2
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/update_notification_webhook.py
@@ -0,0 +1,61 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..types import UNSET, Unset
+
+
+
+
+
+
+T = TypeVar("T", bound="UpdateNotificationWebhook")
+
+
+
+@_attrs_define
+class UpdateNotificationWebhook:
+ """
+ Attributes:
+ url (str | Unset): An `http` or `https` URL. Surrounding whitespace is trimmed. An empty string removes the
+ webhook and its secret.
+ """
+
+ url: str | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ url = self.url
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ })
+ if url is not UNSET:
+ field_dict["url"] = url
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ url = d.pop("url", UNSET)
+
+ update_notification_webhook = cls(
+ url=url,
+ )
+
+ return update_notification_webhook
+
diff --git a/src/volcano_sdk/_generated/models/update_project_git_deploy_settings_request.py b/src/volcano_sdk/_generated/models/update_project_git_deploy_settings_request.py
index 9b0a713e..3d47d83f 100644
--- a/src/volcano_sdk/_generated/models/update_project_git_deploy_settings_request.py
+++ b/src/volcano_sdk/_generated/models/update_project_git_deploy_settings_request.py
@@ -21,20 +21,31 @@
@_attrs_define
class UpdateProjectGitDeploySettingsRequest:
- """ Full replace of a project's Git auto-deploy settings.
+ """ Full replace of a project's Git auto-deploy settings, except apply_migrations, which keeps its saved value when
+ omitted.
Attributes:
auto_deploy_enabled (bool):
deploy_functions (bool):
- frontend_name (str | Unset): Frontend to deploy on push. Omit or empty to deploy no frontend.
+ frontend_name (str | Unset): Legacy frontend to deploy on push. In Git mode, explicitly send an empty string to
+ stop deploying the selected frontend; omit frontend_app_root too. This keeps the serving frontend and Git
+ handover intact. Omitting an existing selection or renaming it is refused in Git mode. In platform mode, omit or
+ empty to deploy no frontend. Explicit source-layout mappings are independent of this legacy selection.
frontend_app_root (str | Unset): App root the frontend builds from. Requires frontend_name; omit for the repo
root.
+ apply_migrations (bool | Unset): Apply the commit's pending migrations before each push deploys. Anyone who can
+ push to the production branch can then run any SQL as the database owner, so protect that branch first. Off
+ until set. Omit to leave the saved value unchanged. Turning it on answers `400` with code `feature_unavailable`
+ where the `databases.migrations` capability is unavailable; `false`, or the saved `true` sent back, is accepted
+ even there. While the project owner's account is `read_only`, the request answers `403` whatever it sends; an
+ `inactive` owner's credentials answer `401`.
"""
auto_deploy_enabled: bool
deploy_functions: bool
frontend_name: str | Unset = UNSET
frontend_app_root: str | Unset = UNSET
+ apply_migrations: bool | Unset = UNSET
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
@@ -50,6 +61,8 @@ def to_dict(self) -> dict[str, Any]:
frontend_app_root = self.frontend_app_root
+ apply_migrations = self.apply_migrations
+
field_dict: dict[str, Any] = {}
field_dict.update(self.additional_properties)
@@ -61,6 +74,8 @@ def to_dict(self) -> dict[str, Any]:
field_dict["frontend_name"] = frontend_name
if frontend_app_root is not UNSET:
field_dict["frontend_app_root"] = frontend_app_root
+ if apply_migrations is not UNSET:
+ field_dict["apply_migrations"] = apply_migrations
return field_dict
@@ -77,11 +92,14 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
frontend_app_root = d.pop("frontend_app_root", UNSET)
+ apply_migrations = d.pop("apply_migrations", UNSET)
+
update_project_git_deploy_settings_request = cls(
auto_deploy_enabled=auto_deploy_enabled,
deploy_functions=deploy_functions,
frontend_name=frontend_name,
frontend_app_root=frontend_app_root,
+ apply_migrations=apply_migrations,
)
diff --git a/src/volcano_sdk/_generated/models/update_scheduler_failure_alert_policy.py b/src/volcano_sdk/_generated/models/update_scheduler_failure_alert_policy.py
new file mode 100644
index 00000000..5044f08d
--- /dev/null
+++ b/src/volcano_sdk/_generated/models/update_scheduler_failure_alert_policy.py
@@ -0,0 +1,94 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from ..models.scheduler_failure_notify_on import check_scheduler_failure_notify_on
+from ..models.scheduler_failure_notify_on import SchedulerFailureNotifyOn
+from ..types import UNSET, Unset
+from typing import cast
+
+
+
+
+
+
+T = TypeVar("T", bound="UpdateSchedulerFailureAlertPolicy")
+
+
+
+@_attrs_define
+class UpdateSchedulerFailureAlertPolicy:
+ """
+ Attributes:
+ notify_on (SchedulerFailureNotifyOn | Unset): When a failing scheduler is announced: on its first failed run, or
+ once `threshold` runs in a row have failed. Either way a streak is announced once, and a scheduler is announced
+ failing at most once an hour.
+ threshold (int | Unset):
+ notify_on_recovery (bool | Unset):
+ """
+
+ notify_on: SchedulerFailureNotifyOn | Unset = UNSET
+ threshold: int | Unset = UNSET
+ notify_on_recovery: bool | Unset = UNSET
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ notify_on: str | Unset = UNSET
+ if not isinstance(self.notify_on, Unset):
+ notify_on = self.notify_on
+
+
+ threshold = self.threshold
+
+ notify_on_recovery = self.notify_on_recovery
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ })
+ if notify_on is not UNSET:
+ field_dict["notify_on"] = notify_on
+ if threshold is not UNSET:
+ field_dict["threshold"] = threshold
+ if notify_on_recovery is not UNSET:
+ field_dict["notify_on_recovery"] = notify_on_recovery
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ _notify_on = d.pop("notify_on", UNSET)
+ notify_on: SchedulerFailureNotifyOn | Unset
+ if isinstance(_notify_on, Unset):
+ notify_on = UNSET
+ else:
+ notify_on = check_scheduler_failure_notify_on(_notify_on)
+
+
+
+
+ threshold = d.pop("threshold", UNSET)
+
+ notify_on_recovery = d.pop("notify_on_recovery", UNSET)
+
+ update_scheduler_failure_alert_policy = cls(
+ notify_on=notify_on,
+ threshold=threshold,
+ notify_on_recovery=notify_on_recovery,
+ )
+
+ return update_scheduler_failure_alert_policy
+
diff --git a/src/volcano_sdk/_tests/test_auth_parser_boundaries.py b/src/volcano_sdk/_tests/test_auth_parser_boundaries.py
index 9c333a5a..e185ea0d 100644
--- a/src/volcano_sdk/_tests/test_auth_parser_boundaries.py
+++ b/src/volcano_sdk/_tests/test_auth_parser_boundaries.py
@@ -23,7 +23,6 @@
from volcano_sdk._generated.models import (
AuthGetUserResponse200,
AuthListOAuthProvidersResponse200,
- AuthListOAuthProvidersResponse200ProvidersItem,
CallOAuthProviderApiResponse200,
)
from volcano_sdk._generated.types import UNSET, Unset
@@ -248,8 +247,36 @@ def test_linked_providers_require_the_collection_to_be_present() -> None:
@pytest.mark.parametrize("provider", [UNSET, "", " \t"])
def test_linked_providers_require_a_nonempty_provider(provider: str | Unset) -> None:
- payload = AuthListOAuthProvidersResponse200(
- providers=[AuthListOAuthProvidersResponse200ProvidersItem(provider=provider)]
+ payload = AuthListOAuthProvidersResponse200.from_dict(
+ {
+ "providers": [
+ {
+ "provider": provider,
+ "provider_user_id": "583231",
+ "linked_at": "2026-08-30T12:00:00Z",
+ "updated_at": "2026-09-01T12:00:00Z",
+ }
+ ]
+ }
+ )
+ with pytest.raises(VolcanoError, match="Expected complete linked OAuth providers"):
+ _ = linked_oauth_providers_from_payload(payload)
+
+
+@pytest.mark.parametrize("provider", [None, False, 42, [], {}])
+def test_linked_providers_reject_nonstring_wire_values(provider: object) -> None:
+ payload = AuthListOAuthProvidersResponse200.from_dict(
+ {
+ "providers": [
+ {
+ "provider": provider,
+ "provider_user_id": "583231",
+ "linked_at": "2026-08-30T12:00:00Z",
+ "updated_at": "2026-09-01T12:00:00Z",
+ }
+ ]
+ }
)
+
with pytest.raises(VolcanoError, match="Expected complete linked OAuth providers"):
_ = linked_oauth_providers_from_payload(payload)
diff --git a/src/volcano_sdk/_tests/test_generated_transport.py b/src/volcano_sdk/_tests/test_generated_transport.py
index e79a811f..fe8e4692 100644
--- a/src/volcano_sdk/_tests/test_generated_transport.py
+++ b/src/volcano_sdk/_tests/test_generated_transport.py
@@ -29,6 +29,8 @@
response_payload,
)
+from .test_auth_facade_recovery import client_for
+
def test_generated_transport_queries_a_database_asynchronously() -> None:
requests: list[httpx.Request] = []
@@ -606,6 +608,7 @@ def handle(request: httpx.Request) -> httpx.Response:
"providers": [
{
"provider": "google",
+ "provider_user_id": "583231",
"linked_at": "2026-08-30T12:00:00Z",
"updated_at": "2026-09-01T12:00:00Z",
}
@@ -638,6 +641,23 @@ def test_generated_transport_rejects_malformed_linked_oauth_providers() -> None:
_ = transport.auth_list_oauth_providers(authorization="access-token")
+@pytest.mark.parametrize("field", ["provider", "linked_at", "updated_at"])
+def test_auth_facade_rejects_missing_oauth_public_fields(field: str) -> None:
+ provider = {
+ "provider": "google",
+ "provider_user_id": "583231",
+ "linked_at": "2026-08-30T12:00:00Z",
+ "updated_at": "2026-09-01T12:00:00Z",
+ }
+ del provider[field]
+ client = client_for(
+ lambda _request: httpx.Response(200, json={"providers": [provider]})
+ )
+
+ with pytest.raises(VolcanoError, match="Expected complete linked OAuth providers"):
+ _ = client.auth.list_linked_oauth_providers()
+
+
def test_generated_transport_preserves_a_malformed_oauth_auth_error() -> None:
transport = GeneratedTransport(
api_url="https://api.test.volcano.dev",
diff --git a/src/volcano_sdk/_tests/test_managed_tls_contract.py b/src/volcano_sdk/_tests/test_managed_tls_contract.py
index 51317c61..357325a2 100644
--- a/src/volcano_sdk/_tests/test_managed_tls_contract.py
+++ b/src/volcano_sdk/_tests/test_managed_tls_contract.py
@@ -58,6 +58,7 @@ def domain_payload() -> dict[str, object]:
"verification_status": "pending",
"routing_target_hostname": ROUTING_TARGET,
"effective_urls": [f"https://{ROUTING_TARGET}/"],
+ "redirect": None,
"created_at": "2026-09-02T12:00:00Z",
"updated_at": "2026-09-02T12:00:00Z",
}
diff --git a/src/volcano_sdk/_tests/test_oauth_transport_compatibility.py b/src/volcano_sdk/_tests/test_oauth_transport_compatibility.py
new file mode 100644
index 00000000..fbc082fd
--- /dev/null
+++ b/src/volcano_sdk/_tests/test_oauth_transport_compatibility.py
@@ -0,0 +1,137 @@
+from __future__ import annotations
+
+from datetime import datetime, timedelta, timezone
+from typing import TYPE_CHECKING
+
+import httpx
+import pytest
+
+from volcano_sdk import LinkedOAuthProvider, VolcanoError
+
+from .test_auth_facade_recovery import client_for
+
+if TYPE_CHECKING:
+ from volcano_sdk.models import JSONValue
+
+
+def provider_payload() -> dict[str, JSONValue]:
+ return {
+ "provider": "future-provider",
+ "linked_at": "2026-08-30T12:00:00Z",
+ "updated_at": "2026-09-01T12:00:00Z",
+ }
+
+
+@pytest.mark.parametrize(
+ "identity",
+ [{}, {"provider_user_id": "583231", "provider_login": "octocat"}],
+ ids=["legacy-three-fields", "current-five-fields"],
+)
+def test_linked_providers_preserve_legacy_and_current_wire_responses(
+ identity: dict[str, JSONValue],
+) -> None:
+ requests: list[httpx.Request] = []
+
+ def handle(request: httpx.Request) -> httpx.Response:
+ requests.append(request)
+ return httpx.Response(
+ 200, json={"providers": [{**provider_payload(), **identity}]}
+ )
+
+ client = client_for(handle)
+ original = client.current_session
+
+ result = client.auth.list_linked_oauth_providers()
+
+ assert result == (
+ LinkedOAuthProvider(
+ provider="future-provider",
+ linked_at=datetime.fromisoformat("2026-08-30T12:00:00+00:00"),
+ updated_at=datetime.fromisoformat("2026-09-01T12:00:00+00:00"),
+ ),
+ )
+ assert [(request.method, request.url.path) for request in requests] == [
+ ("GET", "/auth/oauth/providers")
+ ]
+ assert original is not None
+ assert requests[0].headers["authorization"] == f"Bearer {original.access_token}"
+ assert client.current_session is original
+
+
+@pytest.mark.parametrize("field", ["provider", "linked_at", "updated_at"])
+@pytest.mark.parametrize("value", [None, False, 42, [], {}, "", " \t"])
+def test_linked_provider_wire_values_keep_native_validation(
+ field: str, value: JSONValue
+) -> None:
+ provider = {**provider_payload(), field: value}
+ client = client_for(
+ lambda _request: httpx.Response(200, json={"providers": [provider]})
+ )
+ original = client.current_session
+
+ with pytest.raises(VolcanoError, match="Expected complete linked OAuth providers"):
+ _ = client.auth.list_linked_oauth_providers()
+
+ assert client.current_session is original
+
+
+@pytest.mark.parametrize("field", ["linked_at", "updated_at"])
+@pytest.mark.parametrize(
+ "value",
+ [
+ "2026-02-30T12:00:00Z",
+ "2026-08-30T12:00:00",
+ "2026-08-30",
+ "2026-08-30T12:00:00+24:00",
+ "2026-08-30T12:00:00+05:60",
+ "2026-08-30T12:00:00-24:00",
+ "2026-08-30T12:00:00-05:60",
+ "2026-08-30T24:00:00Z",
+ "2026-08-30T12:00:60Z",
+ ],
+)
+def test_linked_provider_wire_dates_reject_invalid_calendar_values(
+ field: str, value: str
+) -> None:
+ provider = {**provider_payload(), field: value}
+ client = client_for(
+ lambda _request: httpx.Response(200, json={"providers": [provider]})
+ )
+
+ with pytest.raises(VolcanoError, match="Expected complete linked OAuth providers"):
+ _ = client.auth.list_linked_oauth_providers()
+
+
+def test_linked_provider_wire_dates_preserve_fractional_offsets() -> None:
+ provider = {
+ **provider_payload(),
+ "linked_at": "2026-08-30T12:00:00.123456+05:30",
+ "updated_at": "2026-08-30T12:00:00.123456+05:30",
+ }
+ client = client_for(
+ lambda _request: httpx.Response(200, json={"providers": [provider]})
+ )
+
+ result = client.auth.list_linked_oauth_providers()
+
+ expected = datetime(
+ 2026, 8, 30, 12, 0, 0, 123456, tzinfo=timezone(timedelta(hours=5, minutes=30))
+ )
+ assert (result[0].linked_at, result[0].updated_at) == (expected, expected)
+
+
+def test_linked_providers_accept_an_empty_wire_collection() -> None:
+ client = client_for(lambda _request: httpx.Response(200, json={"providers": []}))
+
+ assert client.auth.list_linked_oauth_providers() == ()
+
+
+@pytest.mark.parametrize(
+ "payload",
+ [None, [], {}, {"providers": None}, {"providers": {}}, {"providers": [None]}],
+)
+def test_linked_provider_wire_collection_must_be_complete(payload: JSONValue) -> None:
+ client = client_for(lambda _request: httpx.Response(200, json=payload))
+
+ with pytest.raises(VolcanoError, match="Expected complete linked OAuth providers"):
+ _ = client.auth.list_linked_oauth_providers()
diff --git a/src/volcano_sdk/_tests/test_state.py b/src/volcano_sdk/_tests/test_state.py
index 2d5037af..7bd1d984 100644
--- a/src/volcano_sdk/_tests/test_state.py
+++ b/src/volcano_sdk/_tests/test_state.py
@@ -56,7 +56,7 @@
from volcano_sdk._generated.models.refresh_o_auth_provider_token_response_200 import (
RefreshOAuthProviderTokenResponse200,
)
-from volcano_sdk._generated.types import Unset
+from volcano_sdk._generated.types import UNSET, Unset
from volcano_sdk.database import QueryBuilder
from .client_inspection import InspectedClient
@@ -205,6 +205,7 @@ def _linked_oauth_providers() -> AuthListOAuthProvidersResponse200:
"providers": [
{
"provider": "google",
+ "provider_user_id": "583231",
"linked_at": "2026-08-30T12:00:00Z",
"updated_at": "2026-09-01T12:00:00Z",
}
@@ -1943,16 +1944,18 @@ def test_list_linked_oauth_providers_requires_a_current_session() -> None:
assert transport.list_oauth_providers_calls == []
-def test_list_linked_oauth_providers_rejects_an_incomplete_item() -> None:
+def test_list_linked_oauth_providers_rejects_an_incomplete_item(
+ monkeypatch: pytest.MonkeyPatch,
+) -> None:
transport = StateTransport()
client = InspectedClient(anon_key="anon", _transport=transport)
_ = client.auth.sign_in(email="user@example.com", password="secret")
- transport.list_oauth_providers_response = Response(
- 200,
- AuthListOAuthProvidersResponse200.from_dict(
- {"providers": [{"provider": "google"}]}
- ),
- )
+ payload = _linked_oauth_providers()
+ assert not isinstance(payload.providers, Unset)
+ # Custom transports can return incomplete models without wire parsing.
+ monkeypatch.setattr(payload.providers[0], "linked_at", UNSET)
+ monkeypatch.setattr(payload.providers[0], "updated_at", UNSET)
+ transport.list_oauth_providers_response = Response(200, payload)
with pytest.raises(VolcanoError, match="Expected complete linked OAuth providers"):
_ = client.auth.list_linked_oauth_providers()
@@ -1969,6 +1972,7 @@ def test_list_linked_oauth_providers_accepts_a_future_provider_name() -> None:
"providers": [
{
"provider": "future-provider",
+ "provider_user_id": "583231",
"linked_at": "2026-08-30T12:00:00Z",
"updated_at": "2026-09-01T12:00:00Z",
}
diff --git a/src/volcano_sdk/_transport_auth_account.py b/src/volcano_sdk/_transport_auth_account.py
index 5cf7358a..58e2fed7 100644
--- a/src/volcano_sdk/_transport_auth_account.py
+++ b/src/volcano_sdk/_transport_auth_account.py
@@ -45,9 +45,6 @@
from ._generated.models.auth_link_o_auth_provider_response_200 import (
AuthLinkOAuthProviderResponse200,
)
-from ._generated.models.auth_list_o_auth_providers_response_200 import (
- AuthListOAuthProvidersResponse200,
-)
from ._generated.models.auth_o_auth_exchange_body import AuthOAuthExchangeBody
from ._generated.models.call_o_auth_provider_api_body import CallOAuthProviderApiBody
from ._generated.models.call_o_auth_provider_api_response_200 import (
@@ -169,10 +166,10 @@ def auth_list_oauth_providers(
if response.status_code != HTTP_OK:
return unparsed_response(response)
try:
- payload = AuthListOAuthProvidersResponse200.from_dict(json_object(response))
+ # The stable facade uses provider and timestamps, including responses
+ # from servers that predate the additional provider identity fields.
+ payload = json_object(response)
except (
- AttributeError,
- KeyError,
TypeError,
UnicodeDecodeError,
ValueError,